測試開發【提測平臺】分享12-掌握日期元件&列表狀態格式化最終實現提測管理多條件搜尋展示功能

MrZ大奇發表於2021-10-11

微信搜尋【大奇測試開】,關注這個堅持分享測試開發乾貨的傢伙。

本章內容思維導圖如下,由於需要各種狀態下的選單操作,所以需要先實現提測資訊的列表基礎頁面,然後再推進其他需求開發

基本知識點學習

DatePicker 日期元件

Element ui 元件中有兩個時間相關的控制元件,一個是 TimePicker 元件,以十分秒維度,另一個是 DatePicker 元件,以年月日時分秒維度,兩者用法基本相同,本篇開發用到的是DatePicker,它的基本使用方法為

<el-date-picker
    v-model="繫結變數值"
    align="right"
    type="date"
    placeholder="選擇日期">
</el-date-picker>

其中v-model一如即往的是指繫結的變數引數,align是對其的方向,placeholder標題沒有值的時候提示資訊,最重要的type是指日期的樣式和型別,本例子選中時間後將展示如:2021-10-10 的格式時間,其他型別還報告年、月、星期、時間範圍月範圍等,實戰開發還會用到帶快捷選項 picker-options 屬性,即可以日期選項左側可以設定和快捷選項一個範圍,比如近一個月,近三個月等,樣式如,更多內容參考官方例子 [註解-1]

 

 

 

Select 選擇器

這個元件在之前的文章是講過的,當時直接舉例沒有講清楚具體使用場景,這裡舉例說明下:

場景1: 如果是少量比較固定的,可以直接前端寫<el-option key="",value="",label=""/>

場景2: 如果是動態固定資料,則用v-for的語法繫結一個list選項(用到之前請求介面賦予)

場景3: 如果是動態大量資料,可以使用遠端搜尋模式,即資料關鍵詞後時時請求介面後臺查詢後顯示,如公司使用者查詢選擇。

選項中key關鍵詞、value表示選擇後的值,lebel為實際展示的值

 

SQL聯合表查詢

依稀記得在上學的時候設計資料表的時候,尤其是關係型資料庫表,有很多的關聯表,也很規範的使用外來鍵等,不過目前從工作後,尤其是近幾年很少看到這麼嚴謹了,基本上如果查詢少就在新表中多個相同欄位,否則也是簡單關聯查詢,語法格式為 select A.*,B.欄位 from A, B where A.id=B.aid

在專案編寫後端多條件查詢語句的時候,最好是設計相關表後,插入幾條關聯資料,在資料庫工具裡先寫好關聯查詢語句,測試通過後在去拼寫後端請求程式碼,千萬不要自信滿滿,筆記就是直接上程式碼,可以由於空格,語法等就要浪費好多時間去一點點debug,就本文帶有時間範圍的聯合表查詢,可以先完全先寫sql語句,進行測試,然後再貼上到程式碼裡實現,比如是我先實現的語句驗證OK。

 

需求功能實現

提測列表的搜尋和展示需求其實和之前分享的應用列表管理非常類似,這裡就不再貼需求原型,直接給出實現部分和注意點,最後看下整體實現。

服務查詢介面

1. 查詢介面的資料字典

直接給出如下,方便大家直接除錯

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for request
-- ----------------------------
DROP TABLE IF EXISTS `request`;
CREATE TABLE `request` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `title` varchar(200) DEFAULT NULL COMMENT '提測標題',
  `appId` varchar(50) DEFAULT NULL COMMENT '應用服務',
  `developer` varchar(255) DEFAULT NULL COMMENT '提測RD',
  `tester` varchar(255) DEFAULT NULL COMMENT '測試QA',
  `CcMail` varchar(500) DEFAULT NULL COMMENT '關係人',
  `verison` varchar(100) DEFAULT NULL COMMENT '提測版本',
  `type` tinyint(1) DEFAULT NULL COMMENT '提測型別 1.功能 2.效能 3.安全',
  `scope` text COMMENT '測試說明',
  `gitCode` varchar(200) DEFAULT NULL COMMENT '專案程式碼',
  `wiki` varchar(200) DEFAULT NULL COMMENT '產品文件',
  `more` text COMMENT '是否傳送郵件,0未操作,1成功,2失敗',
  `status` tinyint(1) DEFAULT NULL COMMENT '測試狀態 1-已提測 2-測試中 3-通過 4-失敗 9-廢棄',
  `sendEmail` tinyint(1) DEFAULT NULL COMMENT '是否傳送訊息,0未操作,1成功,2失敗',
  `isDel` tinyint(1) DEFAULT '0' COMMENT '狀態0正常1刪除',
  `createUser` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '建立人',
  `createDate` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
  `updateUser` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '修改人',
  `updateDate` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

