2026-06-24 09:31:10 +08:00
|
|
|
import {Modal, Card, Descriptions, List, Button, Divider, Form, Select, Input, DatePicker, message} from 'antd';
|
2025-11-10 16:28:01 +08:00
|
|
|
import React, { useEffect, useRef,useState } from 'react';
|
|
|
|
|
import { ProDescriptions} from '@ant-design/pro-components';
|
|
|
|
|
import {
|
2026-06-24 09:31:10 +08:00
|
|
|
addCmsUserWorkExperiencesList,
|
|
|
|
|
addCmsInterview,
|
2026-06-24 18:18:42 +08:00
|
|
|
getCmsInterviewList,
|
2025-11-10 16:28:01 +08:00
|
|
|
} from '@/services/Management/list';
|
2026-06-24 09:31:10 +08:00
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
|
|
|
|
|
const { TextArea } = Input;
|
|
|
|
|
const { Option } = Select;
|
|
|
|
|
|
2025-11-10 16:28:01 +08:00
|
|
|
export type ListFormProps = {
|
|
|
|
|
onClose: (flag?: boolean, formVals?: unknown) => void;
|
|
|
|
|
open: boolean;
|
|
|
|
|
values?: Partial<API.MobileUser.ListRow>;
|
|
|
|
|
matching?: any;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const listEdit: React.FC<ListFormProps> = (props) => {
|
|
|
|
|
|
|
|
|
|
const mapRef = useRef(null);
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const [contactInfoList, setContactInfoList] = useState<API.Management.WorkExperence[]>([]);
|
|
|
|
|
|
2026-06-24 09:31:10 +08:00
|
|
|
// 面试邀约相关状态
|
|
|
|
|
const [interviewForm] = Form.useForm();
|
|
|
|
|
const [interviewMethod, setInterviewMethod] = useState<string>('online');
|
|
|
|
|
const [submitting, setSubmitting] = useState<boolean>(false);
|
2026-06-24 18:18:42 +08:00
|
|
|
const [alreadyInvited, setAlreadyInvited] = useState<boolean>(false);
|
|
|
|
|
const [checkingInvitation, setCheckingInvitation] = useState<boolean>(false);
|
2026-06-24 09:31:10 +08:00
|
|
|
|
2025-11-10 16:28:01 +08:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (props.open && props.values) {
|
|
|
|
|
console.log(props.values);
|
|
|
|
|
fetchResumeDetail();
|
2026-06-24 18:18:42 +08:00
|
|
|
checkExistingInvitation();
|
2026-06-24 09:31:10 +08:00
|
|
|
// 重置面试邀约表单
|
|
|
|
|
interviewForm.resetFields();
|
|
|
|
|
setInterviewMethod('online');
|
2025-11-10 16:28:01 +08:00
|
|
|
}
|
|
|
|
|
}, [props.values,props.open]);
|
|
|
|
|
|
2026-06-24 18:18:42 +08:00
|
|
|
// 检查是否已存在有效邀约
|
|
|
|
|
const checkExistingInvitation = async () => {
|
|
|
|
|
if (!props.matching?.jobId || !props.values?.userId) return;
|
|
|
|
|
setCheckingInvitation(true);
|
|
|
|
|
try {
|
|
|
|
|
const res = await getCmsInterviewList({
|
|
|
|
|
jobId: Number(props.matching.jobId),
|
|
|
|
|
userId: props.values.userId,
|
|
|
|
|
});
|
|
|
|
|
if (res?.code === 200 && res?.rows?.length > 0) {
|
|
|
|
|
// 存在非 rejected 的邀约即为已邀约
|
|
|
|
|
const hasActive = res.rows.some(
|
|
|
|
|
(item: API.Management.InterviewInvitation) => item.status !== 'rejected'
|
|
|
|
|
);
|
|
|
|
|
setAlreadyInvited(hasActive);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('检查邀约状态失败:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
setCheckingInvitation(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-10 16:28:01 +08:00
|
|
|
const fetchResumeDetail = async () => {
|
|
|
|
|
if (!props.values?.userId) return;
|
|
|
|
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
try {
|
2026-06-25 17:57:46 +08:00
|
|
|
const parm={userId: props.values.userId, jobId: props.matching?.jobId};
|
2025-11-10 16:28:01 +08:00
|
|
|
const response = await addCmsUserWorkExperiencesList(parm);
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
setContactInfoList(response.rows);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取经历详情失败:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-06-24 09:31:10 +08:00
|
|
|
// 发送面试邀约
|
|
|
|
|
const handleInterviewSubmit = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const values = await interviewForm.validateFields();
|
|
|
|
|
setSubmitting(true);
|
|
|
|
|
|
|
|
|
|
const payload: API.Management.InterviewInvitation = {
|
|
|
|
|
companyId: props.matching?.companyId,
|
|
|
|
|
jobId: Number(props.matching?.jobId),
|
|
|
|
|
userId: props.values?.userId,
|
|
|
|
|
applyId: props.values?.applyId ? Number(props.values.applyId) : undefined,
|
2026-06-24 18:18:42 +08:00
|
|
|
jobName: props.matching?.jobName,
|
2026-06-24 09:31:10 +08:00
|
|
|
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,
|
2026-06-25 13:32:03 +08:00
|
|
|
interviewerName: values.interviewerName,
|
2026-06-24 09:31:10 +08:00
|
|
|
status: 'pending',
|
|
|
|
|
remark: values.remark,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const response = await addCmsInterview(payload);
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
message.success('面试邀约已发送');
|
2026-06-24 18:18:42 +08:00
|
|
|
setAlreadyInvited(true);
|
2026-06-24 09:31:10 +08:00
|
|
|
interviewForm.resetFields();
|
|
|
|
|
setInterviewMethod('online');
|
|
|
|
|
} else {
|
|
|
|
|
message.error(response.msg || '发送失败');
|
|
|
|
|
}
|
2026-06-24 18:18:42 +08:00
|
|
|
} catch (error: any) {
|
|
|
|
|
const errMsg = error?.response?.data?.msg || error?.message || '发送面试邀约失败';
|
|
|
|
|
message.error(errMsg);
|
2026-06-24 09:31:10 +08:00
|
|
|
console.error('发送面试邀约失败:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
setSubmitting(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-10 16:28:01 +08:00
|
|
|
return (
|
|
|
|
|
<Modal
|
|
|
|
|
open={props.open}
|
|
|
|
|
onCancel={() => props.onClose()}
|
|
|
|
|
title="简历详情"
|
|
|
|
|
width={800}
|
|
|
|
|
footer={[
|
|
|
|
|
<Button key="cancel" onClick={() => props.onClose()}>
|
|
|
|
|
取消
|
|
|
|
|
</Button>
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<ProDescriptions
|
|
|
|
|
column={2}
|
|
|
|
|
loading={loading}
|
|
|
|
|
>
|
|
|
|
|
{
|
|
|
|
|
<ProDescriptions.Item
|
|
|
|
|
dataIndex="contactInfoList"
|
|
|
|
|
label=""
|
|
|
|
|
span={2}
|
|
|
|
|
render={() => {
|
|
|
|
|
if (loading) return '加载中...';
|
|
|
|
|
if (!Array.isArray(contactInfoList) || contactInfoList.length === 0) {
|
|
|
|
|
return <span style={{ color: '#999' }}>暂无经历信息</span>;
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<List
|
|
|
|
|
itemLayout="vertical"
|
|
|
|
|
dataSource={contactInfoList}
|
|
|
|
|
renderItem={(item, index) => (
|
|
|
|
|
<List.Item
|
|
|
|
|
style={{ marginBottom: 16 }}
|
|
|
|
|
>
|
|
|
|
|
<Card
|
|
|
|
|
title={`经历信息 #${index + 1}`}
|
|
|
|
|
bordered
|
|
|
|
|
style={{ width: '100%', boxShadow: '0 2px 8px rgba(0,0,0,0.1)' }}
|
|
|
|
|
>
|
|
|
|
|
<Descriptions column={2} size="small">
|
|
|
|
|
<Descriptions.Item label="公司名称">{item.companyName || '未填写'}</Descriptions.Item>
|
|
|
|
|
<Descriptions.Item label="职务">{item.position || '未填写'}</Descriptions.Item>
|
|
|
|
|
<Descriptions.Item label="开始时间">{item.startDate || '未填写'}</Descriptions.Item>
|
|
|
|
|
<Descriptions.Item label="截止时间">{item.endDate || '未填写'}</Descriptions.Item>
|
|
|
|
|
<Descriptions.Item label="描述" span={2}>
|
|
|
|
|
{item.description || '未填写'}
|
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
</Descriptions>
|
|
|
|
|
</Card>
|
|
|
|
|
</List.Item>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
</ProDescriptions>
|
2026-06-24 09:31:10 +08:00
|
|
|
|
|
|
|
|
<Divider />
|
|
|
|
|
<Card title="面试邀约" bordered style={{ marginTop: 16 }}>
|
|
|
|
|
<Form
|
|
|
|
|
form={interviewForm}
|
|
|
|
|
layout="vertical"
|
2026-06-24 18:18:42 +08:00
|
|
|
initialValues={{ interviewMethod: 'online', meetingLink: 'https://mc.repohub.cn/pro.html' }}
|
2026-06-24 09:31:10 +08:00
|
|
|
>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="interviewMethod"
|
|
|
|
|
label="面试方式"
|
|
|
|
|
rules={[{ required: true, message: '请选择面试方式' }]}
|
|
|
|
|
>
|
|
|
|
|
<Select
|
|
|
|
|
placeholder="请选择面试方式"
|
|
|
|
|
onChange={(value) => setInterviewMethod(value)}
|
|
|
|
|
>
|
|
|
|
|
<Option value="online">线上</Option>
|
|
|
|
|
<Option value="offline">线下</Option>
|
|
|
|
|
</Select>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="interviewTime"
|
|
|
|
|
label="面试时间"
|
|
|
|
|
rules={[{ required: true, message: '请选择面试时间' }]}
|
|
|
|
|
>
|
|
|
|
|
<DatePicker
|
|
|
|
|
showTime
|
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
placeholder="请选择面试时间"
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
{interviewMethod === 'online' && (
|
|
|
|
|
<>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="meetingLink"
|
2026-06-24 18:18:42 +08:00
|
|
|
label="在线会议链接"
|
2026-06-24 09:31:10 +08:00
|
|
|
>
|
2026-06-24 18:18:42 +08:00
|
|
|
<Input placeholder="https://mc.repohub.cn/pro.html" disabled />
|
2026-06-24 09:31:10 +08:00
|
|
|
</Form.Item>
|
2026-06-24 18:18:42 +08:00
|
|
|
{/* <Form.Item
|
2026-06-24 09:31:10 +08:00
|
|
|
name="meetingPassword"
|
|
|
|
|
label="会议密码"
|
|
|
|
|
rules={[{ required: true, message: '请输入会议密码' }]}
|
|
|
|
|
>
|
|
|
|
|
<Input placeholder="请输入会议密码" />
|
2026-06-24 18:18:42 +08:00
|
|
|
</Form.Item> */}
|
2026-06-24 09:31:10 +08:00
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{interviewMethod === 'offline' && (
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="interviewLocation"
|
|
|
|
|
label="面试地点"
|
|
|
|
|
rules={[{ required: true, message: '请输入面试地点' }]}
|
|
|
|
|
>
|
|
|
|
|
<Input placeholder="请输入面试地点" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="remark"
|
|
|
|
|
label="备注"
|
|
|
|
|
>
|
|
|
|
|
<TextArea rows={3} placeholder="选填,如有其他注意事项可在此说明" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
2026-06-25 13:32:03 +08:00
|
|
|
<Form.Item
|
|
|
|
|
name="interviewerName"
|
|
|
|
|
label="面试官姓名"
|
|
|
|
|
rules={[{ required: true, message: '请输入面试官姓名' }]}
|
|
|
|
|
>
|
|
|
|
|
<Input placeholder="请输入面试官姓名" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
2026-06-24 09:31:10 +08:00
|
|
|
<Form.Item
|
|
|
|
|
name="contactPhone"
|
|
|
|
|
label="面试官联系方式"
|
|
|
|
|
rules={[{ required: true, message: '请输入面试官联系方式' }]}
|
|
|
|
|
>
|
|
|
|
|
<Input placeholder="请输入手机号或微信等联系方式" />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item>
|
2026-06-24 18:18:42 +08:00
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
loading={submitting || checkingInvitation}
|
|
|
|
|
disabled={alreadyInvited}
|
|
|
|
|
onClick={handleInterviewSubmit}
|
|
|
|
|
>
|
|
|
|
|
{alreadyInvited ? '已邀约' : '发送面试邀约'}
|
2026-06-24 09:31:10 +08:00
|
|
|
</Button>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Form>
|
|
|
|
|
</Card>
|
2025-11-10 16:28:01 +08:00
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default listEdit;
|