Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
388 lines
13 KiB
TypeScript
388 lines
13 KiB
TypeScript
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
|
import { FormattedMessage, useAccess, useNavigate, useParams } from '@umijs/max';
|
|
import { Button, FormInstance, message, Tag } from 'antd';
|
|
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
|
import { FormOutlined, PlusOutlined, AlignLeftOutlined, SendOutlined, FilterOutlined, ArrowLeftOutlined } from '@ant-design/icons';
|
|
import { getDictValueEnum } from '@/services/system/dict';
|
|
import DictTag from '@/components/DictTag';
|
|
import { exportCmsAppUserExport } from '@/services/mobileusers/list';
|
|
import {
|
|
addCmsEmployeeConfirmList,
|
|
exportCmsJobCandidates,
|
|
getCmsJobIds,
|
|
} from '@/services/Management/list';
|
|
import similarityJobs from '@/utils/similarity_Job';
|
|
import Detail from './detail';
|
|
import Hire from './hire';
|
|
import InterviewInvite from '../ResumeRecommend/InterviewInvite';
|
|
import ResumeFilter from './resumeFilter';
|
|
|
|
|
|
const handleExport = async (values: API.MobileUser.ListParams) => {
|
|
const hide = message.loading('正在导出');
|
|
try {
|
|
await exportCmsAppUserExport(values);
|
|
hide();
|
|
message.success('导出成功');
|
|
return true;
|
|
} catch (error) {
|
|
hide();
|
|
message.error('导出失败,请重试');
|
|
return false;
|
|
}
|
|
};
|
|
|
|
function ManagementList() {
|
|
const access = useAccess();
|
|
const navigate = useNavigate();
|
|
|
|
const formTableRef = useRef<FormInstance>();
|
|
const actionRef = useRef<ActionType>();
|
|
|
|
const [jobId, setJobId] = useState<string>();
|
|
const [educationEnum, setEducationEnum] = useState<any>([]);
|
|
const [experienceEnum, setExperienceEnum] = useState<any>([]);
|
|
const [areaEnum, setAreaEnum] = useState<any>([]);
|
|
const [sexEnum, setSexEnum] = useState<any>([]);
|
|
const [hotEnum, setHotEnum] = useState<any>([]);
|
|
const [politicalEnum, setPoliticalEnum] = useState<any>([]);
|
|
const [contractTermEnum, setContractTermEnum] = useState<any>([]);
|
|
const [currentRow, setCurrentRow] = useState<API.MobileUser.ListRow>();
|
|
const [modalVisible, setModalVisible] = useState<boolean>(false);
|
|
const [hireVisible, setHireVisible] = useState<boolean>(false);
|
|
const [jobInfo, setJobInfo] = useState({});
|
|
const [matchingDegree, setMatchingDegree] = useState<any>(null);
|
|
const [inviteVisible, setInviteVisible] = useState<boolean>(false);
|
|
const [filterVisible, setFilterVisible] = useState<boolean>(false);
|
|
const [hireAdd, setHireAdd] = useState<any>(null);
|
|
const [mode, setMode] = useState<'view' | 'edit' | 'create'>('create');
|
|
const params = useParams();
|
|
const id = params.id || '0';
|
|
useEffect(() => {
|
|
if (jobId !== id) {
|
|
setJobId(id);
|
|
getJobInfo(id);
|
|
}
|
|
}, [jobId, params]);
|
|
|
|
const getJobInfo = async (jobId: string) => {
|
|
let resData = await getCmsJobIds(jobId);
|
|
if (resData.code === 200) {
|
|
similarityJobs.setJobInfo(resData.data);
|
|
setJobInfo(resData.data);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
getDictValueEnum('education', true, true).then((data) => {
|
|
setEducationEnum(data);
|
|
});
|
|
getDictValueEnum('experience', true, true).then((data) => {
|
|
setExperienceEnum(data);
|
|
});
|
|
getDictValueEnum('area', true, true).then((data) => {
|
|
setAreaEnum(data);
|
|
});
|
|
getDictValueEnum('sys_user_sex', true).then((data) => {
|
|
setSexEnum(data);
|
|
});
|
|
getDictValueEnum('political_affiliation', true, true).then((data) => {
|
|
setPoliticalEnum(data);
|
|
});
|
|
getDictValueEnum('contract_term', true, true).then((data) => {
|
|
setContractTermEnum(data);
|
|
});
|
|
}, []);
|
|
|
|
const columns: ProColumns<API.MobileUser.ListRow>[] = [
|
|
{
|
|
title: '用户名',
|
|
dataIndex: 'name',
|
|
valueType: 'text',
|
|
align: 'center',
|
|
},
|
|
{
|
|
title: '期望薪资',
|
|
dataIndex: 'minSalary',
|
|
valueType: 'text',
|
|
hideInSearch: true,
|
|
align: 'center',
|
|
render: (_, record) => (
|
|
<>
|
|
{record.salaryMin}-{record.salaryMax}
|
|
</>
|
|
),
|
|
},
|
|
{
|
|
title: '出生日期',
|
|
dataIndex: 'birthDate',
|
|
valueType: 'text',
|
|
align: 'center',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '学历要求',
|
|
dataIndex: 'education',
|
|
valueType: 'select',
|
|
align: 'center',
|
|
valueEnum: educationEnum,
|
|
render: (_, record) => {
|
|
return <DictTag enums={educationEnum} value={record.education} />;
|
|
},
|
|
},
|
|
{
|
|
title: '区域',
|
|
dataIndex: 'area',
|
|
valueType: 'select',
|
|
align: 'center',
|
|
valueEnum: areaEnum,
|
|
render: (_, record) => {
|
|
return <DictTag enums={areaEnum} value={record.area} />;
|
|
},
|
|
},
|
|
{
|
|
title: '性别',
|
|
dataIndex: 'sex',
|
|
valueType: 'select',
|
|
align: 'center',
|
|
valueEnum: sexEnum,
|
|
render: (_, record) => {
|
|
return <DictTag enums={sexEnum} value={record.sex} />;
|
|
},
|
|
},
|
|
{
|
|
title: '政治面貌',
|
|
dataIndex: 'politicalAffiliation',
|
|
valueType: 'select',
|
|
align: 'center',
|
|
valueEnum: politicalEnum,
|
|
render: (_, record) => {
|
|
return <DictTag enums={politicalEnum} value={record.politicalAffiliation} />;
|
|
},
|
|
},
|
|
{
|
|
title: '匹配度',
|
|
dataIndex: 'minSalary',
|
|
valueType: 'text',
|
|
hideInSearch: true,
|
|
align: 'center',
|
|
render: (_, record) => (
|
|
<>{similarityJobs.calculationMatchingDegreeJob(record).overallMatch}</>
|
|
),
|
|
},
|
|
{
|
|
title: '面试状态',
|
|
dataIndex: 'interviewStatus',
|
|
valueType: 'text',
|
|
hideInSearch: true,
|
|
align: 'center',
|
|
width: 100,
|
|
render: (_, record) => {
|
|
const statusMap: Record<string, { text: string; color: string }> = {
|
|
pending: { text: '待确认', color: 'blue' },
|
|
accepted: { text: '已接受', color: 'green' },
|
|
rejected: { text: '已拒绝', color: 'red' },
|
|
completed: { text: '已完成', color: 'purple' },
|
|
};
|
|
const st = statusMap[record.interviewStatus || ''];
|
|
if (!st) return <Tag color="default">未邀约</Tag>;
|
|
return <Tag color={st.color}>{st.text}</Tag>;
|
|
},
|
|
},
|
|
{
|
|
title: '操作',
|
|
hideInSearch: true,
|
|
align: 'center',
|
|
dataIndex: 'jobId',
|
|
width: 280,
|
|
render: (jobId, record) => [
|
|
<div key="first-row" style={{marginBottom: 8, display: 'flex', justifyContent: 'center'}}>
|
|
<Button
|
|
type="link"
|
|
size="small"
|
|
key="view-resume"
|
|
icon={<AlignLeftOutlined/>}
|
|
hidden={!access.hasPerms('cms:userworkexperiences:list')}
|
|
onClick={() => {
|
|
navigate(`/usermgmt/appuser/resume/${record.userId}?readOnly=1`);
|
|
}}
|
|
>
|
|
简历
|
|
</Button>
|
|
<Button
|
|
type="link"
|
|
size="small"
|
|
key="invite-interview"
|
|
icon={<SendOutlined/>}
|
|
hidden={!access.hasPerms('cms:interview:add')}
|
|
onClick={() => {
|
|
setCurrentRow(record);
|
|
setInviteVisible(true);
|
|
}}
|
|
>
|
|
邀请面试
|
|
</Button>
|
|
<Button
|
|
type="link"
|
|
size="small"
|
|
key="hire"
|
|
icon={<FormOutlined/>}
|
|
hidden={!access.hasPerms('cms:employeeConfirm:add')}
|
|
onClick={() => {
|
|
setCurrentRow(record);
|
|
setHireVisible(true);
|
|
setMode('create');
|
|
}}
|
|
>
|
|
录用
|
|
</Button>
|
|
<Button
|
|
type="link"
|
|
size="small"
|
|
key="match-detail"
|
|
icon={<AlignLeftOutlined/>}
|
|
onClick={() => {
|
|
setModalVisible(true);
|
|
setCurrentRow(record);
|
|
const val = similarityJobs.calculationMatchingDegreeJob(record);
|
|
setMatchingDegree(val);
|
|
}}
|
|
>
|
|
查看匹配详情
|
|
</Button>
|
|
</div>,
|
|
<div key="second-row" style={{display: 'flex', justifyContent: 'center'}}>
|
|
<Button
|
|
type="link"
|
|
size="small"
|
|
key="resume-filter"
|
|
icon={<FilterOutlined/>}
|
|
hidden={!access.hasPerms('cms:jobApply:filterQzz')}
|
|
onClick={() => {
|
|
setCurrentRow(record);
|
|
setFilterVisible(true);
|
|
}}
|
|
>
|
|
简历筛选
|
|
</Button>
|
|
</div>
|
|
],
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Fragment>
|
|
<div style={{width: '100%', float: 'right'}}>
|
|
<ProTable<API.MobileUser.ListRow>
|
|
// params 是需要自带的参数
|
|
// 这个参数优先级更高,会覆盖查询表单的参数
|
|
actionRef={actionRef}
|
|
formRef={formTableRef}
|
|
rowKey="jobId"
|
|
key="index"
|
|
columns={columns}
|
|
search={{ defaultCollapsed: false }}
|
|
request={(params) =>
|
|
exportCmsJobCandidates(jobId).then((res) => {
|
|
// const v = similarityJobs.calculationMatchingDegreeJob(res.rows[0]);
|
|
// console.log(v);
|
|
const result = {
|
|
data: res.rows,
|
|
total: res.total,
|
|
success: true,
|
|
};
|
|
return result;
|
|
})
|
|
}
|
|
toolBarRender={() => [
|
|
<Button
|
|
key="back-to-list"
|
|
icon={<ArrowLeftOutlined />}
|
|
onClick={() => navigate(-1)}
|
|
>
|
|
返回岗位列表
|
|
</Button>,
|
|
<Button
|
|
type="primary"
|
|
key="export"
|
|
hidden={!access.hasPerms('system:user:export')}
|
|
onClick={async () => {
|
|
const searchVal = formTableRef.current && formTableRef.current.getFieldsValue();
|
|
handleExport(searchVal as API.MobileUser.ListParams);
|
|
}}
|
|
>
|
|
<PlusOutlined/>
|
|
<FormattedMessage id="pages.searchTable.export" defaultMessage="导出"/>
|
|
</Button>,
|
|
]}
|
|
/>
|
|
<Detail
|
|
values={currentRow}
|
|
open={modalVisible}
|
|
matching={matchingDegree}
|
|
onClose={() => {
|
|
console.log('close');
|
|
setModalVisible(false);
|
|
setCurrentRow(undefined);
|
|
setMatchingDegree(null);
|
|
}}
|
|
></Detail>
|
|
<Hire
|
|
values={currentRow}
|
|
open={hireVisible}
|
|
contractTermEnum={contractTermEnum}
|
|
jobId={jobId}
|
|
onClose={() => {
|
|
console.log('close');
|
|
setHireVisible(false);
|
|
setCurrentRow(undefined);
|
|
setHireAdd(null);
|
|
}}
|
|
onSubmit={async (values) => {
|
|
let resData;
|
|
resData = await addCmsEmployeeConfirmList(values);
|
|
if (resData.code === 200) {
|
|
setHireVisible(false);
|
|
setCurrentRow(undefined);
|
|
message.success('新增成功');
|
|
if (actionRef.current) {
|
|
actionRef.current.reload();
|
|
}
|
|
}
|
|
}}
|
|
></Hire>
|
|
<InterviewInvite
|
|
open={inviteVisible}
|
|
userId={currentRow?.userId}
|
|
userName={currentRow?.name}
|
|
jobId={jobId}
|
|
companyId={(jobInfo as any)?.companyId}
|
|
jobName={(jobInfo as any)?.jobTitle}
|
|
applyId={currentRow?.applyId ? Number(currentRow.applyId) : undefined}
|
|
onClose={(needRefresh) => {
|
|
setInviteVisible(false);
|
|
setCurrentRow(undefined);
|
|
if (needRefresh) {
|
|
actionRef.current?.reload();
|
|
}
|
|
}}
|
|
/>
|
|
<ResumeFilter
|
|
open={filterVisible}
|
|
applyId={currentRow?.applyId}
|
|
userName={currentRow?.name}
|
|
onClose={(needRefresh) => {
|
|
setFilterVisible(false);
|
|
setCurrentRow(undefined);
|
|
if (needRefresh) {
|
|
actionRef.current?.reload();
|
|
}
|
|
}}
|
|
/>
|
|
</div>
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
export default ManagementList;
|