OSDN Git Service

Java版の途中までを追加
authortkskjri05 <t.kujirai@nagatake.co.jp>
Mon, 3 May 2021 03:09:30 +0000 (12:09 +0900)
committertkskjri05 <t.kujirai@nagatake.co.jp>
Mon, 3 May 2021 03:09:30 +0000 (12:09 +0900)
package-lock.json
package.json
src/components/todoAppJava.vue [new file with mode: 0644]
src/store/index.js
src/views/About.vue

index bcf083c..692d756 100644 (file)
       "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
       "dev": true
     },
+    "axios": {
+      "version": "0.21.1",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+      "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+      "requires": {
+        "follow-redirects": "^1.10.0"
+      }
+    },
     "babel-eslint": {
       "version": "10.1.0",
       "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
     "follow-redirects": {
       "version": "1.13.2",
       "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz",
-      "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==",
-      "dev": true
+      "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA=="
     },
     "for-in": {
       "version": "1.0.2",
         "throttle-debounce": "^2.1.0"
       }
     },
+    "vue-axios": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/vue-axios/-/vue-axios-3.2.4.tgz",
+      "integrity": "sha512-8Dgws6dwt+1LoKEU4HDzIPfaRgWHl0xLDLW6kxrAk/z3GAJ2thkajcXC4qZgmqj0cZRx/Z/dzooKi5HWtUQwxA=="
+    },
     "vue-cli-plugin-apollo": {
       "version": "0.22.2",
       "resolved": "https://registry.npmjs.org/vue-cli-plugin-apollo/-/vue-cli-plugin-apollo-0.22.2.tgz",
index c31931e..478af70 100644 (file)
@@ -22,6 +22,7 @@
     "apollo-link": "^1.2.14",
     "apollo-link-http": "^1.5.17",
     "autoprefixer": "^9.8.6",
+    "axios": "^0.21.1",
     "core-js": "^3.6.5",
     "graphql": "^15.5.0",
     "graphql-type-json": "^0.2.1",
@@ -32,6 +33,7 @@
     "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.1.0",
     "vue": "^2.6.11",
     "vue-apollo": "^3.0.7",
+    "vue-axios": "^3.2.4",
     "vue-router": "^3.2.0",
     "vuex": "^3.4.0"
   },
