Small talk

I had planned to record and summarize one of my work in the past few years, but I didn’t want to publicize anything in the past, because I always felt that the number of articles was limited and I was afraid that it would be cut off at any time. Today, I was given some advice by brother Fan, and I figured it out. Maybe before the break more is not too much power, if someone looks at it, it will be passive update.

I have never been very confident, because I do see a lot of god level people. For example, big brother, fan brother, Lu Lu brother and so on. Originally also felt that the article may be the audience is not relevant experience of readers, hope that the big men see the article’s mistakes can be timely pointed out ah, I will continue to learn modestly (lead the charge) ~

Fan elder brother’s public number: test development dry goods (share test development of all dry goods, search test development, the first is)

List one eldest brother hehe (a person who is always working hard) public account: test development parallel goods to see the name also know is to share growth experience

review

The last section has posted all the front-end code of the project list page, because the author did not learn the front-end, so I can only give you a general explanation of it. Or according to the previous several parts to say!

State management

The following variables are set:

  • data

    Holds an array of current items

  • pagination

    Project page

  • visible

    Is the create project form visible by default

  • users

    Since we need to select the project administrator, we need a mapping of userId => user information. Of course, we haven’t implemented this interface yet.

Methods to write

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})
    }
  });
}
Copy the code

Current = page, size = pagination, default pagination if not passed.

ListProject is essentially a wrapped Request method that requests a back-end service.

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

const onSearchProject = async projectName => {
  await process(async() = > {const res = await listProject({page: 1.size: pagination.size, name: projectName});
    if(auth.response(res)) { setData(res.data) setPagination({... pagination,current: 1.total: res.total})
    }
  });
}
Copy the code

UseEffect is a feature in the new react version. It supports two parameters, the first is a method and the second is an array of variables. Passing an empty array will call the method only once each time the component starts rendering.

If we use it formally, there will be multiple test environments. If we make a distinction between the environment of the project, then we should get the project of the different environment when switching the environment.

Assuming we need to implement this functionality, let’s create a variable to env and rewrite useEffect:

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

This way, this method is automatically executed every time the ENV changes. It should be noted that this is only an introduction to the use of useEffect. Since we have not extended it to multiple environments, we can choose [] here.

const onHandleCreate = async values => {
  const res = await insertProject(values);
  if (auth.response(res, true)) {
    // The data on the first page is automatically retrieved after the creation, because the projects are sorted by creation time
    await fetchData(1); }}Copy the code

Here is also the same, after the creation of the interface does not return an error, it will refresh the project list page, and automatically go to the first page.

const content = (item) = > {
  return <div>{/ *<p>Owner: {userMap[item.owner].name}</p>* /}<p>Introduction: {item. The description | | 'no'}</p>
     <p>Update time: {item.updated_at}</p>
  </div>
};

const opt = <Select placeholder="Please select the project leader.">
  {
    Object.keys(users).map(id => <Option key={id} value={id}>{users[id].name}</Option>)}</Select>

const fields = [
    {
      name: 'projectName'.label: 'Project Name'.required: true.message: "Please enter project name".type: 'input'.placeholder: "Please enter project name"}, {name: 'owner'.label: 'Project Leader'.required: true.component: opt,
      type: 'select'}, {name: 'description'.label: 'Project Description'.required: false.message: "Please enter a project description".type: 'textarea'.placeholder: "Please enter a project description"}, {name: 'private'.label: 'Private or not'.required: true.message: "Please select whether the project is private.".type: 'switch'.valuePropName: "checked",},]Copy the code

Content is a method that returns the HTML structure of a div to show details about the project, such as the owner, project description, and so on.

Fields is a form field, because I’ve wrapped the ANTD form a little bit and written a set of higher-order components. The form consists of the input and select components and the switch component.

Talk about this component later!

Finally, look at the components inside the return

    return (
      <PageContainer title={false}>
        <FormForModal width={600} title="Add item" 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)}> Create the project<Tooltip title="Only the super administrator can create projects."><QuestionCircleOutlined/></Tooltip>
            </Button>
          </Col>
          <Col span={6}>
            <Search onSearch={onSearchProject} style={{float: 'right'}} placeholder="Please enter project name"/>
          </Col>
        </Row>
        <Spin spinning={false}>
          <Row gutter={16}>
            {
              data.length === 0 ? <Col span={24} style={{textAlign: 'center', marginBottom: 12}} >
                  <Card><Empty description="No project yet, click" Create project "to create one!"/></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: 16.textAlign: '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>)}Copy the code

PageContainer is the outermost layer, which we see here:

FormForModal is a dialog form, it’s not displayed by default, it’s only displayed when you click create item.

I then split two rows with Row: the Create/search bar and the project display bar

If data.length === 0, the item display bar will display an empty state and prompt the user to add the item, otherwise the item will be displayed. Each item takes up 1/6 of the screen, because Col has 24 copies in total.

Tips: This is similar to bootstrap. There are 24 copies in a row. Therefore, span={4} represents 4/24

The other is the interembedding of Card components and Avatar components. Popover is a floating window, as shown in the figure:

Write an interface to get a list of users

Modify the app/dao/auth/UserDao. Py

Select users that are not deleted.

Modify the app/controllers/auth/user. Py

Here attention to open the permissions, but can not control too dead, can let the login user access.

The front page is written with the listUsers method

Look at the effect

Found a problem: The dialog box did not close after the successful creation

So we need setVisible(false) to close the dialog after the creation.

There is also an area where the project leader, previously commented out, can now be reopened.

Take a look at the search results

So that’s the end of this section, mostly code, because there’s a lot of front-end stuff, so it can get a little confusing. Check out the React and ES6 tutorials if you don’t understand. Arrow function, don’t be afraid to look at it, just be familiar with it.

The next section is probably the edit page for specific projects, which feels like a century of work, followed by the use cases section.