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,用于实现搜索和过滤功能

// @/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);

二、效果展示

在这里插入图片描述


总结

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

相关推荐

  1. 第二章 Web Gateway 管理页面概述

    2024-06-05 22:20:05       41 阅读
  2. 八----react实战

    2024-06-05 22:20:05       59 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-05 22:20:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-05 22:20:05       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-05 22:20:05       82 阅读
  4. Python语言-面向对象

    2024-06-05 22:20:05       91 阅读

热门阅读

  1. 1120大整数加法

    2024-06-05 22:20:05       25 阅读
  2. 台式机ubuntu22.04安装nvidia驱动

    2024-06-05 22:20:05       30 阅读
  3. 物联网行业知识概览(一)

    2024-06-05 22:20:05       25 阅读
  4. WebSocket详解与封装工具类

    2024-06-05 22:20:05       34 阅读
  5. C语言牛客网题目--井字棋代码详解

    2024-06-05 22:20:05       23 阅读
  6. 编程参考 - 如何判断C++的std::funciton是否为空

    2024-06-05 22:20:05       33 阅读
  7. Shell 编程之免交互

    2024-06-05 22:20:05       25 阅读
  8. A-SDM原文

    2024-06-05 22:20:05       31 阅读
  9. 【数据库初阶】SQL--DML

    2024-06-05 22:20:05       26 阅读
  10. 模拟退火算法详细讲解(含实例python代码)

    2024-06-05 22:20:05       34 阅读