bunny笔记|React+Ant Design pro框架实现Admin页面的功能(新增、删除、修改数据、查询列表等功能),采用mock模拟后端返回的数据处理
需求分析
需求:(1)在左侧菜单新增自己对应名词的菜单–例: 老师列表-张三(2)添加对应菜单的页面,老师列表页,提供老师信息的查询,新增功能
列表查询页
分两部分:搜索区域(对应参数入参)+列表区域(对应响应参数)
要求:包含参数中要求的控件组件,最终发起请求的参数齐全,响应成功展示正常即可
新增页面
新增页面以弹窗形式完成
要求:包含参数中要求的控件组件,最终发起请求的参数齐全
查询接口
import {addTea, getTeaList} from @/services/ant-design-pro/api ;
addTea为新增老师接口, getTeaList为查询列表接口
查询列表接口参数

新增老师接口参数(入参)

查询老师列表响应体
{
success:true,
pageSize: 5,
total:100,
data:[
{name:‘张三’,
iPhone:10086,
type:1,
timeList: [1651110000000,1651110314000],
onJob:true,
remarks: “张三是个好老师”
}
], //数组中的对象为Teacher
}
Teacher对象字段


新增老师响应体
{
status:200,
}
功能实现
实现新增

实现删除/修改、查询

实现对列表的搜索查询功能

高级表格自带的其它功能

