Vue3 + laravel10でSPA作成　③詳細画面作成

## はじめに
本記事は[Vue3 + laravel10でSPA作成　②DB連携](https://qiita.com/ddtwn/items/51b4cede883456c599f2)の続きになります。
今回の目標は詳細画面の作成とボタンアクションの実装までとなります。
## 詳細画面作成
### １．router.jsの編集
`resources\js\router.js`を編集し、詳細画面のルーティングを追加します。
```diff_javascript:router.js
：
+ import detail from "../views/Detail.vue"

const routes = [
    {
        path: "/",
        component: home,
        name: "home"
    },
+    {
+        path: "/detail",
+        component: detail,
+        name: "detail"
+    },
]
：
```
### ２．詳細画面コンポーネントの作成
`resources\views\Detail.vue`を作成します。
`style scoped`にしていない理由は、`Vuetify`が生成する`html`に対してスタイルを適用したいためです。ただし他コンポーネントまでスタイル適用されるので、注意が必要です。
```vue:Detail.vue
<template>
    <v-container fluid>
        <h4 class="mb-5">ToDo詳細</h4>
        <div class="input-form">
            <v-row>
                <v-col cols="2" style="text-align: right; vertical-align: middle;">
                    タイトル:
                </v-col>
                <v-col cols="4">
                    <v-text-field density="compact" hide-details variant="solo"
                     class="inner-text" v-model="todoDetail.TODO_NAME"></v-text-field>
                </v-col>
            </v-row>
            <v-row>
                <v-col cols="2" style="text-align: right;">
                    ステータス:
                </v-col>
                <v-col cols="3">
                    <v-text-field density="compact" hide-details variant="solo"
                    class="inner-text" v-model="todoDetail.STATUS"></v-text-field>
                </v-col>
            </v-row>
        </div>
        <div class="mt-5">
            <v-row>
                <v-col cols="5">
                    <v-btn to="/" color="blue-grey-lighten-4">戻る</v-btn>
                </v-col>
                <v-col cols="2">
                    <v-btn v-if='props.todoId == null' @click="createTodo" color="blue-accent-2">新規作成</v-btn>
                    <v-btn v-else @click="updateTodo" color="blue-accent-2">更新</v-btn>
                </v-col>
            </v-row>
        </div>
    </v-container>
</template>

<script setup>
import { ref, onMounted } from 'vue'
// 前画面（ホームからToDoIDを受け取る)
const props = defineProps({
    todoId: String
})


// ToDoデータ取得
const todoDetail = ref({  TODO_NAME: "", STATUS: "", CREATE_DATE: ""})
if (props.todoId != null) {
    onMounted(async () => {
        var res = await axios.post('getTodo', props)
        if (res.data != undefined) {
            todoDetail.value = res.data[0]
        }

    })
}

// 更新
const updateTodo = async () => {
    // ToDo情報にIDを付ける
    todoDetail.TODO_ID = props.todoId
    await axios.post('updateTodo', todoDetail.value);
}

// 新規作成
const createTodo = async () => {
    await axios.post('createTodo', todoDetail.value)
}
</script>
<style>
.input-form {
    font-size: 14px;
}

.inner-text input {
    padding: 0px 2px 0px 2px;
    min-height: 20px;
    font-size: 10px !important;
}

</style>
```
### ３．詳細画面の画面モード
ホーム画面のボタン押下(「更新」,「新規作成」)によって表示を切り替えます。
「更新」ボタンの場合は`todoId`をパラメータとして送るので、詳細画面がパラメータを受け取れるように、`resources\js\router.js`を編集します。
```diff_javascript:router.js
    {
-       path: "/detail",
+       path: "/detail/:todoId?",
        component: detail,
        name: "detail",
+       props: true
    },

```
「更新」押下の場合に、更新モードで詳細画面が表示されることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410887/6403a62e-8130-43a1-53c1-170b45ca414b.png)

### ４．api.phpの編集
取得、新規作成、更新のルーティングを`routes\api.php`に追加する。
```diff_php:api.php
+ Route::post('getTodo',[TodoController::class,'getTodo']);
+ Route::post('updateTodo',[TodoController::class,'updateTodo']);
+ Route::post('createTodo',[TodoController::class,'createTodo']);
+ Route::post('deleteTodo',[TodoController::class,'deleteTodo']);
```
### ５．コントローラの編集
```diff_php
+ use Illuminate\Http\Request;

    public function getTodoList()
    {
        $sql = 'SELECT * FROM TODO_LIST';
        $items = DB::select($sql);
        return $items;
    }

+    // 詳細更新モード起動時
+    public function getTodo(Request $req)
+    {
+        $todoId = $req->input('todoId');
+        $sql = 'SELECT * FROM TODO_LIST WHERE TODO_ID = :todoId';
+        $items = DB::select($sql, ['todoId' => $todoId]);
+        return $items;
+    }

+    // 新規作成
+    public function createTodo(Request $req)
+     {
+        $params = $req -> only(['TODO_NAME', 'STATUS']);
+        $sql = <<< 'SQL'
+        INSERT 
+        INTO todo_list(TODO_NAME, STATUS, CREATE_DATE) 
+        VALUES (:TODO_NAME, :STATUS, CURDATE())
+        SQL;
+        DB::insert($sql, $params);
+     }

+    // 更新
+    public function updateTodo(Request $req)
+    {
+        $params = $req -> only(['TODO_NAME', 'STATUS', 'TODO_ID']);
+        $sql = <<< 'SQL'
+        UPDATE todo_list 
+        SET
+            TODO_NAME = :TODO_NAME
+            , STATUS = :STATUS
+        WHERE
+            TODO_ID = :TODO_ID
+        SQL;
+        DB::update($sql, $params);
+    } 

+        // 削除
+    public function deleteTodo(Request $req)
+    {
+        $todoId = $req -> input('todoId');
+        $sql = 'DELETE FROM TODO_LIST WHERE TODO_ID = :todoId';
+        DB::delete($sql,['todoId' => $todoId]);
+    }
```
### ６．トップページの削除ボタン実装
`resources\views\Home.vue`を編集する。
```diff_vue
-                            <v-btn @click="deleteTodo()" density="compact" color="red">削除</v-btn>
+                            <v-btn @click="deleteTodo(item.TODO_ID)" density="compact" color="red">削除</v-btn>
：
+ // 削除
+ const deleteTodo = async (todoId) => {
+     await axios.post('deleteTodo',  {todoId: todoId})
+     var res = await axios.get('getTodoList')
+     todoList.value = res.data
+ } 
```
# 確認
新規作成、更新についてはボタンを押下し、戻るを押してトップに戻り、内容が反映されているか確認、削除については押下直後に反映されることを確認する。

# さいごに
最後までお読みいただきありがとうございました。
制作時の所感としては、`Vuetify2`,`Vuetify3`の情報の混在や、`laravel10`がまだまだネット記事が充実していないことなどから、環境構築、エラー解消に逐一ハマってしまうことが多かったです汗。
誤りのご指摘、よりよい方法、動作しない等のご意見あればコメントを頂ければと思います。