Vue內容管理系統的搭建(三)

weixin_33860722發表於2017-04-13
4455053-8632b988361a9bb4.jpg
一定要相信越努力越幸運

文/ziven先生
標題圖片/來自 IM free網站

很抱歉好久沒有把系列文章及時的更下去,隔了好久才更第三篇文章,這中間拖拖拉拉發生了一些事,沒有時間把要做的做下去,說來也挺沮喪的,簡單的事情都沒有堅持。還是那句老話,沒有堅持哪有夢想,又不是富二代,官二代,你說是吧?

關於該系列文章,將按照從簡到難地記錄開發過程與遇到的問題,在過程中按照一個個小模組進行細分,其中如果某個模組遇到一個知識點,將在系列文章外的文章記錄博主關於該知識點的學習與想法,並且在系列文章內附上鍊接。

前兩篇做到前端登入頁面和後端express的搭建。登入之後就進入主介面了。在開發主介面前,必須要知道主要介面的需求是啥,有了需求後,怎麼佈局主介面。當然也可以先想好主介面怎麼佈局,再統計下需求是什麼。

關於視覺設計方面,一來這是個管理系統,視覺上的體驗要求其實並不是那麼高,二來由於時間關係,將在系列文章後面記錄該內容,當然正規上線的專案是需要把設計做好才進行開發的。

按照博主的需求,要管理系統管理的網站主要有兩個模組需要進行管理,一個是反饋頁面的反饋資訊進行管理,一個是全景圖頁面的管理,所謂管理就是要增刪改查,圖片要可以上傳等等。
除此之外管理系統,要有使用該管理系統的使用者管理,所以,管理系統還需要使用者管理模組,分為許可權管理,使用者查詢,個性設定等等

總結起來就是反饋管理,全景圖管理,和使用者管理三個模組。從反饋管理最簡單開始,它主要涉及到table的查詢與增刪改查,反饋資訊表,主要有反饋的時間,反饋人的姓名,反饋的資訊等,管理主要是刪除管理資訊,時間和關鍵字來查詢反饋資訊。這樣思路就有了。

4455053-f0c2c277117bb9cc.png
主頁面佈局
element-ui 導航欄的小問題

在開發過程中遇到一個問題,因為之前開發經驗裡,element ui 導航欄通過index 來進行路由跳轉的,不需要另外進行手動編寫程式碼來啟動這個跳轉,然而這次開發過程,設定好index後,發現跳轉無效,路由沒有發生變化,前前後後黏貼官方程式碼也同樣如此,於是根據官方文件,我在el-ment 標籤新增router屬性並且設定為false(雖然文件說預設是false),奇蹟出現了,路由實現了跳轉,不過瀏覽器出現如下的警告性錯誤,字面意思就是router這個屬性獲取的不是boolean型別,這個問題我現在也不知道如何修正,如果有誰知道可以在評論裡告訴博主。


4455053-16c1e669e0c3d41c.png
el-ment 標籤新增router='false'或者router=false的警告性錯誤

我暫時把它當做一個現象吧,當然可能時間版本更換有所不同,elementUI處理機制不同,而我不知道。解決上述不跳轉的現象,需要另闢方法,那就是通過繫結事件,手動寫方法,獲取index 來跳轉。

使用flex佈局

之前說了,側邊欄和顯示欄是兩欄並列顯示,可以使用el-row ,el-col來佈局,然而當瀏覽器寬度縮小時,因為是按百分比佈局,側邊欄和顯示欄都會隨之壓縮,會導致導致佈局混亂,比如顯示欄換行顯示,甚至是ui的樣式也發生重疊的現象,後來發現element-ui在寬度不滿足的情況下,都有類似情況,所以我們必須設定好min-width,側邊欄和顯示欄都要設定,只設定一方,無法解決問題。
如果覺得用element的佈局標籤覺得很麻煩,或者在靈活度上不太舒服,那就使用flex佈局,要實現同樣效果可以輕鬆多了。

element-ui導航欄,重新整理頁面後,導航欄對應的導航文字高亮消失了

我不知道這是bug,還是開發團隊的設計本來就是這樣做,沒有找到確切的api說明,但是不管怎麼樣,還是可以解決,解決方法是,寫個方法,判斷路由路徑,把路徑設定到default-active屬性裡,這樣重新整理頁面,對應導航的文字高亮就不消失了。