例1:
index.tsx页面代码
import React, { useState, useRef } from react ;
import { PlusOutlined, EllipsisOutlined } from @ant-design/icons ;
import { Button, message, Menu, Dropdown, Form } from antd ;
import type { ProColumns, ActionType } from @ant-design/pro-table ;
import ProTable from @ant-design/pro-table ;
import request from umi-request ;
import ProForm, {
ModalForm,
ProFormText,
ProFormTextArea,
ProFormSelect,
ProFormDateTimePicker,
} from @ant-design/pro-form ;
import { useIntl } from umi ;
import { addTea, getTeaList } from @/services/ant-design-pro/api ;
import @ant-design/pro-table/dist/table.css ;
import type { RecordKey } from @ant-design/pro-utils/lib/useEditableArray ;
const columns: ProColumns<API.teaListItem>[] = [
{
dataIndex: index ,
valueType: indexBorder ,
width: 48,
},
{
title: 名称 ,
dataIndex: name ,
copyable: true,
ellipsis: true,
formItemProps: {
},
},
{
title: 手机号 ,
dataIndex: iPhone ,
copyable: true,
ellipsis: true,
},
{
disable: true,
title: 老师类型 ,
dataIndex: type ,
filters: true,
onFilter: true,
valueType: select ,
valueEnum: {
0: {
text: 语文 ,
},
1: {
text: 数学 ,
},
2: {
text: 英语 ,
},
},
},
{
disable: true,
title: 是否在职 ,
dataIndex: onJob ,
filters: true,
onFilter: true,
hideInSearch: true,
valueType: select ,
valueEnum: {
true: {
text: 是 ,
status: Success ,
},
false: {
text: 否 ,
status: Error ,
},
},
},
{
title: 创建时间 ,
key: createTime ,
dataIndex: createTime ,
valueType: dateTime ,
sorter: true,
search: {
transform: (value) => {
return {
createTime: new Date(value).getTime(),
};
},
},
},
{
title: 结束时间 ,
key: endTime ,
dataIndex: endTime ,
valueType: dateTime ,
sorter: true,
search: {
transform: (value) => {
return {
endTime: new Date(value).getTime(),
};
},
},
},
{
disable: true,
title: 备注 ,
dataIndex: remarks ,
search: false,
renderFormItem: (_, { defaultRender }) => {
return defaultRender(_);
},
},
{
title: 操作 ,
valueType: option ,
key: option ,
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.key);
}}
>
编辑
</a>,
],
},
];
const menu = (
<Menu>
<Menu.Item key="1">1st item</Menu.Item>
<Menu.Item key="2">2nd item</Menu.Item>
<Menu.Item key="3">3rd item</Menu.Item>
</Menu>
);
/**
* handleAdd
* @param fields
*/
const handleAdd = async (fields: API.teaListItem) => {
const hide = message.loading( 正在添加 );
// handleList(fields)
try {
await addTea({ ...fields });
hide();
message.success( Added successfully );
return true;
} catch (error) {
hide();
message.error( Adding failed, please try again! );
return false;
}
};
getTeaList;
const hyhList: React.FC = () => {
const actionRef = useRef<ActionType>();
const [createModalVisible, handleModalVisible] = useState<boolean>(false);
const [form] = Form.useForm();
const intl = useIntl();
return (
<ProTable<API.teaListItem>
columns={columns}
actionRef={actionRef}
cardBordered
request={async (params = {}, sort, filter) => {
console.log(sort, filter);
console.log(params, ***params );
let listdata: any;
listdata = await request<{
data: API.teaListItem[];
}>( /api/tea/List , {
params,
});
return Promise.resolve(listdata);
}}
editable={{
type: multiple ,
onSave: (key: RecordKey, row: API.teaListItem) => {
console.log(key, row, onSave );
return Promise.resolve();
},
onDelete: (key: RecordKey, row: API.teaListItem) => {
console.log(key, row, onDelete );
return Promise.resolve();
},
}}
columnsState={{
persistenceKey: pro-table-singe-demos ,
persistenceType: localStorage ,
onChange(value) {
console.log( value: , value);
},
}}
rowKey="key"
search={{
labelWidth: auto ,
}}
pagination={{
pageSize: 5,
onChange: (page) => console.log(page),
}}
dateFormatter="string"
headerTitle="高级表格"
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
type="primary"
onClick={() => {
handleModalVisible(true);
}}
>
新增老师
</Button>,
<Dropdown key="menu" overlay={menu}>
<Button>
<EllipsisOutlined />
</Button>
</Dropdown>,
<ModalForm
title={intl.formatMessage({
id: pages.searchTable.createForm.newRule ,
defaultMessage: New rule ,
})}
width="400px"
visible={createModalVisible}
onVisibleChange={handleModalVisible}
form={form}
onFinish={async (value) => {
//debugger;
const success = await handleAdd(value as API.teaListItem);
if (success) {
handleModalVisible(false);
if (actionRef.current) {
actionRef.current.reload();
form.resetFields();
}
}
}}
>
<ProForm.Group>
<ProFormText
width="sm"
name="name"
label="老师名称"
tooltip="最长为 6 位"
placeholder="请输入老师名称"
/>
<ProFormText width="sm" name="iPhone" label="手机号码" placeholder="请输入手机号" />
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
request={async () => [
{
value: 0,
label: 数学 ,
},
{
value: 1,
label: 语文 ,
},
{
value: 2,
label: 英语 ,
},
]}
width="xs"
name="type"
label="请选择老师类型"
/>
<ProFormSelect
request={async () => [
{
value: true ,
label: 是 ,
},
{
value: false ,
label: 否 ,
},
]}
width="xs"
name="onJob"
label="请选择是否在任职"
/>
<ProFormDateTimePicker
name="createTime"
label="请选择创建时间"
transform={(value) => {
return {
createTime: Date.parse(value),
};
}}
rules={[{ required: true, message: Please select your country! }]}
/>
<ProFormDateTimePicker
name="endTime"
label="请选择结束时间"
transform={(value) => {
return {
endTime: Date.parse(value),
};
}}
rules={[{ required: true, message: Please select your country! }]}
/>
</ProForm.Group>
<ProFormTextArea
width="md"
name="remarks"
label="备注信息"
placeholder="请输入备注信息"
/>
</ModalForm>,
]}
/>
);
};
export default hyhList;
api配置
import { request } from umi ;
import requestumi from umi-request ;
/** 新增老师 /api/addTea */
export async function addTea(options?: { [key: string]: any }) {
console.log(options);
return requestumi<{
data: [];
}>( /api/tea/add , {
method: POST ,
params: {
...options,
},
...(options || {}),
});
}
export async function getTeaList(options?: { [key: string]: any }) {
return requestumi<API.teaListItem>( /api/tea/list , {
method: GET ,
params: {
...options,
},
...(options || {}),
});
}
mock数据处理
import { Request, Response } from express ;
import { parse } from url ;
// mock tableListDataSource
const genList = (current: number, pageSize: number) => {
const tableListDataSource: API.teaListItem[] = [];
for (let i = 0; i < pageSize; i += 1) {
const index = (current - 1) * 10 + i;
tableListDataSource.push({
key: index,
onJob: i % 6 === 0,
name: `张三 ${index}`,
iPhone: Math.floor(Math.random() * 1000),
type: i % 3,
remarks: 这是一段描述 ,
createTime: new Date().getTime(),
endTime: new Date().getTime(),
});
}
tableListDataSource.reverse();
return tableListDataSource;
};
let tableListDataSource = genList(1, 100);
function getTeaList(req: Request, res: Response, u: string) {
let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== [object String] ) {
realUrl = req.url;
}
const { current = 1, pageSize = 10 } = req.query;
const params = parse(realUrl, true).query as unknown as API.PageParams &
API.teaListItem &
API.RuleListItem & {
sorter: any;
filter: any;
};
let dataSource = [...tableListDataSource].slice(
((current as number) - 1) * (pageSize as number),
(current as number) * (pageSize as number),
);
if (params.sorter) {
const sorter = JSON.parse(params.sorter);
dataSource = dataSource.sort((prev, next) => {
let sortNumber = 0;
Object.keys(sorter).forEach((key) => {
if (sorter[key] === descend ) {
if (prev[key] - next[key] > 0) {
sortNumber += -1;
} else {
sortNumber += 1;
}
return;
}
if (prev[key] - next[key] > 0) {
sortNumber += 1;
} else {
sortNumber += -1;
}
});
return sortNumber;
});
}
if (params.filter) {
const filter = JSON.parse(params.filter as any) as {
[key: string]: string[];
};
if (Object.keys(filter).length > 0) {
dataSource = dataSource.filter((item) => {
return Object.keys(filter).some((key) => {
if (!filter[key]) {
return true;
}
if (filter[key].includes(`${item[key]}`)) {
return true;
}
return false;
});
});
}
}
//搜索查询
if (params.name) {
dataSource = dataSource.filter((data) => data?.name?.includes(params.name || ));
}
if (params.iPhone) {
dataSource = dataSource.filter((data) =>
data?.iPhone?.toString().includes(params.iPhone.toString()),
);
}
if (params.type) {
dataSource = dataSource.filter((data) =>
data?.type?.toString().includes(params.type.toString()),
);
}
if (params.createTime) {
dataSource = dataSource.filter(
(data) => data?.createTime,
// data?.createTime >= params.createTime,
);
}
if (params.endTime) {
dataSource = dataSource.filter(
(data) => data?.endTime,
//data?.endTime <= params.endTime,
);
}
const result = {
data: dataSource,
total: tableListDataSource.length,
success: true,
pageSize,
current: parseInt(`${params.current}`, 10) || 1,
};
return res.json(result);
}
function addTea(req: Request, res: Response, u: string, b: Request) {
let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== [object String] ) {
realUrl = req.url;
}
const { pageSize = 1 } = req.query;
const params = parse(realUrl, true).query as unknown as API.PageParams &
API.teaListItem &
API.RuleListItem & {
sorter: any;
filter: any;
};
let dataSource = [...tableListDataSource];
for (let i = 0; i < pageSize; i += 1) {
tableListDataSource.unshift({
key: tableListDataSource.length,
onJob: params.onJob,
name: params.name,
iPhone: params.iPhone,
type: params.type,
remarks: params.remarks,
createTime: new Date().setTime(params.createTime),
endTime: new Date().setTime(params.endTime),
});
}
const resultes = {
data: dataSource,
total: tableListDataSource.length,
success: true,
pageSize,
current: parseInt(`${params.current}`, 10) || 1,
};
return res.json({ status: 200, data: resultes });
}
export default {
GET /api/tea/List : getTeaList,
POST /api/tea/add : addTea,
};
typing.d.ts 类型声明文件
declare namespace API {
type teaListItem = {
key: index,
onJob: boolean,
name: string,
iPhone: number,
type: number,
remarks: string,
createTime: number,
endTime: number,
};
}
proxy.ts文件
export default {
dev: {
/api/ : {
// 要代理的地址
//target: https://preview.pro.ant.design ,
changeOrigin: true,
},
}};
routes.ts文件
export default [
{
name: bunny.list ,
icon: table ,
path: /hyhList ,
component: ./hyhList ,
},]
menu.ts文件(位置:src/locales/zh-CN/..)
export default {
menu.bunny.list : 老师列表-bunny ,
}
另一个比较简单的写法,也是实现admin新增页面,实现增删改查的,与上面的相比差一些,可以用作比较,有异同之处。例2:
api-代码
//--查询列表 mock获取-- (ok)
export const getTeaList = async (params: any) => {
return request( /api/list , { params: params })
}
//--新增老师接口 mock获取--(ok)
export const addTea = async (params: any) => {
console.log(params);
return request( /api/add , {
params: params
})
}
mock-代码
//方法一:指定给定返回数据的参数
// let list = [
// {
// id: 1,
// name: bunny ,
// iPhone: 86688 ,
// type: 数学 ,
// createTime: 1650931200000,
// endTime: 1651276800000,
// onJob: true ,
// remarks: 他是一位好老师 ,
// },
// ]
//方法二:通过for循环push上去
const genList = (current: number, pageSize: number) => {
let list = []
for (let i = 0; i < pageSize; i += 1) {
const index = (current - 1) * 10 + i;
list.push({
id: index,
onJob: i % 6 === 0,
name: `bunny ${index}`,
iPhone: Math.floor(Math.random() * 1000),
type: i % 3,
remarks: 描述说明... ,
createTime: new Date().getTime(),
endTime: new Date().getTime(),
});
}
list.reverse();
return list;
};
let list = genList(1, 100);
export default {
GET /api/list : (req: any, res: any) => {
let query = req.query;
//过滤查询
let dataListSource: any
function filterQuery(list: any) {
let dataList: any[] = []
for (let i in query) {
let lists = list.filter((item: any) => {
return item[i] === query[i]
})
dataList = [...dataList, ...lists]
dataListSource = dataList
}
res.json({ status: 200, data: Array.from(new Set(dataList)), pageSize: 5, total: list.length })
}
if (JSON.stringify(query) === {} ) {
res.json({ status: 200, data: list, pageSize: 5, total: list.length })
} else {
//过滤查询
filterQuery(list)
}
},
GET /api/add : (req: any, res: any) => {
//添加name
// console.log(req);
// res.end( ok )
// res.end(JSON.stringify(req.body)) //req.body 拿到json数据
let timeFun = (tiems: string) => {
let d = new Date(tiems)
let k = d.getTime()
console.log(k)
return k
}
const item: any = {
id: list.length + 1,
name: req.query.name,
iPhone: req.query.iPhone,
type: Number(req.query.type),
createTime: timeFun(req.query.createTime),
endTime: timeFun(req.query.endTime),
onJob: req.query.onJob,
remarks: req.query.remarks,
}
list.unshift(item)
//list.push(item)
// res.end({ status: 200 })
res.json({ status: 200, data: list })
}
}
index.tsx-代码
import { PlusOutlined, EllipsisOutlined } from @ant-design/icons ;
import { Button, Menu, Dropdown, message } from antd ;
import type { ProColumns } from @ant-design/pro-table ;
import ProTable from @ant-design/pro-table ;
import { useState, useEffect } from react ;
import ProForm, {
ModalForm, ProFormText, ProFormDateRangePicker, ProFormSelect,
} from @ant-design/pro-form ;
import { addTea, getTeaList } from @/services/ant-design-pro/api
import type { RecordKey } from @ant-design/pro-utils/lib/useEditableArray ;
import request from umi-request ;
type TeacherIssueItem = {
name: string;//名称
iPhone: number;//手机号
type: number;//老师类型(状态)
createTime: number;//创建时间
endTime: number;//结束时间
onJob: boolean;//是否在职
remarks: string;//备注
id: number;
};
const columns: ProColumns<TeacherIssueItem>[] = [
{
dataIndex: index ,
valueType: indexBorder ,
width: 48,
},
{
title: 名 称 ,
dataIndex: name ,
copyable: true,
ellipsis: true,
},
{
title: 手机号 ,
dataIndex: iPhone ,
copyable: true,
ellipsis: true,
},
{
disable: true,
title: 老师类型 ,
dataIndex: type ,
filters: true,
onFilter: true,
valueType: select ,
valueEnum: {
all: { text: 全部 , status: Default },
0: {
text: 语文 ,
},
1: {
text: 数学 ,
},
2: {
text: 英语 ,
},
},
},
{
title: 创建时间 ,
key: showTime ,
dataIndex: createTime ,
valueType: dateTime ,
sorter: true,
hideInSearch: true,
},
{
title: 创建时间 ,
dataIndex: createTime ,
valueType: dateRange ,
hideInTable: true,
search: {
transform: (value) => {
return {
startTime: value[0],
endTime: value[1],
};
},
},
},
{
title: 结束时间 ,
key: showTime ,
dataIndex: endTime ,
valueType: dateTime ,
sorter: true,
hideInSearch: true,
},
{
title: 结束时间 ,
dataIndex: endTime ,
valueType: dateRange ,
hideInTable: true,
hideInSearch: true,
search: {
transform: (value) => {
return {
startTime: value[0],
endTime: value[1],
};
},
},
},
{
disable: true,
title: 是否在职 ,
dataIndex: onJob ,
filters: true,
onFilter: true,
hideInSearch: true,
valueType: select ,
valueEnum: {
true: {
text: 是 ,
status: Success ,
},
false: {
text: 否 ,
status: Error ,
},
},
},
{
title: 备 注 ,
dataIndex: remarks ,
hideInSearch: true,
copyable: true,
ellipsis: true,
},
{
title: 操作列表 ,
valueType: option ,
key: option ,
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}
>
编辑
</a>,
],
},
];
const menu = (
<Menu>
<Menu.Item key="1">1st item</Menu.Item>
<Menu.Item key="2">2nd item</Menu.Item>
<Menu.Item key="3">3rd item</Menu.Item>
</Menu>
);
// 数据过滤
function filterData(lists: any) {
// lists.forEach((ele: any) => {
// switch (ele.type) {
// case 1:
// ele.type = 数学
// break;
// case 2:
// ele.type = 语文
// break;
// case 3:
// ele.type = 英语
// break;
// case null:
// ele.type = --
// default:
// break;
// }
// })
return lists
}
export default () => {
let [list, setList] = useState([]);
useEffect(async () => {
if (list.length <= 0) {
let lists = await getTeaList({})
setList(filterData(lists.data))
}
}, [])
// //--新增老师数据请求--
const handleForm = async (values: any) => {
console.log(values, "values");
//获取表单新增的数据
let obj = {
createTime: values.contractTime ? values.contractTime[0] : -- ,
endTime: values.contractTime ? values.contractTime[1] : -- ,
name: values.name ? values.name : -- ,
type: values.type ? values.type : -- ,
iPhone: values.iPhone ? values.iPhone : -- ,
onJob: values.onJob ? values.onJob : -- ,
remarks: values.remarks ? values.remarks : --
}
// 请求获取响应数据,并将新增的数据返回到api接口给后端存储
const res = await addTea(obj)
//如果响应状态为200,则是获取成功。添加成功后要刷新列表数据
if (res.status = 200) {
//获取最新的列表数据
let lists = await getTeaList({})
//将数据更新渲染出来
setList(filterData(lists.data))
message.success(res.message)
} else {
message.error(res.message)
}
return true
}
//--添加--搜索
const beforeSearchSubmit = (val: any) => {
getTeaList({ ...val }).then((res) => {
setList(filterData(res.data))
})
}
return (
<ProTable<TeacherIssueItem>
columns={columns}
cardBordered
dataSource={list}
// request={ async() =>list}
// request={async (params) => {
// console.log(params, "params");
// let data: any
// data = await request( /api/List );
// console.log(data, "data");//data:[Array]
// return Promise.resolve(data);//将列表渲染到页面
// // return request<{
// // }>( /api/List , {
// // }).then((res) => {
// // console.log(res, ".then的res");//data:[Array]
// // });
// }}
editable={{
type: multiple ,
onSave: (key: RecordKey, row: TeacherIssueItem & {
index?: number | undefined;
}) => {
console.log(key, row, onSave );
return Promise.resolve();
},
onDelete: (key: RecordKey, row: TeacherIssueItem & {
index?: number | undefined;
}
) => {
console.log(key, row, onDelete );
return Promise.resolve();
}
}}
columnsState={{
persistenceKey: pro-table-singe-demos ,
persistenceType: localStorage ,
onChange(value) {
console.log( value: , value);
},
}}
beforeSearchSubmit={beforeSearchSubmit}
rowKey="id"
search={{
labelWidth: auto ,
}}
form={{
// 由于配置了 transform,提交的参与与定义的不同这里需要转化一下
syncToUrl: (values, type) => {
if (type === get ) {
return {
...values,
//开始时间
createTime: [values.startTime, values.endTime],
};
}
return values;
},
}}
pagination={{
pageSize: 5,
onChange: (page) => console.log(page)
// onChange: onChange,
}}
dateFormatter="string"
headerTitle="高级表格"
toolBarRender={() => [
<ModalForm<{
name: string;
iPhone: number;
}>
title="新增老师"
trigger={
<Button key="button" icon={<PlusOutlined />} type="primary">
新增老师
</Button>
}
autoFocusFirstInput
modalProps={{
onCancel: () => console.log( run ),
}}
submitTimeout={2000}
onFinish={value => handleForm(value)}
>
<ProForm.Group>
<ProFormText
width="sm"
name="name"
label="老师名称"
tooltip="最长为 6 位"
placeholder="请输入老师名称"
/>
<ProFormText width="sm" name="iPhone" label="手机号码" placeholder="请输入手机号" />
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
request={async () => [
{
value: 1,
label: 数学 ,
},
{
value: 2,
label: 语文 ,
},
{
value: 3,
label: 英语 ,
},
]}
width="xs"
name="type"
label="请选择老师类型"
/>
<ProFormSelect
request={async () => [
{
value: true ,
label: 是 ,
},
{
value: false ,
label: 否 ,
}
]}
width="xs"
name="onJob"
label="请选择是否在任职"
/>
<ProFormDateRangePicker name="contractTime" label="请选择起始和结束时间" />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="xl" name="remarks" label="备注信息" placeholder="请输入备注信息" />
</ProForm.Group>
</ModalForm>,
<Dropdown key="menu" overlay={menu}>
<Button>
<EllipsisOutlined />
</Button>
</Dropdown>,
]}
/>
);
};
其它小知识点的笔记
1. 请求接口,响应数据
(1).then和await的区别:
request={async (params) => {
console.log(params, "params");
return request<{
}>( /api/List , {
// params,//去掉传参
}).then((res) => {
console.log(res, ".then的res");
});
}}