diff --git a/src/components/todoAppJava.vue b/src/components/todoAppJava.vue
new file mode 100644 (file)
index 0000000..6a2bad6
--- /dev/null
@@ -0,0 +1,343 @@
+<template>
+  <div class="bg-gray-50">
+    <div class="max-w-xl mx-auto py-1 divide-y md:max-w-4xl">
+      <div class="py-10 px-5 rounded-md shadow-lg">
+        <div>Todo タイトル</div>
+        <input type="text" 
+              list="todo_header" 
+              v-model="titleName" 
+              @input="onHeaderChange"
+              class="w-10/12 px-1 py-2 mb-1 border-b border-gray-500 focus:outline-none focus:border-indigo-500 transition-colors text-gray-900" />
+        <button class="bg-gray-200 w-12 h-12 px-3 py-2 mb-1 ml-0 text-sm font-bold tracking-wider text-gray hover:bg-gray-400 inline-flex items-center justify-center"
+          @click="searchHeader">
+          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-list-check" viewBox="0 0 16 16">
+            <path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zM3.854 2.146a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 3.293l1.146-1.147a.5.5 0 0 1 .708 0zm0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 1 1 .708-.708L2 7.293l1.146-1.147a.5.5 0 0 1 .708 0zm0 4a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0l-.5-.5a.5.5 0 0 1 .708-.708l.146.147 1.146-1.147a.5.5 0 0 1 .708 0z"/>
+          </svg>
+        </button>
+        <button class="bg-blue-500 w-10 h-10 p-3 ml-3 text-sm font-bold tracking-wider text-white rounded-full hover:bg-red-600 inline-flex items-center justify-center"
+          v-if="selectedOption == null"
+          @click="addHeader">
+          <svg xmlns="http://www.w3.org/2000/svg" class="fill-current" viewBox="0 0 24 24">
+            <path d="M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z"/>
+          </svg>
+        </button>
+        <button class="bg-blue-500 w-10 h-10 p-3 ml-3 text-sm font-bold tracking-wider text-white rounded-full hover:bg-red-600 inline-flex items-center justify-center"
+          v-else
+          @click="deleteHeader">
+          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
+            <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
+            <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
+          </svg>
+        </button>
+        
+      </div>
+      <div class="py-10 px-5 rounded-md shadow-lg">
+        <div>Todo リスト</div>
+        <div v-if="loading()">Loading...</div>
+        <div v-else class="py-1" v-for="list in todo_list" :key="list.id">
+          <todo :data="list"
+                @onCheckChange="onCheckChange"
+                @onTextChange="onTextChange"
+                @onDelete="onDelete"/>
+        </div>
+        <div class="py-5">
+          <button
+                class="p-0 w-10 h-10 bg-blue-600 rounded-full hover:bg-blue-700 active:shadow-lg mouse shadow transition ease-in duration-200 focus:outline-none"
+                @click="onAdd"
+                v-if="selectedHeadrId != 0">
+            <svg viewBox="0 0 20 20" enable-background="new 0 0 20 20" class="w-6 h-6 inline-block">
+              <path fill="#FFFFFF" d="M16,10c0,0.553-0.048,1-0.601,1H11v4.399C11,15.951,10.553,16,10,16c-0.553,0-1-0.049-1-0.601V11H4.601
+                                      C4.049,11,4,10.553,4,10c0-0.553,0.049-1,0.601-1H9V4.601C9,4.048,9.447,4,10,4c0.553,0,1,0.048,1,0.601V9h4.399
+                                      C15.952,9,16,9.447,16,10z" />
+            </svg>
+          </button>
+        </div>
+      </div>
+
+      <select-box/>
+      
+      <snack-bar :msg="snackText" ref="snackBar"/>
+      <select-panel 
+        :dataList="todo_header" 
+        title="Todoリスト選択" 
+        ref="selectPanel"
+        @onSelected="onSelected"/>
+
+      <spinner ref="spinner"/>
+
+    </div>
+  </div>
+</template>
+
+<script>
+
+import moment from 'moment'
+import _ from 'lodash' // eslint-disable-line no-unused-vars
+//import { useQuery, useResult } from '@vue/apollo-composable' // eslint-disable-line no-unused-vars
+import gql from 'graphql-tag'
+import selectBox from '@/components/selectBox.vue'
+import todo from '@/components/todo.vue'
+import snackBar from '@/components/snackBar.vue'
+import selectPanel from '@/components/selectPanel.vue'
+import spinner from '@/components/spinner.vue'
+
+export default {
+  name: 'todoApp',
+  components: {
+    selectBox
+    , todo
+    , snackBar
+    , selectPanel
+    , spinner
+  },
+  beforeMount() {
+    this.$store.dispatch('test');
+    this.$apollo.queries.todo_list.refetch({
+        selectedHeadrId: 0
+    })
+  },
+  computed: {
+    // 選択中のオプションオブジェクト。任意入力値の場合は null を返す
+    selectedOption() {
+      if(!this.todo_header){
+        return null
+      }
+      const selected = this.todo_header.find(item => item.name === this.titleName)
+      return selected || null
+    }
+  },
+  //Vue2.6なのでsetupが…
+  // setup() {
+  //   // const { result, loading, error, refetch } = useQuery(gql`
+  //   //   query todo_header {
+  //   //     todo_header {
+  //   //       id
+  //   //       name
+  //   //     }
+  //   //   }
+  //   // `)
+
+  //   // const users = useResult(result)
+
+  //   // return {
+  //   //   users,
+  //   //   loading,
+  //   //   error,
+  //   //   refetch,
+  //   // }
+  //   onBeforeMount(() => {
+  //     console.log('Component is onBeforeMount!')
+  //     // this.$apollo.queries.todo_list.refetch({
+  //     //   selectedHeadrId: 0
+  //     // })
+  //   })
+  // },
+  methods: {
+    selectedTitle(id){
+      this.reFetch(id)
+    },
+    onSelected(head){
+      this.titleName = head.name
+      this.selectedTitle(head.id)
+    },
+    onHeaderChange() {
+      if(this.selectedOption){
+        this.selectedTitle(this.selectedOption.id)
+      } else {
+        this.$apollo.queries.todo_list.refetch({
+          selectedHeadrId: 0
+        })
+        this.selectedHeadrId = 0
+      }
+    },
+    addHeader(){
+      if(_.isEmpty(this.titleName)){
+        this.$refs.snackBar.setMessageAndshow('タイトルが入ってないよ!')
+        return
+      }
+      
+    },
+    deleteHeader(){
+
+    },
+    searchHeader(){
+      this.$refs.spinner.show()
+      this.$apollo.queries.todo_header.refetch()
+      .then(() => {
+          this.$refs.selectPanel.show()
+      }).catch((error) => {
+        this.$refs.snackBar.setMessageAndshow('db error?')
+        console.error(error)
+      }).finally(() => {
+        this.$refs.spinner.close()
+      })
+      
+    },
+    onCheckChange(data) {
+      this.updateMutate(data);
+    },
+    onTextChange(data) {
+      this.updateMutate(data);
+    },
+    updateMutate(data){
+      const UPDATE_DONE = gql`mutation updateTodoMutation($header_id: Int!, $id: Int!, $done: Boolean = false, $name: String = "", $updated: timestamp = "") {
+                                        update_todo_list_by_pk(pk_columns: {header_id: $header_id, id: $id}, _set: {updated: $updated, name: $name, done: $done}) {
+                                          id
+                                          header_id
+                                        }
+                                      }`
+      this.$refs.spinner.show()
+      this.$apollo.mutate({
+            mutation: UPDATE_DONE,
+            variables: {
+                        header_id: data.header_id
+                        , id: data.id
+                        , done: data.done
+                        , name: data.name
+                        , updated: this.getNowFormatted()
+                      }
+          })
+      .catch((error) => {
+        this.$refs.snackBar.setMessageAndshow('update error!')
+        console.error(error)
+      }).finally(() => {
+        this.$refs.spinner.close()
+      })
+    },
+    onDelete(data){
+      const DELETE_TODO = gql`mutation deleteTodoMutation($header_id: Int!, $id: Int!) {
+                                        delete_todo_list_by_pk(id: $id, header_id: $header_id) {
+                                          header_id
+                                          id
+                                        }
+                                      }`
+      this.$refs.spinner.show()
+      this.mutateApollo(DELETE_TODO, {
+                        header_id: data.header_id
+                        , id: data.id
+       }).catch((error) => {
+        this.$refs.snackBar.setMessageAndshow('delete error!')
+        console.error(error)
+      }).finally(() => {
+        this.$refs.spinner.close()
+      })
+    },
+    onAdd(){
+      const now = this.getNowFormatted()
+
+      if(this.selectedHeadrId === 0){
+        console.error("未選択")
+        return
+      }
+      
+      const CREATE_TODO = gql`mutation createTodoMutation($header_id: Int!, 
+                                                  $id: Int!, 
+                                                  $done: Boolean = false, 
+                                                  $name: String = "", 
+                                                  $created: timestamp = "", 
+                                                  $updated: timestamp = "") {
+                                insert_todo_list_one(object: {header_id: $header_id, id: $id, done: $done, name: $name, created: $created, updated: $updated}) {
+                                  header_id
+                                  id
+                                  done
+                                  name
+                                  created
+                                  updated
+                                }
+                              }`
+
+      this.$refs.spinner.show()
+      this.$apollo.queries.todo_list_aggregate.refetch({
+          selectedHeadrId: this.selectedHeadrId
+      }).then(() => {
+        return this.mutateApollo(CREATE_TODO, {
+                        header_id:this.selectedHeadrId
+                        , id:this.todo_list_aggregate.aggregate.max.id + 1
+                        , done: false
+                        , name: ""
+                        , created: now
+                        , updated: now
+                      });
+      }).catch((error) => {
+        this.$refs.snackBar.setMessageAndshow('add error!')
+        console.error(error)
+      }).finally(() => {
+        this.$refs.spinner.close()
+      })
+    },
+    loading(){
+      return this.$apollo.queries.todo_list.loading
+    },
+    getNowFormatted(){
+      return this.formattedData()
+    },
+    formattedData(param){
+      return moment(param).format("YYYY-MM-DDTHH:mm:ss.SSS")
+    },
+    reFetch(titleId){
+      this.$refs.spinner.show()
+      this.$apollo.queries.todo_list.refetch({
+        selectedHeadrId: titleId
+      }).then(() => {
+        this.selectedHeadrId = titleId
+      }).finally(() => {
+        this.$refs.spinner.close()
+      })
+    },
+    mutateApollo(gqlMutation, variables){
+      const promise = this.$apollo.mutate({
+            mutation: gqlMutation,
+            variables: variables
+          })
+      .then(() => {
+        this.reFetch(this.selectedHeadrId)
+        return new Promise(resolve => {resolve()})
+      })
+      .catch((error) => {
+        return new Promise((resolve, reject) => {reject(error)})
+      })
+      return promise
+    },
+  },
+  data() {
+    return {
+      selectedHeadrId: 0,
+      titleName: '',
+      snackText: '',
+    }
+  },
+  apollo: {
+    // Simple query that will update the 'hello' vue property
+    todo_header: gql`query {
+        todo_header {
+        id
+        name
+      }
+    }`,
+    todo_list: gql`query ($selectedHeadrId: Int){
+        todo_list (where: {header_id: {_eq: $selectedHeadrId}}, order_by: {id: asc}) {
+          created
+          done
+          header_id
+          id
+          name
+          updated
+        }
+    }`,
+    todo_list_aggregate: gql`query ($selectedHeadrId: Int){
+        todo_list_aggregate(where: {header_id: {_eq: $selectedHeadrId}}) {
+          aggregate {
+            max {
+              id
+            }
+          }
+        }
+    }`,
+    
+  },
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+</style>
index 332b916..0ac53a3 100644 (file)
@@ -1,7 +1,9 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
+import axios from 'axios'
+import VueAxios from 'vue-axios'
 
-Vue.use(Vuex)
+Vue.use(Vuex, VueAxios, axios)
 
 export default new Vuex.Store({
   state: {
@@ -9,6 +11,14 @@ export default new Vuex.Store({
   mutations: {
   },
   actions: {
+    test(){
+      axios.get('http://localhost:19080/todo/api/findHeaders')
+      .then((response) => {
+        console.error(response)
+      }).catch((error) => {
+        console.error(error)
+      });
+    }
   },
   modules: {
   }
index 89e08ff..877d995 100644 (file)
@@ -1,5 +1,17 @@
 <template>
   <div class="about">
-    <h1>This app is currently under development...</h1>
+    <todo-app-java/>
   </div>
 </template>
+<script>
+
+// @ is an alias to /src
+import todoAppJava from '@/components/todoAppJava.vue'
+
+export default {
+  name: 'Home',
+  components: {
+    todoAppJava
+  }
+}
+</script>
\ No newline at end of file