Files
shz-admin/src/pages/Jobfair/Outdoorfair/Detail/components/FairInfoTab.tsx

249 lines
9.4 KiB
TypeScript
Raw Normal View History

import React, { useCallback, useEffect, useState } from 'react';
import { history, useAccess } from '@umijs/max';
import { Button, Card, Descriptions, Divider, Image, Tag, message } from 'antd';
import { FormOutlined } from '@ant-design/icons';
import type { OutdoorFairDictForm, OutdoorFairItem } from '@/services/jobportal/outdoorFair';
import { addOutdoorFairDictOption, updateOutdoorFair } from '@/services/jobportal/outdoorFair';
import { getVenueInfo, getVenueInfoList } from '@/services/jobportal/venueInfo';
import type { VenueInfoItem } from '@/services/jobportal/venueInfo';
import { getDictSelectOption, getDictValueEnum } from '@/services/system/dict';
2026-06-18 02:30:11 +08:00
import EditModal from '@/pages/Jobfair/Outdoorfair/components/EditModal';
const OUTDOOR_FAIR_TYPE_DICT = 'outdoor_fair_type';
const OUTDOOR_FAIR_REGION_DICT = 'outdoor_fair_region';
const VENUE_INFO_TYPE_DICT = 'venue_info_type';
2026-06-18 02:30:11 +08:00
interface Props {
fairId: number;
fairInfo: OutdoorFairItem;
onFairUpdate: () => void;
}
const FairInfoTab: React.FC<Props> = ({ fairInfo, onFairUpdate }) => {
2026-06-18 02:30:11 +08:00
const access = useAccess();
const [editModalOpen, setEditModalOpen] = useState(false);
const [fairTypeOptions, setFairTypeOptions] = useState<any[]>([]);
const [regionOptions, setRegionOptions] = useState<any[]>([]);
const [venueOptions, setVenueOptions] = useState<any[]>([]);
const [venueDetail, setVenueDetail] = useState<VenueInfoItem>();
const [venueTypeValueEnum, setVenueTypeValueEnum] = useState<Record<string, any>>({});
const refreshEditModalOptions = useCallback(async () => {
const [typeOptions, regionSelectOptions, venueRes, venueTypeValueEnum] = await Promise.all([
getDictSelectOption(OUTDOOR_FAIR_TYPE_DICT),
getDictSelectOption(OUTDOOR_FAIR_REGION_DICT),
getVenueInfoList({ current: 1, pageSize: 999 }),
getDictValueEnum(VENUE_INFO_TYPE_DICT),
]);
setFairTypeOptions(typeOptions);
setRegionOptions(regionSelectOptions);
setVenueTypeValueEnum(venueTypeValueEnum);
if (venueRes.code === 200) {
setVenueOptions(
(venueRes.rows || []).map((item) => ({
label: item.venueName,
value: item.id,
venueAddress: item.venueAddress,
floorCount: item.floorCount,
})),
);
}
}, []);
useEffect(() => {
refreshEditModalOptions();
}, [refreshEditModalOptions]);
// 拉取绑定场地的详细信息
useEffect(() => {
const fetchVenueDetail = async () => {
if (!fairInfo.venueId) {
setVenueDetail(undefined);
return;
}
try {
const res = await getVenueInfo(fairInfo.venueId);
if (res.code === 200 && res.data) {
setVenueDetail(res.data);
} else {
setVenueDetail(undefined);
}
} catch {
setVenueDetail(undefined);
}
};
fetchVenueDetail();
}, [fairInfo.venueId]);
const handleCreateDictOption = async (values: OutdoorFairDictForm) => {
const res = await addOutdoorFairDictOption(values);
if (res.code === 200) {
await refreshEditModalOptions();
message.success('字典项新增成功');
return true;
}
message.error(res.msg || '字典项新增失败');
return false;
};
2026-06-18 02:30:11 +08:00
const fairTypeColors: Record<string, string> = {
: 'blue',
: 'green',
: 'orange',
: 'purple',
: 'cyan',
: 'magenta',
: 'default',
2026-06-18 02:30:11 +08:00
};
return (
<>
2026-06-18 02:30:11 +08:00
<Card
title="基本信息"
extra={
<Button
type="primary"
size="small"
icon={<FormOutlined />}
hidden={!access.hasPerms('cms:outdoorFair:edit')}
onClick={() => setEditModalOpen(true)}
>
</Button>
}
>
<Descriptions column={3} bordered size="small">
<Descriptions.Item label="招聘会标题" span={3}>
{fairInfo.title}
</Descriptions.Item>
2026-06-18 02:30:11 +08:00
<Descriptions.Item label="举办单位">{fairInfo.hostUnit}</Descriptions.Item>
<Descriptions.Item label="招聘会类型">
<Tag color={fairTypeColors[fairInfo.fairType] || 'default'}>{fairInfo.fairType}</Tag>
</Descriptions.Item>
<Descriptions.Item label="举办区域">{fairInfo.region}</Descriptions.Item>
<Descriptions.Item label="绑定场地">
{fairInfo.venueId && fairInfo.venueName ? (
<Button
type="link"
size="small"
onClick={() => history.push(`/jobfair/venue-info/detail?id=${fairInfo.venueId}`)}
>
{fairInfo.venueName}
</Button>
) : (
'--'
)}
</Descriptions.Item>
<Descriptions.Item label="举办地址" span={2}>
{fairInfo.address}
</Descriptions.Item>
2026-06-18 02:30:11 +08:00
<Descriptions.Item label="展位数量">{fairInfo.boothCount}</Descriptions.Item>
<Descriptions.Item label="举办时间">{fairInfo.holdTime}</Descriptions.Item>
<Descriptions.Item label="截止时间">{fairInfo.endTime}</Descriptions.Item>
<Descriptions.Item label="开放申请">{fairInfo.applyStartTime}</Descriptions.Item>
<Descriptions.Item label="截止申请">{fairInfo.applyEndTime}</Descriptions.Item>
<Descriptions.Item label="线上申请">
{fairInfo.onlineApply ? '是' : '否'}
</Descriptions.Item>
<Descriptions.Item label="招聘会照片" span={3}>
{fairInfo.photoUrl ? (
<Image
src={fairInfo.photoUrl}
alt={fairInfo.title}
width={240}
style={{ objectFit: 'cover', borderRadius: 4 }}
/>
) : (
'--'
)}
</Descriptions.Item>
<Descriptions.Item label="招聘会简介" span={3}>
<div style={{ whiteSpace: 'pre-wrap' }}>{fairInfo.fairIntroduction || '--'}</div>
</Descriptions.Item>
<Descriptions.Item label="招聘会整体流程" span={3}>
<div style={{ whiteSpace: 'pre-wrap' }}>{fairInfo.fairProcess || '--'}</div>
</Descriptions.Item>
2026-06-18 02:30:11 +08:00
</Descriptions>
<Divider orientation="left" plain>
</Divider>
<Descriptions column={3} bordered size="small">
<Descriptions.Item label="需携带资料" span={3}>
<div style={{ whiteSpace: 'pre-wrap' }}>{fairInfo.requiredMaterials || '--'}</div>
</Descriptions.Item>
<Descriptions.Item label="到场须知" span={3}>
<div style={{ whiteSpace: 'pre-wrap' }}>{fairInfo.attendanceNotes || '--'}</div>
</Descriptions.Item>
</Descriptions>
2026-06-18 02:30:11 +08:00
</Card>
<Card title="场地信息" style={{ marginTop: 16 }}>
{venueDetail ? (
<Descriptions column={3} bordered size="small">
<Descriptions.Item label="场地名称" span={3}>
{venueDetail.venueName || '--'}
</Descriptions.Item>
<Descriptions.Item label="场地类型">
{venueTypeValueEnum[venueDetail.venueType]?.text ||
venueTypeValueEnum[venueDetail.venueType]?.label ||
venueDetail.venueType ||
'--'}
</Descriptions.Item>
<Descriptions.Item label="场地面积">
{venueDetail.venueArea != null ? `${venueDetail.venueArea}` : '--'}
</Descriptions.Item>
<Descriptions.Item label="展位数量">
{venueDetail.floorCount ?? '--'}
</Descriptions.Item>
<Descriptions.Item label="场地地址" span={2}>
{venueDetail.venueAddress || '--'}
</Descriptions.Item>
<Descriptions.Item label="联系电话">
{venueDetail.contactPhone || '--'}
</Descriptions.Item>
<Descriptions.Item label="乘坐线路" span={3}>
{venueDetail.routeLineNames || '--'}
</Descriptions.Item>
<Descriptions.Item label="经办日期">
{venueDetail.handleDate || '--'}
</Descriptions.Item>
<Descriptions.Item label="经办机构">
{venueDetail.handleOrg || '--'}
</Descriptions.Item>
<Descriptions.Item label="经办人">
{venueDetail.handler || '--'}
</Descriptions.Item>
<Descriptions.Item label="备注" span={3}>
{venueDetail.remark || '--'}
</Descriptions.Item>
</Descriptions>
) : (
<div style={{ color: '#999' }}></div>
)}
2026-06-18 02:30:11 +08:00
</Card>
<EditModal
open={editModalOpen}
values={fairInfo}
fairTypeOptions={fairTypeOptions}
regionOptions={regionOptions}
venueOptions={venueOptions}
onCreateDictOption={handleCreateDictOption}
2026-06-18 02:30:11 +08:00
onCancel={() => setEditModalOpen(false)}
onSubmit={async (values) => {
const res = await updateOutdoorFair(values as any);
if (res.code === 200) {
message.success('修改成功');
setEditModalOpen(false);
onFairUpdate();
} else {
message.error(res.msg || '操作失败');
}
}}
/>
</>
2026-06-18 02:30:11 +08:00
);
};
export default FairInfoTab;