zoukankan      html  css  js  c++  java
  • 测试平台系列(22) 编写项目的增删改查接口和页面(4)

    闲聊

    本来打算自己记录总结一下自己这几年的一个工作内容,也没想过去大力宣传啥的,因为总觉得文章数量有限,也怕随时就会断更。今天被饭哥的指点了一些,也想通了。也许之前断更都是没有太多动力吧,如果有人看的话,也会被动更新的。

    自己一直都不是很自信吧,因为确实见识过很多大神级别的人物。比如大师兄饭哥露露哥等等。本来也觉得文章可能受众面是没有相关经验的读者,希望大佬们看到文章的错误可以及时指出呀,我将继续虚心学习(带头冲锋)~

    饭哥的公众号: 测试开发干货 (分享测试开发的一切干货,搜索测试开发,第一条就是)

    榜一大哥赫赫(一个始终在努力的人)的公众号: 测试开发二货 看名字也知道是分享成长经验

    回顾

    上一节已经贴出了项目列表页面的全部前端代码,由于笔者前端也没有深入学习,所以只能给大家大概讲解一下吧。还是按照之前的几个部分来说吧!

    状态管理

    设置了如下变量:

    • data

      存放当前项目数组

    • pagination

      项目分页

    • visible

      创建项目表单是否可见,默认是否

    • users

      由于我们需要选择项目管理员,所以需要一个userId => 用户信息的映射。当然这个接口我们暂时还没有实现。

    方法编写

    const fetchData = async (current=pagination.current, size=pagination.size) => {
      await process(async ()=> {
        const res = await listProject({page: current, size });
        if (auth.response(res)) {
          setData(res.data)
          setPagination({...pagination, total: res.total})
        }
      });
    }

    这个方法是获取项目列表的方法,current代表page,size代表分页大小,如果不传入则是pagination默认的值。

    listProject其实就是包装的request方法,请求后端服务。

    useEffect(async () => {
      await fetchData();
    }, [])

    const onSearchProject = async projectName => {
      await process(async ()=> {
        const res = await listProject({page1size: pagination.size, name: projectName});
        if (auth.response(res)) {
          setData(res.data)
          setPagination({...pagination, current1total: res.total})
        }
      });
    }

    useEffectreact新版本的特性,它支持2个参数,第一个是方法,第二个是变量数组,传入空数组的话,则每次这个组件开始渲染的时候会调用且只调用一次方法。

    我们如果正式使用的话,是会有多套测试环境的。如果我们对项目做了环境的区分,那么就应该在切换环境的时候,获取不同环境的项目。

    假设我们需要实现这种功能,那么我们先创建一个env的变量,然后改写useEffect:

    useEffect(async () => {
      await fetchData();
    }, [env])

    这样的话,每当env发生变化,这个方法就会自动执行一次。需要说明的是,这里只是介绍一下useEffect的使用方式,因为我们这边暂时还没有扩展到多套环境,所以此处我们选择[]即可

    const onHandleCreate = async values => {
      const res = await insertProject(values);
      if (auth.response(res, true)) {
        // 创建成功后自动获取第一页的数据, 因为项目会按创建时间排序
        await fetchData(1);
      }
    }

    这边也如出一辙,创建完毕了之后如果接口未返回错误,则刷新项目列表页面,并且自动去第一页

    const content = (item) => {
      return <div>
         {/* <p>负责人: {userMap[item.owner].name}</p> */}
         <p>简介: {item.description || '无'}</p>
         <p>更新时间: {item.updated_at}</p>
      </div>

    };

    const opt = <Select placeholder="请选择项目负责人">
      {
        Object.keys(users).map(id => <Option key={id} value={id}>{users[id].name}</Option>)
      }
    </Select>


    const fields = [
        {
          name'projectName',
          label'项目名称',
          requiredtrue,
          message"请输入项目名称",
          type'input',
          placeholder"请输入项目名称",
        },
        {
          name'owner',
          label'项目负责人',
          requiredtrue,
          component: opt,
          type'select',
        },
        {
          name'description',
          label'项目描述',
          requiredfalse,
          message"请输入项目描述",
          type'textarea',
          placeholder"请输入项目描述",
        },
        {
          name'private',
          label'是否私有',
          requiredtrue,
          message"请选择项目是否私有",
          type'switch',
          valuePropName"checked",
        },
      ]

    这里content是一个方法,会返回一个div的html结构,目的是为了展示项目的详情,比如负责人项目描述等。

    fields的话,是表单的字段,因为我针对antd的form进行了一点封装,编写了一套高阶组件。等于说是规划好了表单里面的表单组成,由input和select以及switch组件组成

    待会会讲这个组件!

    最后看return里面的组件

        return (
          <PageContainer title={false}>
            <FormForModal width={600} title="添加项目" left={6} right={18} record={{}}
                          visible={visible} onCancel={() =>
     setVisible(false)} fields={fields} onFinish={onHandleCreate}
            />
            <Row gutter={8} style={{marginBottom: 16}}>
              <Col span={18}>
                <Button type="primary" onClick={() => setVisible(true)}>创建项目
                  <Tooltip title="只有超级管理员可以创建项目"><QuestionCircleOutlined/></Tooltip>
                </Button>
              </Col>
              <Col span={6}>
                <Search onSearch={onSearchProject} style={{float: 'right'}} placeholder="请输入项目名称"/>
              </Col>
            </Row>
            <Spin spinning={false}>
              <Row gutter={16}>
                {
                  data.length === 0 ? <Col span={24} style={{textAlign: 'center', marginBottom: 12}}>
                      <Card><Empty description="暂无项目, 快点击『创建项目』创建一个吧!"/></Card>
                    </Col> :
                    data.map(item =>
                      <Col key={item.id} span={4} style={{marginBottom: 12}}>
                        <Popover content={content(item)} placement="rightTop">
                          <Card hoverable bordered={false} style={{borderRadius: 16textAlign: 'center'}}
                                bodyStyle={{padding: 16}} onClick={() =>
     {
                            history.push(`/project/${item.id}`);
                          }}>
                            <Avatar style={{backgroundColor: '#87d068'}} size={64}
                            >
    {item.name.slice(0, 2)}</Avatar>
                            <p style={{
                              textAlign: 'center',
                              fontWeight: 'bold',
                              fontSize: 18,
                              marginTop: 8
                            }}>
    {item.name}</p>
                          </Card>
                        </Popover>
                      </Col>
                    )
                }
              </Row>
            </Spin>
          </PageContainer>

        )
    }

    PageContainer是最外层,也就是咱们看到的这一块:

    FormForModal是一个对话框表单,默认是不显示的,只有点击创建项目才会显示。

    然后用Row分了2行: 分别是 创建栏/搜索栏和项目展示栏

    这边项目展示栏如果data.length === 0就展示一个空状态,提示用户去添加项目,否则就把项目展示出来,每个项目占屏幕的1/6,因为Col总共有24份。

    tips: 这里类似于bootstrap,一行共有24份,所以span={4}代表的是4/24,可参考: 官网介绍

    其他的就是Card(卡片)组件和Avatar(头像)组件的互相嵌入,Popover是悬浮窗口,如图:

    编写获取用户列表的接口

    修改app/dao/auth/UserDao.py

    筛选出未被删除的用户即可。

    修改app/controllers/auth/user.py

    这里注意开启一下权限,但是不能控制太死,能让登录用户访问即可。

    前端页面编写listUsers方法

    看下效果

    发现一个问题: 创建成功后,对话框没有关闭

    所以我们需要在创建成果后,setVisible(false)去关闭对话框。

    还有一个地方就是之前注释掉的项目负责人,现在可以重新开启了。

    看下搜索效果

    这就是本节的内容了,大部分是讲解代码为主,因为前端内容居多,所以可能有点懵逼。如果有不理解的地方,还请多多看看reactes6相关的教程。箭头函数,看着别怕,熟悉了就好。

    下一节可能是具体项目的编辑页面了,感觉这一讲就讲了一个世纪,再后面就是用例那块了。

  • 相关阅读:
    基于学习的超分辨率技术
    图像缩放技术
    cifar-10 图片可视化
    python图像插值
    替换空格
    配置Windows Server 2008/2012/2016允许多个用户同时远程桌面
    安装XPS文件查看器的方法
    win10外接显示器时有些应用和里面的字体显示比较模糊
    关于中行长城跨境通卡的网上支付常见问题&支付实例
    分布式中Redis实现Session(将Session保存到Redis)
  • 原文地址:https://www.cnblogs.com/we8fans/p/14641834.html
Copyright © 2011-2022 走看看