2026-06-25 11:30:40 +08:00
|
|
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
2026-06-18 02:30:11 +08:00
|
|
|
import { useAccess, history } from '@umijs/max';
|
|
|
|
|
import { Button, message, Modal } from 'antd';
|
|
|
|
|
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
|
|
|
|
|
import { PlusOutlined, DeleteOutlined, FormOutlined, EyeOutlined } from '@ant-design/icons';
|
|
|
|
|
import {
|
|
|
|
|
getOutdoorFairList,
|
|
|
|
|
addOutdoorFair,
|
|
|
|
|
updateOutdoorFair,
|
|
|
|
|
deleteOutdoorFair,
|
2026-06-25 11:30:40 +08:00
|
|
|
addOutdoorFairDictOption,
|
2026-06-18 02:30:11 +08:00
|
|
|
} from '@/services/jobportal/outdoorFair';
|
|
|
|
|
import type {
|
|
|
|
|
OutdoorFairItem,
|
|
|
|
|
OutdoorFairListParams,
|
|
|
|
|
OutdoorFairForm,
|
2026-06-25 11:30:40 +08:00
|
|
|
OutdoorFairDictForm,
|
2026-06-18 02:30:11 +08:00
|
|
|
} from '@/services/jobportal/outdoorFair';
|
2026-06-25 11:30:40 +08:00
|
|
|
import { getDictSelectOption, getDictValueEnum } from '@/services/system/dict';
|
2026-06-25 12:47:53 +08:00
|
|
|
import { getVenueInfoList } from '@/services/jobportal/venueInfo';
|
2026-06-18 02:30:11 +08:00
|
|
|
import EditModal from './components/EditModal';
|
|
|
|
|
|
2026-06-25 11:30:40 +08:00
|
|
|
const OUTDOOR_FAIR_TYPE_DICT = 'outdoor_fair_type';
|
|
|
|
|
const OUTDOOR_FAIR_REGION_DICT = 'outdoor_fair_region';
|
|
|
|
|
|
2026-06-18 02:30:11 +08:00
|
|
|
const OutdoorFairList: React.FC = () => {
|
|
|
|
|
const access = useAccess();
|
|
|
|
|
const actionRef = useRef<ActionType>();
|
|
|
|
|
const [modalVisible, setModalVisible] = useState(false);
|
|
|
|
|
const [currentRow, setCurrentRow] = useState<OutdoorFairItem>();
|
2026-06-25 11:30:40 +08:00
|
|
|
const [fairTypeValueEnum, setFairTypeValueEnum] = useState<Record<string, any>>({});
|
|
|
|
|
const [fairTypeOptions, setFairTypeOptions] = useState<any[]>([]);
|
|
|
|
|
const [regionValueEnum, setRegionValueEnum] = useState<Record<string, any>>({});
|
|
|
|
|
const [regionOptions, setRegionOptions] = useState<any[]>([]);
|
2026-06-25 12:47:53 +08:00
|
|
|
const [venueOptions, setVenueOptions] = useState<any[]>([]);
|
2026-06-25 11:30:40 +08:00
|
|
|
|
|
|
|
|
const refreshDictOptions = useCallback(async () => {
|
|
|
|
|
const [typeValueEnum, typeOptions, regionEnum, regionSelectOptions] = await Promise.all([
|
|
|
|
|
getDictValueEnum(OUTDOOR_FAIR_TYPE_DICT),
|
|
|
|
|
getDictSelectOption(OUTDOOR_FAIR_TYPE_DICT),
|
|
|
|
|
getDictValueEnum(OUTDOOR_FAIR_REGION_DICT),
|
|
|
|
|
getDictSelectOption(OUTDOOR_FAIR_REGION_DICT),
|
|
|
|
|
]);
|
|
|
|
|
setFairTypeValueEnum(typeValueEnum);
|
|
|
|
|
setFairTypeOptions(typeOptions);
|
|
|
|
|
setRegionValueEnum(regionEnum);
|
|
|
|
|
setRegionOptions(regionSelectOptions);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
refreshDictOptions();
|
|
|
|
|
}, [refreshDictOptions]);
|
|
|
|
|
|
2026-06-25 12:47:53 +08:00
|
|
|
const refreshVenueOptions = useCallback(async () => {
|
|
|
|
|
const res = await getVenueInfoList({ current: 1, pageSize: 999 });
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
setVenueOptions(
|
|
|
|
|
(res.rows || []).map((item) => ({
|
|
|
|
|
label: item.venueName,
|
|
|
|
|
value: item.id,
|
|
|
|
|
venueAddress: item.venueAddress,
|
|
|
|
|
floorCount: item.floorCount,
|
|
|
|
|
})),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
refreshVenueOptions();
|
|
|
|
|
}, [refreshVenueOptions]);
|
|
|
|
|
|
2026-06-25 11:30:40 +08:00
|
|
|
const handleCreateDictOption = async (values: OutdoorFairDictForm) => {
|
|
|
|
|
const res = await addOutdoorFairDictOption(values);
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
await refreshDictOptions();
|
|
|
|
|
message.success('字典项新增成功');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
message.error(res.msg || '字典项新增失败');
|
|
|
|
|
return false;
|
|
|
|
|
};
|
2026-06-18 02:30:11 +08:00
|
|
|
|
|
|
|
|
const handleDelete = async (id: number) => {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: '确认删除',
|
|
|
|
|
content: '确定要删除该户外招聘会吗?',
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
const res = await deleteOutdoorFair(id);
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
message.success('删除成功');
|
|
|
|
|
actionRef.current?.reload();
|
|
|
|
|
} else {
|
|
|
|
|
message.error(res.msg || '删除失败');
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const columns: ProColumns<OutdoorFairItem>[] = [
|
|
|
|
|
{
|
|
|
|
|
title: '招聘会标题',
|
|
|
|
|
dataIndex: 'title',
|
|
|
|
|
ellipsis: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '举办单位',
|
|
|
|
|
dataIndex: 'hostUnit',
|
|
|
|
|
ellipsis: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '招聘会类型',
|
|
|
|
|
dataIndex: 'fairType',
|
|
|
|
|
ellipsis: true,
|
2026-06-25 11:30:40 +08:00
|
|
|
valueType: 'select',
|
|
|
|
|
valueEnum: fairTypeValueEnum,
|
2026-06-18 02:30:11 +08:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '举办区域',
|
|
|
|
|
dataIndex: 'region',
|
|
|
|
|
ellipsis: true,
|
2026-06-25 11:30:40 +08:00
|
|
|
valueType: 'select',
|
|
|
|
|
valueEnum: regionValueEnum,
|
2026-06-18 02:30:11 +08:00
|
|
|
},
|
2026-06-25 12:47:53 +08:00
|
|
|
{
|
|
|
|
|
title: '绑定场地',
|
|
|
|
|
dataIndex: 'venueName',
|
|
|
|
|
ellipsis: true,
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
render: (_, record) =>
|
|
|
|
|
record.venueId && record.venueName ? (
|
|
|
|
|
<Button
|
|
|
|
|
type="link"
|
|
|
|
|
size="small"
|
|
|
|
|
onClick={() => history.push(`/jobfair/venue-info/detail?id=${record.venueId}`)}
|
|
|
|
|
>
|
|
|
|
|
{record.venueName}
|
|
|
|
|
</Button>
|
|
|
|
|
) : (
|
|
|
|
|
'--'
|
|
|
|
|
),
|
|
|
|
|
},
|
2026-06-18 02:30:11 +08:00
|
|
|
{
|
|
|
|
|
title: '举办地址',
|
|
|
|
|
dataIndex: 'address',
|
|
|
|
|
ellipsis: true,
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '展位数量',
|
|
|
|
|
dataIndex: 'boothCount',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '举办时间',
|
|
|
|
|
dataIndex: 'holdTime',
|
|
|
|
|
valueType: 'dateTime',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '截止时间',
|
|
|
|
|
dataIndex: 'endTime',
|
|
|
|
|
valueType: 'dateTime',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '开放申请',
|
|
|
|
|
dataIndex: 'applyStartTime',
|
|
|
|
|
valueType: 'dateTime',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '截止申请',
|
|
|
|
|
dataIndex: 'applyEndTime',
|
|
|
|
|
valueType: 'dateTime',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '线上申请',
|
|
|
|
|
dataIndex: 'onlineApply',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
render: (_, record) => (record.onlineApply ? '是' : '否'),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '招聘会照片',
|
|
|
|
|
dataIndex: 'photoUrl',
|
|
|
|
|
hideInSearch: true,
|
|
|
|
|
render: (_, record) =>
|
|
|
|
|
record.photoUrl ? (
|
|
|
|
|
<img
|
|
|
|
|
src={record.photoUrl}
|
|
|
|
|
alt={record.title}
|
|
|
|
|
style={{ width: 60, height: 45, objectFit: 'cover', borderRadius: 4 }}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
'--'
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '操作',
|
|
|
|
|
valueType: 'option',
|
|
|
|
|
width: 160,
|
|
|
|
|
fixed: 'right',
|
|
|
|
|
render: (_, record) => [
|
|
|
|
|
<Button
|
|
|
|
|
key="detail"
|
|
|
|
|
type="link"
|
|
|
|
|
size="small"
|
|
|
|
|
icon={<EyeOutlined />}
|
|
|
|
|
onClick={() => history.push(`/jobfair/outdoor-fair/detail?id=${record.id}`)}
|
|
|
|
|
>
|
|
|
|
|
详情
|
|
|
|
|
</Button>,
|
|
|
|
|
<Button
|
|
|
|
|
key="edit"
|
|
|
|
|
type="link"
|
|
|
|
|
size="small"
|
|
|
|
|
icon={<FormOutlined />}
|
|
|
|
|
hidden={!access.hasPerms('cms:outdoorFair:edit')}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setCurrentRow(record);
|
|
|
|
|
setModalVisible(true);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
编辑
|
|
|
|
|
</Button>,
|
|
|
|
|
<Button
|
|
|
|
|
key="delete"
|
|
|
|
|
type="link"
|
|
|
|
|
size="small"
|
|
|
|
|
danger
|
|
|
|
|
icon={<DeleteOutlined />}
|
|
|
|
|
hidden={!access.hasPerms('cms:outdoorFair:remove')}
|
|
|
|
|
onClick={() => handleDelete(record.id)}
|
|
|
|
|
>
|
|
|
|
|
删除
|
|
|
|
|
</Button>,
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<PageContainer>
|
|
|
|
|
<ProTable<OutdoorFairItem>
|
|
|
|
|
headerTitle="户外招聘会管理列表"
|
|
|
|
|
actionRef={actionRef}
|
|
|
|
|
rowKey="id"
|
|
|
|
|
columns={columns}
|
|
|
|
|
scroll={{ x: 'max-content' }}
|
|
|
|
|
request={async (params) => {
|
|
|
|
|
const res = await getOutdoorFairList({
|
|
|
|
|
current: params.current,
|
|
|
|
|
pageSize: params.pageSize,
|
|
|
|
|
title: params.title,
|
|
|
|
|
hostUnit: params.hostUnit,
|
|
|
|
|
fairType: params.fairType,
|
2026-06-25 11:30:40 +08:00
|
|
|
region: params.region,
|
2026-06-25 12:47:53 +08:00
|
|
|
venueId: params.venueId,
|
2026-06-18 02:30:11 +08:00
|
|
|
} as OutdoorFairListParams);
|
|
|
|
|
return { data: res.rows, total: res.total, success: true };
|
|
|
|
|
}}
|
|
|
|
|
toolBarRender={() => [
|
|
|
|
|
<Button
|
|
|
|
|
key="add"
|
|
|
|
|
type="primary"
|
|
|
|
|
icon={<PlusOutlined />}
|
|
|
|
|
hidden={!access.hasPerms('cms:outdoorFair:add')}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setCurrentRow(undefined);
|
|
|
|
|
setModalVisible(true);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
新增
|
|
|
|
|
</Button>,
|
|
|
|
|
]}
|
|
|
|
|
/>
|
|
|
|
|
<EditModal
|
|
|
|
|
open={modalVisible}
|
|
|
|
|
values={currentRow}
|
2026-06-25 11:30:40 +08:00
|
|
|
fairTypeOptions={fairTypeOptions}
|
|
|
|
|
regionOptions={regionOptions}
|
2026-06-25 12:47:53 +08:00
|
|
|
venueOptions={venueOptions}
|
2026-06-25 11:30:40 +08:00
|
|
|
onCreateDictOption={handleCreateDictOption}
|
2026-06-18 02:30:11 +08:00
|
|
|
onCancel={() => {
|
|
|
|
|
setModalVisible(false);
|
|
|
|
|
setCurrentRow(undefined);
|
|
|
|
|
}}
|
|
|
|
|
onSubmit={async (values: OutdoorFairForm) => {
|
2026-06-25 11:30:40 +08:00
|
|
|
const res = values.id ? await updateOutdoorFair(values) : await addOutdoorFair(values);
|
2026-06-18 02:30:11 +08:00
|
|
|
if (res.code === 200) {
|
|
|
|
|
message.success(values.id ? '修改成功' : '新增成功');
|
|
|
|
|
setModalVisible(false);
|
|
|
|
|
setCurrentRow(undefined);
|
|
|
|
|
actionRef.current?.reload();
|
|
|
|
|
} else {
|
|
|
|
|
message.error(res.msg || '操作失败');
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</PageContainer>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default OutdoorFairList;
|