在羣裏請教了一下這樣的頁面有沒有標準的稱謂,有的叫標準的CRUD頁面,有的說是表格信息頁,我也不知道叫什麼,上邊是查詢下邊是列表,索性就叫查詢列表頁了,藉助羅永浩的口頭禪:」少廢話,先看東西「。 演示地址 前端
從去年9月份換工做之後,參與了幾個項目,有數據BI平臺,有可視化平臺,有大屏項目,有JIRA的二次開發,種類繁多,技術棧也豐富多彩,學習到不少。vue
說了這麼多,想表達的是」查詢列表頁面出現的頻率過高了「,不論是BI系統、可視化系統,仍是toB的中臺系統,就前端崗位而言,不可避免的要開發不少這樣的查詢列表頁面,沒有什麼技術要求門檻,但就是得作,所謂的」低端重複勞動「。react
以前BI的項目裏用iview的table和Page組件封裝了一個分頁組件,只須要傳入表頭、api地址、查詢條件,就完成了,全部分頁列表都是用它實現的。ios
接到重構以前一箇中臺系統的需求,拆分紅三個應用,後端給過來三個基於vue-element-admin的git項目地址,粗略的瞄了一下以前的系統,幾乎全部左側頻道點進去都是查詢列表頁面,直接引入以前的分頁組件開發v0.1版本,v1.0需求愈來愈多,索性抽了兩天時間把查詢條件也一塊封裝了吧😃。git
查詢條件通常都是key:value
的形式,好比後端給出的文檔以下圖。ajax
咱們把查詢條件和列表封裝成一個組件,查詢條件其實就是一個option配置,,組件必不可少的三個入參,接口地址、查詢條件配置、自定義表頭,開發過程當中每每都是先新建.vue組件、引入查詢列表組件、編寫入參,而後再引入必要的工具方法,其實也很繁瑣。json
因而咱們本身寫了個生成工具,按照文檔把入參填寫一下,點擊導出,vue組件代碼直接就複製到剪切板,新建.vue
文件,而後ctrl+v
便可。axios
工具地址後端
日光之下無新事,頁面可視化的工具不少,借用以前可視化文章裏的觀點,你們爲何不用可視化,可視化工具爲何沒火起來。api
這麼簡單的小東西,能知足業務需求嗎?入參類型夠全嗎?能夠加權限判斷嗎? 怎麼自定義表頭?
這個組件也是在實際開發過程當中封裝出來的,不一樣的業務場景、開發的體驗、測試的反饋才能使這個組件更穩定、更好用,咱們也是在一個一個的實際需求版本迭代中才把api給肯定下來。
先看看組件作什麼,很簡單,組件分爲兩部分,上邊是查詢條件、下邊分頁表格。
這個組件就是在點擊查詢,把查詢條件的結果拼成入參傳入列表分頁,上半部分的將來就是封裝更多類型,代碼也很簡單,後續能夠在組件代碼裏本身增長。
主要仍是在下半部分,也能夠單獨使用列表組件,一塊兒看看列表分頁的主要入參吧。url
是接口地址,每一個列表的接口地址確定不同,靈活配置;searchData
是要查詢條件,Columns
是iview的表格組件表頭,在巨人的肩膀子真的是有益,具體見iview的表格api文檔 能夠自定義列的展現;allDate
是一個鉤子,能夠修改後端返回的結果,好比根據權限判斷是否增長操做按鈕等。
剩下的就是上一頁、下一頁、跳轉、修改頁數的操做了,和後端訂好格式就OK了。
列表的數據格式也有必定要求,dataCount
總條數,tableData
表體數據,Columns
表頭,pageSize
每頁條數,以下
{
"code": 1,
"msg": "",
"data": {
"dataCount": 444,
"tableData": [{
"id": 443,
"order_no": "1016410719705984",
"source": 10,
"order_type": 1,
"order_status": 1,
"car_name": "奧迪 A6 2006款 1.8 手動"
}, {
"id": 443,
"order_no": "1016410719705984",
"source": 10,
"order_type": 1,
"order_status": 1,
"car_name": "奧迪 A6 2006款 1.8 手動"
}],
"Columns": [{
"key": "order_no",
"title": "訂單ID"
}, {
"key": "order_type",
"title": "訂單類型"
}, {
"key": "source",
"title": "來源"
}, {
"key": "car_name",
"title": "車型"
}, {
"key": "order_status",
"title": "狀態"
}],
"pageSize": 10
}
}
複製代碼
咱們再回顧一下,整個組件的功能。
說了這麼多,到底有哪些api
能夠講下吧?
template
部分
除了組件上的props,須要提一下的就是buttons
這個solt
了,除了頁面上的搜索和重置按鈕,每每須要增長其餘的按鈕,最多見的好比新建
。
url
接口地址字符串類型,每一個列表都有本身不一樣的地址
apiType
全局地址字符串類型,咱們ajax使用的是axios
,若是是微服務的項目會有多個域名配置,把axios
的實例名稱填上便可,默認爲http,在main.js中給vue原型指向。
// 引入微服務apis
import { http, OderApi, ReportApi} from '@/lib/apis.js'
Vue.prototype.$http = http // 默認地址
Vue.prototype.$OderApi = OderApi // 訂單服務
Vue.prototype.$reportApi = ReportApi // 報表服務
複製代碼
fromOption
表單配置數組類型,每個查詢項爲一個對象,目前僅支持四種輸入項,後續會增長其餘類型,本着小步快跑原則,先把文章發出來,省的要夭折在本身的筆記軟件中(我太懶)。
select
:下拉項 date-picker
:開始-結束日期 input
:輸入框 selectAndInput
:下拉+輸入
select
{
label:'沿途城市', // 標籤名稱
name:['cityId'], // *入參名稱 必須惟一
type:'select', // *元素類型 selectAndInput
dataType:'arr', // 數據格式 arr/json
arrKey:{ // arr數組格式下爲必填
value:'city_id',
key:'name'
},
value:'', // *默認選中值
options:{ // *element組件屬性
data:[ // 列表數據 僅在select類型下可用
{
city_id:'',
name:'所有'
},
{
city_id:1001,
name:'北京'
},
{
city_id:1002,
name:'上海'
}
]
}
},
複製代碼
下拉菜單的數據支持數組和對象兩種格式,分別爲arr
和json
表示,後續可能會優化掉這一入參,直接用類型判斷。 dataType
爲json
時的數據格式,推薦使用json
,能夠減小遍歷操做。
options:{ // *element組件屬性
data:[ // 列表數據 僅在select類型下可用
{
所有:'',
北京:1001,
上海:1002
}
]
}
複製代碼
date-picker
使用的elementUI
的日期組件,options
能夠傳入elementUI
組件的官方屬性,type
目前僅支持daterange
,elementUI 日期date-picker文檔。
注:由於目前項目是基於vue-element-admin
,封裝時沒有考慮,結果上半部分是elementUI
的表單組件,下半部分爲iviewUI
的表格組件,後期會統一。
{
label:'操做時間',
name:['start_time','end_time'], // *入參名稱2個
type:'date-picker',
value:'',
options:{
'value-format':"yyyy-MM-dd",
type:"daterange"
}
}
複製代碼
input
{
label:'車牌號',
name:['car_no'], // *入參名稱2個
value:'', // *默認值
type:'input'
}
複製代碼
selectAndInput
{
label: "ID",
type: "selectAndInput",
value: "",
defaulType:"id", // 默認選中的下拉項值
name: // 下拉菜單數據
{
運單:'transport_order_id',
主運單:'transport_order_main_id'
},
selectOption:{}, // 下拉框官網api設置
inputOtions:{} // 輸入框官網api設置
}
複製代碼
以往咱們在生成這類查詢條件時,會特別檢查一下後端的接口。 謹防接口設計爲類型字段和id字段,不利於拆分爲單個查詢條件。
// 錯誤類型入參實例
{
type:'transport_order_id',
id:'99234i88845'
}
// 正確入參實例
{
transport_order_main_id:'99234i88845'
}
// 或
{
transport_order_id:'99234i88845'
}
複製代碼
Columns
自定義表頭數組類型
使用過iview
的表格組件應該就很熟悉了文檔。
[
{ key: "order_no", minWidth:200, fixed: 'left'},
{
key: "order_status",
minWidth:90,
render:(h, params) => {
let text = this.matchType('order_status',params)
return h('div',text)
}
},
{
key: "source",
render:(h, params) => {
let text = this.matchTypeArr('source',params)
return h('div',text)
}
},
{title: "操做", key: "action",align:'center', minWidth:200, fixed: 'right',
render:(h, params) => {
let setingBtn = h('Button', {
props: {
type: 'primary',
size: 'small'
},
on: {
click: () => {
this.showSet(params.row)
}
}
}, '發運設置')
let editBtn = h('Button', {
props: {
type: 'primary',
size: 'small'
},
style:{
marginLeft:'10px'
},
on: {
click: () => {
this.$router.push('/constExplorer/editorLine/' + params.row.id)
}
}
}, '班車設置')
return h('div',[setingBtn,editBtn])
}
}
]
複製代碼
allDate
修改返回結果函數類型
其實就是一個鉤子函數,在每次翻頁、搜索的時候,拿到數據並作一些修改,好比給每列加一個最小寬度,或者根據權限判斷是否展現操做按鈕。
addWidth(data){
// 列最小寬度
data.data.Columns.forEach(item => {
item.minWidth = 170
})
// 操做按鈕權限判斷
if(_.get(this.powers, 'oderList')){
data.data.Columns.push({title: "操做", key: "action"})
}
}
複製代碼
平常的實際開發中,除了api,還有不少咱們經常使用的操做,好比下拉菜單是接口,格式化表格數據等,咱們來一塊兒過一下吧,把代碼貼一下,提升咱們的開發效率。
下拉菜單調接口數據在組件初始化時獲取下拉菜單的數據
created(){
this.$http.get('/mock/city.json').then(res => {
// 城市列表 數組格式
let formIndex = _.findIndex(this.form, ['name', ['cityid']]);
this.form[formIndex].options.data = this.form[formIndex].options.data.concat(res.data)
})
// 城市列表 對象格式
let formIndex = _.findIndex(this.form, ['name', ['cityid']]);
this.form[formIndex].options.data = Object.assign(this.form[formIndex].options.data,res.data)
})
},
複製代碼
表格列數據格式化 好比這樣的場景,查詢條件中存儲了狀態碼,咱們須要根據查詢條件中的數據格式化表格的列數據。
查詢條件
列數據中返回的是1
或100
這樣的格式,咱們封裝了兩個方法,分別進行格式化,後期會優化爲一個方法。
// 表頭格式
{
key: "order_type",
render:(h, params) => {
let text = this.matchType('order_type',params)
return h('div',text)
}
},
{
key: "source",
render:(h, params) => {
let text = this.matchTypeArr('source',params)
return h('div',text)
}
},
複製代碼
matchType(key,params){
let formIndex = _.findIndex(this.form, ['name', [key]]);
let formType = this.form[formIndex].options.data
let text = _.findKey(formType, item => {
return item == params.row[key]
});
return text
}
matchTypeArr(key,params){
let formIndex = _.findIndex(this.form, ['name', [key]]);
let formType = this.form[formIndex].options.data
let keyName = this.form[formIndex].arrKey.value
let text = _.find(formType, item => {
return item[keyName] == params.row[key]
});
return text.name
}
複製代碼
按鈕權限
權限管理有一些須要精確到按鈕,咱們有專門的接口獲取權限並存在store裏,在allData裏進行判斷,是否展現操做按鈕。
addWidth(data){
// 操做按鈕權限判斷
if(_.get(this.powers, 'oderList')){
data.data.Columns.push({title: "操做", key: "action"})
}
}
複製代碼