SET FOREIGN_KEY_CHECKS = 1;

 

2. 後端提測資料查詢介面

新建檔案testmanager.py,沿用資料連結池不變,這裡主要注意程式碼裡的拼接,按照知識點裡說最好現在把測試語句在資料庫查詢命令列中測試通過,注意需要支援分頁。

# -*- coding:utf-8 -*-
# testmanager.py

from flask import Blueprint
from dbutils.pooled_db import PooledDB
from configs import config, format

from flask import request
import pymysql.cursors
import json

# 使用資料庫連線池的方式連結資料庫,提高資源利用率
pool = PooledDB(pymysql, mincached=2, maxcached=5,host=config.MYSQL_HOST, port=config.MYSQL_PORT,
                user=config.MYSQL_USER, passwd= config.MYSQL_PASSWORD, database=config.MYSQL_DATABASE,
                cursorclass=pymysql.cursors.DictCursor)

test_manager = Blueprint("test_manager", __name__)

@test_manager.route("/api/test/search",methods=['POST'])
def searchBykey():
    body = request.get_data()
    body = json.loads(body)

    # 基礎語句定義
    sql = ""

    # 獲取pageSize和
    pageSize = 10 if 'pageSize' not in body or body['pageSize'] is None else body['pageSize']
    currentPage = 1 if 'currentPage' not in body or body['currentPage'] is None else body['currentPage']

    # 拼接查詢條件
    if 'productId' in body and body['productId'] != '':
        sql = sql + " AND A.productId LIKE '%{}%'".format(body['productId'])
    if 'appId' in body and body['appId'] != '':
        sql = sql + " AND A.appId LIKE '%{}%'".format(body['appId'])
    if 'tester' in body and body['tester'] != '':
        sql = sql + " AND R.tester LIKE '%{}%'".format(body['tester'])
    if 'developer' in body and body['developer'] != '':
        sql = sql + " AND R.developer LIKE '%{}%'".format(body['developer'])
    if 'status' in body and body['status'] != '':
        sql = sql + " AND R.status = '{}'".format(body['status'])
    if 'pickTime' in body and body['pickTime'] != '':
        sql = sql + " AND R.updateDate >= '{}' and R.updateDate <= '{}' ".format(body['pickTime'][0],body['pickTime'][1])

    # 排序和頁數拼接
    sql = sql + ' ORDER BY R.updateDate DESC LIMIT {},{}'.format((currentPage - 1) * pageSize, pageSize)
    print(sql)

    # 使用連線池連結資料庫
    connection = pool.connection()

    with connection:
        # 先查詢總數
        with connection.cursor() as cursor:
            count_select = 'SELECT COUNT(*) as `count` FROM request as R , apps as A where R.appId = A.id AND R.isDel=0' + sql
            print(count_select)
            cursor.execute(count_select)
            total = cursor.fetchall()

        # 執行查詢
        with connection.cursor() as cursor:
            # 按照條件進行查詢
            cursor.execute('SELECT A.appId,R.* FROM request as R , apps as A where R.appId = A.id AND R.isDel=0' + sql)
            data = cursor.fetchall()

    # 按分頁模版返回查詢資料
    response = format.resp_format_success
    response['data'] = data
    response['total'] = total[0]['count']
    return response

 

前端多條件搜尋

此區域位於提測vue頁面的頂部,有兩個下拉選擇框,分別是“歸屬分類” 資料從服務介面獲,“測試狀態” 所有選項只有幾個前端寫了就行,點選查詢按鈕進行介面請求和查詢,其中一個“新建提測”按鈕為預留,下一篇新頁面路由跳轉的邏輯。     

1. HTML部分程式碼參考

