diff --git a/config/routes.ts b/config/routes.ts index 4513fcd..0da0fa4 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -189,6 +189,11 @@ export default [ path: '/management/see-matching/index/:id', component: './Management/List/SeeMatching', }, + { + name: '简历推荐', + path: '/management/resume-recommend/index/:id', + component: './Management/List/ResumeRecommend', + }, { name: '面试列表', path: '/management/interview-list', diff --git a/src/pages/Management/List/ResumeRecommend/InterviewInvite.tsx b/src/pages/Management/List/ResumeRecommend/InterviewInvite.tsx new file mode 100644 index 0000000..3ee5055 --- /dev/null +++ b/src/pages/Management/List/ResumeRecommend/InterviewInvite.tsx @@ -0,0 +1,206 @@ +import { Modal, Card, Form, Select, Input, DatePicker, Button, message } from 'antd'; +import React, { useEffect, useState } from 'react'; +import { addCmsInterview, getCmsInterviewList } from '@/services/Management/list'; +import dayjs from 'dayjs'; + +const { TextArea } = Input; +const { Option } = Select; + +export type InterviewInviteProps = { + onClose: (needRefresh?: boolean) => void; + open: boolean; + userId?: number; + userName?: string; + jobId?: string; + companyId?: number; + jobName?: string; +}; + +const InterviewInvite: React.FC = (props) => { + const { open, userId, jobId, companyId, jobName } = props; + + const [interviewForm] = Form.useForm(); + const [interviewMethod, setInterviewMethod] = useState('online'); + const [submitting, setSubmitting] = useState(false); + const [alreadyInvited, setAlreadyInvited] = useState(false); + const [checkingInvitation, setCheckingInvitation] = useState(false); + + useEffect(() => { + if (open && userId && jobId) { + checkExistingInvitation(); + interviewForm.resetFields(); + setInterviewMethod('online'); + } + }, [open, userId, jobId]); + + // 检查是否已存在有效邀约 + const checkExistingInvitation = async () => { + if (!jobId || !userId) return; + setCheckingInvitation(true); + try { + const res = await getCmsInterviewList({ + jobId: Number(jobId), + userId: userId, + }); + if (res?.code === 200 && res?.rows?.length > 0) { + const hasActive = res.rows.some( + (item: API.Management.InterviewInvitation) => item.status !== 'rejected' + ); + setAlreadyInvited(hasActive); + } else { + setAlreadyInvited(false); + } + } catch (error) { + console.error('检查邀约状态失败:', error); + } finally { + setCheckingInvitation(false); + } + }; + + // 发送面试邀约 + const handleInterviewSubmit = async () => { + try { + const values = await interviewForm.validateFields(); + setSubmitting(true); + + const payload: API.Management.InterviewInvitation = { + companyId: companyId, + jobId: Number(jobId), + userId: userId, + jobName: jobName, + interviewTime: values.interviewTime + ? dayjs(values.interviewTime).format('YYYY-MM-DD HH:mm:ss') + : undefined, + interviewMethod: values.interviewMethod, + meetingLink: values.meetingLink, + meetingPassword: values.meetingPassword, + interviewLocation: values.interviewLocation, + contactPhone: values.contactPhone, + interviewerName: values.interviewerName, + status: 'pending', + remark: values.remark, + }; + + const response = await addCmsInterview(payload); + if (response.code === 200) { + message.success('面试邀约已发送'); + setAlreadyInvited(true); + interviewForm.resetFields(); + setInterviewMethod('online'); + } 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 ( + props.onClose()} + title="邀请面试" + width={700} + footer={[ + , + ]} + destroyOnClose + > + +
+ + + + + + + + + {interviewMethod === 'online' && ( + + + + )} + + {interviewMethod === 'offline' && ( + + + + )} + + +