request={async (params) => {
console.log(params, "params");
let data: any
data = await request( /api/List );
console.log(data, "data");//data:[Array]
return Promise.resolve(data);//将列表渲染到页面
// return request<{
// }>( /api/List , {
// }).then((res) => {
// console.log(res, ".then的res");
// });
}}

也可以用表单自带的dataSource来获取请求的数据,如例2里就是这样实现的。
—
2. 使用antd实现 表单输入完成后重置默认状态(也就是清空原来已经输入的值)
import { Form } from antd ;
const hyhList: React.FC = () => {
const [form] = Form.useForm();//重置表格
return (
<ProTable<API.teaListItem>
<ModalForm
form={form};//新增
onFinish={async (value) => {
if (success) {
form.resetFields();//重置
}
}
</ModalForm>
</ProTable>
)
}
export default hyhList;
3. 使用mock转化为时间戳
但是,这样的话,在<ProFormDateTimePicker/>中点击选择时间,得到的时间的的字符串参数就是时间戳格式了。如下图:
let timeFun = (tiems: string) => {
let d = new Date(tiems)
let k = d.getTime()
console.log(k)
return k
}
const item: any = {
createTime: timeFun(req.query.createTime),
endTime: timeFun(req.query.endTime),
}

但列表所得的时间格式是时间戳格式:

4.在新增表单中,获取新增数据后转化为时间戳再返回给mock处理时间转化为时间日期格式再返回表单页面
<ProFormDateTimePicker
name="createTime"
label="请选择创建时间"
transform={(value) => {
return {
createTime: Date.parse(value),
};
}}
rules={[{ required: true, message: Please select your country! }]}
/>
<ProFormDateTimePicker
name="endTime"
label="请选择结束时间"
transform={(value) => {
return {
endTime: Date.parse(value),
};
}}
rules={[{ required: true, message: Please select your country! }]}
/>


5. ProFormDateTimePicker和 fieldProps的使用
<ProFormDateTimePicker
name="createTime"
label="请选择创建时间"
fieldProps={{
format: (value) => value.format( YYYY-MM-DD ),
}}
rules={[{ required: true, message: Please select your country! }]}
/>
<ProFormDateTimePicker
name="endTime"
label="请选择结束时间"
fieldProps={{
format: (value) => value.format( YYYY-MM-DD ),
}}
rules={[{ required: true, message: Please select your country! }]}
/>
6. index.tsx的页面结构部署

7. 编辑的用法,实现删除和保存
{
title: 操作 ,
valueType: option ,
key: option ,
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.key);
}}
>
编辑
</a>,
],
},
editable={{
type: multiple ,
onSave: (key: RecordKey, row: API.teaListItem) => {
console.log(key, row, onSave );
return Promise.resolve();
},
onDelete: (key: RecordKey, row: API.teaListItem) => {
console.log(key, row, onDelete );
return Promise.resolve();
},
}}
8. 想要新增的数据显示在第一条 有两种方式
(1)list.push({
//data数据…
})
list.reverse();
return list;
(2)直接把push()方法 改为 const item={//data数据…} list.unshift(item)



大佬们分享下完整的代码吗?学习学习