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
CodeQL / Analyze (javascript) (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
252 lines
7.3 KiB
TypeScript
252 lines
7.3 KiB
TypeScript
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
||
import { useAccess, useNavigate } from '@umijs/max';
|
||
import { Button, FormInstance, message, Tag } from 'antd';
|
||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||
import { StarFilled, FileTextOutlined, SendOutlined } from '@ant-design/icons';
|
||
import { getDictValueEnum } from '@/services/system/dict';
|
||
import DictTag from '@/components/DictTag';
|
||
import { delHrTalentCollect, getHrTalentCollectList } from '@/services/mobileusers/list';
|
||
import InterviewInvite from '@/pages/Management/List/ResumeRecommend/InterviewInvite';
|
||
|
||
function TalentCollectList() {
|
||
const access = useAccess();
|
||
const navigate = useNavigate();
|
||
|
||
const formTableRef = useRef<FormInstance>();
|
||
const actionRef = useRef<ActionType>();
|
||
|
||
const [educationEnum, setEducationEnum] = useState<any>({});
|
||
const [areaEnum, setAreaEnum] = useState<any>({});
|
||
const [sexEnum, setSexEnum] = useState<any>({});
|
||
const [inviteVisible, setInviteVisible] = useState<boolean>(false);
|
||
const [currentRow, setCurrentRow] = useState<API.TalentCollect.ListRow>();
|
||
|
||
useEffect(() => {
|
||
getDictValueEnum('education', false, true).then((data) => setEducationEnum(data));
|
||
getDictValueEnum('area', false, true).then((data) => setAreaEnum(data));
|
||
getDictValueEnum('sys_user_sex', false).then((data) => setSexEnum(data));
|
||
}, []);
|
||
|
||
// 取消收藏(接口路径参数为收藏记录主键id)
|
||
const handleCancelCollect = async (record: API.TalentCollect.ListRow) => {
|
||
if (!record.id) return;
|
||
try {
|
||
const res = await delHrTalentCollect(String(record.id));
|
||
if (res.code === 200) {
|
||
message.success('已取消收藏');
|
||
actionRef.current?.reload();
|
||
} else {
|
||
message.error(res.msg || '取消收藏失败');
|
||
}
|
||
} catch (error: any) {
|
||
message.error(error?.response?.data?.msg || error?.message || '取消收藏失败');
|
||
}
|
||
};
|
||
|
||
const intentionLevelMap: Record<string, { text: string; color: string }> = {
|
||
'1': { text: '高意向', color: 'red' },
|
||
'2': { text: '中等意向', color: 'blue' },
|
||
'3': { text: '低意向', color: 'default' },
|
||
};
|
||
|
||
const sourceTypeMap: Record<string, string> = {
|
||
'1': '简历搜索',
|
||
'2': '投递记录',
|
||
'3': '邀约面试',
|
||
'4': '手动录入',
|
||
};
|
||
|
||
const columns: ProColumns<API.TalentCollect.ListRow>[] = [
|
||
{
|
||
title: '用户名',
|
||
dataIndex: 'name',
|
||
valueType: 'text',
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: '联系方式',
|
||
dataIndex: 'phone',
|
||
valueType: 'text',
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: '意向等级',
|
||
dataIndex: 'intentionLevel',
|
||
valueType: 'select',
|
||
align: 'center',
|
||
valueEnum: {
|
||
'1': '高意向',
|
||
'2': '中等意向',
|
||
'3': '低意向',
|
||
},
|
||
render: (_, record) => {
|
||
const info = intentionLevelMap[record.intentionLevel || ''];
|
||
if (!info) return '-';
|
||
return <Tag color={info.color}>{info.text}</Tag>;
|
||
},
|
||
},
|
||
{
|
||
title: '人才标签',
|
||
dataIndex: 'collectTags',
|
||
valueType: 'text',
|
||
align: 'center',
|
||
render: (_, record) => {
|
||
if (!record.collectTags) return '-';
|
||
const tags = record.collectTags.split(',').filter(Boolean);
|
||
return (
|
||
<>
|
||
{tags.map((tag) => (
|
||
<Tag key={tag} color="blue">
|
||
{tag.trim()}
|
||
</Tag>
|
||
))}
|
||
</>
|
||
);
|
||
},
|
||
},
|
||
{
|
||
title: '收藏来源',
|
||
dataIndex: 'sourceType',
|
||
valueType: 'select',
|
||
align: 'center',
|
||
valueEnum: {
|
||
'1': '简历搜索',
|
||
'2': '投递记录',
|
||
'3': '邀约面试',
|
||
'4': '手动录入',
|
||
},
|
||
render: (_, record) => sourceTypeMap[record.sourceType || ''] || '-',
|
||
},
|
||
{
|
||
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: 'createTime',
|
||
valueType: 'dateTime',
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
},
|
||
{
|
||
title: '操作',
|
||
hideInSearch: true,
|
||
align: 'center',
|
||
dataIndex: 'userId',
|
||
width: 280,
|
||
render: (_, record) => [
|
||
<Button
|
||
type="link"
|
||
size="small"
|
||
key="resume"
|
||
icon={<FileTextOutlined />}
|
||
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="cancel-collect"
|
||
icon={<StarFilled style={{ color: '#faad14' }} />}
|
||
hidden={!access.hasPerms('cms:hrTalentCollect:remove')}
|
||
onClick={() => handleCancelCollect(record)}
|
||
>
|
||
取消收藏
|
||
</Button>,
|
||
],
|
||
},
|
||
];
|
||
|
||
return (
|
||
<Fragment>
|
||
<div style={{ width: '100%', float: 'right' }}>
|
||
<ProTable<API.TalentCollect.ListRow>
|
||
search={{ labelWidth: 'auto' }}
|
||
actionRef={actionRef}
|
||
formRef={formTableRef}
|
||
rowKey="id"
|
||
key="talentCollect"
|
||
columns={columns}
|
||
request={(params) => {
|
||
const { current, pageSize, ...searchParams } = params;
|
||
const filteredParams: Record<string, any> = {};
|
||
Object.keys(searchParams).forEach((key) => {
|
||
const val = (searchParams as any)[key];
|
||
if (val !== undefined && val !== null && val !== '') {
|
||
filteredParams[key] = val;
|
||
}
|
||
});
|
||
return getHrTalentCollectList({
|
||
pageNum: current,
|
||
pageSize,
|
||
...filteredParams,
|
||
}).then((res: any) => {
|
||
const result = {
|
||
data: res.rows,
|
||
total: res.total,
|
||
success: true,
|
||
};
|
||
return result;
|
||
});
|
||
}}
|
||
/>
|
||
<InterviewInvite
|
||
open={inviteVisible}
|
||
userId={currentRow?.userId}
|
||
userName={currentRow?.name}
|
||
companyId={currentRow?.companyId}
|
||
onClose={(needRefresh) => {
|
||
setInviteVisible(false);
|
||
setCurrentRow(undefined);
|
||
if (needRefresh) {
|
||
actionRef.current?.reload();
|
||
}
|
||
}}
|
||
/>
|
||
</div>
|
||
</Fragment>
|
||
);
|
||
}
|
||
|
||
export default TalentCollectList;
|