11
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
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
This commit is contained in:
140
src/pages/Jobfair/Indoorjobfair/Detail/components/BoothTab.tsx
Normal file
140
src/pages/Jobfair/Indoorjobfair/Detail/components/BoothTab.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useAccess } from '@umijs/max';
|
||||
import { Button, message, Modal, Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable, ModalForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';
|
||||
import { PlusOutlined, DeleteOutlined, FormOutlined, LockOutlined, UnlockOutlined, PaperClipOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
getBoothList,
|
||||
addBooth,
|
||||
updateBooth,
|
||||
fixBooth,
|
||||
reserveBooth,
|
||||
releaseBooth,
|
||||
} from '@/services/jobportal/indoorJobFair';
|
||||
import type { BoothItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const BoothTab: React.FC<Props> = () => {
|
||||
const access = useAccess();
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [editingBooth, setEditingBooth] = useState<BoothItem | null>(null);
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
available: { text: '可用', color: 'green' },
|
||||
fixed: { text: '固定', color: 'blue' },
|
||||
reserved: { text: '预留', color: 'orange' },
|
||||
locked: { text: '锁定', color: 'red' },
|
||||
};
|
||||
|
||||
const columns: ProColumns<BoothItem>[] = [
|
||||
{ title: '展位号', dataIndex: 'boothNumber', width: 100 },
|
||||
{ title: '企业名称', dataIndex: 'companyName', ellipsis: true, render: (_, r) => r.companyName || '--' },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
render: (_, record) => {
|
||||
const s = statusMap[record.status] || { text: record.status, color: 'default' };
|
||||
return <Tag color={s.color}>{s.text}</Tag>;
|
||||
},
|
||||
},
|
||||
{ title: '操作人', dataIndex: 'operator', width: 100, render: (_, r) => r.operator || '--' },
|
||||
{ title: '操作时间', dataIndex: 'operateTime', width: 170, render: (_, r) => r.operateTime || '--' },
|
||||
{ title: '备注', dataIndex: 'remark', ellipsis: true, render: (_, r) => r.remark || '--' },
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 250,
|
||||
render: (_, record) => [
|
||||
<Button key="edit" type="link" size="small" icon={<FormOutlined />}
|
||||
onClick={() => { setEditingBooth(record); setModalOpen(true); }}
|
||||
>编辑</Button>,
|
||||
<Button key="fix" type="link" size="small" icon={<LockOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit') || record.status === 'fixed'}
|
||||
onClick={async () => {
|
||||
const res = await fixBooth(record.id, '当前用户');
|
||||
if (res.code === 200) { message.success('固定成功'); actionRef.current?.reload(); }
|
||||
else { message.error(res.msg); }
|
||||
}}
|
||||
>固定</Button>,
|
||||
<Button key="reserve" type="link" size="small" icon={<PaperClipOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit') || record.status === 'reserved'}
|
||||
onClick={async () => {
|
||||
const res = await reserveBooth(record.id, '当前用户');
|
||||
if (res.code === 200) { message.success('预留成功'); actionRef.current?.reload(); }
|
||||
else { message.error(res.msg); }
|
||||
}}
|
||||
>预留</Button>,
|
||||
<Button key="release" type="link" size="small" icon={<UnlockOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit') || record.status === 'available'}
|
||||
onClick={async () => {
|
||||
const res = await releaseBooth(record.id);
|
||||
if (res.code === 200) { message.success('解除成功'); actionRef.current?.reload(); }
|
||||
else { message.error(res.msg); }
|
||||
}}
|
||||
>解除</Button>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="摊位信息列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
request={async (params) => {
|
||||
const res = await getBoothList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
boothNumber: params.boothNumber,
|
||||
companyName: params.companyName,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button key="add" type="primary" icon={<PlusOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:add')}
|
||||
onClick={() => { setEditingBooth(null); setModalOpen(true); }}
|
||||
>新增摊位</Button>,
|
||||
]}
|
||||
/>
|
||||
|
||||
<ModalForm
|
||||
title={editingBooth ? '编辑摊位' : '新增摊位'}
|
||||
open={modalOpen}
|
||||
width={400}
|
||||
modalProps={{ destroyOnClose: true, onCancel: () => setModalOpen(false) }}
|
||||
onFinish={async (values) => {
|
||||
const res = editingBooth
|
||||
? await updateBooth({ id: editingBooth.id, ...values })
|
||||
: await addBooth({ venueId: 1, ...values } as any);
|
||||
if (res.code === 200) { message.success(res.msg); setModalOpen(false); actionRef.current?.reload(); return true; }
|
||||
message.error(res.msg); return false;
|
||||
}}
|
||||
initialValues={editingBooth}
|
||||
>
|
||||
<ProFormText name="boothNumber" label="展位号" rules={[{ required: true, message: '请输入展位号' }]} placeholder="如:A01" />
|
||||
<ProFormText name="companyName" label="企业名称" placeholder="请输入企业名称" />
|
||||
<ProFormSelect name="status" label="状态"
|
||||
options={[
|
||||
{ label: '可用', value: 'available' },
|
||||
{ label: '固定', value: 'fixed' },
|
||||
{ label: '预留', value: 'reserved' },
|
||||
{ label: '锁定', value: 'locked' },
|
||||
]}
|
||||
/>
|
||||
<ProFormText name="remark" label="备注" placeholder="请输入备注" />
|
||||
</ModalForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoothTab;
|
||||
@@ -0,0 +1,77 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Button, message } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||
import { ExportOutlined } from '@ant-design/icons';
|
||||
import { getCompanyQueryList } from '@/services/jobportal/indoorJobFair';
|
||||
import type { CompanyQueryItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const CompanyQueryTab: React.FC<Props> = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
|
||||
const handleExport = async (type: string) => {
|
||||
if (type === 'selected' && selectedRowKeys.length === 0) {
|
||||
message.warning('请先选择要导出的数据');
|
||||
return;
|
||||
}
|
||||
message.success(`已导出${type === 'selected' ? '选中' : type === 'page' ? '当前页' : '全部'}数据(模拟)`);
|
||||
};
|
||||
|
||||
const columns: ProColumns<CompanyQueryItem>[] = [
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true, hideInSearch: true },
|
||||
{
|
||||
title: '招聘会名称',
|
||||
dataIndex: 'fairName',
|
||||
hideInTable: true,
|
||||
order: 1,
|
||||
},
|
||||
{ title: '单位名称', dataIndex: 'companyName', ellipsis: true },
|
||||
{ title: '行业', dataIndex: 'industry', width: 120, hideInSearch: true },
|
||||
{ title: '规模', dataIndex: 'scale', width: 120, hideInSearch: true },
|
||||
{ title: '联系人', dataIndex: 'contactPerson', width: 100, hideInSearch: true },
|
||||
{ title: '联系电话', dataIndex: 'contactPhone', width: 130, hideInSearch: true },
|
||||
{ title: '报名时间', dataIndex: 'registrationTime', valueType: 'dateTime', width: 170, hideInSearch: true },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="参会单位列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
rowSelection={{
|
||||
selectedRowKeys,
|
||||
onChange: setSelectedRowKeys,
|
||||
}}
|
||||
request={async (params) => {
|
||||
const res = await getCompanyQueryList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
fairName: params.fairName,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button key="exportSelected" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('selected')}
|
||||
>导出选中</Button>,
|
||||
<Button key="exportPage" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('page')}
|
||||
>导出当前页</Button>,
|
||||
<Button key="exportAll" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('all')}
|
||||
>导出全部</Button>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CompanyQueryTab;
|
||||
@@ -0,0 +1,153 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useAccess } from '@umijs/max';
|
||||
import { Button, message, Modal, Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable, ModalForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';
|
||||
import { EyeOutlined } from '@ant-design/icons';
|
||||
import { getCompanyRecordList, updateCompanyRecordStatus, updateCompanyCreditStatus } from '@/services/jobportal/indoorJobFair';
|
||||
import type { CompanyRecordItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const CompanyRecordTab: React.FC<Props> = () => {
|
||||
const access = useAccess();
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [currentRecord, setCurrentRecord] = useState<CompanyRecordItem | null>(null);
|
||||
const [modalType, setModalType] = useState<'status' | 'credit'>('status');
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
normal: { text: '正常', color: 'green' },
|
||||
abnormal: { text: '异常', color: 'red' },
|
||||
};
|
||||
|
||||
const creditStatusMap: Record<string, { text: string; color: string }> = {
|
||||
good: { text: '良好', color: 'green' },
|
||||
poor: { text: '失信', color: 'red' },
|
||||
};
|
||||
|
||||
const handleUpdateStatus = async (values: any) => {
|
||||
if (!currentRecord) return false;
|
||||
const res = await updateCompanyRecordStatus(currentRecord.id, values.status);
|
||||
if (res.code === 200) {
|
||||
message.success('状态修改成功');
|
||||
setModalOpen(false);
|
||||
actionRef.current?.reload();
|
||||
return true;
|
||||
}
|
||||
message.error(res.msg);
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleUpdateCredit = async (values: any) => {
|
||||
if (!currentRecord) return false;
|
||||
const res = await updateCompanyCreditStatus(currentRecord.id, values.creditStatus);
|
||||
if (res.code === 200) {
|
||||
message.success('失信记录更新成功');
|
||||
setModalOpen(false);
|
||||
actionRef.current?.reload();
|
||||
return true;
|
||||
}
|
||||
message.error(res.msg);
|
||||
return false;
|
||||
};
|
||||
|
||||
const columns: ProColumns<CompanyRecordItem>[] = [
|
||||
{ title: '单位名称', dataIndex: 'companyName', ellipsis: true },
|
||||
{ title: '行业', dataIndex: 'industry', width: 100, hideInSearch: true },
|
||||
{ title: '规模', dataIndex: 'scale', width: 100, hideInSearch: true },
|
||||
{ title: '联系人', dataIndex: 'contactPerson', width: 100, hideInSearch: true },
|
||||
{ title: '联系电话', dataIndex: 'contactPhone', width: 130, hideInSearch: true },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => {
|
||||
const s = statusMap[record.status] || { text: record.status, color: 'default' };
|
||||
return <Tag color={s.color}>{s.text}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '失信情况',
|
||||
dataIndex: 'creditStatus',
|
||||
width: 80,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => {
|
||||
const s = creditStatusMap[record.creditStatus] || { text: record.creditStatus, color: 'default' };
|
||||
return <Tag color={s.color}>{s.text}</Tag>;
|
||||
},
|
||||
},
|
||||
{ title: '参会次数', dataIndex: 'fairCount', width: 80, hideInSearch: true },
|
||||
{ title: '创建时间', dataIndex: 'createTime', valueType: 'dateTime', width: 170, hideInSearch: true },
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 150,
|
||||
render: (_, record) => [
|
||||
<Button key="view" type="link" size="small" icon={<EyeOutlined />}
|
||||
onClick={() => message.info('查看单位基本信息(模拟)')}
|
||||
>基本信息</Button>,
|
||||
<Button key="status" type="link" size="small"
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit')}
|
||||
onClick={() => { setCurrentRecord(record); setModalType('status'); setModalOpen(true); }}
|
||||
>修改状态</Button>,
|
||||
<Button key="credit" type="link" size="small" danger
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit')}
|
||||
onClick={() => { setCurrentRecord(record); setModalType('credit'); setModalOpen(true); }}
|
||||
>失信记录</Button>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="单位参会查询列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
request={async (params) => {
|
||||
const res = await getCompanyRecordList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
companyName: params.companyName,
|
||||
contactPerson: params.contactPerson,
|
||||
contactPhone: params.contactPhone,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
/>
|
||||
|
||||
<ModalForm
|
||||
title={modalType === 'status' ? '修改状态' : '失信记录'}
|
||||
open={modalOpen}
|
||||
width={400}
|
||||
modalProps={{ destroyOnClose: true, onCancel: () => setModalOpen(false) }}
|
||||
onFinish={modalType === 'status' ? handleUpdateStatus : handleUpdateCredit}
|
||||
initialValues={currentRecord}
|
||||
>
|
||||
{modalType === 'status' ? (
|
||||
<ProFormSelect name="status" label="状态"
|
||||
options={[
|
||||
{ label: '正常', value: 'normal' },
|
||||
{ label: '异常', value: 'abnormal' },
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<ProFormSelect name="creditStatus" label="失信情况"
|
||||
options={[
|
||||
{ label: '良好', value: 'good' },
|
||||
{ label: '失信', value: 'poor' },
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</ModalForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CompanyRecordTab;
|
||||
@@ -0,0 +1,153 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useAccess } from '@umijs/max';
|
||||
import { Button, message, Modal, Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||
import { ExportOutlined, EyeOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons';
|
||||
import { getCompanyReviewList, batchApproveCompany, batchRejectCompany } from '@/services/jobportal/indoorJobFair';
|
||||
import type { CompanyReviewItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const CompanyReviewTab: React.FC<Props> = () => {
|
||||
const access = useAccess();
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
pending: { text: '待审核', color: 'default' },
|
||||
approved: { text: '已通过', color: 'green' },
|
||||
rejected: { text: '已拒绝', color: 'red' },
|
||||
};
|
||||
|
||||
const handleBatchApprove = async () => {
|
||||
if (selectedRowKeys.length === 0) {
|
||||
message.warning('请先选择要审核的数据');
|
||||
return;
|
||||
}
|
||||
const res = await batchApproveCompany(selectedRowKeys as number[]);
|
||||
if (res.code === 200) {
|
||||
message.success('批量审核成功');
|
||||
setSelectedRowKeys([]);
|
||||
actionRef.current?.reload();
|
||||
} else {
|
||||
message.error(res.msg);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBatchReject = async () => {
|
||||
if (selectedRowKeys.length === 0) {
|
||||
message.warning('请先选择要审核的数据');
|
||||
return;
|
||||
}
|
||||
const res = await batchRejectCompany(selectedRowKeys as number[]);
|
||||
if (res.code === 200) {
|
||||
message.success('批量审核失败');
|
||||
setSelectedRowKeys([]);
|
||||
actionRef.current?.reload();
|
||||
} else {
|
||||
message.error(res.msg);
|
||||
}
|
||||
};
|
||||
|
||||
const handleExport = async (type: string) => {
|
||||
if (type === 'selected' && selectedRowKeys.length === 0) {
|
||||
message.warning('请先选择要导出的数据');
|
||||
return;
|
||||
}
|
||||
message.success(`已导出${type === 'selected' ? '选中' : type === 'page' ? '当前页' : '全部'}数据(模拟)`);
|
||||
};
|
||||
|
||||
const columns: ProColumns<CompanyReviewItem>[] = [
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true, hideInSearch: true },
|
||||
{
|
||||
title: '招聘会名称',
|
||||
dataIndex: 'fairName',
|
||||
hideInTable: true,
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
title: '单位名称',
|
||||
dataIndex: 'companyName',
|
||||
order: 2,
|
||||
},
|
||||
{ title: '单位名称', dataIndex: 'companyName', ellipsis: true, hideInSearch: true },
|
||||
{ title: '行业', dataIndex: 'industry', width: 100, hideInSearch: true },
|
||||
{ title: '规模', dataIndex: 'scale', width: 100, hideInSearch: true },
|
||||
{ title: '联系人', dataIndex: 'contactPerson', width: 100, hideInSearch: true },
|
||||
{ title: '联系电话', dataIndex: 'contactPhone', width: 130, hideInSearch: true },
|
||||
{
|
||||
title: '审核状态',
|
||||
dataIndex: 'reviewStatus',
|
||||
valueType: 'select',
|
||||
width: 100,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => {
|
||||
const s = statusMap[record.reviewStatus] || { text: record.reviewStatus, color: 'default' };
|
||||
return <Tag color={s.color}>{s.text}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 150,
|
||||
render: (_, record) => [
|
||||
<Button key="viewCompany" type="link" size="small" icon={<EyeOutlined />}
|
||||
onClick={() => message.info('查看单位基本信息(模拟)')}
|
||||
>单位信息</Button>,
|
||||
<Button key="viewFair" type="link" size="small" icon={<EyeOutlined />}
|
||||
onClick={() => message.info('查看招聘会详情(模拟)')}
|
||||
>查看展会</Button>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="参会单位审核列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
rowSelection={{
|
||||
selectedRowKeys,
|
||||
onChange: setSelectedRowKeys,
|
||||
}}
|
||||
request={async (params) => {
|
||||
const res = await getCompanyReviewList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
fairName: params.fairName,
|
||||
companyName: params.companyName,
|
||||
reviewStatus: params.reviewStatus,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button key="batchApprove" type="primary" icon={<CheckOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit')}
|
||||
onClick={handleBatchApprove}
|
||||
>批量审核成功</Button>,
|
||||
<Button key="batchReject" danger icon={<CloseOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit')}
|
||||
onClick={handleBatchReject}
|
||||
>批量审核失败</Button>,
|
||||
<Button key="exportSelected" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('selected')}
|
||||
>导出选中</Button>,
|
||||
<Button key="exportPage" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('page')}
|
||||
>导出当前页</Button>,
|
||||
<Button key="exportAll" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('all')}
|
||||
>导出全部</Button>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CompanyReviewTab;
|
||||
@@ -0,0 +1,147 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useAccess } from '@umijs/max';
|
||||
import { Button, message, Modal, Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable, ModalForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';
|
||||
import { PlusOutlined, DeleteOutlined, FormOutlined, ApartmentOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
getJobFairList,
|
||||
addJobFair,
|
||||
updateJobFair,
|
||||
deleteJobFair,
|
||||
} from '@/services/jobportal/indoorJobFair';
|
||||
import type { JobFairItem, JobFairForm } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
fairInfo: JobFairItem;
|
||||
onFairUpdate: () => void;
|
||||
}
|
||||
|
||||
const FairManageTab: React.FC<Props> = ({ fairInfo }) => {
|
||||
const access = useAccess();
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [editingFair, setEditingFair] = useState<JobFairItem | null>(null);
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
pending: { text: '筹备中', color: 'default' },
|
||||
ongoing: { text: '进行中', color: 'green' },
|
||||
finished: { text: '已结束', color: 'red' },
|
||||
};
|
||||
|
||||
const columns: ProColumns<JobFairItem>[] = [
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true },
|
||||
{ title: '场地名称', dataIndex: 'venueName', ellipsis: true, hideInSearch: true },
|
||||
{ title: '开始日期', dataIndex: 'startDate', hideInSearch: true },
|
||||
{ title: '结束日期', dataIndex: 'endDate', hideInSearch: true },
|
||||
{ title: '使用展位数', dataIndex: 'boothUseCount', hideInSearch: true },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
hideInSearch: true,
|
||||
render: (_, record) => {
|
||||
const s = statusMap[record.status] || { text: record.status, color: 'default' };
|
||||
return <Tag color={s.color}>{s.text}</Tag>;
|
||||
},
|
||||
},
|
||||
{ title: '创建时间', dataIndex: 'createTime', valueType: 'dateTime', hideInSearch: true },
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 200,
|
||||
render: (_, record) => [
|
||||
<Button key="booth" type="link" size="small" icon={<ApartmentOutlined />}
|
||||
onClick={() => message.info('展位管理功能开发中')}
|
||||
>展位管理</Button>,
|
||||
<Button key="edit" type="link" size="small" icon={<FormOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit')}
|
||||
onClick={() => { setEditingFair(record); setModalOpen(true); }}
|
||||
>编辑</Button>,
|
||||
<Button key="delete" type="link" size="small" danger icon={<DeleteOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:remove')}
|
||||
onClick={() => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定删除招聘会「${record.fairName}」吗?`,
|
||||
onOk: async () => {
|
||||
const res = await deleteJobFair(record.id);
|
||||
if (res.code === 200) { message.success('删除成功'); actionRef.current?.reload(); }
|
||||
else { message.error(res.msg); }
|
||||
},
|
||||
});
|
||||
}}
|
||||
>删除</Button>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const venueOptions = [
|
||||
{ label: '石河子大学体育馆', value: 1 },
|
||||
{ label: '第八师人力资源市场', value: 2 },
|
||||
{ label: '阿拉尔市人才交流中心', value: 3 },
|
||||
{ label: '图木舒克市职业介绍所', value: 4 },
|
||||
];
|
||||
|
||||
const venueNameMap: Record<number, string> = {
|
||||
1: '石河子大学体育馆',
|
||||
2: '第八师人力资源市场',
|
||||
3: '阿拉尔市人才交流中心',
|
||||
4: '图木舒克市职业介绍所',
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="招聘会列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
request={async (params) => {
|
||||
const res = await getJobFairList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
fairName: params.fairName,
|
||||
startDate: params.startDate,
|
||||
endDate: params.endDate,
|
||||
} as any);
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button key="add" type="primary" icon={<PlusOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:add')}
|
||||
onClick={() => { setEditingFair(null); setModalOpen(true); }}
|
||||
>新增招聘会</Button>,
|
||||
]}
|
||||
/>
|
||||
|
||||
<ModalForm
|
||||
title={editingFair ? '编辑招聘会' : '新增招聘会'}
|
||||
open={modalOpen}
|
||||
width={500}
|
||||
modalProps={{ destroyOnClose: true, onCancel: () => setModalOpen(false) }}
|
||||
onFinish={async (values) => {
|
||||
const submitValues = {
|
||||
...values,
|
||||
venueName: venueNameMap[values.venueId as number] || '',
|
||||
};
|
||||
const res = editingFair
|
||||
? await updateJobFair({ id: editingFair.id, ...submitValues } as JobFairForm)
|
||||
: await addJobFair(submitValues as JobFairForm);
|
||||
if (res.code === 200) { message.success(res.msg); setModalOpen(false); actionRef.current?.reload(); return true; }
|
||||
message.error(res.msg); return false;
|
||||
}}
|
||||
initialValues={editingFair}
|
||||
>
|
||||
<ProFormText name="fairName" label="招聘会名称" rules={[{ required: true, message: '请输入招聘会名称' }]} />
|
||||
<ProFormSelect name="venueId" label="选择场地" rules={[{ required: true, message: '请选择场地' }]}
|
||||
options={venueOptions} />
|
||||
<ProFormText name="startDate" label="开始日期" rules={[{ required: true, message: '请输入开始日期' }]} />
|
||||
<ProFormText name="endDate" label="结束日期" rules={[{ required: true, message: '请输入结束日期' }]} />
|
||||
</ModalForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FairManageTab;
|
||||
@@ -0,0 +1,90 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Button, message } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||
import { ExportOutlined } from '@ant-design/icons';
|
||||
import { getJobQueryList } from '@/services/jobportal/indoorJobFair';
|
||||
import type { JobQueryItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const JobQueryTab: React.FC<Props> = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
|
||||
const handleExport = async (type: string) => {
|
||||
if (type === 'selected' && selectedRowKeys.length === 0) {
|
||||
message.warning('请先选择要导出的数据');
|
||||
return;
|
||||
}
|
||||
message.success(`已导出${type === 'selected' ? '选中' : type === 'page' ? '当前页' : '全部'}数据(模拟)`);
|
||||
};
|
||||
|
||||
const columns: ProColumns<JobQueryItem>[] = [
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true, hideInSearch: true },
|
||||
{
|
||||
title: '招聘会名称',
|
||||
dataIndex: 'fairName',
|
||||
hideInTable: true,
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
title: '单位名称',
|
||||
dataIndex: 'companyName',
|
||||
hideInTable: true,
|
||||
order: 2,
|
||||
},
|
||||
{ title: '单位名称', dataIndex: 'companyName', ellipsis: true, hideInSearch: true },
|
||||
{ title: '职位名称', dataIndex: 'jobTitle', ellipsis: true },
|
||||
{
|
||||
title: '薪资范围',
|
||||
dataIndex: 'salary',
|
||||
hideInSearch: true,
|
||||
render: (_, record) => `${record.minSalary}-${record.maxSalary}`,
|
||||
},
|
||||
{ title: '学历要求', dataIndex: 'education', width: 100, hideInSearch: true },
|
||||
{ title: '经验要求', dataIndex: 'experience', width: 100, hideInSearch: true },
|
||||
{ title: '招聘人数', dataIndex: 'vacancies', width: 80, hideInSearch: true },
|
||||
{ title: '状态', dataIndex: 'status', width: 80, hideInSearch: true, render: (_, r) => r.status === 'open' ? '招聘中' : '已结束' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="参会岗位列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
rowSelection={{
|
||||
selectedRowKeys,
|
||||
onChange: setSelectedRowKeys,
|
||||
}}
|
||||
request={async (params) => {
|
||||
const res = await getJobQueryList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
fairName: params.fairName,
|
||||
companyName: params.companyName,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button key="exportSelected" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('selected')}
|
||||
>导出选中</Button>,
|
||||
<Button key="exportPage" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('page')}
|
||||
>导出当前页</Button>,
|
||||
<Button key="exportAll" icon={<ExportOutlined />}
|
||||
onClick={() => handleExport('all')}
|
||||
>导出全部</Button>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default JobQueryTab;
|
||||
@@ -0,0 +1,140 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useAccess } from '@umijs/max';
|
||||
import { Button, message, Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable, ModalForm, ProFormText } from '@ant-design/pro-components';
|
||||
import { EyeOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons';
|
||||
import { getJobReviewList, approveJob, rejectJob } from '@/services/jobportal/indoorJobFair';
|
||||
import type { JobReviewItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const JobReviewTab: React.FC<Props> = () => {
|
||||
const access = useAccess();
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [reviewModalOpen, setReviewModalOpen] = useState(false);
|
||||
const [currentJob, setCurrentJob] = useState<JobReviewItem | null>(null);
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
pending: { text: '待审核', color: 'default' },
|
||||
approved: { text: '已通过', color: 'green' },
|
||||
rejected: { text: '已拒绝', color: 'red' },
|
||||
};
|
||||
|
||||
const handleApprove = async (values: any) => {
|
||||
if (!currentJob) return false;
|
||||
const res = await approveJob(currentJob.id, values.reviewRemark);
|
||||
if (res.code === 200) {
|
||||
message.success('审核通过');
|
||||
setReviewModalOpen(false);
|
||||
actionRef.current?.reload();
|
||||
return true;
|
||||
}
|
||||
message.error(res.msg);
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleReject = async (values: any) => {
|
||||
if (!currentJob) return false;
|
||||
const res = await rejectJob(currentJob.id, values.reviewRemark);
|
||||
if (res.code === 200) {
|
||||
message.success('审核不通过');
|
||||
setReviewModalOpen(false);
|
||||
actionRef.current?.reload();
|
||||
return true;
|
||||
}
|
||||
message.error(res.msg);
|
||||
return false;
|
||||
};
|
||||
|
||||
const columns: ProColumns<JobReviewItem>[] = [
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true, hideInSearch: true },
|
||||
{
|
||||
title: '单位名称',
|
||||
dataIndex: 'companyName',
|
||||
order: 1,
|
||||
},
|
||||
{ title: '单位名称', dataIndex: 'companyName', ellipsis: true, hideInSearch: true },
|
||||
{
|
||||
title: '职位名称',
|
||||
dataIndex: 'jobTitle',
|
||||
order: 2,
|
||||
},
|
||||
{ title: '职位名称', dataIndex: 'jobTitle', ellipsis: true, hideInSearch: true },
|
||||
{ title: '学历要求', dataIndex: 'education', width: 100, hideInSearch: true },
|
||||
{ title: '经验要求', dataIndex: 'experience', width: 100, hideInSearch: true },
|
||||
{ title: '招聘人数', dataIndex: 'vacancies', width: 80, hideInSearch: true },
|
||||
{
|
||||
title: '审核状态',
|
||||
dataIndex: 'reviewStatus',
|
||||
valueType: 'select',
|
||||
width: 100,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => {
|
||||
const s = statusMap[record.reviewStatus] || { text: record.reviewStatus, color: 'default' };
|
||||
return <Tag color={s.color}>{s.text}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 200,
|
||||
render: (_, record) => [
|
||||
<Button key="view" type="link" size="small" icon={<EyeOutlined />}
|
||||
onClick={() => message.info('查看单位基本信息(模拟)')}
|
||||
>单位信息</Button>,
|
||||
record.reviewStatus === 'pending' && (
|
||||
<Button key="review" type="link" size="small"
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit')}
|
||||
onClick={() => { setCurrentJob(record); setReviewModalOpen(true); }}
|
||||
>审核</Button>
|
||||
),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="招聘会职位审核列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
request={async (params) => {
|
||||
const res = await getJobReviewList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
companyName: params.companyName,
|
||||
jobTitle: params.jobTitle,
|
||||
reviewStatus: params.reviewStatus,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
/>
|
||||
|
||||
<ModalForm
|
||||
title="职位审核"
|
||||
open={reviewModalOpen}
|
||||
width={500}
|
||||
modalProps={{ destroyOnClose: true, onCancel: () => setReviewModalOpen(false) }}
|
||||
onFinish={async (values) => {
|
||||
if (values.action === 'approve') {
|
||||
return handleApprove(values);
|
||||
} else {
|
||||
return handleReject(values);
|
||||
}
|
||||
}}
|
||||
initialValues={currentJob}
|
||||
>
|
||||
<ProFormText name="jobTitle" label="职位名称" disabled />
|
||||
<ProFormText name="companyName" label="单位名称" disabled />
|
||||
<ProFormText name="reviewRemark" label="审核意见" placeholder="请输入审核意见" />
|
||||
</ModalForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default JobReviewTab;
|
||||
@@ -0,0 +1,51 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||
import { getReservationRecordList } from '@/services/jobportal/indoorJobFair';
|
||||
import type { ReservationRecordItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const ReservationRecordTab: React.FC<Props> = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
|
||||
const columns: ProColumns<ReservationRecordItem>[] = [
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true, hideInSearch: true },
|
||||
{
|
||||
title: '操作人',
|
||||
dataIndex: 'operator',
|
||||
order: 1,
|
||||
},
|
||||
{ title: '操作人', dataIndex: 'operator', width: 100, hideInSearch: true },
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true, hideInSearch: true },
|
||||
{ title: '展位号', dataIndex: 'boothNumber', width: 100, hideInSearch: true },
|
||||
{ title: '企业名称', dataIndex: 'companyName', ellipsis: true, hideInSearch: true, render: (_, r) => r.companyName || '--' },
|
||||
{ title: '操作类型', dataIndex: 'operateType', width: 100, hideInSearch: true },
|
||||
{ title: '操作时间', dataIndex: 'operateTime', valueType: 'dateTime', width: 170, hideInSearch: true },
|
||||
{ title: '备注', dataIndex: 'remark', ellipsis: true, hideInSearch: true, render: (_, r) => r.remark || '--' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="预留操作记录列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
request={async (params) => {
|
||||
const res = await getReservationRecordList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
operator: params.operator,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReservationRecordTab;
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||
import { getUnsubscribeList } from '@/services/jobportal/indoorJobFair';
|
||||
import type { UnsubscribeItem } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const UnsubscribeTab: React.FC<Props> = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
|
||||
const columns: ProColumns<UnsubscribeItem>[] = [
|
||||
{ title: '招聘会名称', dataIndex: 'fairName', ellipsis: true, hideInSearch: true },
|
||||
{
|
||||
title: '招聘会名称',
|
||||
dataIndex: 'fairName',
|
||||
hideInTable: true,
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
title: '单位名称',
|
||||
dataIndex: 'companyName',
|
||||
order: 2,
|
||||
},
|
||||
{ title: '单位名称', dataIndex: 'companyName', ellipsis: true, hideInSearch: true },
|
||||
{ title: '展位号', dataIndex: 'boothNumber', width: 100, hideInSearch: true },
|
||||
{ title: '联系人', dataIndex: 'contactPerson', width: 100, hideInSearch: true },
|
||||
{ title: '联系电话', dataIndex: 'contactPhone', width: 130, hideInSearch: true },
|
||||
{ title: '退订时间', dataIndex: 'unsubscribeTime', valueType: 'dateTime', width: 170, hideInSearch: true },
|
||||
{ title: '退订原因', dataIndex: 'reason', ellipsis: true, hideInSearch: true },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="退订信息列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
request={async (params) => {
|
||||
const res = await getUnsubscribeList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
fairName: params.fairName,
|
||||
companyName: params.companyName,
|
||||
boothNumber: params.boothNumber,
|
||||
contactPerson: params.contactPerson,
|
||||
contactPhone: params.contactPhone,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UnsubscribeTab;
|
||||
131
src/pages/Jobfair/Indoorjobfair/Detail/components/VenueTab.tsx
Normal file
131
src/pages/Jobfair/Indoorjobfair/Detail/components/VenueTab.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useAccess } from '@umijs/max';
|
||||
import { Button, message, Modal, Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable, ModalForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';
|
||||
import { PlusOutlined, DeleteOutlined, FormOutlined, LayoutOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
getVenueList,
|
||||
addVenue,
|
||||
updateVenue,
|
||||
deleteVenue,
|
||||
} from '@/services/jobportal/indoorJobFair';
|
||||
import type { VenueItem, VenueForm } from '@/services/jobportal/indoorJobFair';
|
||||
|
||||
interface Props {
|
||||
fairId: number;
|
||||
}
|
||||
|
||||
const VenueTab: React.FC<Props> = () => {
|
||||
const access = useAccess();
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [editingVenue, setEditingVenue] = useState<VenueItem | null>(null);
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
active: { text: '启用', color: 'green' },
|
||||
inactive: { text: '停用', color: 'red' },
|
||||
};
|
||||
|
||||
const columns: ProColumns<VenueItem>[] = [
|
||||
{ title: '场地名称', dataIndex: 'venueName', ellipsis: true },
|
||||
{ title: '就业机构', dataIndex: 'employmentAgency', ellipsis: true },
|
||||
{ title: '场地类型', dataIndex: 'venueType', width: 100 },
|
||||
{ title: '场地地址', dataIndex: 'venueAddress', ellipsis: true, hideInSearch: true },
|
||||
{ title: '联系人', dataIndex: 'contactPerson', width: 100, hideInSearch: true },
|
||||
{ title: '联系电话', dataIndex: 'contactPhone', width: 130, hideInSearch: true },
|
||||
{ title: '展位数', dataIndex: 'boothCount', width: 80, hideInSearch: true },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 80,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => {
|
||||
const s = statusMap[record.status] || { text: record.status, color: 'default' };
|
||||
return <Tag color={s.color}>{s.text}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 150,
|
||||
render: (_, record) => [
|
||||
<Button key="edit" type="link" size="small" icon={<FormOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:edit')}
|
||||
onClick={() => { setEditingVenue(record); setModalOpen(true); }}
|
||||
>编辑</Button>,
|
||||
<Button key="layout" type="link" size="small" icon={<LayoutOutlined />}
|
||||
onClick={() => message.info('场地布局功能开发中')}
|
||||
>布局</Button>,
|
||||
<Button key="delete" type="link" size="small" danger icon={<DeleteOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:remove')}
|
||||
onClick={() => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定删除场地「${record.venueName}」吗?`,
|
||||
onOk: async () => {
|
||||
const res = await deleteVenue(record.id);
|
||||
if (res.code === 200) { message.success('删除成功'); actionRef.current?.reload(); }
|
||||
else { message.error(res.msg); }
|
||||
},
|
||||
});
|
||||
}}
|
||||
>删除</Button>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ProTable
|
||||
headerTitle="场地信息列表"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
scroll={{ x: 'max-content' }}
|
||||
search={{ labelWidth: 100 }}
|
||||
request={async (params) => {
|
||||
const res = await getVenueList({
|
||||
current: params.current,
|
||||
pageSize: params.pageSize,
|
||||
employmentAgency: params.employmentAgency,
|
||||
venueName: params.venueName,
|
||||
venueType: params.venueType,
|
||||
});
|
||||
return { data: res.rows, total: res.total, success: true };
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
<Button key="add" type="primary" icon={<PlusOutlined />}
|
||||
hidden={!access.hasPerms('cms:indoorJobFair:add')}
|
||||
onClick={() => { setEditingVenue(null); setModalOpen(true); }}
|
||||
>新增场地</Button>,
|
||||
]}
|
||||
/>
|
||||
|
||||
<ModalForm
|
||||
title={editingVenue ? '编辑场地' : '新增场地'}
|
||||
open={modalOpen}
|
||||
width={500}
|
||||
modalProps={{ destroyOnClose: true, onCancel: () => setModalOpen(false) }}
|
||||
onFinish={async (values) => {
|
||||
const res = editingVenue
|
||||
? await updateVenue({ id: editingVenue.id, ...values })
|
||||
: await addVenue(values as VenueForm);
|
||||
if (res.code === 200) { message.success(res.msg); setModalOpen(false); actionRef.current?.reload(); return true; }
|
||||
message.error(res.msg); return false;
|
||||
}}
|
||||
initialValues={editingVenue}
|
||||
>
|
||||
<ProFormText name="venueName" label="场地名称" rules={[{ required: true, message: '请输入场地名称' }]} />
|
||||
<ProFormText name="employmentAgency" label="就业机构" rules={[{ required: true, message: '请输入就业机构' }]} />
|
||||
<ProFormSelect name="venueType" label="场地类型" rules={[{ required: true, message: '请选择场地类型' }]}
|
||||
options={[{ label: '室内', value: '室内' }, { label: '室外', value: '室外' }]} />
|
||||
<ProFormText name="venueAddress" label="场地地址" rules={[{ required: true, message: '请输入场地地址' }]} />
|
||||
<ProFormText name="contactPerson" label="联系人" rules={[{ required: true, message: '请输入联系人' }]} />
|
||||
<ProFormText name="contactPhone" label="联系电话" rules={[{ required: true, message: '请输入联系电话' }]} />
|
||||
<ProFormText name="boothCount" label="展位数" rules={[{ required: true, message: '请输入展位数' }]} />
|
||||
</ModalForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VenueTab;
|
||||
Reference in New Issue
Block a user