4455053-be20e072debd371b.png
反饋頁面初略顯示

好了,前端檢視層的效果和編碼差不多了(這裡程式碼就不一一貼出來,因為有點多,也不是重點,所以有興趣瞭解程式碼是什麼樣的,去github吧),可是資料是死的,接下來,我們就必須把前端邏輯層和後臺用express獲得資料,把這些資料查出來,並且能通過關鍵字和時間區間來進行查詢。

前端要做的事情就是邏輯處理,路由處理等。邏輯處理有反饋頁面的刪除記錄操作、條件查詢、分頁查詢。路由處理就是,怎麼處理路由跳轉,怎麼設定路由路徑。博主採用的是前後端分離的概念,所以在前端傳送到後臺請求時,由於前後端埠不同,有本地跨域的問題,這時候需要用到vue-cli的跨域設定,下面將會說到。

直接貼程式碼,反饋頁面的邏輯方法實現:

<pre> import { queryFeedbacks, deleteFeedback } from 'api/api';
export default {
data() {
return {
formInline: {
name: '',
keywords: '',
daterange: ''
},
pickerOptions2: {
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]);
}
}, {
text: '最近三個月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit('pick', [start, end]);
}
}]
},
feedbacks: [],
filtr: {
name: '',
kyw: '',
bdate: '',
edate: '',
page: 1,
pageSize: 10
},
page: {
total: 0,
sizes: [10, 20, 30],
}
}
},
mounted() {
this.getFeedbacks();
},
methods: {
onSubmit() {
this.filtr.name = this.formInline.name;
this.filtr.kyw = this.formInline.keywords;
this.filtr.bdate = this.formInline.daterange[0] ? new Date(this.formInline.daterange[0]).Format("yyyy-MM-dd") : '';
this.filtr.edate = this.formInline.daterange[1] ? new Date(this.formInline.daterange[1]).Format("yyyy-MM-dd") : '';
console.log(this.filtr)
this.getFeedbacks();
},
getFeedbacks() {
let that = this;
let param = this.filtr;
queryFeedbacks(param).then(response => {
let res = response.data;
console.log(res)
if (res.code) {
that.page.total = res.data.total;
that.feedbacks = res.data.feedbacks;
} else {
this.$message({
type: 'error',
message: res.message
})
}
})
},
handleDelete(index, row) {
this.$confirm('此操作將永久刪除該檔案, 是否繼續?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
removeFeedback(row.id).then(res => {
this.$message({
type: 'success',
message: '刪除成功!'
});
}).catch(() => {
this.$message({
type: 'alert',
message: '刪除失敗'
});
})
});
},
handleSizeChange(val) {
this.filtr.pageSize = val;
this.getFeedbacks();
},
handleCurrentChange(val) {
this.filtr.page = val;
this.getFeedbacks();
}
}
}
Date.prototype.Format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小時
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
</pre>

傳送請求的外掛使用axios ,vue-source已不再被維護

