从0开始的中后台管理系统-5(userList动态展示以及上传图片和弹出创建用户表单)

项目用的都是antd组件,这里的userList组件展示的表单组件的数据直接get请求拿过来展示的,这里随机生成了50个用户只是为了展示表单的api设置。首先就是表单展示需要两个参数current和pageSize两个属性控制表单的最大分页和当前页面。那么我们就设置初始值然后通过访问服务器返回来一些数据,这里我们不用服务器返回的,只是用自己设置的一些数据去展示效果,还有onChange自带的api监听page和pageSize去获取变化后的然后更新就好了,.直接上代码。

1.userList动态展示

效果图

​编辑

typescript 复制代码
import React, { useState, useEffect, useRef } from 'react'
import type { PageParams, User } from '@/types/api'
import type { TableColumnsType } from 'antd'
import { Button, Table, Form, Input, Select, Space } from 'antd'
import api from '@/api/index'
import { toLocalDate } from '@/utils'
import CreateUser from './CreateUser'
import type { IAction } from '@/types/modal'
export default function UserList() {
  const userRef = useRef<{
    open: (type: IAction, data?: User.UserItem) => void | undefined
  }>(null)
  //获取表单对象 用里面的方法 getFieldsValue获取表单中填写的内容
  const [form] = Form.useForm()
  const [data, setData] = useState<User.UserItem[]>([])
  const [total, setTotal] = useState(0)
  const [pagination, setPagination] = useState({
    current: 1,
    pageSize: 10
  })
  // 获取用户列表
  const getUserList = async (params: PageParams) => {
    const values = form.getFieldsValue()
    const data = await api.getUserList({
      ...values,
      pageNum: params.pageNum,
      pageSize: params.pageSize
    })
    const list = Array.from({ length: 51 })
      .fill({})
      .map((item: any) => {
        item = { ...data.list[0] }
        item.userId = Math.random()
        return item
      })
    setData(list) // 注意:接口返回结构要和这里匹配
    setTotal(list.length)
    setPagination({
      current: params.pageNum,
      pageSize: params.pageSize
    })
  }
  //创建
  const handleCreate = () => {
    userRef.current?.open('create')
  }
  //搜索
  const handleSearch = () => {
    getUserList({
      pageNum: 1,
      pageSize: pagination.pageSize
    })
  }
  //重置 表单
  const handleReset = () => {
    form.resetFields()
  }
  // 组件挂载时调用
  useEffect(() => {
    getUserList({
      pageNum: pagination.current,
      pageSize: pagination.pageSize
    })
  }, [pagination.current, pagination.pageSize])

  const columns: TableColumnsType<User.UserItem> = [
    {
      title: '用户ID',
      dataIndex: 'userId',
      key: 'userId'
    },
    {
      title: '用户名称',
      dataIndex: 'userName',
      key: 'userName'
    },
    {
      title: '用户邮箱',
      dataIndex: 'userEmail',
      key: 'userEmail'
    },
    {
      title: '用户角色',
      dataIndex: 'role',
      key: 'role',
      render(role: number) {
        return {
          0: '超级管理员',
          1: '管理员',
          2: '体验管理员',
          3: '普通用户'
        }[role]
      }
    },
    {
      title: '用户状态',
      dataIndex: 'state',
      key: 'state',
      render(state: number) {
        return {
          1: '在职',
          2: '离职',
          3: '试用期'
        }[state]
      }
    },
    {
      title: '注册时间',
      dataIndex: 'create', // 你的字段是 create,不是 createTime
      key: 'create',
      render(createTime: string) {
        return toLocalDate(createTime)
      }
    },
    {
      title: '操作',
      key: 'action',
      render(_, record) {
        return (
          <Space>
            <Button type='text'>编辑</Button>
            <Button type='text' danger>
              删除
            </Button>
          </Space>
        )
      }
    }
  ]
  return (
    <div className='user-list'>
      <Form
        form={form}
        className='search-form'
        layout='inline'
        initialValues={{ state: 0 }}
      >
        <Form.Item name='userId' label='用户ID'>
          <Input placeholder='请输入用户ID' />
        </Form.Item>
        <Form.Item name='userName' label='用户名称'>
          <Input placeholder='请输入用户名称' />
        </Form.Item>
        <Form.Item name='state' label='状态'>
          <Select style={{ width: 120 }}>
            <Select.Option value={0}>所有</Select.Option>
            <Select.Option value={1}>在职</Select.Option>
            <Select.Option value={2}>试用</Select.Option>
            <Select.Option value={3}>离职</Select.Option>
          </Select>
        </Form.Item>
        <Form.Item>
          <Space>
            <Button onClick={handleSearch} type='primary' className='mr10'>
              搜索
            </Button>
            <Button onClick={handleReset} type='default'>
              重置
            </Button>
          </Space>
        </Form.Item>
      </Form>

      <div className='base-table'>
        <div className='header-wrapper'>
          <div className='title'>用户列表</div>
          <div className='action'>
            <Button type='primary' onClick={handleCreate}>
              新增
            </Button>
            <Button type='primary' danger>
              批量删除
            </Button>
          </div>
        </div>
        <Table
          rowKey='userId' // 保证每行有唯一 key
          pagination={{
            position: ['bottomRight'],
            current: pagination.current,
            pageSize: pagination.pageSize,
            total: total,
            showQuickJumper: true,
            showSizeChanger: true,
            showTotal: function (total) {
              return 总共:${total}条
            },
            onChange: (page, pageSize) => {
              setPagination({
                current: page,
                pageSize: pageSize
              })
            }
          }}
          bordered
          rowSelection={{ type: 'checkbox' }}
          dataSource={data}
          columns={columns}
        />
      </div>
      <CreateUser
        mRef={userRef}
        updata={() => {
          getUserList({
            pageNum: 1,
            pageSize: 10
          })
        }}
      />
    </div>
  )
}

