简历筛选功能开发
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

This commit is contained in:
francis-fh
2026-07-22 18:26:51 +08:00
parent 86e70a38d0
commit cd92dd4628
6 changed files with 214 additions and 18 deletions

View File

@@ -2,7 +2,7 @@ import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess, 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 } from '@ant-design/icons';
import { FormOutlined, PlusOutlined, AlignLeftOutlined, SendOutlined, FilterOutlined } from '@ant-design/icons';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
import { exportCmsAppUserExport } from '@/services/mobileusers/list';
@@ -16,6 +16,7 @@ import Detail from './detail';
import Hire from './hire';
import ResumeView from './resumeView';
import InterviewInvite from '../ResumeRecommend/InterviewInvite';
import ResumeFilter from './resumeFilter';
const handleExport = async (values: API.MobileUser.ListParams) => {
@@ -53,6 +54,7 @@ function ManagementList() {
const [matchingDegree, setMatchingDegree] = useState<any>(null);
const [resumeVisible, setResumeVisible] = useState<boolean>(false);
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();
@@ -250,6 +252,21 @@ function ManagementList() {
>
</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>
],
},
@@ -353,6 +370,18 @@ function ManagementList() {
}
}}
/>
<ResumeFilter
open={filterVisible}
applyId={currentRow?.applyId}
userName={currentRow?.name}
onClose={(needRefresh) => {
setFilterVisible(false);
setCurrentRow(undefined);
if (needRefresh) {
actionRef.current?.reload();
}
}}
/>
</div>
</Fragment>
);

View File

@@ -0,0 +1,119 @@
import { Modal, Form, Radio, Select, message } from 'antd';
import React, { useEffect, useState } from 'react';
import { filterQzz } from '@/services/Management/list';
import { getDictValueEnum } from '@/services/system/dict';
const { Option } = Select;
export type ResumeFilterProps = {
onClose: (needRefresh?: boolean) => void;
open: boolean;
applyId?: string;
userName?: string;
};
const ResumeFilter: React.FC<ResumeFilterProps> = (props) => {
const { open, applyId, userName } = props;
const [form] = Form.useForm();
const [submitting, setSubmitting] = useState<boolean>(false);
const [filterStatus, setFilterStatus] = useState<string>('0');
const [reasonEnum, setReasonEnum] = useState<any>({});
useEffect(() => {
if (open) {
form.resetFields();
setFilterStatus('0');
// 加载不通过筛选原因的字典
getDictValueEnum('resume_file_type', false, true).then((data) => {
setReasonEnum(data);
});
}
}, [open]);
const handleSubmit = async () => {
try {
const values = await form.validateFields();
setSubmitting(true);
const payload: { id: string; filterStatus: string; filterReason?: string } = {
id: applyId || '',
filterStatus: values.filterStatus,
};
// 如果不通过筛选,拼接原因
if (values.filterStatus === '2' && values.filterReason && values.filterReason.length > 0) {
payload.filterReason = values.filterReason.join('、');
}
const response = await filterQzz(payload);
if (response.code === 200) {
message.success('简历筛选完成');
form.resetFields();
props.onClose(true);
} else {
message.error(response.msg || '筛选失败');
}
} catch (error: any) {
const errMsg = error?.response?.data?.msg || error?.message || '简历筛选失败';
message.error(errMsg);
console.error('简历筛选失败:', error);
} finally {
setSubmitting(false);
}
};
return (
<Modal
open={open}
onCancel={() => props.onClose()}
title={`简历筛选${userName ? ` - ${userName}` : ''}`}
width={520}
onOk={handleSubmit}
confirmLoading={submitting}
destroyOnClose
>
<Form
form={form}
layout="vertical"
initialValues={{ filterStatus: '0' }}
>
<Form.Item
name="filterStatus"
label="筛选结果"
rules={[{ required: true, message: '请选择筛选结果' }]}
>
<Radio.Group
onChange={(e) => setFilterStatus(e.target.value)}
>
<Radio value="0"></Radio>
<Radio value="2"></Radio>
</Radio.Group>
</Form.Item>
{filterStatus === '2' && (
<Form.Item
name="filterReason"
label="不通过原因"
rules={[{ required: true, message: '请选择或输入不通过原因' }]}
>
<Select
mode="tags"
placeholder="请选择或输入不通过原因,按回车添加"
style={{ width: '100%' }}
tokenSeparators={['、', ',', '']}
>
{Object.keys(reasonEnum).map((key) => (
<Option key={key} value={reasonEnum[key].text}>
{reasonEnum[key].text}
</Option>
))}
</Select>
</Form.Item>
)}
</Form>
</Modal>
);
};
export default ResumeFilter;