<div class="filter-container">
  <el-form :inline="true" :model="search">
    <el-form-item label="歸屬分類">
      <el-select v-model="search.productId">
        <el-option value="" label="所有" />
        <el-option
          v-for="item in optsProduct"
          :key="item.id"
          :label="item.title"
          :value="item.id"
        />
      </el-select>
    </el-form-item>
    <el-form-item label="應用ID">
      <el-input v-model="search.appId" placeholder="服務ID關鍵詞" style="width: 200px;" clearable />
    </el-form-item>
    <el-form-item label="測試人">
      <el-input v-model="search.tester" placeholder="預設測試" style="width: 210px;" clearable />
    </el-form-item>
    <el-form-item label="提測人">
      <el-input v-model="search.developer" placeholder="預設測試" style="width: 210px;" clearable />
    </el-form-item>
    <el-form-item label="時間範圍">
      <el-date-picker
        v-model="search.pickTime"
        type="datetimerange"
        :picker-options="pickerOptions"
        range-separator="至"
        start-placeholder="開始日期"
        end-placeholder="結束日期"
        align="right">
      </el-date-picker>
    </el-form-item>
    <el-form-item label="測試狀態">
      <el-select v-model="search.status" placeholder="請選擇">
        <el-option value="" label="所有" />
        <el-option key=1 label="已提測" value=1></el-option>
        <el-option key=2 label="測試中" value=2></el-option>
        <el-option key=3 label="通過" value=3></el-option>
        <el-option key=4 label="失敗" value=4></el-option>
        <el-option key=9 label="廢棄" value=9></el-option>
      </el-select>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" plain @click="searchClick()">查詢</el-button>
    </el-form-item>
  </el-form>
  <el-button type="primary" icon="el-icon-plus" style="float:right" @click="doCommit()">新建提測</el-button>
</div>

 

2. JS部分所涉及程式碼參考

所屬分類的介面請求不需要新寫,沿用應用管理那部分實現

 

1)data() 變數定義

主要是繫結的搜尋條件、日期快捷,順便定義table儲存變數

import { apiAppsProduct } from '@/api/apps'
// 新定義的提測api js檔案
import { apiTestSearch } from '@/api/test.js'

data() {
  return {
    // 條件查詢變數定義
    search: {
      productId: '',
      appId: '',
      developer: '',
      tester: '',
      status: '',
      pickTime: ''
    },
    // 範圍日期元件的快捷選項配置
    pickerOptions: {
      shortcuts: [{
        text: '最近一週',
        onClick(picker) {
          const end = new Date()
          const start = new Date() // 當前時間
          start.setTime(start.getTime() - 3600 * 1000 * 24 * 7) //單位毫秒加減計算
          picker.$emit('pick', [start, end])
        }
      }, {
        text: '最近一個月',
        onClick(picker) {
          const end = new Date()
          const start = new Date()
          start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
          picker.$emit('pick', [start, end])
        }
      }]
    },
    // 所屬分類選項-沿用應用管理
    optsProduct: [],
    // 資料表格展示和分頁變數資料定義
    testData: [],
    pageValues: {
      pageSize: 10,
      currentPage: 1,
      total: 0
    }
  }
}

 

2. methods方法相關實現

預設歸類資料的請求與賦值,以及點選搜尋按鈕後的查詢介面請求和表格資料回填,頁碼資料回填。

// 所屬歸類選項資料查詢
productList() {
  apiAppsProduct().then(resp => {
    this.optsProduct = resp.data
  })
},
// 按照條件查詢,如果某個控制元件為空,則不會此欄位請求
searchClick() {
  const body = {
    pageSize: this.pageValues.pageSize,
    currentPage: this.pageValues.currentPage,
    productId: this.search.productId,
    appId: this.search.appId,
    tester: this.search.tester,
    developer: this.search.developer,
    pickTime: this.search.pickTime,
    status: this.search.status
  }
  apiTestSearch(body).then(response => {
    // 將返回的結果賦值給表格自動匹配
    this.testData = response.data
    this.pageValues.total = response.total
  })
},

資料展示和操作邏輯

上邊已經完成了所有資料繫結部分,接著就是進行展示

 

1. 分別定義 table 和 pagination 元素

這裡特別要關注實現就是操作的功能的按鈕要根據每條資料的狀態數值判斷是否給予顯示。之前需求文件給出來的邏輯如下(測試中狀態有更正)

 測試狀態

 狀態碼

 操作選單

已提測

1(新建預設)

開始測試 / 編輯提測 / 提測詳細

測試中

