bunny笔记|React+Ant Design pro框架实现Admin页面的功能(新增、删除、修改数据、查询列表等功能),采用mock模拟后端返回的数据处理

需求分析

需求:(1)在左侧菜单新增自己对应名词的菜单--例: 老师列表-张三(2)添加对应菜单的页面,老师列表页,提供老师信息的查询,新增功能

列表查询页

分两部分:搜索区域(对应参数入参)+列表区域(对应响应参数)
要求:包含参数中要求的控件组件,最终发起请求的参数齐全,响应成功展示正常即可

新增页面

新增页面以弹窗形式完成
要求:包含参数中要求的控件组件,最终发起请求的参数齐全

查询接口

import {addTea, getTeaList} from '@/services/ant-design-pro/api';
addTea为新增老师接口, getTeaList为查询列表接口

查询列表接口参数


image.png

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


image.png

查询老师列表响应体

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

Teacher对象字段


image.png

image.png

新增老师响应体

{
status:200,
}

功能实现

实现新增
image.png
实现删除/修改、查询
image.png
实现对列表的搜索查询功能
image.png

高级表格自带的其它功能

image.png
例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[] = [
  {
    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) => [
       {
          action?.startEditable?.(record.key);
        }}
      >
        编辑
      ,
    ],
  },
];

const menu = (
  
    1st item
    2nd item
    3rd item
  
);

/**
 * 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();
  const [createModalVisible, handleModalVisible] = useState(false);
  const [form] = Form.useForm();
  const intl = useIntl();
  return (
    
      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={() => [
        ,
        
          
        ,
         {
            //debugger;
            const success = await handleAdd(value as API.teaListItem);
            if (success) {
              handleModalVisible(false);
              if (actionRef.current) {
                actionRef.current.reload();
                form.resetFields();
              }
            }
          }}
        >
          
            

            
          
          
             [
                {
                  value: 0,
                  label: '数学',
                },
                {
                  value: 1,
                  label: '语文',
                },
                {
                  value: 2,
                  label: '英语',
                },
              ]}
              width="xs"
              name="type"
              label="请选择老师类型"
            />
             [
                {
                  value: 'true',
                  label: '是',
                },
                {
                  value: 'false',
                  label: '否',
                },
              ]}
              width="xs"
              name="onJob"
              label="请选择是否在任职"
            />
             {
                return {
                  createTime: Date.parse(value),
                };
              }}
              rules={[{ required: true, message: 'Please select your country!' }]}
            />
             {
                return {
                  endTime: Date.parse(value),
                };
              }}
              rules={[{ required: true, message: 'Please select your country!' }]}
            />
          
          
        ,
      ]}
    />
  );
};
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/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[] = [
 {
   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) => [
      {
         action?.startEditable?.(record.id);
       }}
     >
       编辑
     ,
   ],
 },
];

const menu = (
 
   1st item
   2nd item
   3rd item
 
);

// 数据过滤
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 (
   
     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={() => [
       
         title="新增老师"
         trigger={
           
         }
         autoFocusFirstInput
         modalProps={{
           onCancel: () => console.log('run'),
         }}
         submitTimeout={2000}
         onFinish={value => handleForm(value)}
       >
         
           

           
         
         
            [
               {
                 value: 1,
                 label: '数学',
               },
               {
                 value: 2,
                 label: '语文',
               },
               {
                 value: 3,
                 label: '英语',
               },
             ]}
             width="xs"
             name="type"
             label="请选择老师类型"
           />
            [
               {
                 value: 'true',
                 label: '是',
               },
               {
                 value: 'false',
                 label: '否',
               }
             ]}
             width="xs"
             name="onJob"
             label="请选择是否在任职"
           />
           
         
         
           
         
       ,
       
         
       ,
     ]}
   />
 );
};

其它小知识点的笔记

1. 请求接口,响应数据

(1).then和await的区别:

      request={async (params) => {
        console.log(params, "params");
        return request<{
        }>('/api/List', {
        //  params,//去掉传参
        }).then((res) => {
          console.log(res, ".then的res");
        });
      }}
image.png
      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");
        // });
      }}
image.png
也可以用表单自带的dataSource来获取请求的数据,如例2里就是这样实现的。

--

2. 使用antd实现 表单输入完成后重置默认状态(也就是清空原来已经输入的值)

import {  Form } from 'antd';
const hyhList: React.FC = () => {
  const [form] = Form.useForm();//重置表格
  return (
    
         {
            if (success) {
                form.resetFields();//重置
              }
            }
         
     
)
}
export default hyhList;

3. 使用mock转化为时间戳

但是,这样的话,在中点击选择时间,得到的时间的的字符串参数就是时间戳格式了。如下图:

    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),
    }
image.png

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

image.png

4.在新增表单中,获取新增数据后转化为时间戳再返回给mock处理时间转化为时间日期格式再返回表单页面

             {
                return {
                  createTime: Date.parse(value),
                };
              }}
              rules={[{ required: true, message: 'Please select your country!' }]}
            />
             {
                return {
                  endTime: Date.parse(value),
                };
              }}
              rules={[{ required: true, message: 'Please select your country!' }]}
            />
image.png
image.png

5. ProFormDateTimePicker和 fieldProps的使用

             value.format('YYYY-MM-DD'),
              }}
              rules={[{ required: true, message: 'Please select your country!' }]}
            />
             value.format('YYYY-MM-DD'),
              }}
              rules={[{ required: true, message: 'Please select your country!' }]}
            />

6. index.tsx的页面结构部署

image.png

7. 编辑的用法,实现删除和保存

{
    title: '操作',
    valueType: 'option',
    key: 'option',
    render: (text, record, _, action) => [
       {
          action?.startEditable?.(record.key);
        }}
      >
        编辑
      ,
    ],
  },
      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)

9.Hooks

9.其它嘛,多用多练,多多熟悉吧,一起加油吧~

你可能感兴趣的:(bunny笔记|React+Ant Design pro框架实现Admin页面的功能(新增、删除、修改数据、查询列表等功能),采用mock模拟后端返回的数据处理)