測試平臺系列(21) 編寫項目的增刪改查接口和頁面(3)

回顧

上回我們編寫好了添加項目和查詢項目2個接口宴合,那今天我們就把它應(yīng)用到項目中吧!所以本節(jié)內(nèi)容會以前端部分為主迹鹅,目的是為了聯(lián)調(diào)后端編寫好的接口卦洽,并在頁面上能夠給用戶使用。

調(diào)整項目表

是這樣的斜棚,因為我們的項目有對應(yīng)的圖片阀蒂,并且缺少描述字段该窗,所以我們這里把項目表進行一些調(diào)整。

  • 圖片字段
  • 描述字段

描述字段很好說蚤霞,至于圖片字段就比較麻煩了酗失!如果對于單節(jié)點部署的應(yīng)用,圖片可以放入類似static的目錄中争便,以xxx.jpg的形式存在级零。但是如果我們需要部署到多臺機器的話,假設(shè)是2臺機器滞乙,用戶上傳一次圖片奏纪,其中只有一個服務(wù)接收到了圖片文件,那就會很麻煩斩启。

那么怎么解決這個問題呢序调?

在企業(yè)中,一般公司會有oss(云存儲)服務(wù)兔簇,比如: 阿里云oss发绢,騰訊云cos,還有七牛云等等垄琐。我之前太監(jiān)的項目用的就是七牛云+自有域名边酒,由于沒續(xù)費,所以我們換一種簡單的方式:

直接在數(shù)據(jù)庫加一個TEXT字段狸窘,存放圖片的base64數(shù)據(jù)墩朦,但是注意大小一定要限制,然后html里面通過img標簽解析數(shù)據(jù)即可翻擒。

由于項目可能不太需要頭像這種東西氓涣,以后這種圖片留到個人頭像會比較好一點,antd提供了文字頭像陋气,相信大家用過釘釘?shù)菼M工具的都知道劳吠,有的人如果沒有頭像的話,會用名字當頭像比如"鳴人"巩趁。

所以我們這里就不用那么麻煩了痒玩,直接只加一個描述字段就好了!頭像用默認的就行议慰!

  • 調(diào)整models/Project.py
添加描述字段
  • 調(diào)整ProjectDao.py
image
  • 調(diào)整添加項目接口
image

描述字段加進去即可凰荚,因為這個字段不是必填的,所以我們給他一個默認值: 空字符串

構(gòu)思頁面

回憶一下我們當時編寫postman頁面的時候褒脯,我們是把對應(yīng)的組件分層了便瑟。由于我們當時做postman頁面的時候是有成品給我們參考的,但是關(guān)于項目管理頁面番川,我們的的確確是沒有任何參考到涂,所以我們先要在腦海里構(gòu)思一下頁面大概長什么樣脊框!

參考Ant Design Pro,我們就可以有個大概的方向了践啄!

image

采用這種卡片列表浇雹,可以幫助我們展示項目。

引入滾動條

達到這樣的效果就好了

這個頁面是我從之前一個太監(jiān)了的項目里面拷貝來的屿讽,為了節(jié)約時間就繼續(xù)沿用了昭灵。

  • 安裝依賴
cnpm install nprogress --save

在src/utils/utils.js添加方法

import NProgress from 'nprogress';
// 引入樣式
import 'nprogress/nprogress.css'

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

這樣當我們需要在某個方法執(zhí)行之前加載進度條的時候,調(diào)用process方法即可伐谈。

項目卡片列表頁面代碼

其實react并不是一個很復(fù)雜的框架烂完,可能對于Jsx需要有一定的了解。

