review

Last time we wrote a good add project and query project 2 interface, that today we apply it to the project! Therefore, this section will focus on the front end. The purpose is to combine the compiled interface of the back end and enable it to be used by users on the page.

Adjust item list

Yes, because our project has corresponding pictures and lacks description fields, we will make some adjustments to the project table.

  • Image field
  • Description field

Description field is very easy to say, as for the picture field is more troublesome! For single-node applications, the image can be saved in a directory similar to static, in xxx.jpg format. But if we need to deploy to multiple machines, let’s say two machines, and the user uploads the image once and only one of the services receives the image file, that’s a hassle.

So how to solve this problem?

In enterprises, companies generally have OSS (cloud storage) services, such as Ali Cloud OSS, Tencent Cloud COS, and Qiniuyun. My previous eunuch project used qiniuyun + own domain name, because there is no renewal, so we change to a simple way:

Add a TEXT field to the database to store the base64 data of the image, but note that the size must be limited, and then the IMG tag in the HTML can parse the data.

Since the project may not need such a thing as profile picture, it would be better to leave such pictures in personal profile picture in the future. Antd provides text profile picture. I believe all of you who have used Dingding and other IM tools know that some people will use their name as profile picture if they don't have profile picture, such as naruto.

So we don’t have to bother here, just add a description field! Use the default profile picture!

  • Adjust the models/Project. Py

  • Adjust the ProjectDao. Py

  • Adjust add project interface

Just add the description field, which is not required, so we give it a default value: an empty string

Design page

Recall that when we wrote the Postman page, we layered the corresponding components. Since we had a finished product to refer to when we were doing the Postman page, we really didn’t have any reference to the project management page, so we had to have an idea of what the page would look like!

By referring to Ant Design Pro, we can get a general direction!

Using this card list helps us present the project.

Introducing scrollbars

I copied this page from a previous eunuch project and used it to save time.

  • Install dependencies
cnpm install nprogress --save
Copy the code

Add methods in SRC /utils/utils.js

import NProgress from 'nprogress';
// Introduce styles
import 'nprogress/nprogress.css'

export const process = async func => {
  NProgress.start();
  await func();
  NProgress.done();
};
Copy the code

This allows us to call the process method when we need to load the progress bar before a method is executed.

Project card list page code

React is not a very complex framework, so you may need to understand Jsx.

Our components can be subdivided into four parts:

  • reference

    That is, introducing additional components or libraries

  • State management

    What is the concept of state? For example, if you have a loading component on your page, when it loads and when it stops loading, you can judge whether it is loading or not by what variable, which is called state.

    Our page also has a lot of state representation. For example, we store our list of items with data(array), initialized as an empty array. When the page starts rendering and the component starts loading, we remove the backend service to pull the data, rewrite the data array, and put the project information into the array.

    Notice that the state has changed! React automatically compares the changed state to render a new page, which is a complicated process. It is recommended to check react related materials. I am not familiar with the details. If you want to know about react, you can search virtual DOM.

  • Writing interactive methods

    We have a lot of components that involve some kind of interaction, like clicking a button and triggering an event. All of these need to be written in a way. For example, in the picture above, the user clicks add item. What do we need to do?

    We need to display the dialog, right? So what we need to do is: change the state of the dialog box from hidden to show.

  • Class HTML page preparation

    This step is easier, using JSX syntax to write HTML pages. Basically the same as HTML, but here can write some JS code, through {} can be wrapped JS code, relatively speaking is very convenient! React: JSX, ES6, react

import React, { useEffect, useState } from 'react';
import { PageContainer } from '@ant-design/pro-layout';
import { Avatar, Button, Card, Col, Empty, Input, Popover, Row, Select, Spin, Tooltip } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import FormForModal from '@/components/PityForm/FormForModal';
import { history } from 'umi';
import { listProject } from '@/services/project';
import auth from '@/utils/auth';
import { process } from '@/utils/utils';

const {Search} = Input;
const {Option} = Select;

export default() = > {const [data, setData] = useState([]);
  const [pagination, setPagination] = useState({current: 1.pageSize: 10.total: 0});
  const [visible, setVisible] = useState(false);
  const [users, setUsers] = useState([]);
  const [userMap, setUserMap] = useState({});

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

  const onSearchProject = projectName= > {
    // this.props.dispatch({
    // type: 'project/fetch',
    // payload: {page: 1, size: 1000, projectName}
    // })
  }

  const onHandleModal = status= > {
    setVisible(status);
  }

  const onHandleCreate = values= > {
    // this.props.dispatch({
    // type: 'project/insert',
    // payload: values,
    // })
  }


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

  const opt = <Select placeholder="Please select the project leader">
    {
      users.map(item => <Option key={item.value} value={item.value}>{item.label}</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",},]return (
      <PageContainer title={false}>
        <FormForModal width={600} title="Add item" left={6} right={18} record={{}}
                      visible={visible} onCancel={()= > {
          onHandleModal(false)
        }} fields={fields} onFinish={onHandleCreate}
        />
        <Row gutter={8} style={{marginBottom: 16}} >
          <Col span={18}>
            <Button type="primary" onClick={()= >{onHandleModal(true)}}> Create 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 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

Take a look at the code and I’ll follow up. That’s all for today ~😁