2026-06-27 17:57:45 +08:00
|
|
|
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
|
|
|
|
import { useAccess, useParams } from '@umijs/max';
|
|
|
|
|
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
|
|
|
|
import { Button, message } from 'antd';
|
|
|
|
|
import { AlignLeftOutlined, SendOutlined } from '@ant-design/icons';
|
|
|
|
|
import { getDictValueEnum } from '@/services/system/dict';
|
|
|
|
|
import DictTag from '@/components/DictTag';
|
|
|
|
|
import { getRecommendByJobId, getCmsJobIds } from '@/services/Management/list';
|
|
|
|
|
import ResumeDetail from './ResumeDetail';
|
|
|
|
|
import InterviewInvite from './InterviewInvite';
|
|
|
|
|
|
|
|
|
|
function ResumeRecommend() {
|
|
|
|
|
const access = useAccess();
|
|
|
|
|
|
|
|
|
|
const actionRef = useRef<ActionType>();
|
|
|
|
|
|
|
|
|
|
const [educationEnum, setEducationEnum] = useState<any>([]);
|
|
|
|
|
const [areaEnum, setAreaEnum] = useState<any>([]);
|
|
|
|
|
const [sexEnum, setSexEnum] = useState<any>([]);
|
|
|
|
|
const [politicalEnum, setPoliticalEnum] = useState<any>([]);
|
|
|
|
|
const [currentRow, setCurrentRow] = useState<API.ManagementList.RecommendUser>();
|
|
|
|
|
const [detailVisible, setDetailVisible] = useState<boolean>(false);
|
|
|
|
|
const [inviteVisible, setInviteVisible] = useState<boolean>(false);
|
|
|
|
|
const [jobInfo, setJobInfo] = useState<any>({});
|
|
|
|
|
|
|
|
|
|
const params = useParams();
|
|
|
|
|
const jobId = params.id || '0';
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
getDictValueEnum('education', true, true).then((data) => {
|
|
|
|
|
setEducationEnum(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);
|
|
|
|
|
});
|
|
|
|
|
getJobInfo(jobId);
|
|
|
|
|
}, [jobId]);
|
|
|
|
|
|
|
|
|
|
const getJobInfo = async (id: string) => {
|
|
|
|
|
try {
|
|
|
|
|
const resData = await getCmsJobIds(id);
|
|
|
|
|
if (resData.code === 200 && resData.data) {
|
|
|
|
|
const data = resData.data as any;
|
|
|
|
|
setJobInfo({
|
|
|
|
|
jobTitle: data.jobTitle || '',
|
|
|
|
|
companyId: data.companyId,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取岗位信息失败:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const columns: ProColumns<API.ManagementList.RecommendUser>[] = [
|
|
|
|
|
{
|
|
|
|
|
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: 'phone',
|
|
|
|
|
valueType: 'text',
|
|
|
|
|
align: 'center',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '匹配级别',
|
|
|
|
|
dataIndex: 'matchLevelDesc',
|
|
|
|
|
valueType: 'text',
|
|
|
|
|
align: 'center',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
width: 200,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '操作',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
align: 'center',
|
|
|
|
|
dataIndex: 'userId',
|
|
|
|
|
width: 200,
|
|
|
|
|
render: (_, record) => [
|
|
|
|
|
<div key="actions" style={{ display: 'flex', justifyContent: 'center', gap: 8 }}>
|
|
|
|
|
<Button
|
|
|
|
|
type="link"
|
|
|
|
|
size="small"
|
|
|
|
|
key="view-resume"
|
|
|
|
|
icon={<AlignLeftOutlined />}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setCurrentRow(record);
|
|
|
|
|
setDetailVisible(true);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
查看详情
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="link"
|
|
|
|
|
size="small"
|
|
|
|
|
key="invite-interview"
|
|
|
|
|
icon={<SendOutlined />}
|
|
|
|
|
hidden={!access.hasPerms('cms:interview:add')}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setCurrentRow(record);
|
|
|
|
|
setInviteVisible(true);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
邀请面试
|
|
|
|
|
</Button>
|
|
|
|
|
</div>,
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Fragment>
|
|
|
|
|
<div style={{ width: '100%', float: 'right' }}>
|
|
|
|
|
<ProTable<API.ManagementList.RecommendUser>
|
|
|
|
|
actionRef={actionRef}
|
|
|
|
|
rowKey="userId"
|
|
|
|
|
key="index"
|
|
|
|
|
headerTitle={`简历推荐${jobInfo.jobTitle ? ` - ${jobInfo.jobTitle}` : ''}`}
|
|
|
|
|
columns={columns}
|
|
|
|
|
request={async () => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await getRecommendByJobId(jobId);
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
const data = res.data || [];
|
|
|
|
|
return {
|
|
|
|
|
data,
|
|
|
|
|
total: data.length,
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
message.error(res.msg || '获取推荐简历失败');
|
|
|
|
|
return {
|
|
|
|
|
data: [],
|
|
|
|
|
total: 0,
|
|
|
|
|
success: false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
message.error('获取推荐简历失败');
|
|
|
|
|
return {
|
|
|
|
|
data: [],
|
|
|
|
|
total: 0,
|
|
|
|
|
success: false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
search={false}
|
|
|
|
|
pagination={{ pageSize: 10 }}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<ResumeDetail
|
|
|
|
|
values={currentRow}
|
|
|
|
|
open={detailVisible}
|
|
|
|
|
jobId={jobId}
|
|
|
|
|
onClose={() => {
|
|
|
|
|
setDetailVisible(false);
|
|
|
|
|
setCurrentRow(undefined);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<InterviewInvite
|
|
|
|
|
open={inviteVisible}
|
|
|
|
|
userId={currentRow?.userId}
|
|
|
|
|
userName={currentRow?.name}
|
|
|
|
|
jobId={jobId}
|
|
|
|
|
companyId={jobInfo.companyId}
|
|
|
|
|
jobName={jobInfo.jobTitle}
|
2026-06-28 18:23:47 +08:00
|
|
|
applyId={currentRow?.applyId ? Number(currentRow.applyId) : undefined}
|
2026-06-27 17:57:45 +08:00
|
|
|
onClose={(needRefresh) => {
|
|
|
|
|
setInviteVisible(false);
|
|
|
|
|
setCurrentRow(undefined);
|
|
|
|
|
if (needRefresh) {
|
|
|
|
|
actionRef.current?.reload();
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Fragment>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default ResumeRecommend;
|