Day28已建立好環境了,接下來開始製作CURD功能囉~
php artisan make:controller KeywordController
KeywordController負責進行實際對MongoDB的CRUD操作,再將資料回傳到View用Vue作呈現
<?php
namespace App\Http\Controllers;
use App\Models\Keyword;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Pagination\Paginator;
use Carbon\Carbon;
class KeywordController extends Controller
{
public function getKeywordView(){
return view('keyword');
}
public function index(Request $request){
$perPage = 5;
$page = (int)$request->page;
$from= ($page * $perPage) - ($perPage - 1);
$keyword = Keyword::all()->splice($from, $perPage);
$total = Keyword::count();
$response = [
'pagination' => [
'total' => $total,
'per_page' => $perPage,
'current_page' => $page,
'last_page' => ceil($total / $perPage),
'from' => $from,
'to' => $page * $perPage
],
'keyword' => $keyword, 'add' => route('addKeyword'), 'update' => route('updateKeyword'),
'delete' => route('deleteKeyword')
];
return response()->json($response);
}
public function addKeywordData(Request $request)
{
$english_name = $request->english_name;
$chinese_name = $request->chinese_name;
$datetime = Carbon::now()->toDateTimeString();
$status = 'success';
$message = '新增成功!';
try {
Keyword::insert([
'english_name' => $english_name,
'chinese_name' => $chinese_name,
'created_at' => $datetime,
'updated_at' => $datetime
]);
} catch (Exception $e) {
$status = 'error';
$message = '新增失敗!';
}
return [
'status' => $status,
'message' => $message
];
}
public function updateKeywordData(Request $request){
$english_name = $request->english_name;
$chinese_name = $request->chinese_name;
$datetime = Carbon::now()->toDateTimeString();
$status = 'success';
$message = '更新成功!';
$data = [
'english_name' => $english_name,
'chinese_name' => $chinese_name,
'updated_at' => $datetime
];
try {
Keyword::where('_id', $request->id)->update($data);
} catch (Exception $e) {
$status = 'error';
$message = ' 更新失敗!';
}
return [
'status' => $status,
'message' => $message
];
}
public function deleteKeywordData(Request $request){
$datetime = Carbon::now()->toDateTimeString();
$status = 'success';
$message = '刪除成功!';
try {
Keyword::where('_id', $request->id)->delete();
} catch (Exception $e) {
$status = 'error';
$message = '刪除失敗!';
}
return [
'status' => $status,
'message' => $message
];
}
}
keyword.js
裡引用Edit.vue
、List.vue、NavbarPagination.vue
import keywordList from './components/keyword/List.vue';
import keywordEdit from './components/keyword/Edit.vue';
import NavbarPagination from './components/NavbarPagination.vue'
let app = new Vue({
el: '#app',
components: {
'keyword-list': keywordList,
'keyword-edit': keywordEdit,
'navbar-pagination': NavbarPagination
},
data: {
editTitle: '',
showEdit: false,
isAdd: false,
keyword: [],
urlAdd: '',
urlUpdate: '',
urlDelete: '',
pagination: {},
getPage:1,
params: {
'id': '',
'enName': '',
'chName': ''
},
keyWordDataIndex: null
},
mounted() {
this.getKeywordData(1)
},
methods: {
getPagination(getPage) {
this.getKeywordData(getPage)
},
getKeywordData(page){
axios.get('/getKeywordData?page=' + page).then(response => {
this.keyword = response.data.keyword,
this.urlAdd = response.data.add,
this.urlUpdate = response.data.update,
this.urlDelete = response.data.delete,
this.pagination = response.data.pagination
}).catch((error) => {
//顯示請求資料失敗的錯誤訊息
if (error.response){
//在log顯示response錯誤的資料、狀態、表頭
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
}else{
//在log顯示r錯誤訊息
console.log('Error',error.message);
}
})
},
getAddKeyword() {
this.editTitle = '新增關鍵字'
this.showEdit = true
this.isAdd = true
this.params = {
'id': '',
'enName': '',
'chName': ''
}
},
updateKeyword(id, enName, chName, index) {
this.editTitle = '更新關鍵字'
this.showEdit = true
this.params = {
'id': id,
'enName': enName,
'chName': chName
}
this.keyWordDataIndex = index
},
updateKeywordData(params) {
if (this.keyWordDataIndex != null) {
this.keyword[this.keyWordDataIndex].chinese_name = params.chinese_name
this.keyword[this.keyWordDataIndex].english_name = params.english_name
}
},
deleteKeywordData(index) {
this.keyWordDataIndex = index
if (this.keyWordDataIndex != null) {
this.keyword.splice(this.keyWordDataIndex, 1)
}
},
isShowMessage(isSuccess, message){
let isAdd = this.isAdd
swal({
title: message,
confirmButtonColor: "#e6b930",
icon: isSuccess ? 'success':'error',
showCloseButton: true
}).then(function() {
if (isSuccess && isAdd){
location.reload()
}
})
if (isSuccess) {
this.showEdit = false
}
}
},
})
mountedgetKeywordData()
取得該分頁的關鍵字資料
method
getPagination()
切換分頁時,會更新分頁對應的關鍵字資料getAddKeyword()
顯示新增的視窗updateKeyword()
顯示更新的視窗updateKeywordData()
更新目前的資料deleteKeywordData()
移除目前的資料isShowMessage()
顯示提示訊息Edit.vue
List.vue
NavbarPagination.vue
<!-- Edit.vue -->
<script>
import swal from "sweetalert"
export default {
props: {
title: {
type:String
},
params: {
type:Object
},
urlAdd: {
type:String
},
urlUpdate: {
type:String
},
isAdd: {
type:Boolean
}
},
data() {
return {
enName: this.params.enName,
chName: this.params.chName,
messageText: '',
}
},
methods: {
checkKeyword(enName, chName) {
let isSuccess = false
this.messageText = ''
if (enName === '' && chName === '') {
this.messageText = "英文或中文名稱不能為空"
} else if (enName === '') {
this.messageText = "英文名稱不能為空"
} else if(/[\u4e00-\u9fa5]/.test(enName)) {
this.messageText = "英文名稱不能輸入中文"
} else if (chName === '') {
this.messageText = "中文名稱不能為空"
} else if(/[A-Za-z]/.test(chName)) {
this.messageText = "中文名稱不能輸入英文"
}
if (this.messageText == '') {
isSuccess = true
} else {
this.$emit('is-show-message', isSuccess, this.messageText)
}
return isSuccess
},
saveKeyword(){
let enName = this.enName
let chName = this.chName
let url = this.isAdd ? this.urlAdd : this.urlUpdate
let isSuccess = this.checkKeyword(enName, chName)
if (isSuccess) {
let data = {
'english_name' : enName,
'chinese_name' : chName,
}
if (!this.isAdd) {
data['id'] = this.params.id
}
axios.post(url, data).then((response) => {
let isSuccess = response.data.status == 'success' ? true : false
if (isSuccess && !this.isAdd) {
this.$emit('update-keyword-data', data)
}
this.$emit('is-show-message', isSuccess, response.data.message)
}).catch((error) => {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
console.log('Error', error.message);
}
this.$emit('is-show-message', false, '發生意外錯誤!')
})
}
}
},
}
</script>
Edit.vue
是編輯關鍵字資料的視窗,sweetalert
是能強大、美觀又容易使用的dialog library。
props
title
傳視窗的標題params
關鍵字的資料urlAdd
新增資料的Route
urlUpdate
新增資料的Route
isAdd
要新增資料的布林值methods
checkKeyword()
是檢查關鍵字資料是否問題,有問題就使用emit
傳訊息文字saveKeyword()
是儲存關鍵字資料用的<!-- List.vue -->
<script>
export default {
props: {
keyWordData: {
type:Array
},
urlDelete: {
type:String
}
},
data() {
return {
}
},
methods: {
deleteKeyword(id, index) {
let url = this.urlDelete
let params = {
id: id
}
axios.post(url, params).then((response) => {
let isSuccess = response.data.status == 'success' ? true : false
if (isSuccess) {
this.$emit('delete-keyword-data', index)
}
this.isShowMessage(isSuccess, response.data.message)
}).catch((error) => {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
console.log('Error', error.message);
}
this.$emit('is-show-message', false, '發生意外錯誤!')
})
}
}
}
</script>
List.vue
是顯示關鍵字資料的表
props
keyWordData
傳全部關鍵字資料urlDelete
移除資料Route
methodsdeleteKeyword
() 移出關鍵字資料
<!-- NavbarPagination.vue -->
<script>
export default {
props:{
paginationData:{
type:Object
}
},
data:function(){
return {
offset: 4
}
},
computed: {
isActived: function () {
return this.paginationData.current_page;
},
pagesNumber: function () {
if (!this.paginationData.to) {
return [];
}
let from = this.paginationData.current_page - this.offset;
if (from < 1) {
from = 1;
}
let to = from + (this.offset * 2);
if (to >= this.paginationData.last_page) {
to = this.paginationData.last_page;
}
let pagesArray = [];
while (from <= to) {
pagesArray.push(from);
from++;
}
return pagesArray;
}
},
methods: {
changePage: function (page) {
this.$emit('change-pagination', page)
}
}
}
</script>
NavbarPagination.vue
是分頁的導覽列
props
paginationData
分頁資料的物件computed
isActived()
計算目前第幾頁pagesNumber()
重新排列分頁資料methods
changePage()
切換分頁時,將目前頁數使用emit
傳遞<!-- keyword.blade.php-->
<html>
<head>
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="Access-Control-Allow-Origin" content="*" />
</head>
<style>
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: table;
transition: opacity 0.3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>
<body>
<div class="container">
<div v-cloak id="app" class="content">
<form action="" method="POST">
{{ csrf_field() }}
<h2
id="title"
class="text-center text-black font-weight-bold"
style="margin-bottom:20px;">
關鍵字查詢
</h2>
<div style="text-align:right">
<input type="button" id="btn_insert" class="btn btn-primary" @click="getAddKeyword()" value="新增" />
</div><br/>
<keyword-list
:key-word-data="keyword"
:url-delete="urlDelete"
@update-keyword="updateKeyword"
@delete-keyword-data="deleteKeywordData"
>
</keyword-list>
<keyword-edit
v-if="showEdit"
@close="showEdit = false"
:title="editTitle"
:is-add="isAdd"
:url-add="urlAdd"
:url-update="urlUpdate"
:params="params"
@update-keyword-data="updateKeywordData"
@is-show-message="isShowMessage"
>
</keyword-edit>
<navbar-pagination
@change-pagination="getPagination"
:pagination-data="pagination"
>
</navbar-pagination>
</form>
</div>
</div>
<script src="{{mix('js/app.js')}}"></script>
<script src="{{mix('js/keyword.js')}}"></script>
<link rel="stylesheet" type="text/css" href="{{mix('/css/app.css')}}">
</body>
</html>
Route
Route::get('/keyword', 'KeywordController@getKeywordView');
Route::get('/getKeywordData','KeywordController@index');
Route::get('/updateKeyword', 'KeywordController@updateKeywordData');
Route::post('/addKeyword', 'KeywordController@addKeywordData')
->name('addKeyword');
Route::post('/updateKeyword', 'KeywordController@updateKeywordData')
->name('updateKeyword');
Route::post('/deleteKeyword', 'KeywordController@deleteKeywordData')
->name('deleteKeyword');
在webpack.mix.js
新增keyword.js
、app.sass
檔案進行邊ㄧ
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/keyword.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css');
npm run watch
$ php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
啟動之後,輸入網址為http://127.0.0.1:8000/keyword
Resource
xampp-gmongodb
laravel-mongodb