React后台管理(十四)-- 完整示例页面构建教学

文章目录


前言

经过了前面文章的学习,终于到最后一步了,那就是一个管理页面的构建,包括处理列表请求,搜索、重置和展开/收起等功能。

结合之前封装的布局、功能相关组件,在本文只需要按需引入,统一了代码标准,减少重复代码,提高代码的可维护性和可复用性。


一、组件源码+详细注释说明+技术分析

页面技术分析:

(1)React Hooks:使用了React的Hooks,如useState、useEffect和useRef,用于管理状态和副作用

(2)React Router DOM:使用了React Router DOM,实现页面路由和导航

(3)MobX-React lite:使用了MobX-React lite,实现响应式数据管理

(4)Ant Design:使用了Ant Design,用于构建表格、按钮、输入框等用户界面元素

(5)自定义组件:使用了自定义组件,如SearchIndex、SearchItem和SearchButton,用于实现搜索和过滤功能

c 复制代码
// @/page/chainManage/index.jsx
import { useEffect, useState, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { observer } from "mobx-react-lite";
import { Table, Space, Button, Select, message, Input } from "antd";
import { DeleteOutlined } from "@ant-design/icons";
// api
import { ApiCustomersList, ApiDeleteCustomer } from "@/api";
// hook
import { useTable, useSearch } from "@/hook/index.js";
// 函数组件
import SearchIndex from "@/components/search/index.jsx";
import SearchItem from "@/components/search/item.jsx";
import SearchButton from "@/components/search/button.jsx";
import CdList from "@/layout/list/index.jsx";
import CdTabs from "@/layout/tabs/index.jsx";

const Customer = () => {
  // table
  const [loading, setLoading] = useState(false);
  const { getHeight, tableHeight } = useTable();
  // 请求参数初始化
  const { getReq, updateReq } = useSearch({
    name: "",
    liaisonName: "",
    liaisonMobile: "",
    brandStatus: undefined,
  });
  // table ref
  const tableRef = useRef();
  // 消息
  const [messageApi, contextHolder] = message.useMessage();
  // 路由导航
  const navigate = useNavigate();
  // 搜索ref
  const searchRef = useRef();
  // 是否展示更多搜索条件
  const [open, setOpen] = useState(false);
  // 客户参数管理
  const [params, setParams] = useState({
    page: 1,
    per_page: 10,
  });
  // 客户列表管理
  const [customerData, setCustomerData] = useState({
    list: [], // 客户列表
    count: 0, // 客户数量
  });
  // 状态select列表
  const [statusOptions] = useState([
    { value: "1", label: "及格" },
    { value: "0", label: "不及格" },
  ]);
  // 表格column项
  const columns = [
    {
      title: "客户名称",
      dataIndex: "brandName",
      key: "brandName",
      width: 220,
      render: (text) => <a>{text}</a>,
    },
    {
      title: "状态",
      dataIndex: "brandStatus",
      key: "brandStatus",
      ellipsis: true,
    },
    {
      title: "费率",
      dataIndex: "serviceChargeRateStr",
      key: "serviceChargeRateStr",
      width: 220,
      align: "right",
    },
    {
      title: "联系人",
      dataIndex: "liaisonName",
      key: "liaisonName",
      ellipsis: true,
    },
    {
      title: "联系人手机",
      dataIndex: "liaisonMobile",
      key: "liaisonMobile",
      ellipsis: true,
    },
    {
      title: "操作",
      width: 240,
      render: (data) => {
        return (
          <Space>
            <Button type="link" size="small" icon={<i className="iconfont icon-eye" />} onClick={() => handlerEdit(data)}>
              详情
            </Button>
            <Button type="link" size="small" icon={<i className="iconfont icon-edit" />} onClick={() => handlerEdit(data)}>
              编辑
            </Button>
            <Button type="link" size="small" icon={<DeleteOutlined />} onClick={() => handlerDel(data)}>
              删除
            </Button>
          </Space>
        );
      },
      fixed: "right",
    },
  ];
  // 获取客户列表数据
  const getList = async () => {
    setLoading(true); // 页面loading打开
    ApiCustomersList(getReq())
      .then((res) => {
        console.log("getReq", getReq());
        setCustomerData({
          list: res.data?.records || [],
          count: res.data?.total || 0,
        }); // 表格数据
        setLoading(false); // 页面loading关闭
        tableRef.current && tableRef.current.setTotal(res.data?.total); // 设置分页器总条数
      })
      .catch(() => {
        setLoading(false); // 页面loading关闭
      });
  };
  // 切换页码
  const changePage = () => {
    return getList();
  };
  // 设置表格区域高度以及请求列表数据
  useEffect(() => {
    getHeight().then(() => {
      getList();
    });
  }, []);
  // 展开/收起
  const handlerToggle = (value) => {
    setOpen(value);
    getHeight();
  };
  // 搜索
  const handlerSearch = () => {
    console.log("搜索", searchRef.current.getFieldValue());
    searchRef.current.getFieldValue() && updateReq(searchRef.current.getFieldValue());
    tableRef.current.reset();
    getList();
  };
  // 重置
  const handlerReset = () => {
    searchRef.current.reset();
    getList();
  };
  // 状态select下拉
  const onStatusChange = (val) => {
    searchRef.current.setFieldValue("brandStatus", val);
  };
  // 编辑
  const handlerEdit = (data) => {
    navigate(`/layout/publish?id=${data.id}`);
  };
  // 删除
  const handlerDel = async (data) => {
    ApiDeleteCustomer({ id: data.id }).then((res) => {
      // 刷新列表
      setParams({
        ...params,
        page: 1,
      });
      getList();
      messageApi.open({
        type: "success",
        content: "删除成功",
      });
    });
  };

  return (
    <>
      {contextHolder}
      <CdList tableRef={tableRef} page={changePage}>
        {{
          tabs: (
            <CdTabs title="客户管理">
              <Space size={10}>
                <Button type="primary">新增</Button>
                <Button>导 出</Button>
              </Space>
            </CdTabs>
          ),
          search: (
            <>
              {/* 筛选区域 */}
              <SearchIndex searchRef={searchRef}>
                <SearchItem label="客户名:" name="name" labelWidth="60px">
                  <Input placeholder="请输入名称/简称" maxLength={100} />
                </SearchItem>
                <SearchItem label="联系人:" name="liaisonName" labelWidth="60px">
                  <Input placeholder="请输入" maxLength={100} />
                </SearchItem>
                <SearchItem label="联系人手机:" name="liaisonMobile" labelWidth="90px">
                  <Input placeholder="请输入" maxLength={20} />
                </SearchItem>
                {open ? (
                  <SearchItem label="状态:" name="brandStatus" labelWidth="45px">
                    <Select placeholder="请选择" options={statusOptions} onChange={onStatusChange} allowClear />
                  </SearchItem>
                ) : null}
                <SearchItem span={open ? 24 : 6}>
                  <SearchButton toggle={handlerToggle} reset={handlerReset} search={handlerSearch}></SearchButton>
                </SearchItem>
              </SearchIndex>
            </>
          ),
          default: (
            <>
              {/* 客户列表区域 */}
              <Table
                rowKey="id"
                loading={loading}
                columns={columns}
                dataSource={customerData.list}
                scroll={{
                  y: tableHeight,
                }}
                pagination={false}
              />
            </>
          ),
        }}
      </CdList>
    </>
  );
};

export default observer(Customer);

二、效果展示


总结

关注本栏目,会实时更新。

相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
浪浪山小白兔6 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
光头程序员7 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
limit for me7 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者7 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架