我們的組件都可以細分成4個部分:

  • 引用

    即引入其他組件或者庫

  • 狀態(tài)管理

    狀態(tài)是什么概念呢诵棵,舉個例子抠蚣,你頁面有個loading組件,什么時候他loading履澳,什么時候結(jié)束loading嘶窄,你通過什么來判斷它是否loading,這個判斷的變量距贷,就叫做狀態(tài)柄冲。

    而咱們的頁面也有很多地方通過狀態(tài)來展示,比如我們通過data(數(shù)組)來存放我們的項目列表忠蝗,初始化為空數(shù)組羊初。當頁面開始渲染,組件開始加載的時候什湘,我們變?nèi)ズ蠖朔?wù)拉取數(shù)據(jù),改寫data數(shù)組晦攒,把項目的信息放入到數(shù)組里面闽撤。

    注意,這個時候狀態(tài)就發(fā)生了變更脯颜!react會自動對比變更的狀態(tài)來渲染新的頁面哟旗,這里面過程很復(fù)雜。建議去查閱react相關(guān)資料栋操,筆者也不是很熟悉里面的細節(jié)闸餐,想要了解的話,去搜索virtual dom矾芙。

  • 交互方法的編寫

    我們有很多組件都有涉及到一些交互方法舍沙,比如說: 點擊某個按鈕,觸發(fā)什么事件剔宪。這些都是需要編寫方法的拂铡,比如上圖中 用戶點擊添加項目壹无,我們需要做什么呢?

    我們需要把對話框顯示出來對不對感帅?所以我們需要做的就是: 改變對話框的狀態(tài)斗锭,把他從隱藏改為顯示

  • 類HTML頁面的編寫

    這一步比較簡單了失球,采用jsx的語法去編寫html頁面岖是。大體上和html都差不多,只不過這邊可以寫一些js代碼实苞,通過{}就可以包裹JS代碼豺撑,相對來說還是很方便的!掌握了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>負責人: {userMap[item.owner].name}</p> */}
      {/* <p>簡介: {item.description || '無'}</p> */}
      {/* <p>更新時間: {item.updateTime}</p> */}
    </div>
  };

  const opt = <Select placeholder="請選擇項目組長">
    {
      users.map(item => <Option key={item.value} value={item.value}>{item.label}</Option>)
    }
  </Select>
    const fields = [
      {
        name: 'projectName',
        label: '項目名稱',
        required: true,
        message: "請輸入項目名稱",
        type: 'input',
        placeholder: "請輸入項目名稱",
      },
      {
        name: 'owner',
        label: '項目負責人',
        required: true,
        component: opt,
        type: 'select',
      },
      {
        name: 'description',
        label: '項目描述',
        required: false,
        message: "請輸入項目描述",
        type: 'textarea',
        placeholder: "請輸入項目描述",
      },
      {
        name: 'private',
        label: '是否私有',
        required: true,
        message: "請選擇項目是否私有",
        type: 'switch',
        valuePropName: "checked",
      },
    ]
    return (
      <PageContainer title={false}>
        <FormForModal width={600} title="添加項目" 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)
            }}>創(chuàng)建項目
              <Tooltip title="只有超級管理員可以創(chuàng)建項目"><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="暫無項目, 快點擊『創(chuàng)建項目』創(chuàng)建一個吧!"/></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>
    )
}

先大致瞅瞅這段代碼荧止,后續(xù)筆者會跟進講解屹电。今天內(nèi)容就到這里吧~??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市跃巡,隨后出現(xiàn)的幾起案子危号,更是在濱河造成了極大的恐慌,老刑警劉巖素邪,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件外莲,死亡現(xiàn)場離奇詭異,居然都是意外死亡兔朦,警方通過查閱死者的電腦和手機偷线,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沽甥,“玉大人声邦,你說我怎么就攤上這事“谥郏” “怎么了亥曹?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恨诱。 經(jīng)常有香客問我媳瞪,道長,這世上最難降的妖魔是什么照宝? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任蛇受,我火速辦了婚禮,結(jié)果婚禮上厕鹃,老公的妹妹穿的比我還像新娘龙巨。我一直安慰自己笼呆,他們只是感情好,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布旨别。 她就那樣靜靜地躺著诗赌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秸弛。 梳的紋絲不亂的頭發(fā)上铭若,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音镜雨,去河邊找鬼。 笑死荚坞,一個胖子當著我的面吹牛颓影,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播璃俗,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼剖膳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仑濒,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎热凹,沒想到半個月后般妙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡攒霹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片高蜂。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡露泊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捺宗,到底是詐尸還是另有隱情,我是刑警寧澤弯囊,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布霎烙,位于F島的核電站甘苍,受9級特大地震影響载庭,放射性物質(zhì)發(fā)生泄漏看彼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望顽铸。 院中可真熱鬧谓松,春花似錦、人聲如沸男窟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至春缕,卻和暖如春票灰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宅荤。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工屑迂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冯键。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓惹盼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惫确。 傳聞我的和親對象是個殘疾皇子手报,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容