【Laravel】【Vue.js】【ホテル予約管理】予約の編集を行う

前回までの状況はこちら

前回の予約詳細画面。

これに、編集ボタンを追加して、予約編集できるようにします。

これが思いの外大変だった。

まずはテンプレートを編集。

        <div id="overlay" v-show="showContent">
            <div id="content">
                <p v-if="error_flg == true" class="error">{{error_message}}</p>
                <table class="edit">
                    <tbody>
                        <tr>
                            <th>名前</th>
                            <td v-if="edit_flg == true"><input type="text" v-model=contents.name /></td>
                            <td v-else>{{ contents.name }}</td>
                        </tr>
                        <tr>
                            <th>住所</th>
                            <td v-if="edit_flg == true"><input type="text" v-model=contents.address /></td>
                            <td v-else>{{ contents.address }}</td>
                        </tr>
                        <tr>
                            <th>電話番号</th>
                            <td v-if="edit_flg == true"><input type="text" v-model=contents.phone /></td>
                            <td v-else>{{ contents.phone }}</td>
                        </tr>
                        <tr>
                            <th>人数</th>
                            <td v-if="edit_flg == true">
                                <select v-model=contents.num>
                                    <option v-for="num in nums" v-bind:value="num.value">{{ num.text }}</option>
                                </select>
                            </td>
                            <td v-else>{{ contents.num }}</td>
                        </tr>
                        <tr>
                            <th>宿泊部屋</th>
                            <td v-if="edit_flg == true">
                                <select v-model="contents.roomid">
                                    <option v-for="room in rooms" v-bind:value="room.id">{{ room.name }}</option>
                                </select>
                            </td>
                            <td v-else>{{ contents.room }}</td>
                        </tr>
                        <tr>
                            <th>宿泊日数</th>
                            <td v-if="edit_flg == true"><input type="number" v-model=contents.days /></td>
                            <td v-else>{{ contents.days }}</td>
                        </tr>
                        <tr>
                            <th>宿泊日</th>
                            <td v-if="edit_flg == true"><input type="date" v-model=contents.start_day /></td>
                            <td v-else>{{ contents.start_day }}</td>
                        </tr>
                        <tr>
                            <th>チェックアウト</th>
                            <td v-if="edit_flg == true">
                                <select v-model="contents.checkout">
                                    <option v-for="time in timeList" v-bind:value="time.key">{{ time.value }}</option>
                                </select>
                            <td v-else>{{ contents.checkout }}</td>
                        </tr>
                    </tbody>
                </table>
            <p>
                <button @click="closeModal">close</button>
                <button v-if="edit_flg == false" @click="onClickEdit">編集</button>
                <button v-else @click="onClickSave">保存</button>
            </p>
            </div>
        </div>

edit_flgという状態変数を見て、これがtrueならば、タグをinputに置き換える、という作りになっています。

では、データの方はというと、

        data() {
            return {
                error_message: "",
                error_flg:false,
                errors: {},

 中略

                nums: [
                    {text:'1', value:1},
                    {text:'2', value:2}
                ],
                timeList:[],
                selectRoom: 0,
                rooms: [],
                result: [],
                param: {
                    year: 2019,
                    month: 1,
                    room: 1
                },
                registers: [],
                showContent: false,
                contents: {
                    name: "",
                    address: "",
                    phone: "",
                    num: 0,
                    roomid: 0,
                    room: "",
                    days: 0,
                    start_day: "",
                    checkout: "",
                },
                edit_flg: false
            }
        },

ポイントはedit_flg。これをtrueにすることで、テンプレートが編集用に置き換わります。

なお、編集中のテンプレートは、予約追加時と同じくらいの機能を持たなくてはいけません。

もう、予約追加処理も、この中に入れてしまってもいいのかもしれない。