2.创建表单以及上传头像功能(点击新增弹出取消关闭以及发送成功关闭)

效果图

​编辑

静态的展示就不说了,用户头像我们在上传之前,

​编辑

无非就是上传之后服务器发送回来url然后去替换展示,然后三元表达式就实现了。主要是怎么可以实现点击新增跳出来子组件也就是创建表单。

首先我们可以设置子组件默认不展示的,也就是open我们设置为关闭,我们希望父组件可以操作子组件的属性,而且我们还希望添加成功后立马重新加载获取新列表,那么我们就给子组件传递参数,一个我们设置的ref扔过去,以及一个更新方法。

然后子组件mRef绑定父组件设置的ref那么就拿到了子组件的DOM元素了,但是方法还是拿不到,也就是我们没办法去操作子组件设置的vibale状态去控制子组件的展示和关闭,那么子组件用useImperativehandle暴露一个open方法,然后open方法可以接收一个类型,因为这个表单我们要在增加更新都需要用到,然后更新vision,这样就实现了完整了逻辑。上代码。

typescript 复制代码
import React, { useState, useEffect, useRef } from 'react'
import type { PageParams, User } from '@/types/api'
import type { TableColumnsType } from 'antd'
import { Button, Table, Form, Input, Select, Space } from 'antd'
import api from '@/api/index'
import { toLocalDate } from '@/utils'
import CreateUser from './CreateUser'
import type { IAction } from '@/types/modal'
export default function UserList() {
  const userRef = useRef<{
    open: (type: IAction, data?: User.UserItem) => void | undefined
  }>(null)
  //获取表单对象 用里面的方法 getFieldsValue获取表单中填写的内容
  const [form] = Form.useForm()
  const [data, setData] = useState<User.UserItem[]>([])
  const [total, setTotal] = useState(0)
  const [pagination, setPagination] = useState({
    current: 1,
    pageSize: 10
  })
  // 获取用户列表
  const getUserList = async (params: PageParams) => {
    const values = form.getFieldsValue()
    const data = await api.getUserList({
      ...values,
      pageNum: params.pageNum,
      pageSize: params.pageSize
    })
    const list = Array.from({ length: 51 })
      .fill({})
      .map((item: any) => {
        item = { ...data.list[0] }
        item.userId = Math.random()
        return item
      })
    setData(list) // 注意:接口返回结构要和这里匹配
    setTotal(list.length)
    setPagination({
      current: params.pageNum,
      pageSize: params.pageSize
    })
  }
  //创建
  const handleCreate = () => {
    userRef.current?.open('create')
  }
  //搜索
  const handleSearch = () => {
    getUserList({
      pageNum: 1,
      pageSize: pagination.pageSize
    })
  }
  //重置 表单
  const handleReset = () => {
    form.resetFields()
  }
  // 组件挂载时调用
  useEffect(() => {
    getUserList({
      pageNum: pagination.current,
      pageSize: pagination.pageSize
    })
  }, [pagination.current, pagination.pageSize])

  const columns: TableColumnsType<User.UserItem> = [
    {
      title: '用户ID',
      dataIndex: 'userId',
      key: 'userId'
    },
    {
      title: '用户名称',
      dataIndex: 'userName',
      key: 'userName'
    },
    {
      title: '用户邮箱',
      dataIndex: 'userEmail',
      key: 'userEmail'
    },
    {
      title: '用户角色',
      dataIndex: 'role',
      key: 'role',
      render(role: number) {
        return {
          0: '超级管理员',
          1: '管理员',
          2: '体验管理员',
          3: '普通用户'
        }[role]
      }
    },
    {
      title: '用户状态',
      dataIndex: 'state',
      key: 'state',
      render(state: number) {
        return {
          1: '在职',
          2: '离职',
          3: '试用期'
        }[state]
      }
    },
    {
      title: '注册时间',
      dataIndex: 'create', // 你的字段是 create,不是 createTime
      key: 'create',
      render(createTime: string) {
        return toLocalDate(createTime)
      }
    },
    {
      title: '操作',
      key: 'action',
      render(_, record) {
        return (
          <Space>
            <Button type='text'>编辑</Button>
            <Button type='text' danger>
              删除
            </Button>
          </Space>
        )
      }
    }
  ]
  return (
    <div className='user-list'>
      <Form
        form={form}
        className='search-form'
        layout='inline'
        initialValues={{ state: 0 }}
      >
        <Form.Item name='userId' label='用户ID'>
          <Input placeholder='请输入用户ID' />
        </Form.Item>
        <Form.Item name='userName' label='用户名称'>
          <Input placeholder='请输入用户名称' />
        </Form.Item>
        <Form.Item name='state' label='状态'>
          <Select style={{ width: 120 }}>
            <Select.Option value={0}>所有</Select.Option>
            <Select.Option value={1}>在职</Select.Option>
            <Select.Option value={2}>试用</Select.Option>
            <Select.Option value={3}>离职</Select.Option>
          </Select>
        </Form.Item>
        <Form.Item>
          <Space>
            <Button onClick={handleSearch} type='primary' className='mr10'>
              搜索
            </Button>
            <Button onClick={handleReset} type='default'>
              重置
            </Button>
          </Space>
        </Form.Item>
      </Form>

      <div className='base-table'>
        <div className='header-wrapper'>
          <div className='title'>用户列表</div>
          <div className='action'>
            <Button type='primary' onClick={handleCreate}>
              新增
            </Button>
            <Button type='primary' danger>
              批量删除
            </Button>
          </div>
        </div>
        <Table
          rowKey='userId' // 保证每行有唯一 key
          pagination={{
            position: ['bottomRight'],
            current: pagination.current,
            pageSize: pagination.pageSize,
            total: total,
            showQuickJumper: true,
            showSizeChanger: true,
            showTotal: function (total) {
              return 总共:${total}条
            },
            onChange: (page, pageSize) => {
              setPagination({
                current: page,
                pageSize: pageSize
              })
            }
          }}
          bordered
          rowSelection={{ type: 'checkbox' }}
          dataSource={data}
          columns={columns}
        />
      </div>
      <CreateUser
        mRef={userRef}
        updata={() => {
          getUserList({
            pageNum: 1,
            pageSize: 10
          })
        }}
      />
    </div>
  )
}

相关推荐
Bdygsl1 小时前
前端开发:HTML(5)—— 表单
前端·html
望获linux1 小时前
【实时Linux实战系列】实时数据流处理框架分析
linux·运维·前端·数据库·chrome·操作系统·wpf
国家不保护废物1 小时前
TailwindCSS:原子化CSS的革命,让React开发爽到飞起!🚀
前端·css·react.js
程序视点2 小时前
如何高效率使用 Cursor ?
前端·后端·cursor
前端领航者2 小时前
重学Vue3《 v-for的key属性:性能差异与最佳实践》
前端·javascript
归于尽2 小时前
跨域问题从青铜到王者:JSONP、CORS原理详解与实战(前端必会)
前端·浏览器
Andy_GF2 小时前
纯血鸿蒙HarmonyOS Next 远程测试包分发
前端·ios·harmonyos
嗑药狂写9W行代码2 小时前
cesium修改源码支持4490坐标系
前端
小山不高2 小时前
react实现leaferjs编辑器之形状裁剪功能点
前端
20262 小时前
13.2 ssr基本原理,构建步骤
前端·vue.js