- ant design pro 如何去保存颜色
- ant design pro v6 如何做好角色管理
- ant design 的 tree 如何作为角色中的权限选择之一
- ant design 的 tree 如何作为角色中的权限选择之二
- ant design pro access.ts 是如何控制多角色的权限的
- ant design pro 中用户的表单如何控制多个角色
- ant design pro 如何实现动态菜单带上 icon 的
- ant design pro 的表分层级如何处理
- ant design pro 如何处理权限管理
- ant design pro 技巧之自制复制到剪贴板组件
像上图那样,我们经常给列表页做分类的,
这种多标签如何处理呢?
肯定是要得到动态数据对吧。
每次点击的时候要发请求,得到不同的数据。
其实 ant design pro 是支持的。
在 index.tsx 中的 protable 里加上这个就好。
toolbar={{
menu: {
type: 'tab',
activeKey: activeKey,
items: [
{
label: <FormattedMessage id="platform.all" defaultMessage="All" />,
key: '',
},
{
label: <FormattedMessage id="platform.online" defaultMessage="Online" />,
key: 'true',
},
{
label: <FormattedMessage id="platform.offline" defaultMessage="Offline" />,
key: 'false',
},
],
onChange: (key: any) => {
setActiveKey(key);
if (actionRef.current) {
actionRef.current.reload();
}
},
},
}}
完整代码是这样的:
import { addItem, queryList, removeItem, updateItem } from '@/services/ant-design-pro/api';
import { PlusOutlined } from '@ant-design/icons';
import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components';
import { FooterToolbar, PageContainer, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, message, Modal, Switch, Tooltip } from 'antd';
import React, { useRef, useState } from 'react';
import type { FormValueType } from './components/Update';
import Update from './components/Update';
import Create from './components/Create';
import Show from './components/Show';
import { useIntl } from '@umijs/max';
import { carTypeMap } from '@/utils/constants';
import CopyToClipboard from '@/components/CopyToClipboard';
import ConfigureForm from './components/ConfigureForm';
/**
* @en-US Add node
* @zh-CN 添加节点
* @param fields
*/
const handleAdd = async (fields: API.ItemData) => {
const hide = message.loading(<FormattedMessage id="adding" defaultMessage="Adding..." />);
try {
await addItem('/platforms', { ...fields });
hide();
message.success(<FormattedMessage id="add.success" defaultMessage="Added successfully" />);
return true;
} catch (error: any) {
hide();
message.error(
error?.response?.data?.message ?? (
<FormattedMessage id="add.failed" defaultMessage="Adding failed, please try again!" />
),
);
return false;
}
};
/**
* @en-US Update node
* @zh-CN 更新节点
*
* @param fields
*/
const handleUpdate = async (fields: FormValueType) => {
const hide = message.loading(<FormattedMessage id="updating" defaultMessage="Updating..." />);
try {
await updateItem(`/platforms/${fields._id}`, fields);
hide();
message.success(<FormattedMessage id="update.success" defaultMessage="Updated successfully" />);
return true;
} catch (error: any) {
hide();
message.error(
error?.response?.data?.message ?? (
<FormattedMessage id="update.failed" defaultMessage="Update failed, please try again!" />
),
);
return false;
}
};
/**
* Delete node
* @zh-CN 删除节点
*
* @param selectedRows
*/
const handleRemove = async (ids: string[]) => {
const hide = message.loading(<FormattedMessage id="deleting" defaultMessage="Deleting..." />);
if (!ids) return true;
try {
await removeItem('/platforms', {
ids,
});
hide();
message.success(
<FormattedMessage
id="delete.success"
defaultMessage="Deleted successfully and will refresh soon"
/>,
);
return true;
} catch (error: any) {
hide();
message.error(
error.response.data.message ?? (
<FormattedMessage id="delete.failed" defaultMessage="Delete failed, please try again" />
),
);
return false;
}
};
const TableList: React.FC = () => {
const intl = useIntl();
/**
* @en-US Pop-up window of new window
* @zh-CN 新建窗口的弹窗
* */
const [createModalOpen, handleModalOpen] = useState<boolean>(false);
/**2024fc.xyz
* @en-US The pop-up window of the distribution update window
* @zh-CN 分布更新窗口的弹窗
* */
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
const [showDetail, setShowDetail] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<API.ItemData>();
const [selectedRowsState, setSelectedRows] = useState<API.ItemData[]>([]);
const access = useAccess();
const [activeKey, setActiveKey] = useState<string | undefined>('');
const [configureModalVisible, setConfigureModalVisible] = useState<boolean>(false);
/**
* @en-US International configuration
* @zh-CN 国际化配置
* */
const columns: ProColumns<API.ItemData>[] = [
{
title: intl.formatMessage({ id: 'platform.name' }),
dataIndex: 'name',
width: 150,
copyable: true,
render: (dom, entity) => {
return (
<a
onClick={() => {
setCurrentRow(entity);
setShowDetail(true);
}}
>
{dom}
</a>
);
},
},
{
title: intl.formatMessage({ id: 'platform.image' }),
dataIndex: 'image',
width: 100,
hideInSearch: true,
valueType: 'image',
},
{
title: intl.formatMessage({ id: 'platform.region' }),
dataIndex: 'region',
width: 200,
render: (_, record: any) =>
record.region && (
<>
{record.region.name} <CopyToClipboard text={record.region.name} />
</>
),
},
{
title: intl.formatMessage({ id: 'platform.price' }),
dataIndex: 'price',
width: 150,
hideInSearch: true,
render: (text, record: any) => (
<Tooltip title={`€ ${record.priceInEuro}`}>
<strong>$ {text}</strong>/{carTypeMap[record.carType as keyof typeof carTypeMap]}
</Tooltip>
),
},
{
title: intl.formatMessage({ id: 'platform.tips' }),
ellipsis: true,
width: 150,
hideInTable: true,
hideInSearch: true,
dataIndex: 'tips',
},
{
title: intl.formatMessage({ id: 'platform.boardingMethod' }),
dataIndex: 'boardingMethod',
width: 150,
hideInSearch: true,
hideInTable: true,
valueEnum: {
'': { text: intl.formatMessage({ id: 'all' }), status: 'Default' },
fullCar: { text: intl.formatMessage({ id: 'platform.fullCar' }) },
batchCar: { text: intl.formatMessage({ id: 'platform.batchCar' }) },
},
},
{
title: intl.formatMessage({ id: 'platform.deliveryMethod' }),
dataIndex: 'deliveryMethod',
width: 150,
hideInSearch: true,
hideInTable: true,
valueEnum: {
'': { text: intl.formatMessage({ id: 'all' }), status: 'Default' },
autoDelivery: { text: intl.formatMessage({ id: 'platform.autoDelivery' }) },
inviteLink: { text: intl.formatMessage({ id: 'platform.inviteLink' }) },
},
},
{
title: intl.formatMessage({ id: 'platform.status' }),
dataIndex: 'isOnline',
width: 150,
hideInSearch: true,
render: (_, record: any) => (
<Switch
checkedChildren={intl.formatMessage({ id: 'platform.online' })}
unCheckedChildren={intl.formatMessage({ id: 'platform.offline' })}
checked={record.isOnline}
onChange={async () => {
await handleUpdate({ _id: record._id, isOnline: !record.isOnline });
if (actionRef.current) {
actionRef.current.reload();
}
}}
/>
),
},
{
title: intl.formatMessage({ id: 'platform.remark' }),
ellipsis: true,
width: 150,
hideInSearch: true,
dataIndex: 'remark',
},
{
title: intl.formatMessage({ id: 'platform.userCount' }),
hideInSearch: true,
width: 150,
hideInTable: true,
dataIndex: 'userCount',
},
{
title: intl.formatMessage({ id: 'platform.user' }),
hideInSearch: true,
width: 150,
dataIndex: 'user',
render: (_, record) => record.user && record.user.name,
},
{
title: <FormattedMessage id="creation_time" defaultMessage="Creation Time" />,
width: 250,
dataIndex: 'createdAt',
valueType: 'dateTime',
hideInSearch: true,
},
{
title: <FormattedMessage id="platform.description" defaultMessage="platform.description" />,
width: 250,
dataIndex: 'descriptions',
hideInSearch: true,
hideInTable: true,
render: (text) => (Array.isArray(text) ? text.join(', ') : text),
},
{
title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="Operating" />,
dataIndex: 'option',
valueType: 'option',
fixed: 'right',
render: (_, record) => [
<a
key="update"
onClick={() => {
handleUpdateModalOpen(true);
setCurrentRow(record);
}}
>
<FormattedMessage id="edit" defaultMessage="Edit" />
</a>,
access.canSuperAdmin && (
<a
key="delete"
onClick={() => {
return Modal.confirm({
title: intl.formatMessage({ id: 'confirm.delete' }),
onOk: async () => {
await handleRemove([record._id!]);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
},
content: intl.formatMessage({ id: 'confirm.delete.content' }),
okText: intl.formatMessage({ id: 'confirm' }),
cancelText: intl.formatMessage({ id: 'cancel' }),
});
}}
>
<FormattedMessage id="delete" defaultMessage="Delete" />
</a>
),
<a
key="configure"
onClick={() => {
setConfigureModalVisible(true);
setCurrentRow(record);
}}
>
{intl.formatMessage({
id: 'configure',
defaultMessage: 'Configure',
})}
</a>,
],
},
];
return (
<PageContainer>
<ProTable<API.ItemData, API.PageParams>
headerTitle={intl.formatMessage({ id: 'list' })}
actionRef={actionRef}
rowKey="_id"
scroll={{ x: 1200 }}
search={{
labelWidth: 120,
collapsed: false,
}}
toolBarRender={() => [
<Button
type="primary"
key="primary"
onClick={() => {
handleModalOpen(true);
}}
>
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
</Button>,
selectedRowsState?.length > 0 && access.canSuperAdmin && (
<Button
danger
onClick={() => {
return Modal.confirm({
title: intl.formatMessage({ id: 'confirm.delete' }),
onOk: async () => {
await handleRemove(selectedRowsState?.map((item) => item._id!));
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
},
content: intl.formatMessage({ id: 'confirm.delete.content' }),
okText: intl.formatMessage({ id: 'confirm' }),
cancelText: intl.formatMessage({ id: 'cancel' }),
});
}}
>
<FormattedMessage
id="pages.searchTable.batchDeletion"
defaultMessage="Batch deletion"
/>
</Button>
),
]}
toolbar={{
menu: {
type: 'tab',
activeKey: activeKey,
items: [
{
label: <FormattedMessage id="platform.all" defaultMessage="All" />,
key: '',
},
{
label: <FormattedMessage id="platform.online" defaultMessage="Online" />,
key: 'true',
},
{
label: <FormattedMessage id="platform.offline" defaultMessage="Offline" />,
key: 'false',
},
],
onChange: (key: any) => {
setActiveKey(key);
if (actionRef.current) {
actionRef.current.reload();
}
},
},
}}
request={async (params, sort, filter) =>
queryList('/platforms', { ...params, isOnline: activeKey }, sort, filter)
}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => {
setSelectedRows(selectedRows);
},
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
<FormattedMessage id="pages.searchTable.chosen" defaultMessage="Chosen" />{' '}
<a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}
<FormattedMessage id="pages_searchTable_item" defaultMessage="items" />
</div>
}
></FooterToolbar>
)}
<Create
open={createModalOpen}
onOpenChange={handleModalOpen}
onFinish={async (value) => {
const success = await handleAdd(value as API.ItemData);
if (success) {
handleModalOpen(false);
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
/>
<Update
onSubmit={async (value) => {
const success = await handleUpdate(value);
if (success) {
handleUpdateModalOpen(false);
setCurrentRow(undefined);
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={handleUpdateModalOpen}
updateModalOpen={updateModalOpen}
values={currentRow || {}}
/>
<ConfigureForm
onSubmit={async (value) => {
const success = await handleUpdate(value);
if (success) {
setConfigureModalVisible(false);
setCurrentRow(undefined);
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={setConfigureModalVisible}
updateModalOpen={configureModalVisible}
values={currentRow || {}}
/>
<Show
open={showDetail}
currentRow={currentRow as API.ItemData}
columns={columns as ProDescriptionsItemProps<API.ItemData>[]}
onClose={() => {
setCurrentRow(undefined);
setShowDetail(false);
}}
/>
</PageContainer>
);
};
export default TableList;
主要是上面的 menu 的选项处理,还有
const [activeKey, setActiveKey] = useState<string | undefined>(‘’);
然后是请求列表里比较重要,
要把 activeKey 传给后端
request={async (params, sort, filter) =>
queryList('/platforms', { ...params, isOnline: activeKey }, sort, filter)
}
后端的参数是叫 isOnline ,要对上 key 和 value
其它的都没啥的问题。
我们拥有 12 年建站编程经验
- 虚拟产品交易平台定制开发
- WordPress 外贸电商独立站建站