Files
shz-admin/src/pages/Jobfair/Outdoorfair/Detail/components/FairInfoTab.tsx
lapuda 5213215c65
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
feat: 更新招聘会时间字段标签和验证逻辑
2026-07-23 20:32:34 +08:00

249 lines
9.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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';
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';
interface Props {
fairId: number;
fairInfo: OutdoorFairItem;
onFairUpdate: () => void;
}
const FairInfoTab: React.FC<Props> = ({ fairInfo, onFairUpdate }) => {
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;
};
const fairTypeColors: Record<string, string> = {
: 'blue',
: 'green',
: 'orange',
: 'purple',
: 'cyan',
: 'magenta',
: 'default',
};
return (
<>
<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>
<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>
<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>
</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>
</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>
)}
</Card>
<EditModal
open={editModalOpen}
values={fairInfo}
fairTypeOptions={fairTypeOptions}
regionOptions={regionOptions}
venueOptions={venueOptions}
onCreateDictOption={handleCreateDictOption}
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 || '操作失败');
}
}}
/>
</>
);
};
export default FairInfoTab;