Files
shz-admin/src/pages/Jobfair/PublicJobFair/index.tsx

395 lines
12 KiB
TypeScript
Raw Normal View History

2026-01-11 10:00:56 +08:00
import React, { useRef, useState, useEffect } from 'react';
import { useAccess, history } from '@umijs/max';
import { Button, FormInstance, message, Modal, Tag } from 'antd';
2026-01-11 10:00:56 +08:00
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import {
PlusOutlined,
DeleteOutlined,
FormOutlined,
ExportOutlined,
EyeOutlined,
} from '@ant-design/icons';
2026-01-11 10:00:56 +08:00
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
import {
getPublicJobFairList,
getPublicJobFairDetail,
signupPublicJobFair,
2026-01-11 10:00:56 +08:00
addPublicJobFair,
updatePublicJobFair,
deletePublicJobFair,
exportPublicJobFair,
} from '@/services/jobfair/publicJobFair';
import EditModal from './components/EditModal';
import CompanyJobManageModal from './components/CompanyJobManageModal';
import FairExportModal from '../components/FairExportModal';
import type { RecruitmentFairExportParams } from '@/services/jobfair/recruitmentFairExport';
2026-01-11 10:00:56 +08:00
const PublicJobFairList: React.FC = () => {
const access = useAccess();
const isEnterprise = Boolean(access.isEnterprise);
2026-06-09 16:08:39 +08:00
const formRef = useRef<FormInstance>();
2026-01-11 10:00:56 +08:00
const actionRef = useRef<ActionType>();
const [modalVisible, setModalVisible] = useState(false);
const [currentRow, setCurrentRow] = useState<API.PublicJobFair.JobFairItem>();
const [companyJobModalOpen, setCompanyJobModalOpen] = useState(false);
const [currentJobFair, setCurrentJobFair] = useState<API.PublicJobFair.JobFairItem>();
2026-01-11 10:00:56 +08:00
const [jobFairTypeEnum, setJobFairTypeEnum] = useState<any>({});
const [jobFairRegionTypeEnum, setJobFairRegionTypeEnum] = useState<any>({});
const [yesNoEnum, setYesNoEnum] = useState<any>({});
2026-01-11 10:00:56 +08:00
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [exportModalOpen, setExportModalOpen] = useState(false);
2026-01-11 10:00:56 +08:00
useEffect(() => {
getDictValueEnum('job_fair_type', true).then(setJobFairTypeEnum);
getDictValueEnum('job_fair_region_type').then(setJobFairRegionTypeEnum);
getDictValueEnum('sys_yes_no').then(setYesNoEnum);
2026-01-11 10:00:56 +08:00
}, []);
const handleDelete = async (ids: string) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除选中的招聘会吗?',
onOk: async () => {
const res = await deletePublicJobFair(ids);
if (res.code === 200) {
message.success('删除成功');
actionRef.current?.reload();
setSelectedRowKeys([]);
} else {
message.error(res.msg || '删除失败');
}
},
});
};
const handleSignup = (record: API.PublicJobFair.JobFairItem) => {
Modal.confirm({
title: '报名线上招聘会',
content: `确定报名「${record.jobFairTitle}」吗?报名后需要等待管理员审核。`,
onOk: async () => {
const res = await signupPublicJobFair(record.jobFairId);
if (res.code === 200) {
message.success('报名成功,请等待管理员审核');
actionRef.current?.reload();
} else {
message.error(res.msg || '报名失败');
}
},
});
};
const handleExport = async (params: RecruitmentFairExportParams) => {
2026-01-11 10:00:56 +08:00
message.loading('正在导出...');
try {
await exportPublicJobFair(params);
2026-01-11 10:00:56 +08:00
message.success('导出成功');
setExportModalOpen(false);
2026-01-11 10:00:56 +08:00
} catch {
message.error('导出失败');
}
};
const dictOptions = (valueEnum: Record<string, any>) =>
Object.entries(valueEnum).map(([value, item]) => ({
value,
label: item?.text || item?.label || value,
}));
2026-01-11 10:00:56 +08:00
const columns: ProColumns<API.PublicJobFair.JobFairItem>[] = [
2026-06-09 16:08:39 +08:00
{
title: '时间范围',
dataIndex: 'dateRange',
hideInTable: true,
valueType: 'dateRange',
fieldProps: {
format: 'YYYY-MM-DD',
},
search: {
transform: (value) => ({
startDate: value[0],
endDate: value[1],
}),
},
},
2026-01-11 10:00:56 +08:00
{
title: '招聘会标题',
dataIndex: 'jobFairTitle',
ellipsis: true,
},
{
title: '地址',
dataIndex: 'jobFairAddress',
hideInSearch: true,
ellipsis: true,
},
2026-07-24 09:46:54 +08:00
/* 线便
2026-01-11 10:00:56 +08:00
{
title: '类型',
dataIndex: 'jobFairType',
valueType: 'select',
valueEnum: jobFairTypeEnum,
render: (_, record) => <DictTag enums={jobFairTypeEnum} value={record.jobFairType} />,
},
2026-07-24 09:46:54 +08:00
*/
{
title: '区域类型',
dataIndex: 'jobFairRegionType',
valueType: 'select',
valueEnum: jobFairRegionTypeEnum,
render: (_, record) => (
<DictTag enums={jobFairRegionTypeEnum} value={record.jobFairRegionType} />
),
},
{
title: '举办状态',
dataIndex: 'jobFairStatus',
hideInSearch: true,
render: (_, record) => {
const status = record.jobFairStatus;
if (!status) return '-';
const color = status === '未举办' ? 'blue' : status === '正在举办' ? 'green' : 'default';
return <Tag color={color}>{status}</Tag>;
},
},
{
title: '报名审核状态',
dataIndex: 'enterpriseReviewStatus',
hideInSearch: true,
hideInTable: !isEnterprise,
render: (_, record) => {
if (record.isSignUp === undefined) return '-';
if (record.isSignUp !== '1') return <Tag></Tag>;
const statusMap: Record<string, { text: string; color: string }> = {
'0': { text: '待审核', color: 'gold' },
'1': { text: '已通过', color: 'green' },
'2': { text: '已驳回', color: 'red' },
};
const status = statusMap[record.enterpriseReviewStatus || '0'] || statusMap['0'];
return (
<span>
<Tag color={status.color}>{status.text}</Tag>
{record.enterpriseReviewComments && (
<span title={record.enterpriseReviewComments} style={{ color: '#999' }}>
</span>
)}
</span>
);
},
},
{
title: '是否跨域',
dataIndex: 'isCrossDomain',
valueType: 'select',
valueEnum: yesNoEnum,
render: (_, record) => <DictTag enums={yesNoEnum} value={record.isCrossDomain} />,
},
2026-01-11 10:00:56 +08:00
{
title: '开始时间',
dataIndex: 'jobFairStartTime',
valueType: 'dateTime',
hideInSearch: true,
},
{
title: '结束时间',
dataIndex: 'jobFairEndTime',
valueType: 'dateTime',
hideInSearch: true,
},
2026-06-09 16:08:39 +08:00
{
title: '创建时间',
dataIndex: 'createTime',
valueType: 'dateTime',
hideInSearch: true,
},
2026-01-11 10:00:56 +08:00
{
title: '操作',
valueType: 'option',
width: 360,
fixed: 'right',
render: (_, record) => {
const canViewDetail = !isEnterprise && access.hasPerms('cms:publicJobFair:query');
const canSignUp =
isEnterprise &&
access.hasPerms('cms:publicJobFair:signup') &&
(record.canSignUp ?? (record.isSignUp !== '1' || record.enterpriseReviewStatus === '2'));
const canEditCompanyJobs =
isEnterprise &&
access.hasPerms('cms:publicJobFair:job:edit') &&
(record.canEditJobs ?? record.enterpriseReviewStatus === '1');
return [
canViewDetail && (
<Button
key="detail"
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => history.push(`/jobfair/public-job-fair/detail?id=${record.jobFairId}`)}
>
</Button>
),
canSignUp && (
<Button
key="signup"
type="link"
size="small"
icon={<PlusOutlined />}
onClick={() => handleSignup(record)}
>
</Button>
),
canEditCompanyJobs && (
<Button
key="companyJobs"
type="link"
size="small"
icon={<FormOutlined />}
onClick={() => {
setCurrentJobFair(record);
setCompanyJobModalOpen(true);
}}
>
</Button>
),
<Button
key="edit"
type="link"
size="small"
icon={<FormOutlined />}
hidden={!access.hasPerms('cms:publicJobFair:edit')}
onClick={async () => {
const res = await getPublicJobFairDetail(record.jobFairId);
if (res.code === 200) {
setCurrentRow(res.data);
setModalVisible(true);
}
}}
>
</Button>,
<Button
key="delete"
type="link"
size="small"
danger
icon={<DeleteOutlined />}
hidden={!access.hasPerms('cms:publicJobFair:remove')}
onClick={() => handleDelete(record.jobFairId)}
>
</Button>,
];
},
2026-01-11 10:00:56 +08:00
},
];
return (
<PageContainer>
<ProTable<API.PublicJobFair.JobFairItem>
headerTitle="公共招聘会列表"
actionRef={actionRef}
2026-06-09 16:08:39 +08:00
formRef={formRef}
2026-01-11 10:00:56 +08:00
rowKey="jobFairId"
columns={columns}
scroll={{ x: 'max-content' }}
2026-01-11 10:00:56 +08:00
rowSelection={{
selectedRowKeys,
onChange: setSelectedRowKeys,
}}
request={async (params) => {
const res = await getPublicJobFairList({
pageNum: params.current,
pageSize: params.pageSize,
jobFairTitle: params.jobFairTitle,
jobFairType: params.jobFairType,
jobFairRegionType: params.jobFairRegionType,
2026-06-09 16:08:39 +08:00
startDate: params.startDate,
endDate: params.endDate,
2026-01-11 10:00:56 +08:00
});
return { data: res.rows, total: res.total, success: true };
}}
toolBarRender={() => [
<Button
key="add"
type="primary"
icon={<PlusOutlined />}
hidden={!access.hasPerms('cms:publicJobFair:add')}
onClick={() => {
setCurrentRow(undefined);
setModalVisible(true);
}}
>
</Button>,
selectedRowKeys.length > 0 && (
<Button
key="batchDelete"
danger
icon={<DeleteOutlined />}
hidden={!access.hasPerms('cms:publicJobFair:remove')}
onClick={() => handleDelete(selectedRowKeys.join(','))}
>
</Button>
),
<Button
key="export"
icon={<ExportOutlined />}
hidden={!access.hasPerms('cms:publicJobFair:export')}
onClick={() => setExportModalOpen(true)}
>
2026-01-11 10:00:56 +08:00
</Button>,
]}
/>
<EditModal
open={modalVisible}
values={currentRow}
jobFairTypeEnum={jobFairTypeEnum}
jobFairRegionTypeEnum={jobFairRegionTypeEnum}
2026-01-11 10:00:56 +08:00
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined);
}}
onSubmit={async (values) => {
const res = values.jobFairId
? await updatePublicJobFair(values)
: await addPublicJobFair(values);
if (res.code === 200) {
message.success(values.jobFairId ? '修改成功' : '新增成功');
setModalVisible(false);
setCurrentRow(undefined);
actionRef.current?.reload();
} else {
message.error(res.msg || '操作失败');
}
}}
/>
<CompanyJobManageModal
open={companyJobModalOpen}
jobFairId={currentJobFair?.jobFairId || ''}
jobFairTitle={currentJobFair?.jobFairTitle}
onCancel={() => {
setCompanyJobModalOpen(false);
setCurrentJobFair(undefined);
}}
/>
<FairExportModal
open={exportModalOpen}
channel="online"
fairTypeOptions={dictOptions(jobFairTypeEnum)}
regionOptions={dictOptions(jobFairRegionTypeEnum)}
onCancel={() => setExportModalOpen(false)}
onExport={handleExport}
/>
2026-01-11 10:00:56 +08:00
</PageContainer>
);
};
export default PublicJobFairList;