2

新增結果 / 編輯提測 / 提測詳細

通過

3

檢視報告 / 編輯結果 / 提測詳細

失敗

4

檢視報告 / 編輯結果 / 提測詳細

廢棄

9

刪除提測 / 編輯結果 / 提測詳細

html程式碼參考

<div>
  <el-table :data="testData">
<!--:data prop繫結{}中的key,label為自定義顯示的列表頭-->
    <el-table-column prop="appId" label="應用ID" />
    <el-table-column prop="title" label="提測標題" show-overflow-tooltip />
    <el-table-column :formatter="formatStatus" prop="status" label="測試狀態"/>
    <el-table-column :formatter="formatType" prop="type" label="型別" />
    <el-table-column prop="developer" label="提測人" />
    <el-table-column prop="tester" label="測試人" />
    <el-table-column prop="updateUser" label="更新人" />
    <el-table-column :formatter="formatDate" prop="updateDate" label="更新時間" />
    <el-table-column label="操作" width="300">
      <template slot-scope="scope">
        <!--<label>選單邏輯判斷一列</label>-->
        <el-link type="primary" v-if="scope.row.status===1" @click="startTest(scope.row)">開始測試</el-link>
        <el-link type="primary" v-if="scope.row.status===2" >新增結果</el-link>
        <el-link type="primary" v-if="scope.row.status===3 || scope.row.status == 4" >檢視報告</el-link>
        <el-link type="primary" v-if="scope.row.status===9" >刪除結果</el-link>
        <!--<label>選單邏輯判斷二列</label>-->
        <el-divider direction="vertical"></el-divider>
        <el-link type="primary" v-if="[1,2].includes(scope.row.status)">編輯提測</el-link>
        <el-link type="primary" v-if="[3,4,9].includes(scope.row.status)">編輯結果</el-link>
        <el-divider direction="vertical"></el-divider>
        <el-link type="primary" >提測詳情</el-link>
      </template>
    </el-table-column>
  </el-table>
</div>
<div>
  <br>
  <el-pagination
    background
    :current-page.sync="pageValues.currentPage"
    :page-size="pageValues.pageSize"
    layout="total, sizes, prev, pager, next"
    :page-sizes="[5, 10, 20, 30, 50]"
    :total="pageValues.total"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />
</div>

 

2. 對應元素JS程式碼

分別要對時間格式化(之前有案例),狀態和型別列也要格式化,使用javascript 中的swith case 語法語句進行判斷,實現將本來的不可辨別的數字翻譯成對應的文字展示。

formatDate(row, column) {
  const date = row[column.property]
  if (date === undefined) {
    return ''
  }
  // 使用moment格式化時間,由於我的資料庫是預設時區,偏移量設定0,各自根據情況進行配置
  return moment(date).utcOffset(0).format('YYYY-MM-DD HH:mm')
},
formatStatus(row, column) {
  const status = row[column.property]
  switch (status) {
    case 1:
      return '已提測'
    case 2:
      return '測試中'
    case 3:
      return '通過'
    case 4:
      return '失敗'
    case 9:
      return '已廢棄'
    default:
      return '未知狀態'
  }
},
formatType(row, column) {
  const type = row[column.property]
  switch (type) {
    case 1:
      return '功能測試'
    case 2:
      return '效能測試'
    case 3:
      return '安全測試'
    default:
      return '未知狀態'
  }
},

另外一部分js程式碼是對分頁的實現,請自行實現或參考git上原始碼。

 

至此前後的邏輯程式碼部分已經全部給出來了,沒有給出部分是api請求request 和本頁的選單配置,相信如果你是一步步跟著之前文章實戰下來的,這些已經太輕車熟路了,啟動前後端最終實現頁面如下,最後再想想需要寫哪些CASE對本功能進行一個全面的測試。

 

學習交流群已經開放,可以關注公眾號【大奇測試開發】傳送 “測試開發” 獲取最新二維碼入群。

 

【程式碼更新】

  • 地址:https://github.com/mrzcode/TestProjectManagement

  • TAG:TPMShare12

【註解&參考】

  • [註解-1] : https://element.eleme.io/#/zh-CN/component/date-picker

堅持原創,堅持實踐,堅持乾貨,如果你覺得有用,請點選推薦,也歡迎關注我部落格園和微信公眾號。

相關文章