diff --git a/src/pages/JobPortal/JobFair/Detail/index.tsx b/src/pages/JobPortal/JobFair/Detail/index.tsx index d327e2c..119ea61 100644 --- a/src/pages/JobPortal/JobFair/Detail/index.tsx +++ b/src/pages/JobPortal/JobFair/Detail/index.tsx @@ -231,6 +231,9 @@ const PortalJobFairDetailPage: React.FC = () => { {detail.boothNum && ( {detail.boothNum} )} + {channel === 'outdoor' && detail.boothMapCount !== undefined && ( + {detail.boothMapCount} + )} {detail.jobFairPhone && ( = ({ fairInfo, onFairUpdate }) => { {fairInfo.fairProcess || '--'} + + 企业参会专属信息(仅报名企业可见) + + + + {fairInfo.requiredMaterials || '--'} + + + {fairInfo.attendanceNotes || '--'} + + diff --git a/src/pages/Jobfair/Outdoorfair/components/CompanyBoothMapModal.tsx b/src/pages/Jobfair/Outdoorfair/components/CompanyBoothMapModal.tsx new file mode 100644 index 0000000..c61fd0f --- /dev/null +++ b/src/pages/Jobfair/Outdoorfair/components/CompanyBoothMapModal.tsx @@ -0,0 +1,152 @@ +import React, { useEffect, useMemo, useState } from 'react'; +import { Empty, Modal, Space, Spin, Tag, Tooltip, message } from 'antd'; +import { + getCurrentCompanyOutdoorFairBoothMap, + type OutdoorFairCompanyBoothMap, +} from '@/services/jobportal/outdoorFair'; +import type { VenueBoothItem } from '@/services/jobportal/venueInfo'; + +interface Props { + fairId?: number; + open: boolean; + onCancel: () => void; +} + +const BOOTH_WIDTH = 76; +const BOOTH_HEIGHT = 48; +const BOOTH_PADDING = 44; + +const CompanyBoothMapModal: React.FC = ({ fairId, open, onCancel }) => { + const [loading, setLoading] = useState(false); + const [mapData, setMapData] = useState(); + + useEffect(() => { + if (!open || !fairId) { + return; + } + let cancelled = false; + const loadBooths = async () => { + setLoading(true); + try { + const res = await getCurrentCompanyOutdoorFairBoothMap(fairId); + if (cancelled) { + return; + } + if (res.code === 200 && res.data) { + setMapData(res.data); + } else { + setMapData(undefined); + message.error(res.msg || '展位图加载失败'); + } + } catch { + if (!cancelled) { + setMapData(undefined); + message.error('展位图加载失败'); + } + } finally { + if (!cancelled) { + setLoading(false); + } + } + }; + void loadBooths(); + return () => { + cancelled = true; + }; + }, [fairId, open]); + + const canvasSize = useMemo(() => { + const booths = mapData?.booths || []; + const maxX = booths.reduce((max, booth) => Math.max(max, booth.positionX || 0), 0); + const maxY = booths.reduce((max, booth) => Math.max(max, booth.positionY || 0), 0); + return { + width: Math.max(920, maxX + BOOTH_WIDTH + BOOTH_PADDING), + height: Math.max(480, maxY + BOOTH_HEIGHT + BOOTH_PADDING), + }; + }, [mapData?.booths]); + + const renderBooth = (booth: VenueBoothItem, index: number) => { + const reserved = booth.status === 'reserved'; + const isCurrentCompany = reserved && booth.companyId === mapData?.currentCompanyId; + const color = isCurrentCompany ? '#f5222d' : reserved ? '#52c41a' : '#1890ff'; + const stateText = isCurrentCompany ? '本企业' : reserved ? '已预定' : '未预定'; + const tooltip = reserved ? `${booth.boothNumber}:${booth.companyName || stateText}` : `${booth.boothNumber}:未预定`; + return ( + + + {booth.boothNumber} + {stateText} + + + ); + }; + + return ( + + + + 本企业展位 + 其他已预定展位 + 未预定展位 + 展位图仅供查看,不能编辑或调整。 + + {mapData?.booths?.length ? ( + + + {mapData.booths.map(renderBooth)} + + + ) : ( + !loading && + )} + + + ); +}; + +export default CompanyBoothMapModal; diff --git a/src/pages/Jobfair/Outdoorfair/components/CompanyFairDetailModal.tsx b/src/pages/Jobfair/Outdoorfair/components/CompanyFairDetailModal.tsx new file mode 100644 index 0000000..cd3312b --- /dev/null +++ b/src/pages/Jobfair/Outdoorfair/components/CompanyFairDetailModal.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { Descriptions, Divider, Image, Modal, Tag } from 'antd'; +import type { OutdoorFairItem } from '@/services/jobportal/outdoorFair'; + +interface Props { + fair?: OutdoorFairItem | null; + open: boolean; + onCancel: () => void; +} + +const content = (value?: string) => {value || '--'}; + +const CompanyFairDetailModal: React.FC = ({ fair, open, onCancel }) => ( + + {fair && ( + <> + + + {fair.title || '--'} + + {fair.hostUnit || '--'} + {fair.fairType || '--'} + {fair.region || '--'} + {fair.venueName || '--'} + + {fair.address || '--'} + + {fair.boothCount ?? '--'} + {fair.reservedBoothCount ?? 0} + {fair.holdTime || '--'} + {fair.endTime || '--'} + {fair.applyStartTime || '--'} + {fair.applyEndTime || '--'} + + {fair.onlineApply ? '是' : '否'} + + + {fair.photoUrl ? ( + + ) : ( + '--' + )} + + + {content(fair.fairIntroduction)} + + + {content(fair.fairProcess)} + + + + 企业参会专属信息 + + + {content(fair.requiredMaterials)} + {content(fair.attendanceNotes)} + + > + )} + +); + +export default CompanyFairDetailModal; diff --git a/src/pages/Jobfair/Outdoorfair/components/EditModal.tsx b/src/pages/Jobfair/Outdoorfair/components/EditModal.tsx index 85af73d..7a9e10a 100644 --- a/src/pages/Jobfair/Outdoorfair/components/EditModal.tsx +++ b/src/pages/Jobfair/Outdoorfair/components/EditModal.tsx @@ -310,6 +310,21 @@ const EditModal: React.FC = ({ placeholder="请输入招聘会整体流程" fieldProps={{ maxLength: 5000, showCount: true, autoSize: { minRows: 4, maxRows: 8 } }} /> + + 企业参会专属信息(仅报名企业可见) + + + { const [qrInfo, setQrInfo] = useState(null); const [rejectReasonModalOpen, setRejectReasonModalOpen] = useState(false); const [rejectReason, setRejectReason] = useState(''); + const [companyDetailFair, setCompanyDetailFair] = useState(null); + const [companyBoothFair, setCompanyBoothFair] = useState(null); const [fairTypeValueEnum, setFairTypeValueEnum] = useState>({}); const [fairTypeOptions, setFairTypeOptions] = useState([]); const [regionValueEnum, setRegionValueEnum] = useState>({}); @@ -202,6 +206,14 @@ const OutdoorFairList: React.FC = () => { setRejectReasonModalOpen(true); }; + const openCompanyDetail = (record: OutdoorFairItem) => { + setCompanyDetailFair(record); + }; + + const openCompanyBoothMap = (record: OutdoorFairItem) => { + setCompanyBoothFair(record); + }; + const jobColumns: ProColumns[] = [ { title: '岗位名称', dataIndex: 'jobTitle', ellipsis: true }, { @@ -362,7 +374,7 @@ const OutdoorFairList: React.FC = () => { { title: '操作', valueType: 'option', - width: isEnterprise ? 280 : 160, + width: isEnterprise ? 520 : 160, fixed: 'right', render: (_, record) => [ isEnterprise && !record.signedUp ? ( @@ -397,6 +409,16 @@ const OutdoorFairList: React.FC = () => { 查看报名岗位 ) : null, + isEnterprise ? ( + openCompanyDetail(record)}> + 招聘会详情 + + ) : null, + isEnterprise && record.signedUp && record.reviewStatus === '1' ? ( + openCompanyBoothMap(record)}> + 查看展位图 + + ) : null, { {rejectReason} + setCompanyDetailFair(null)} + /> + setCompanyBoothFair(null)} + /> { venueName?: string; address?: string; boothCount?: number; + boothMapCount?: number; holdTime?: string; endTime?: string; photoUrl?: string; @@ -206,6 +209,7 @@ export async function getPortalJobFairDetail(channel: JobFairChannel, jobFairId: jobFairImage: fair.jobFairImage || fair.photoUrl, boothNum: fair.boothNum || (fair.boothCount === undefined ? undefined : String(fair.boothCount)), + boothMapCount: fair.boothMapCount, jobFairRegion: fair.jobFairRegion || fair.region, jobFairVenueName: fair.jobFairVenueName || fair.venueName, }, diff --git a/src/services/jobportal/outdoorFair.ts b/src/services/jobportal/outdoorFair.ts index 580944f..950666d 100644 --- a/src/services/jobportal/outdoorFair.ts +++ b/src/services/jobportal/outdoorFair.ts @@ -1,4 +1,5 @@ import { request } from '@umijs/max'; +import type { VenueBoothItem } from './venueInfo'; /** 户外招聘会列表项 */ export interface OutdoorFairItem { @@ -37,6 +38,10 @@ export interface OutdoorFairItem { fairIntroduction?: string; /** 招聘会整体流程 */ fairProcess?: string; + /** 企业参加招聘会需携带的资料 */ + requiredMaterials?: string; + /** 企业到场须知 */ + attendanceNotes?: string; /** 当前企业ID */ companyId?: number; /** 当前企业名称 */ @@ -96,6 +101,10 @@ export interface OutdoorFairForm { fairIntroduction?: string; /** 招聘会整体流程 */ fairProcess?: string; + /** 企业参加招聘会需携带的资料 */ + requiredMaterials?: string; + /** 企业到场须知 */ + attendanceNotes?: string; /** 更换场地时确认清空旧展位图与预定,并按新模板重建 */ resetBoothMap?: boolean; } @@ -125,6 +134,12 @@ export interface OutdoorFairCompanyQrCodeInfo { qrCodeContent: string; } +/** 企业审核通过后可读取的只读展位图。 */ +export interface OutdoorFairCompanyBoothMap { + currentCompanyId: number; + booths: VenueBoothItem[]; +} + /** 户外招聘会字典新增表单 */ export interface OutdoorFairDictForm { dictType: 'outdoor_fair_type' | 'outdoor_fair_region'; @@ -169,6 +184,17 @@ export async function getOutdoorFairInfo(id: number) { }); } +/** + * 当前企业查看户外招聘会展位图。 + * 服务端会校验当前企业已报名且审核通过,接口只提供读取能力。 + */ +export async function getCurrentCompanyOutdoorFairBoothMap(fairId: number) { + return request<{ code: number; msg?: string; data?: OutdoorFairCompanyBoothMap }>( + `${CMS_OUTDOOR_FAIR_BASE}/${fairId}/company/booth-map`, + { method: 'GET' }, + ); +} + /** 招聘会统计-时间桶序列项(曲线图用) */ export interface OutdoorFairStatisticsSeriesItem { time: string;