Files
shz-admin/src/pages/Management/List/SeeMatching/index.tsx
francis-fh 4900040e6b
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
申请人简历生成器集成
2026-07-24 11:26:57 +08:00

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;