面试功能开发
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
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
This commit is contained in:
@@ -189,6 +189,11 @@ export default [
|
|||||||
path: '/management/see-matching/index/:id',
|
path: '/management/see-matching/index/:id',
|
||||||
component: './Management/List/SeeMatching',
|
component: './Management/List/SeeMatching',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: '面试列表',
|
||||||
|
path: '/management/interview-list',
|
||||||
|
component: './Management/InterviewList',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
Button,
|
Button,
|
||||||
Empty,
|
Empty,
|
||||||
|
Modal,
|
||||||
message,
|
message,
|
||||||
Spin
|
Spin
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
@@ -19,7 +20,7 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { history } from '@umijs/max';
|
import { history } from '@umijs/max';
|
||||||
import JobPortalHeader from '@/components/JobPortalHeader';
|
import JobPortalHeader from '@/components/JobPortalHeader';
|
||||||
import { getAppInterviewList } from '@/services/Management/list';
|
import { getAppInterviewList, updateAppInterviewStatus } from '@/services/Management/list';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
@@ -78,6 +79,27 @@ const InterviewsPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleStatusUpdate = (interviewId: number, status: string, statusText: string) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '提示',
|
||||||
|
content: `确定${statusText}该面试邀约吗?`,
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
const response = await updateAppInterviewStatus(interviewId, status);
|
||||||
|
if (response.code === 200) {
|
||||||
|
message.success(status === 'accepted' ? '已接受面试邀请' : '已婉拒面试邀请');
|
||||||
|
fetchInterviews();
|
||||||
|
} else {
|
||||||
|
message.error(response.msg || '操作失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新面试状态失败:', error);
|
||||||
|
message.error('操作失败,请重试');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
history.push('/job-portal/personal-center');
|
history.push('/job-portal/personal-center');
|
||||||
};
|
};
|
||||||
@@ -131,7 +153,7 @@ const InterviewsPage: React.FC = () => {
|
|||||||
<Tag color={item.interviewMethod === 'online' ? 'blue' : 'orange'}>
|
<Tag color={item.interviewMethod === 'online' ? 'blue' : 'orange'}>
|
||||||
{item.interviewMethod === 'online' ? '线上' : '线下'}
|
{item.interviewMethod === 'online' ? '线上' : '线下'}
|
||||||
</Tag>
|
</Tag>
|
||||||
{/* <Tag color={st.color}>{st.text}</Tag> */}
|
<Tag color={st.color}>{st.text}</Tag>
|
||||||
</Space>
|
</Space>
|
||||||
<div style={{ marginTop: 8 }}>
|
<div style={{ marginTop: 8 }}>
|
||||||
{item.interviewMethod === 'online' ? (
|
{item.interviewMethod === 'online' ? (
|
||||||
@@ -166,6 +188,25 @@ const InterviewsPage: React.FC = () => {
|
|||||||
<Text type="secondary">备注:{item.remark}</Text>
|
<Text type="secondary">备注:{item.remark}</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{item.status === 'pending' && (
|
||||||
|
<div style={{ marginTop: 12 }}>
|
||||||
|
<Space>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
onClick={() => handleStatusUpdate(item.id!, 'accepted', '接受')}
|
||||||
|
>
|
||||||
|
接受邀请
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => handleStatusUpdate(item.id!, 'rejected', '婉拒')}
|
||||||
|
>
|
||||||
|
婉拒
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
154
src/pages/Management/InterviewList/index.tsx
Normal file
154
src/pages/Management/InterviewList/index.tsx
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
import React, { useRef } from 'react';
|
||||||
|
import { Tag } from 'antd';
|
||||||
|
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||||
|
import { getCmsInterviewList } from '@/services/Management/list';
|
||||||
|
|
||||||
|
const interviewStatusMap: Record<string, { text: string; color: string }> = {
|
||||||
|
pending: { text: '待确认', color: 'blue' },
|
||||||
|
accepted: { text: '已接受', color: 'green' },
|
||||||
|
rejected: { text: '已拒绝', color: 'red' },
|
||||||
|
completed: { text: '已完成', color: 'purple' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const interviewMethodMap: Record<string, { text: string; color: string }> = {
|
||||||
|
online: { text: '线上', color: 'blue' },
|
||||||
|
offline: { text: '线下', color: 'orange' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const InterviewList: React.FC = () => {
|
||||||
|
const actionRef = useRef<ActionType>();
|
||||||
|
|
||||||
|
const columns: ProColumns<API.Management.InterviewInvitation>[] = [
|
||||||
|
{
|
||||||
|
title: '求职者姓名',
|
||||||
|
dataIndex: 'applicantName',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
render: (_, record) => record.applicantName || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '联系方式',
|
||||||
|
dataIndex: 'applicantPhone',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 130,
|
||||||
|
hideInSearch: true,
|
||||||
|
render: (_, record) => record.applicantPhone || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '应聘岗位',
|
||||||
|
dataIndex: 'jobTitle',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
render: (_, record) => record.jobTitle || record.jobName || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '公司名称',
|
||||||
|
dataIndex: 'companyName',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
hideInSearch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '面试时间',
|
||||||
|
dataIndex: 'interviewTime',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 160,
|
||||||
|
hideInSearch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '面试方式',
|
||||||
|
dataIndex: 'interviewMethod',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 80,
|
||||||
|
hideInSearch: true,
|
||||||
|
render: (_, record) => {
|
||||||
|
const m = interviewMethodMap[record.interviewMethod || ''];
|
||||||
|
if (!m) return '-';
|
||||||
|
return <Tag color={m.color}>{m.text}</Tag>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '面试官姓名',
|
||||||
|
dataIndex: 'interviewerName',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
hideInSearch: true,
|
||||||
|
render: (_, record) => record.interviewerName || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '面试官联系方式',
|
||||||
|
dataIndex: 'contactPhone',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 140,
|
||||||
|
hideInSearch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'status',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 80,
|
||||||
|
render: (_, record) => {
|
||||||
|
const st = interviewStatusMap[record.status || ''];
|
||||||
|
if (!st) return <Tag color="default">未知</Tag>;
|
||||||
|
return <Tag color={st.color}>{st.text}</Tag>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '备注',
|
||||||
|
dataIndex: 'remark',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
hideInSearch: true,
|
||||||
|
render: (_, record) => record.remark || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
valueType: 'text',
|
||||||
|
align: 'center',
|
||||||
|
width: 160,
|
||||||
|
hideInSearch: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProTable<API.Management.InterviewInvitation>
|
||||||
|
actionRef={actionRef}
|
||||||
|
rowKey="id"
|
||||||
|
columns={columns}
|
||||||
|
headerTitle="面试列表"
|
||||||
|
request={async (params) => {
|
||||||
|
const { current, pageSize, ...searchParams } = params;
|
||||||
|
const response = await getCmsInterviewList({
|
||||||
|
...searchParams,
|
||||||
|
pageNum: current,
|
||||||
|
pageSize,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
data: response.rows || [],
|
||||||
|
total: response.total || 0,
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
search={{
|
||||||
|
labelWidth: 'auto',
|
||||||
|
}}
|
||||||
|
pagination={{
|
||||||
|
defaultPageSize: 10,
|
||||||
|
showSizeChanger: true,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InterviewList;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
||||||
import { FormattedMessage, useAccess, useParams } from '@umijs/max';
|
import { FormattedMessage, useAccess, useParams } from '@umijs/max';
|
||||||
import { Button, FormInstance, message } from 'antd';
|
import { Button, FormInstance, message, Tag } from 'antd';
|
||||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||||
import { FormOutlined, PlusOutlined,AlignLeftOutlined } from '@ant-design/icons';
|
import { FormOutlined, PlusOutlined,AlignLeftOutlined } from '@ant-design/icons';
|
||||||
import { getDictValueEnum } from '@/services/system/dict';
|
import { getDictValueEnum } from '@/services/system/dict';
|
||||||
@@ -167,6 +167,25 @@ function ManagementList() {
|
|||||||
<>{similarityJobs.calculationMatchingDegreeJob(record).overallMatch}</>
|
<>{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: '操作',
|
title: '操作',
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ const listEdit: React.FC<ListFormProps> = (props) => {
|
|||||||
meetingPassword: values.meetingPassword,
|
meetingPassword: values.meetingPassword,
|
||||||
interviewLocation: values.interviewLocation,
|
interviewLocation: values.interviewLocation,
|
||||||
contactPhone: values.contactPhone,
|
contactPhone: values.contactPhone,
|
||||||
|
interviewerName: values.interviewerName,
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
remark: values.remark,
|
remark: values.remark,
|
||||||
};
|
};
|
||||||
@@ -250,6 +251,14 @@ const listEdit: React.FC<ListFormProps> = (props) => {
|
|||||||
<TextArea rows={3} placeholder="选填,如有其他注意事项可在此说明" />
|
<TextArea rows={3} placeholder="选填,如有其他注意事项可在此说明" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="interviewerName"
|
||||||
|
label="面试官姓名"
|
||||||
|
rules={[{ required: true, message: '请输入面试官姓名' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入面试官姓名" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="contactPhone"
|
name="contactPhone"
|
||||||
label="面试官联系方式"
|
label="面试官联系方式"
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ const listEdit: React.FC<ListFormProps> = (props) => {
|
|||||||
}}
|
}}
|
||||||
placeholder="请输入公司名称选择公司"
|
placeholder="请输入公司名称选择公司"
|
||||||
rules={[{ required: true, message: '请输入公司名称选择公司!' }]}
|
rules={[{ required: true, message: '请输入公司名称选择公司!' }]}
|
||||||
label="招聘会公司"
|
label="招聘公司"
|
||||||
/>
|
/>
|
||||||
<ProFormDigit
|
<ProFormDigit
|
||||||
name="minSalary"
|
name="minSalary"
|
||||||
|
|||||||
@@ -131,3 +131,11 @@ export async function getCmsInterviewDetail(id: string) {
|
|||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 求职者端:更新面试邀约状态(接受/拒绝) */
|
||||||
|
export async function updateAppInterviewStatus(id: number, status: string) {
|
||||||
|
return request<API.Management.InterviewPageResult>(`/api/app/interview/status/${id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
data: { status },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
3
src/types/Management/interview.d.ts
vendored
3
src/types/Management/interview.d.ts
vendored
@@ -13,6 +13,9 @@ declare namespace API.Management {
|
|||||||
meetingPassword?: string;
|
meetingPassword?: string;
|
||||||
interviewLocation?: string;
|
interviewLocation?: string;
|
||||||
contactPhone?: string;
|
contactPhone?: string;
|
||||||
|
interviewerName?: string;
|
||||||
|
applicantName?: string;
|
||||||
|
applicantPhone?: string;
|
||||||
companyName?: string;
|
companyName?: string;
|
||||||
jobName?: string;
|
jobName?: string;
|
||||||
jobTitle?: string;
|
jobTitle?: string;
|
||||||
|
|||||||
2
src/types/mobileusers/list.d.ts
vendored
2
src/types/mobileusers/list.d.ts
vendored
@@ -30,6 +30,8 @@ declare namespace API.MobileUser {
|
|||||||
jobName?: string;
|
jobName?: string;
|
||||||
hire?:string;
|
hire?:string;
|
||||||
idCard?:string;
|
idCard?:string;
|
||||||
|
interviewStatus?: string;
|
||||||
|
interviewId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListParams {
|
export interface ListParams {
|
||||||
|
|||||||
Reference in New Issue
Block a user