- Added QR code functionality for companies signing up for outdoor fairs. - Implemented job management for outdoor fairs, including job listing and editing. - Updated Public Job Fair detail view to reflect new data structure. - Refactored EditModal to support dynamic lists for host, co-organizer, and organizing units. - Introduced cross-domain city selection for job fairs. - Enhanced API services for managing cross-domain jobs and cities. - Improved data handling for outdoor fair items, including review status and QR code content. - Updated type definitions to accommodate new fields and structures.
276 lines
8.3 KiB
TypeScript
276 lines
8.3 KiB
TypeScript
import React, { useRef, useState } from 'react';
|
|
import { useAccess } from '@umijs/max';
|
|
import { Button, Modal, message, Typography } from 'antd';
|
|
import {
|
|
ActionType,
|
|
ProColumns,
|
|
ProTable,
|
|
ModalForm,
|
|
ProFormText,
|
|
ProFormSelect,
|
|
} from '@ant-design/pro-components';
|
|
import { PlusOutlined, DeleteOutlined, LinkOutlined, DisconnectOutlined } from '@ant-design/icons';
|
|
import {
|
|
getOutdoorFairDeviceList,
|
|
addOutdoorFairDevice,
|
|
bindOutdoorFairDevice,
|
|
deleteOutdoorFairDevice,
|
|
getOutdoorFairCompanyOptions,
|
|
} from '@/services/jobportal/outdoorFairDevice';
|
|
import type { OutdoorFairDeviceItem } from '@/services/jobportal/outdoorFairDevice';
|
|
|
|
interface Props {
|
|
fairId: number;
|
|
}
|
|
|
|
const DeviceTab: React.FC<Props> = ({ fairId }) => {
|
|
const access = useAccess();
|
|
const actionRef = useRef<ActionType>();
|
|
const [addVisible, setAddVisible] = useState(false);
|
|
const [bindVisible, setBindVisible] = useState(false);
|
|
const [currentRow, setCurrentRow] = useState<OutdoorFairDeviceItem>();
|
|
|
|
const handleDelete = (id: number) => {
|
|
Modal.confirm({
|
|
title: '确认删除',
|
|
content: '确定要删除该设备码吗?',
|
|
onOk: async () => {
|
|
const res = await deleteOutdoorFairDevice(id);
|
|
if (res.code === 200) {
|
|
message.success('删除成功');
|
|
actionRef.current?.reload();
|
|
} else {
|
|
message.error(res.msg || '删除失败');
|
|
}
|
|
},
|
|
});
|
|
};
|
|
|
|
const handleUnbind = (record: OutdoorFairDeviceItem) => {
|
|
Modal.confirm({
|
|
title: '确认解绑',
|
|
content: `确定要解除设备码与「${record.companyName}」的绑定吗?`,
|
|
onOk: async () => {
|
|
const res = await bindOutdoorFairDevice(record.id, undefined);
|
|
if (res.code === 200) {
|
|
message.success('解绑成功');
|
|
actionRef.current?.reload();
|
|
} else {
|
|
message.error(res.msg || '解绑失败');
|
|
}
|
|
},
|
|
});
|
|
};
|
|
|
|
const columns: ProColumns<OutdoorFairDeviceItem>[] = [
|
|
{
|
|
title: '设备码',
|
|
dataIndex: 'deviceCode',
|
|
ellipsis: true,
|
|
render: (_, record) => (
|
|
<Typography.Text copyable code>
|
|
{record.deviceCode}
|
|
</Typography.Text>
|
|
),
|
|
},
|
|
{
|
|
title: '绑定企业',
|
|
dataIndex: 'companyName',
|
|
ellipsis: true,
|
|
hideInSearch: true,
|
|
render: (_, record) => (record.companyName ? record.companyName : '— 未绑定 —'),
|
|
},
|
|
{
|
|
title: '绑定时间',
|
|
dataIndex: 'bindTime',
|
|
valueType: 'dateTime',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '操作',
|
|
valueType: 'option',
|
|
width: 200,
|
|
fixed: 'right',
|
|
render: (_, record) => [
|
|
record.companyId ? (
|
|
<Button
|
|
key="unbind"
|
|
type="link"
|
|
size="small"
|
|
icon={<DisconnectOutlined />}
|
|
hidden={!access.hasPerms('cms:outdoorFair:edit')}
|
|
onClick={() => handleUnbind(record)}
|
|
>
|
|
解绑
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
key="bind"
|
|
type="link"
|
|
size="small"
|
|
icon={<LinkOutlined />}
|
|
hidden={!access.hasPerms('cms:outdoorFair:edit')}
|
|
onClick={() => {
|
|
setCurrentRow(record);
|
|
setBindVisible(true);
|
|
}}
|
|
>
|
|
绑定企业
|
|
</Button>
|
|
),
|
|
<Button
|
|
key="delete"
|
|
type="link"
|
|
size="small"
|
|
danger
|
|
icon={<DeleteOutlined />}
|
|
hidden={!access.hasPerms('cms:outdoorFair:remove')}
|
|
onClick={() => handleDelete(record.id)}
|
|
>
|
|
删除
|
|
</Button>,
|
|
],
|
|
},
|
|
];
|
|
|
|
return (
|
|
<>
|
|
<ProTable<OutdoorFairDeviceItem>
|
|
actionRef={actionRef}
|
|
rowKey="id"
|
|
headerTitle="设备管理"
|
|
search={{ labelWidth: 'auto' }}
|
|
options={false}
|
|
pagination={{ pageSize: 10 }}
|
|
scroll={{ x: 'max-content' }}
|
|
toolBarRender={() => [
|
|
<Button
|
|
key="add"
|
|
type="primary"
|
|
icon={<PlusOutlined />}
|
|
hidden={!access.hasPerms('cms:outdoorFair:add')}
|
|
onClick={() => setAddVisible(true)}
|
|
>
|
|
新增设备码
|
|
</Button>,
|
|
]}
|
|
request={async (params) => {
|
|
const res = await getOutdoorFairDeviceList({
|
|
fairId,
|
|
current: params.current,
|
|
pageSize: params.pageSize,
|
|
deviceCode: params.deviceCode,
|
|
companyName: params.companyName,
|
|
});
|
|
return { data: res.rows || [], total: res.total || 0, success: res.code === 200 };
|
|
}}
|
|
columns={columns}
|
|
/>
|
|
|
|
<ModalForm<{ deviceCode: string; companyId?: number }>
|
|
title="新增设备码"
|
|
open={addVisible}
|
|
modalProps={{ destroyOnClose: true, onCancel: () => setAddVisible(false) }}
|
|
onFinish={async (values) => {
|
|
const res = await addOutdoorFairDevice({
|
|
fairId,
|
|
deviceCode: values.deviceCode.trim(),
|
|
companyId: values.companyId,
|
|
});
|
|
if (res.code === 200) {
|
|
message.success('新增成功');
|
|
setAddVisible(false);
|
|
actionRef.current?.reload();
|
|
return true;
|
|
}
|
|
message.error(res.msg || '新增失败');
|
|
return false;
|
|
}}
|
|
>
|
|
<ProFormText
|
|
name="deviceCode"
|
|
label="设备码"
|
|
placeholder="请输入设备码"
|
|
fieldProps={{ maxLength: 64 }}
|
|
rules={[
|
|
{ required: true, message: '请输入设备码' },
|
|
{ max: 64, message: '设备码长度不能超过64个字符' },
|
|
]}
|
|
/>
|
|
<ProFormSelect
|
|
name="companyId"
|
|
label="绑定企业"
|
|
placeholder="选填,不选则创建未绑定的设备码"
|
|
showSearch
|
|
allowClear
|
|
request={async () => {
|
|
const [companies, devicesRes] = await Promise.all([
|
|
getOutdoorFairCompanyOptions(fairId),
|
|
getOutdoorFairDeviceList({ fairId, current: 1, pageSize: 1000 }),
|
|
]);
|
|
// 排除已绑定到其他设备的企业
|
|
const boundIds = new Set(
|
|
(devicesRes.rows || [])
|
|
.map((d) => d.companyId)
|
|
.filter((cid): cid is number => cid != null),
|
|
);
|
|
return companies
|
|
.filter((item) => !boundIds.has(item.companyId))
|
|
.map((item) => ({
|
|
label: item.companyName,
|
|
value: item.companyId,
|
|
}));
|
|
}}
|
|
/>
|
|
</ModalForm>
|
|
|
|
<ModalForm<{ companyId: number }>
|
|
title="绑定参会企业"
|
|
open={bindVisible}
|
|
modalProps={{ destroyOnClose: true, onCancel: () => setBindVisible(false) }}
|
|
onFinish={async (values) => {
|
|
if (!currentRow) return false;
|
|
const res = await bindOutdoorFairDevice(currentRow.id, values.companyId);
|
|
if (res.code === 200) {
|
|
message.success('绑定成功');
|
|
setBindVisible(false);
|
|
setCurrentRow(undefined);
|
|
actionRef.current?.reload();
|
|
return true;
|
|
}
|
|
message.error(res.msg || '绑定失败');
|
|
return false;
|
|
}}
|
|
>
|
|
<ProFormSelect
|
|
name="companyId"
|
|
label="参会企业"
|
|
placeholder="请选择参会企业"
|
|
showSearch
|
|
request={async () => {
|
|
const [companies, devicesRes] = await Promise.all([
|
|
getOutdoorFairCompanyOptions(fairId),
|
|
getOutdoorFairDeviceList({ fairId, current: 1, pageSize: 1000 }),
|
|
]);
|
|
// 排除已绑定到其他设备的企业
|
|
const boundIds = new Set(
|
|
(devicesRes.rows || [])
|
|
.map((d) => d.companyId)
|
|
.filter((cid): cid is number => cid != null),
|
|
);
|
|
return companies
|
|
.filter((item) => !boundIds.has(item.companyId))
|
|
.map((item) => ({
|
|
label: item.companyName,
|
|
value: item.companyId,
|
|
}));
|
|
}}
|
|
rules={[{ required: true, message: '请选择参会企业' }]}
|
|
/>
|
|
</ModalForm>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default DeviceTab;
|