與vue-source相比,axios可以說要簡潔乾淨一些,後來,發現axios確實不錯,vue官方就開始推薦使用它,vue2以後,vue-source已經停止了維護。axios對http請求的封裝使得get也可以寫得看上去和post請求一樣,當然了,也可以把引數直接附在url後面來傳送get請求。詳細看官網,比較簡單,不再贅述。
傳送門:https://github.com/mzabriskie/axios
系統用到axios:
<pre>
import axios from 'axios'; let apiUrl='/api'; export const removeFeedback=params=>{ return axios.get(\${apiUrl}/feedbacks/remove`,{params:params})}
export const queryFeedbacks=params=>{ return axios.get(`${apiUrl}/feedbacks/query`,{params:params})}`
</pre>

本地跨域使用proxytable解決

如果你在啟動看到如下的錯誤,那你就得用這個設定代理了,位置在config資料夾的index.js(前提是你是用vue-cli構建的專案)。
``xhr.js?14ed:177 XMLHttpRequest cannot load localhost:3000/feedbacks/query?name=&kyw=&bdate=&edate=. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.`
proxytable傳送門:https://vuejs-templates.github.io/webpack/proxy.html
系統中設定的代理:
<pre>
dev: {
env: require('./dev.env'),
port: 8080,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {//外掛會虛擬一個引起跨域的伺服器,代替8080埠傳送請求,從而避免跨域
'/api':{//這個吧表的意思就是隻要連線裡有/api就轉為http://127.0.0.1:3000
target:'http://127.0.0.1:3000',
changeOrigin:true,
pathRewrite:{
'^/api':''//這裡意思就是轉化後不用新增/api,比如/api/1就是http://127.0.01:3000/1
}
}
},
</pre>

express只負責查資料,邏輯處理還給前端

express很簡單,只是進行查詢,刪除操作,這裡查詢,博主把條件查詢,分頁查詢,全部查詢都融合到同一個方法中
<pre>router.get('/remove', function (req, res, next) {
let _feedback = req.body;
console.log(_feedback.id);
let id = connection.escape(_feedback.id);
let sql = 'DELETE FROM feedbacks WHERE id=' + id;
connection.query(sql, function (err, results) {
if (results) {
res.json({ 'code': 1, message: '刪除成功!' })
} else {
res.json({ 'code': 0, message: '刪除失敗!' })
}
})
})
router.get('/query', function (req, res, next) {
let _fb = req.query;
let page = (_fb.page - 1) * 10;//計算查詢的起點
let ps = Number(_fb.pageSize);//計算結束點
console.log(_fb.name || _fb.kyw ? 1:0)
console.log(_fb.bdate ? 1:0)
console.log((_fb.bdate ? 1:0) & (_fb.name || _fb.kyw ? 1:0))
console.log(_fb.name || _fb.kyw)
console.log(_fb.bdate & (_fb.name || _fb.kyw))
let flitr = (_fb.name || _fb.kyw || _fb.bdate ? ' WHERE '//如果存在一條條件查詢就加where,如果沒有直接為空字串
+ (_fb.name ? 'name="' + _fb.name + '"' : '')//判斷name是否需要查詢
+ (_fb.name & _fb.kyw ? ' AND ' : '')//如果兩者都存在就加上and
+ (_fb.kyw ? ' info like "%' + _fb.kyw + '%"' : '') : '')//判斷關鍵字是否需要查詢
+ ((_fb.bdate ? 1:0) & (_fb.name || _fb.kyw ? 1:0) ? ' AND ' : '')//如果時間區間存在並且前面兩個條件查詢有一個存在就加上and
+ (_fb.bdate ? 'date BETWEEN "' + _fb.bdate + '" AND "' + _fb.edate + '"' : '')
let sql1 = 'SELECT count(*) as total FROM feedbacks ' + flitr + ' ; '
let sql2 = 'SELECT id, name,DATE_FORMAT(date,"%Y-%m-%d") date,info FROM feedbacks ' + flitr + ' LIMIT ' + page + ' , ' + ps
console.log(sql1 + sql2)
connection.query(sql1 + sql2, function (err, results) {
if (err) {
console.log(err);
res.json({
code: 0,
message: '[查詢失敗]' + err
})
} else {
res.json({
data: {
total: JSON.parse(JSON.stringify(results[0]))[0].total,//這裡要特別注意,mysql查出來的資料是object但不是可以直接鍵值對就可以獲得值得,需要json轉化。
feedbacks: results[1]
},
code: 1,
message: '查詢成功'
})
console.log(results[1])
}
})
})</pre>

最終效果圖:

4455053-2a1dfcbde88054a8.gif
反饋頁面模組效果

託管的程式碼地址:
<pre>
前端:https://github.com/githubziven/font
後臺:https://github.com/githubziven/service
</pre>

好了,差不多了,終於把第三篇比較完整的寫出來,有很多不完善的地方,將在後面幾篇文章釋出的同時,進行同步更新。下篇也就是第四篇,是關於框架的上傳下載,就是全景圖頁面的實現。不足之處,評論指出,萬分感謝!!

系列文章:

1、Vue2.0+Element+express+mysql 內容管理系統的搭建(一)
2、Vue2.0+Element+express+mysql 內容管理系統的搭建(二)
3、Vue2.0+Element+express+mysql 內容管理系統的搭建(三)

相關文章