実際の処理は、

        created: function() {
            this.getRooms();
            this.getTimeList();
        },
        methods: {
            getRooms: function() {
                var self = this;
                axios.post('/api/rooms').then(function(response){
                    response.data.roomLists.forEach(element => {
                        self.rooms.push({id:element.id, name:element.name});
                    });
                }).catch(function(error){
                    console.log("失敗しました");
                });
            },
            getRegisters: function() {
                var self = this;
                this.param.year = this.selectYear;
                this.param.month = this.selectMonth;
                this.param.room = this.selectRoom;
                axios.post('/api/registers', this.param).then(function(response){
                    self.registers = [];
                    response.data.registerLists.forEach(element => {
                        self.registers.push(
                            {
                                id:element.id, 
                                name:element.name,
                                address:element.address,
                                phone:element.phone,
                                num:element.num,
                                roomid:element.roomid,
                                room:element.room,
                                days:element.days,
                                start_day:element.start_day, 
                                checkout:element.checkout
                            }
                        );
                    });
                }).catch(function(error){
                    console.log("失敗しました");
                });
            },
            onClickEdit: function(){
                this.edit_flg = true;
                var checkoutTime = this.contents.checkout.split(" ")[1];
                this.timeList.forEach(element => {
                    if(checkoutTime == element.value+":00"){
                        this.contents.checkout = element.key;
                    }
                });
            },
            onClickSave: function(){
                var self = this;
                this.param.year = this.selectYear;
                this.param.month = this.selectMonth;
                this.param.room = this.selectRoom;
                this.param.contents = this.contents;
                axios.post('/api/update', this.param).then(function(response){
                    self.registers = [];
                    response.data.registerLists.forEach(element => {
                        self.registers.push(
                            {
                                id:element.id, 
                                name:element.name,
                                address:element.address,
                                phone:element.phone,
                                num:element.num,
                                roomid:element.roomid,
                                room:element.room,
                                days:element.days,
                                start_day:element.start_day, 
                                checkout:element.checkout
                            }
                        );
                    });
                    self.closeModal();
                }).catch(function(error){
                    self.error_flg = true;
                    self.error_message = error.response.data.errors;
                });
            },
            openModal: function(id){
                for(var i = 0; i< this.registers.length; i++){
                    if(this.registers[i].id == id){
                        this.contents.id = this.registers[i].id;
                        this.contents.name = this.registers[i].name;
                        this.contents.address = this.registers[i].address;
                        this.contents.phone = this.registers[i].phone;
                        this.contents.num = this.registers[i].num;
                        this.contents.roomid = this.registers[i].roomid;
                        this.contents.room = this.registers[i].room;
                        this.contents.days = this.registers[i].days;
                        this.contents.start_day = this.registers[i].start_day;
                        this.contents.checkout = this.registers[i].checkout;
                        break;
                    }
                }
                this.showContent = true;
                this.edit_flg = false;
            },
            closeModal: function(){
                this.showContent = false;
                this.edit_flg = false;
            },
            getTimeList: function(){
                var self = this;
                axios.post('/api/timelist').then(function(response){
                    for (let [key, value] of Object.entries(response.data.timelist)){
                        self.timeList.push({key: key, value: value});
                    }
                }).catch(function(error){
                    console.log("失敗しました");
                });
            }

onClickEdit()で、詳細画面から、編集画面に切り替わります。

そして、onClickSave()で、入力したデータをLaravel側のAPI処理にデータを渡します。

うん、予約追加もこの中でいいよね。

あと、サーバ側でエラーが発生した場合のメッセージ表示も追加しています。

error_flgがtureになったらテンプレートにもその要素が表示され、API側で送られたメッセージが画面に表示されます。

では、API側の処理。

ルーティングに以下を追加します。

Route::post('/api/update', 'ApiController@update');
Route::post('/api/timelist', 'ApiController@timelist');

処理は、

    public function timelist(Request $request)
    {
        return response()->json(['timelist' => $this->registerManagement->getTimeList()]);
    }

    public function update(Request $request)
    {
        \Log::debug(print_r($request->contents, true));
        if($this->registerManagement->checkScheduleForUpdate($request->contents["start_day"], 
                                                            $request->contents["days"], 
                                                            $request->contents["id"], 
                                                            $request->contents["roomid"]) == false)
        {
            \Log::debug("スケジュールが重複しています");
            return response()->json([
                'errors' => "スケジュールが重複しています"
            ], 400);
        }
        $param = $this->registerManagement->getParam();
        $this->registerManagement->updateById($request->contents["id"],
        [
            $param[0] => $request->contents["name"],
            $param[1] => $request->contents["address"],
            $param[2] => $request->contents["phone"],
            $param[3] => $request->contents["num"],
            $param[4] => $request->contents["days"],
            $param[5] => $request->contents["start_day"],
            $param[6] => false,
            $param[7] => date('Y-m-d H:i', strtotime($request->contents["start_day"].' + '.$request->contents["days"].' day') + $request->contents["checkout"])
        ], $request->contents["roomid"]);
        return response()->json(['registerLists' => $this->registerManagement->getListByMonth(
            $request->year,
            $request->month,
            $request->room
        )]);
    }

timelist()というのは、データベースで処理するtick値と画面に表示する時刻のテーブルです。

これがあるためにつまずいた。

tick: “時刻(00:00)”

という形でデータを持っていたために、これがうまくVueで処理されないので、JavaScriptで形を変換したのですよ。

このやり方を見つけるのに苦労した・・・。

            getTimeList: function(){
                var self = this;
                axios.post('/api/timelist').then(function(response){
                    for (let [key, value] of Object.entries(response.data.timelist)){
                        self.timeList.push({key: key, value: value});
                    }
                }).catch(function(error){
                    console.log("失敗しました");
                });
            }

ここの処理ね、

[{tick: “時刻(00:00)”},{ },・・・]

このフォーマットを

[{key:tick, value:”時刻”},{ },・・・}

に変換したのですよ。

これを導き出すのに苦労しました。

でも、これができれば今までのサーバ側の処理が、ほぼ、そのまま使えるわけで、

編集画面でも、予約追加と同じことができるようになりました。

っていうか、追加処理もこの形にしよう。

ってなことで次回。