diff --git a/src/pages/Jobfair/Outdoorfair/index.tsx b/src/pages/Jobfair/Outdoorfair/index.tsx index 82462db..f5c23ed 100644 --- a/src/pages/Jobfair/Outdoorfair/index.tsx +++ b/src/pages/Jobfair/Outdoorfair/index.tsx @@ -9,6 +9,7 @@ import { EyeOutlined, QrcodeOutlined, UnorderedListOutlined, + ExportOutlined, } from '@ant-design/icons'; import { getOutdoorFairList, @@ -19,6 +20,7 @@ import { signupOutdoorFair, getMyOutdoorFairQrCode, getOutdoorFairMiniProgramQrCode, + exportOutdoorFair, } from '@/services/jobportal/outdoorFair'; import type { OutdoorFairItem, @@ -36,6 +38,8 @@ import EditModal from './components/EditModal'; import CompanyBoothMapModal from './components/CompanyBoothMapModal'; import CompanyFairDetailModal from './components/CompanyFairDetailModal'; import JobEditModal from './Detail/components/JobEditModal'; +import FairExportModal from '../components/FairExportModal'; +import type { RecruitmentFairExportParams } from '@/services/jobfair/recruitmentFairExport'; const OUTDOOR_FAIR_TYPE_DICT = 'outdoor_fair_type'; const OUTDOOR_FAIR_REGION_DICT = 'outdoor_fair_region'; @@ -70,6 +74,7 @@ const OutdoorFairList: React.FC = () => { const [experienceEnum, setExperienceEnum] = useState({}); const [areaEnum, setAreaEnum] = useState({}); const [jobTypeEnum, setJobTypeEnum] = useState({}); + const [exportModalOpen, setExportModalOpen] = useState(false); const renderReviewStatus = (status?: string) => { const map: Record = { @@ -237,6 +242,17 @@ const OutdoorFairList: React.FC = () => { setCompanyBoothFair(record); }; + const handleExport = async (params: RecruitmentFairExportParams) => { + message.loading('正在导出...'); + try { + await exportOutdoorFair(params); + message.success('导出成功'); + setExportModalOpen(false); + } catch { + message.error('导出失败'); + } + }; + const jobColumns: ProColumns[] = [ { title: '岗位名称', dataIndex: 'jobTitle', ellipsis: true }, { @@ -334,19 +350,19 @@ const OutdoorFairList: React.FC = () => { hideInSearch: true, }, { - title: '截止时间', + title: '结束时间', dataIndex: 'endTime', valueType: 'dateTime', hideInSearch: true, }, { - title: '开放申请', + title: '报名开始时间', dataIndex: 'applyStartTime', valueType: 'dateTime', hideInSearch: true, }, { - title: '截止申请', + title: '报名截止时间', dataIndex: 'applyEndTime', valueType: 'dateTime', hideInSearch: true, @@ -535,6 +551,14 @@ const OutdoorFairList: React.FC = () => { > 新增 , + , ]} /> { actionRef.current?.reload(); }} /> + setExportModalOpen(false)} + onExport={handleExport} + /> ); }; diff --git a/src/pages/Jobfair/PublicJobFair/index.tsx b/src/pages/Jobfair/PublicJobFair/index.tsx index 38f0449..f765eca 100644 --- a/src/pages/Jobfair/PublicJobFair/index.tsx +++ b/src/pages/Jobfair/PublicJobFair/index.tsx @@ -22,6 +22,8 @@ import { } 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'; const PublicJobFairList: React.FC = () => { const access = useAccess(); @@ -36,6 +38,7 @@ const PublicJobFairList: React.FC = () => { const [jobFairRegionTypeEnum, setJobFairRegionTypeEnum] = useState({}); const [yesNoEnum, setYesNoEnum] = useState({}); const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [exportModalOpen, setExportModalOpen] = useState(false); useEffect(() => { getDictValueEnum('job_fair_type', true).then(setJobFairTypeEnum); @@ -76,27 +79,23 @@ const PublicJobFairList: React.FC = () => { }); }; - const buildListSearchParams = (values: Record): API.PublicJobFair.ListParams => { - const { dateRange, current, pageSize, ...rest } = values || {}; - const params = { ...rest } as API.PublicJobFair.ListParams; - if (dateRange?.[0] && dateRange?.[1]) { - params.startDate = dateRange[0]; - params.endDate = dateRange[1]; - } - return params; - }; - - const handleExport = async () => { + const handleExport = async (params: RecruitmentFairExportParams) => { message.loading('正在导出...'); try { - const searchVal = formRef.current?.getFieldsValue(); - await exportPublicJobFair(buildListSearchParams(searchVal || {})); + await exportPublicJobFair(params); message.success('导出成功'); + setExportModalOpen(false); } catch { message.error('导出失败'); } }; + const dictOptions = (valueEnum: Record) => + Object.entries(valueEnum).map(([value, item]) => ({ + value, + label: item?.text || item?.label || value, + })); + const columns: ProColumns[] = [ { title: '时间范围', @@ -336,7 +335,12 @@ const PublicJobFairList: React.FC = () => { 批量删除 ), - , ]} @@ -373,6 +377,14 @@ const PublicJobFairList: React.FC = () => { setCurrentJobFair(undefined); }} /> + setExportModalOpen(false)} + onExport={handleExport} + /> ); }; diff --git a/src/pages/Jobfair/components/FairExportModal.tsx b/src/pages/Jobfair/components/FairExportModal.tsx new file mode 100644 index 0000000..7a67a65 --- /dev/null +++ b/src/pages/Jobfair/components/FairExportModal.tsx @@ -0,0 +1,265 @@ +import React, { useEffect } from 'react'; +import type { Dayjs } from 'dayjs'; +import { Button, Col, DatePicker, Form, Input, Modal, Row, Select, Space } from 'antd'; +import type { + RecruitmentFairExportChannel, + RecruitmentFairExportParams, + RecruitmentFairExportType, +} from '@/services/jobfair/recruitmentFairExport'; + +const { RangePicker } = DatePicker; + +interface Option { + label?: React.ReactNode; + text?: React.ReactNode; + value: string | number | boolean; +} + +interface FormValues { + exportType: RecruitmentFairExportType; + title?: string; + hostUnit?: string; + fairType?: string; + region?: string; + venueId?: number; + address?: string; + startRange?: [Dayjs, Dayjs]; + endRange?: [Dayjs, Dayjs]; + applyRange?: [Dayjs, Dayjs]; + createRange?: [Dayjs, Dayjs]; + fairStatus?: RecruitmentFairExportParams['fairStatus']; + isCrossDomain?: string; + onlineApply?: boolean; + reviewStatus?: RecruitmentFairExportParams['reviewStatus']; +} + +interface Props { + open: boolean; + channel: RecruitmentFairExportChannel; + fairTypeOptions?: Option[]; + regionOptions?: Option[]; + venueOptions?: Option[]; + onCancel: () => void; + onExport: (params: RecruitmentFairExportParams) => Promise; +} + +const toOptions = (options: Option[] = []) => + options.map((item) => ({ + label: item.label ?? item.text, + value: item.value, + })); + +const dateRange = (range?: [Dayjs, Dayjs]) => + range + ? { + start: range[0].format('YYYY-MM-DD HH:mm:ss'), + end: range[1].format('YYYY-MM-DD HH:mm:ss'), + } + : undefined; + +const FairExportModal: React.FC = ({ + open, + channel, + fairTypeOptions, + regionOptions, + venueOptions, + onCancel, + onExport, +}) => { + const [form] = Form.useForm(); + const isOnline = channel === 'online'; + + useEffect(() => { + if (open) { + form.resetFields(); + form.setFieldsValue({ exportType: 'companies' }); + } + }, [form, open]); + + const submit = async (values: FormValues) => { + const start = dateRange(values.startRange); + const end = dateRange(values.endRange); + const apply = dateRange(values.applyRange); + const create = dateRange(values.createRange); + await onExport({ + exportType: values.exportType, + title: values.title?.trim() || undefined, + hostUnit: values.hostUnit?.trim() || undefined, + fairType: values.fairType, + region: values.region, + venueId: values.venueId, + address: values.address?.trim() || undefined, + startTime: start?.start, + endTime: end?.end, + applyStartTime: apply?.start, + applyEndTime: apply?.end, + createStartTime: create?.start, + createEndTime: create?.end, + fairStatus: values.fairStatus, + isCrossDomain: isOnline ? values.isCrossDomain : undefined, + onlineApply: isOnline ? undefined : values.onlineApply, + reviewStatus: values.reviewStatus, + }); + }; + + return ( + + + form={form} + layout="vertical" + initialValues={{ exportType: 'companies' }} + onFinish={submit} + > + + + + + + + + + + + + + + + {!isOnline && ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) : ( + + + + + + + + + + + + + + ); +}; + +export default FairExportModal; diff --git a/src/services/jobfair/publicJobFair.ts b/src/services/jobfair/publicJobFair.ts index 63c1e33..1926531 100644 --- a/src/services/jobfair/publicJobFair.ts +++ b/src/services/jobfair/publicJobFair.ts @@ -1,5 +1,6 @@ import { request } from '@umijs/max'; import { downLoadXlsx } from '@/utils/downloadfile'; +import type { RecruitmentFairExportParams } from './recruitmentFairExport'; const BASE_URL = '/api/cms/publicJobFair'; @@ -227,6 +228,10 @@ export async function getJobFairCompanies(jobFairId: string) { } /** 导出招聘会 */ -export async function exportPublicJobFair(params?: API.PublicJobFair.ListParams) { - return downLoadXlsx(`${BASE_URL}/export`, { params }, `job_fair_${new Date().getTime()}.xlsx`); +export async function exportPublicJobFair(params: RecruitmentFairExportParams) { + return downLoadXlsx( + `${BASE_URL}/export`, + { params }, + `online_fair_participants_${new Date().getTime()}.xlsx`, + ); } diff --git a/src/services/jobfair/recruitmentFairExport.ts b/src/services/jobfair/recruitmentFairExport.ts new file mode 100644 index 0000000..c30e641 --- /dev/null +++ b/src/services/jobfair/recruitmentFairExport.ts @@ -0,0 +1,37 @@ +import { downLoadXlsx } from '@/utils/downloadfile'; + +export type RecruitmentFairExportType = 'companies' | 'jobs' | 'companyJobs'; + +export interface RecruitmentFairExportParams { + exportType: RecruitmentFairExportType; + title?: string; + hostUnit?: string; + fairType?: string; + region?: string; + venueId?: number; + venueName?: string; + address?: string; + startTime?: string; + endTime?: string; + applyStartTime?: string; + applyEndTime?: string; + createStartTime?: string; + createEndTime?: string; + fairStatus?: 'NOT_STARTED' | 'ONGOING' | 'ENDED'; + isCrossDomain?: string; + onlineApply?: boolean; + reviewStatus?: '0' | '1' | '2'; +} + +export type RecruitmentFairExportChannel = 'online' | 'outdoor'; + +/** 下载线上/户外招聘会参会数据 Excel。 */ +export function exportRecruitmentFair( + channel: RecruitmentFairExportChannel, + params: RecruitmentFairExportParams, +) { + const endpoint = + channel === 'online' ? '/api/cms/publicJobFair/export' : '/api/cms/outdoor-fair/export'; + const filePrefix = channel === 'online' ? 'online_fair' : 'outdoor_fair'; + return downLoadXlsx(endpoint, { params }, `${filePrefix}_participants_${Date.now()}.xlsx`); +} diff --git a/src/services/jobportal/outdoorFair.ts b/src/services/jobportal/outdoorFair.ts index 3ff38af..3ffcfb5 100644 --- a/src/services/jobportal/outdoorFair.ts +++ b/src/services/jobportal/outdoorFair.ts @@ -1,5 +1,7 @@ import { request } from '@umijs/max'; import type { VenueBoothItem } from './venueInfo'; +import { downLoadXlsx } from '@/utils/downloadfile'; +import type { RecruitmentFairExportParams } from '@/services/jobfair/recruitmentFairExport'; /** 户外招聘会列表项 */ export interface OutdoorFairItem { @@ -24,11 +26,11 @@ export interface OutdoorFairItem { reservedBoothCount?: number; /** 举办时间 */ holdTime: string; - /** 截止时间 */ + /** 招聘会结束时间 */ endTime: string; - /** 开放申请 */ + /** 报名开始时间 */ applyStartTime: string; - /** 截止申请 */ + /** 报名截止时间 */ applyEndTime: string; /** 是否开启线上申请 */ onlineApply: boolean; @@ -188,6 +190,15 @@ export async function getOutdoorFairList(params?: OutdoorFairListParams) { }); } +/** 导出户外招聘会参会企业/岗位。 */ +export async function exportOutdoorFair(params: RecruitmentFairExportParams) { + return downLoadXlsx( + `${CMS_OUTDOOR_FAIR_BASE}/export`, + { params }, + `outdoor_fair_participants_${new Date().getTime()}.xlsx`, + ); +} + /** * 获取户外招聘会详情 * GET /api/cms/outdoor-fair/{id}