Compare commits
No commits in common. "631629d9ddfadae95ad6c7af2e0a054e29173834" and "5ff12cab9d8df1fe90814b2ec7e2929a81af6dad" have entirely different histories.
631629d9dd
...
5ff12cab9d
5
.env
5
.env
@ -8,4 +8,9 @@ VUE_APP_AUTH_HOST="http://localhost:2000"
|
|||||||
VUE_APP_BACKEND_HOST="http://localhost:3000"
|
VUE_APP_BACKEND_HOST="http://localhost:3000"
|
||||||
|
|
||||||
#LocalStorage는 Edge 브라우저의 개발툴 > 응용프로그램 > 로컬 저장소에서 확인가능
|
#LocalStorage는 Edge 브라우저의 개발툴 > 응용프로그램 > 로컬 저장소에서 확인가능
|
||||||
|
VUE_APP_SESSIONSTORAGE_JWT_NAME="access_token"
|
||||||
|
VUE_APP_SESSIONSTORAGE_REDIRECT_NAME = "RedirectPATH"
|
||||||
|
|
||||||
|
|
||||||
VUE_APP_TABLE_DEFAULT_PERPAGE = 10
|
VUE_APP_TABLE_DEFAULT_PERPAGE = 10
|
||||||
|
VUE_APP_TABLE_DEFAULT_TABLE_PAGE = 1
|
||||||
@ -42,16 +42,18 @@
|
|||||||
</b-input-group>
|
</b-input-group>
|
||||||
</validation-provider>
|
</validation-provider>
|
||||||
<b-button type="submit" variant="primary">Login</b-button>
|
<b-button type="submit" variant="primary">Login</b-button>
|
||||||
|
<b-button type="reset" variant="danger" @click="onReset()"
|
||||||
|
>Reset</b-button
|
||||||
|
>
|
||||||
</b-form>
|
</b-form>
|
||||||
</validation-observer>
|
</validation-observer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// 참고 : https://kdydesign.github.io/2019/04/06/vuejs-vuex-helper/
|
import axios from 'axios'
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
//console.log(this.$route)
|
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
email: null,
|
email: null,
|
||||||
@ -79,21 +81,66 @@ export default {
|
|||||||
getValidationState({ dirty, validated, valid = null }) {
|
getValidationState({ dirty, validated, valid = null }) {
|
||||||
return dirty || validated ? valid : null
|
return dirty || validated ? valid : null
|
||||||
},
|
},
|
||||||
onSubmit() {
|
async onSubmit() {
|
||||||
this.$store
|
const result = await this.callAPI('/auth/login', {
|
||||||
.dispatch('AuthStore/login', {
|
|
||||||
email: this.form.email,
|
email: this.form.email,
|
||||||
password: this.form.password
|
password: this.form.password
|
||||||
})
|
})
|
||||||
|
console.log(result)
|
||||||
|
if (!result) {
|
||||||
|
console.log(result)
|
||||||
|
sessionStorage.removeItem(process.env.VUE_APP_SESSIONSTORAGE_JWT_NAME)
|
||||||
|
alert('로그인 실패...')
|
||||||
|
//this.$router.back()
|
||||||
|
} else {
|
||||||
|
// localStorage를 사용하면, 브라우저에 key-value 값을 Storage에 저장할 수 있습니다
|
||||||
|
sessionStorage.setItem(
|
||||||
|
process.env.VUE_APP_SESSIONSTORAGE_JWT_NAME,
|
||||||
|
result
|
||||||
|
)
|
||||||
|
alert('로그인 성공...')
|
||||||
|
//저장된 redirect path를 이용 이동시킴
|
||||||
|
this.$router.replace(
|
||||||
|
sessionStorage.getItem(
|
||||||
|
process.env.VUE_APP_SESSIONSTORAGE_REDIRECT_NAME
|
||||||
|
) || '/'
|
||||||
|
)
|
||||||
|
//저장된 정보 CLear
|
||||||
|
this.onReset()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onReset() {
|
||||||
|
// Reset our form values
|
||||||
|
this.form.email = ''
|
||||||
|
this.form.pasword = ''
|
||||||
|
//저장된 redirect path Clear
|
||||||
|
sessionStorage.removeItem(
|
||||||
|
process.env.VUE_APP_SESSIONSTORAGE_REDIRECT_NAME
|
||||||
|
)
|
||||||
|
// Trick to reset/clear native browser form validation state
|
||||||
|
// this.$nextTick(() => {
|
||||||
|
// this.$refs.observer.reset()
|
||||||
|
// })
|
||||||
|
},
|
||||||
|
async callAPI(url, params) {
|
||||||
|
console.log('CallAPI..', [url, params])
|
||||||
|
axios.defaults.baseURL = process.env.VUE_APP_AUTH_HOST
|
||||||
|
//전송 Header에 추가
|
||||||
|
const headers = {
|
||||||
|
Authorization:
|
||||||
|
'Bearer ' +
|
||||||
|
sessionStorage.getItem(process.env.VUE_APP_SESSIONSTORAGE_JWT_NAME)
|
||||||
|
}
|
||||||
|
return await axios
|
||||||
|
.post(url, params, headers)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.log(response)
|
// console.log(response)
|
||||||
const return_url = this.$route.params.return_url || 'home'
|
return response.status === 201 ? response.data : null
|
||||||
alert('로그인 성공... -> ' + return_url)
|
|
||||||
this.$router.push({ name: return_url }).catch((e) => {
|
|
||||||
console.log(e)
|
|
||||||
})
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
return null
|
||||||
})
|
})
|
||||||
.catch(({ message }) => alert('로그인 실패...:' + message))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,104 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- 참조: https://codesandbox.io/s/3v0m1?file=/src/components/board/BoardList.vue -->
|
|
||||||
<b-table
|
|
||||||
ref="BTable"
|
|
||||||
:page="page"
|
|
||||||
:items="items"
|
|
||||||
:fields="fields"
|
|
||||||
:per-page="perPage"
|
|
||||||
:sort-by.sync="sortBy"
|
|
||||||
:sort-desc.sync="sortDesc"
|
|
||||||
@sort-changed="sortClick"
|
|
||||||
selectable
|
|
||||||
select-mode="multi"
|
|
||||||
@row-selected="selectedRowToggle"
|
|
||||||
:sticky-header="commonTableAttributes.stickyHeader"
|
|
||||||
:no-border-collapse="commonTableAttributes.noBorderCollapse"
|
|
||||||
:striped="commonTableAttributes.striped"
|
|
||||||
:hover="commonTableAttributes.hover"
|
|
||||||
:no-local-sorting="commonTableAttributes.noLocalSorting"
|
|
||||||
:bordered="commonTableAttributes.bordered"
|
|
||||||
:dark="commonTableAttributes.dark"
|
|
||||||
:head-variant="commonTableAttributes.headVariant"
|
|
||||||
>
|
|
||||||
<!-- Field별 Filter용 -->
|
|
||||||
<template #head(is_done)="fields">
|
|
||||||
<b-form-select
|
|
||||||
:value="filterIsDone"
|
|
||||||
:options="fields.field.Options"
|
|
||||||
@change="isDoneClick"
|
|
||||||
></b-form-select>
|
|
||||||
</template>
|
|
||||||
<!-- 비/선택 Row 토글용 -->
|
|
||||||
<template #cell(rowSelect)="{ rowSelected }">
|
|
||||||
<template v-if="rowSelected">✓</template>
|
|
||||||
</template>
|
|
||||||
<!-- Row의 Index 이용한 번호 출력용 -->
|
|
||||||
<template #cell(id)="row">
|
|
||||||
<b-link ref="edit/{{row.item.id}}">
|
|
||||||
{{ total - (page * perPage + row.index) + parseInt(perPage) }}
|
|
||||||
</b-link>
|
|
||||||
</template>
|
|
||||||
<!-- 제목부분 출력용 -->
|
|
||||||
<template #cell(title)="row">
|
|
||||||
{{ row.item.title }}
|
|
||||||
</template>
|
|
||||||
<!-- 상세 내용 출력용 -->
|
|
||||||
<template #cell(content)="row">
|
|
||||||
<b-button size="sm" @click="row.toggleDetails" class="mr-2">
|
|
||||||
[{{ row.item.id }}] {{ row.detailsShowing ? '숨기기' : '보기' }}
|
|
||||||
</b-button>
|
|
||||||
</template>
|
|
||||||
<template #row-details="row">
|
|
||||||
<b-card>
|
|
||||||
<b-row>
|
|
||||||
<b-col v-html="row.item.content"></b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-button size="sm" @click="row.toggleDetails">숨기기</b-button>
|
|
||||||
</b-card>
|
|
||||||
</template>
|
|
||||||
<!-- 사용여부 출력용 -->
|
|
||||||
<template #cell(is_done)="row">
|
|
||||||
{{ row.value }}
|
|
||||||
</template>
|
|
||||||
</b-table>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'TableComponent',
|
|
||||||
props: [
|
|
||||||
'fields',
|
|
||||||
'items',
|
|
||||||
'total',
|
|
||||||
'page',
|
|
||||||
'perPage',
|
|
||||||
'selectedRows',
|
|
||||||
'filterIsDone'
|
|
||||||
],
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
perPageOptions: [
|
|
||||||
{ text: '5줄', value: 5 },
|
|
||||||
{ text: '10줄', value: 10 },
|
|
||||||
{ text: '30줄', value: 30 },
|
|
||||||
{ text: '60줄', value: 60 },
|
|
||||||
{ text: '100줄', value: 100 }
|
|
||||||
],
|
|
||||||
// 속성옵션
|
|
||||||
commonTableAttributes: {
|
|
||||||
stickyHeader: '50%',
|
|
||||||
//noBorderCollapse: false,
|
|
||||||
striped: true,
|
|
||||||
hover: true,
|
|
||||||
noLocalSorting: true,
|
|
||||||
bordered: true,
|
|
||||||
dark: false,
|
|
||||||
headVariant: 'light'
|
|
||||||
},
|
|
||||||
sortBy: 'id',
|
|
||||||
sortDesc: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped></style>
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
<template>
|
|
||||||
<b-container fluid>
|
|
||||||
<b-row>
|
|
||||||
<b-col class="border">
|
|
||||||
<b-input-group>
|
|
||||||
<label class="input-group-text">
|
|
||||||
<b-form-checkbox @change="selectedRowAllToggle"
|
|
||||||
>All</b-form-checkbox
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
</b-input-group>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="4" class="border">
|
|
||||||
<b-input-group>
|
|
||||||
<label class="input-group-text">
|
|
||||||
<b-form-checkbox-group
|
|
||||||
class="d-flex flex-nowrap"
|
|
||||||
v-model="searchFields"
|
|
||||||
:options="searchFieldOptions"
|
|
||||||
></b-form-checkbox-group>
|
|
||||||
</label>
|
|
||||||
<b-form-input
|
|
||||||
v-model="search"
|
|
||||||
type="text"
|
|
||||||
placeholder="검색어"
|
|
||||||
@keydown.enter="searchClick"
|
|
||||||
></b-form-input>
|
|
||||||
<b-button @click="searchClick">검색</b-button>
|
|
||||||
</b-input-group>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="4" class="border">
|
|
||||||
<b-input-group>
|
|
||||||
<b-form-select
|
|
||||||
class="d-flex flex-nowrap"
|
|
||||||
:value="filterDateField"
|
|
||||||
:options="filterDateFieldOptions"
|
|
||||||
></b-form-select>
|
|
||||||
<b-form-input :value="filterDateStart" type="date"></b-form-input>
|
|
||||||
~
|
|
||||||
<b-form-input :value="filterDateEnd" type="date"></b-form-input>
|
|
||||||
<b-button @click="dateClick">선택</b-button>
|
|
||||||
</b-input-group>
|
|
||||||
</b-col>
|
|
||||||
<b-col class="border">
|
|
||||||
<b-input-group class="justify-content-end">
|
|
||||||
<label class="input-group-text">줄수</label>
|
|
||||||
<b-form-select
|
|
||||||
:value="perPage"
|
|
||||||
:options="perPageOptions"
|
|
||||||
@change="perPageClick"
|
|
||||||
></b-form-select>
|
|
||||||
</b-input-group>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'TableHeaderComponent',
|
|
||||||
props: [
|
|
||||||
'searchFields',
|
|
||||||
'searchFieldOptions',
|
|
||||||
'filterDateField',
|
|
||||||
'filterDateFieldOptions',
|
|
||||||
'filterDateStart',
|
|
||||||
'filterDateEnd'
|
|
||||||
],
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
perPageOptions: [
|
|
||||||
{ text: '5줄', value: 5 },
|
|
||||||
{ text: '10줄', value: 10 },
|
|
||||||
{ text: '30줄', value: 30 },
|
|
||||||
{ text: '60줄', value: 60 },
|
|
||||||
{ text: '100줄', value: 100 }
|
|
||||||
],
|
|
||||||
search: null,
|
|
||||||
filter: null,
|
|
||||||
filterField: null,
|
|
||||||
filterDateStart: null,
|
|
||||||
filterDateEnd: null,
|
|
||||||
selectedRowAll: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped></style>
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<b-pagination
|
|
||||||
:total-rows="total"
|
|
||||||
:page="page"
|
|
||||||
:per-page="perPage"
|
|
||||||
@page-click="pageClick"
|
|
||||||
last-number
|
|
||||||
class="justify-content-center"
|
|
||||||
>
|
|
||||||
</b-pagination>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'TablePaginationComponent',
|
|
||||||
props: ['total', 'page', 'perPage', 'pageClick']
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped></style>
|
|
||||||
@ -31,51 +31,20 @@
|
|||||||
<b-dropdown-item href="#">FA</b-dropdown-item>
|
<b-dropdown-item href="#">FA</b-dropdown-item>
|
||||||
</b-nav-item-dropdown> -->
|
</b-nav-item-dropdown> -->
|
||||||
|
|
||||||
<template v-if="isAuthenticated">
|
|
||||||
<b-nav-item-dropdown right>
|
<b-nav-item-dropdown right>
|
||||||
<!-- Using 'button-content' slot -->
|
<!-- Using 'button-content' slot -->
|
||||||
<template #button-content>
|
<template #button-content>
|
||||||
<em>User</em>
|
<em>User</em>
|
||||||
</template>
|
</template>
|
||||||
<b-dropdown-item href="/profile">Profile</b-dropdown-item>
|
<b-dropdown-item href="#">Profile</b-dropdown-item>
|
||||||
<b-dropdown-item @click="logout()">Sign Out</b-dropdown-item>
|
<b-dropdown-item href="#">Sign Out</b-dropdown-item>
|
||||||
</b-nav-item-dropdown>
|
</b-nav-item-dropdown>
|
||||||
</template>
|
|
||||||
<template v-else
|
|
||||||
><b-dropdown-item href="/login"
|
|
||||||
>Login {{ isAuthenticated }}</b-dropdown-item
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</b-navbar-nav>
|
</b-navbar-nav>
|
||||||
</b-collapse>
|
</b-collapse>
|
||||||
</b-navbar>
|
</b-navbar>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { createNamespacedHelpers } from 'vuex'
|
|
||||||
const authStore = createNamespacedHelpers('AuthStore')
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HeaderLayout',
|
name: 'HeaderLayout'
|
||||||
computed: {
|
|
||||||
...authStore.mapGetters(['isAuthenticated'])
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
redirect() {
|
|
||||||
if (!this.isAuthenticated && this.$router.name != 'home') {
|
|
||||||
this.$router
|
|
||||||
.push({
|
|
||||||
name: 'home'
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e + ':' + this.$router)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
logout() {
|
|
||||||
this.$store
|
|
||||||
.dispatch('AuthStore/logout', {})
|
|
||||||
.then(() => this.redirect())
|
|
||||||
.catch(({ message }) => alert(message))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,4 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<b-modal
|
||||||
|
id="inputForm"
|
||||||
|
centered
|
||||||
|
title="입력폼"
|
||||||
|
size="lg"
|
||||||
|
:header-bg-variant="headerBgVariant"
|
||||||
|
:header-text-variant="headerTextVariant"
|
||||||
|
:body-bg-variant="bodyBgVariant"
|
||||||
|
:body-text-variant="bodyTextVariant"
|
||||||
|
:footer-bg-variant="footerBgVariant"
|
||||||
|
:footer-text-variant="footerTextVariant"
|
||||||
|
>
|
||||||
<validation-observer ref="observer" v-slot="{ handleSubmit }">
|
<validation-observer ref="observer" v-slot="{ handleSubmit }">
|
||||||
<b-form @submit.stop.prevent="handleSubmit(onSubmit)">
|
<b-form @submit.stop.prevent="handleSubmit(onSubmit)">
|
||||||
<validation-provider
|
<validation-provider
|
||||||
@ -48,11 +61,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</b-form>
|
</b-form>
|
||||||
</validation-observer>
|
</validation-observer>
|
||||||
|
</b-modal>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
//import { VueEditor } from 'vue2-editor/dist/vue2-editor.core.js'
|
//import { VueEditor } from 'vue2-editor/dist/vue2-editor.core.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {},
|
components: {},
|
||||||
data() {
|
data() {
|
||||||
@ -77,7 +93,23 @@ export default {
|
|||||||
rules: { required: true, min: 10 },
|
rules: { required: true, min: 10 },
|
||||||
style: 'height: 200px'
|
style: 'height: 200px'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
variants: [
|
||||||
|
'primary',
|
||||||
|
'secondary',
|
||||||
|
'success',
|
||||||
|
'warning',
|
||||||
|
'danger',
|
||||||
|
'info',
|
||||||
|
'light',
|
||||||
|
'dark'
|
||||||
|
],
|
||||||
|
headerBgVariant: 'dark',
|
||||||
|
headerTextVariant: 'light',
|
||||||
|
bodyBgVariant: 'light',
|
||||||
|
bodyTextVariant: 'dark',
|
||||||
|
footerBgVariant: 'warning',
|
||||||
|
footerTextVariant: 'dark'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@ -60,9 +60,10 @@
|
|||||||
</b-row>
|
</b-row>
|
||||||
</b-container>
|
</b-container>
|
||||||
<b-table
|
<b-table
|
||||||
ref="BTable"
|
id="todoTable"
|
||||||
|
ref="todoTable"
|
||||||
:page="page"
|
:page="page"
|
||||||
:items="getRows"
|
:items="rows"
|
||||||
:fields="fields"
|
:fields="fields"
|
||||||
:per-page="perPage"
|
:per-page="perPage"
|
||||||
:sort-by.sync="sortBy"
|
:sort-by.sync="sortBy"
|
||||||
@ -74,6 +75,7 @@
|
|||||||
:select-mode="selectedRowMode"
|
:select-mode="selectedRowMode"
|
||||||
selectable
|
selectable
|
||||||
@row-selected="rowSelectedToggle"
|
@row-selected="rowSelectedToggle"
|
||||||
|
:busy="isBusy"
|
||||||
:sticky-header="commonTableAttributes.stickyHeader"
|
:sticky-header="commonTableAttributes.stickyHeader"
|
||||||
:no-border-collapse="commonTableAttributes.noBorderCollapse"
|
:no-border-collapse="commonTableAttributes.noBorderCollapse"
|
||||||
:striped="commonTableAttributes.striped"
|
:striped="commonTableAttributes.striped"
|
||||||
@ -94,11 +96,12 @@
|
|||||||
<!-- 비/선택 Row 토글용 -->
|
<!-- 비/선택 Row 토글용 -->
|
||||||
<template #cell(rowSelect)="{ rowSelected }">
|
<template #cell(rowSelect)="{ rowSelected }">
|
||||||
<template v-if="rowSelected"> ✓ </template>
|
<template v-if="rowSelected"> ✓ </template>
|
||||||
|
<template v-else> </template>
|
||||||
</template>
|
</template>
|
||||||
<!-- Row의 Index 이용한 번호 출력용 -->
|
<!-- Row의 Index 이용한 번호 출력용 -->
|
||||||
<template #cell(id)="row">
|
<template #cell(id)="row">
|
||||||
<b-link ref="edit/{{row.item.id}}">
|
<b-link ref="edit/{{row.item.id}}">
|
||||||
{{ getTotal - (page * perPage + row.index) + Number(perPage) }}
|
{{ total - (page * perPage + row.index) + perPage }}
|
||||||
</b-link>
|
</b-link>
|
||||||
</template>
|
</template>
|
||||||
<!-- 제목부분 출력용 -->
|
<!-- 제목부분 출력용 -->
|
||||||
@ -123,6 +126,13 @@
|
|||||||
<template #cell(is_done)="row">
|
<template #cell(is_done)="row">
|
||||||
{{ row.value }}
|
{{ row.value }}
|
||||||
</template>
|
</template>
|
||||||
|
<!-- 데이터 로딩중 출력용 -->
|
||||||
|
<template #table-busy>
|
||||||
|
<div class="text-center text-danger my-2">
|
||||||
|
<b-spinner class="align-middle"></b-spinner>
|
||||||
|
<strong>Loading...</strong>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</b-table>
|
</b-table>
|
||||||
<b-container fluid>
|
<b-container fluid>
|
||||||
<b-row>
|
<b-row>
|
||||||
@ -132,33 +142,32 @@
|
|||||||
<b-col>
|
<b-col>
|
||||||
<b-pagination
|
<b-pagination
|
||||||
:page="page"
|
:page="page"
|
||||||
:total-rows="getTotal"
|
:total-rows="total"
|
||||||
:per-page="perPage"
|
:per-page="perPage"
|
||||||
@page-click="pageClick"
|
@page-click="pageClick"
|
||||||
last-number
|
last-number
|
||||||
|
aria-controls="todoTable"
|
||||||
class="justify-content-center"
|
class="justify-content-center"
|
||||||
>
|
>
|
||||||
</b-pagination>
|
</b-pagination>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col> </b-col>
|
<b-col>
|
||||||
|
<b-input-group class="justify-content-end">
|
||||||
|
<b-button @click="busyToggle">Toggle Busy State</b-button>
|
||||||
|
</b-input-group>
|
||||||
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
</b-container>
|
</b-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { createNamespacedHelpers } from 'vuex'
|
|
||||||
const todoStore = createNamespacedHelpers('TodoStore')
|
|
||||||
// 참조 : https://vuejsexamples.com/vuejs-tables-and-select-all-checkbox/
|
// 참조 : https://vuejsexamples.com/vuejs-tables-and-select-all-checkbox/
|
||||||
|
import axios from 'axios'
|
||||||
export default {
|
export default {
|
||||||
components: {},
|
components: {},
|
||||||
computed: {
|
|
||||||
...todoStore.mapGetters(['getTotal', 'getRows'])
|
|
||||||
},
|
|
||||||
created: function () {
|
|
||||||
this.setDatas()
|
|
||||||
},
|
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
rows: [],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
key: 'rowSelect',
|
key: 'rowSelect',
|
||||||
@ -212,7 +221,8 @@ export default {
|
|||||||
sortByFormatted: true //fomatter결과에따른 Sort가 필요시 true
|
sortByFormatted: true //fomatter결과에따른 Sort가 필요시 true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
page: 1, // 현재 페이지
|
total: 0,
|
||||||
|
page: process.env.VUE_APP_TABLE_DEFAULT_PAGE, // 현재 페이지
|
||||||
perPage: process.env.VUE_APP_TABLE_DEFAULT_PERPAGE, // 페이지당 보여줄 갯수
|
perPage: process.env.VUE_APP_TABLE_DEFAULT_PERPAGE, // 페이지당 보여줄 갯수
|
||||||
perPageOptions: [
|
perPageOptions: [
|
||||||
{ text: '5줄', value: 5 },
|
{ text: '5줄', value: 5 },
|
||||||
@ -232,6 +242,7 @@ export default {
|
|||||||
dark: false,
|
dark: false,
|
||||||
headVariant: 'light'
|
headVariant: 'light'
|
||||||
},
|
},
|
||||||
|
isBusy: false,
|
||||||
sortBy: 'id',
|
sortBy: 'id',
|
||||||
sortDesc: true,
|
sortDesc: true,
|
||||||
search: null,
|
search: null,
|
||||||
@ -256,10 +267,17 @@ export default {
|
|||||||
selectedRowModes: ['multi', 'single', 'range']
|
selectedRowModes: ['multi', 'single', 'range']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setup: function () {},
|
||||||
|
created: function () {},
|
||||||
|
mounted: function () {
|
||||||
|
this.getDatas()
|
||||||
|
},
|
||||||
|
unmounted() {},
|
||||||
methods: {
|
methods: {
|
||||||
setDatas(page = 1) {
|
async getDatas(page = 1) {
|
||||||
this.$store
|
this.isBusy = true
|
||||||
.dispatch('TodoStore/setData', {
|
const results = await this.callAPI('/todo', {
|
||||||
|
params: {
|
||||||
page: page,
|
page: page,
|
||||||
perPage: this.perPage,
|
perPage: this.perPage,
|
||||||
sortBy: this.sortBy,
|
sortBy: this.sortBy,
|
||||||
@ -270,60 +288,90 @@ export default {
|
|||||||
filterField: this.filterField,
|
filterField: this.filterField,
|
||||||
filterDateStart: this.filterDateStart,
|
filterDateStart: this.filterDateStart,
|
||||||
filterDateEnd: this.filterDateEnd
|
filterDateEnd: this.filterDateEnd
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
//console.log(JSON.stringify(results))
|
||||||
alert(error)
|
console.log(results)
|
||||||
})
|
this.total = results.total
|
||||||
|
this.perPage = results.perPage
|
||||||
|
this.page = results.page
|
||||||
|
this.sortBy = results.sortBy
|
||||||
|
this.sortDesc = results.sortDesc === 'true' ? true : false
|
||||||
|
this.rows = results.rows
|
||||||
|
this.isBusy = false
|
||||||
},
|
},
|
||||||
searchClick() {
|
searchClick() {
|
||||||
this.setDatas()
|
this.getDatas()
|
||||||
},
|
},
|
||||||
pageClick(event, page) {
|
pageClick(bvEvent, page) {
|
||||||
//console.log(event)
|
console.log(bvEvent)
|
||||||
this.setDatas(page)
|
this.getDatas(page)
|
||||||
// event.preventDefault()
|
// bvEvent.preventDefault()
|
||||||
},
|
},
|
||||||
perPageClick(perPage) {
|
perPageClick(perPage) {
|
||||||
this.perPage = perPage
|
this.perPage = perPage
|
||||||
//console.log(this.perPage)
|
console.log(this.perPage)
|
||||||
this.setDatas()
|
this.getDatas()
|
||||||
},
|
},
|
||||||
sortClick(event) {
|
sortClick(event) {
|
||||||
//console.log(event)
|
console.log(event)
|
||||||
this.sortBy = event.sortBy
|
this.sortBy = event.sortBy
|
||||||
this.sortDesc = event.sortDesc
|
this.sortDesc = event.sortDesc
|
||||||
this.setDatas()
|
this.getDatas()
|
||||||
},
|
},
|
||||||
dateClick() {
|
dateClick() {
|
||||||
this.filterField = this.filterDateField
|
this.filterField = this.filterDateField
|
||||||
this.setDatas()
|
this.getDatas()
|
||||||
},
|
},
|
||||||
isDoneClick() {
|
isDoneClick() {
|
||||||
this.filter = this.filterIsDone
|
this.filter = this.filterIsDone
|
||||||
this.filterField = 'is_done'
|
this.filterField = 'is_done'
|
||||||
this.setDatas()
|
this.getDatas()
|
||||||
|
},
|
||||||
|
busyToggle() {
|
||||||
|
this.isBusy = !this.isBusy
|
||||||
},
|
},
|
||||||
rowSelectedToggle(selectedRow) {
|
rowSelectedToggle(selectedRow) {
|
||||||
this.selectedRows = selectedRow
|
this.selectedRows = selectedRow
|
||||||
},
|
},
|
||||||
rowSelectAllToggle() {
|
rowSelectAllToggle() {
|
||||||
if (this.selectedRowAllToggle) {
|
if (this.selectedRowAllToggle) {
|
||||||
this.$refs.BTable.clearSelected()
|
this.$refs.todoTable.clearSelected()
|
||||||
this.selectedRowAllToggle = false
|
this.selectedRowAllToggle = false
|
||||||
} else {
|
} else {
|
||||||
this.$refs.BTable.selectAllRows()
|
this.$refs.todoTable.selectAllRows()
|
||||||
this.selectedRowAllToggle = true
|
this.selectedRowAllToggle = true
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
// rowSelectSet(id) {
|
// rowSelectSet(id) {
|
||||||
// // Rows are indexed from 0, so the third row is index 2
|
// // Rows are indexed from 0, so the third row is index 2
|
||||||
// this.$refs.BTable.selectRow(id)
|
// this.$refs.todoTable.selectRow(id)
|
||||||
// },
|
// },
|
||||||
// rowSelectUnSet(id) {
|
// rowSelectUnSet(id) {
|
||||||
// // Rows are indexed from 0, so the third row is index 2
|
// // Rows are indexed from 0, so the third row is index 2
|
||||||
// this.$refs.BTable.unselectRow(id)
|
// this.$refs.todoTable.unselectRow(id)
|
||||||
// }
|
// }
|
||||||
|
async callAPI(url, params) {
|
||||||
|
console.log('CallAPI..', [url, params])
|
||||||
|
axios.defaults.baseURL = process.env.VUE_APP_BACKEND_HOST
|
||||||
|
//전송 Header에 추가
|
||||||
|
const headers = {
|
||||||
|
Authorization:
|
||||||
|
'Bearer ' +
|
||||||
|
sessionStorage.getItem(process.env.VUE_APP_LOCALSTORAGE_NAME)
|
||||||
}
|
}
|
||||||
|
return await axios
|
||||||
|
.get(url, params, headers)
|
||||||
|
.then((response) => {
|
||||||
|
return response.status === 200 ? response.data : []
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import HomeView from '../views/HomeView.vue'
|
import HomeView from '../views/HomeView.vue'
|
||||||
import store from '../store'
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
@ -33,8 +33,8 @@ const routes = [
|
|||||||
component: () =>
|
component: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "api", webpackPrefetch:true */ '@/views/todoView.vue'
|
/* webpackChunkName: "api", webpackPrefetch:true */ '@/views/todoView.vue'
|
||||||
),
|
)
|
||||||
meta: { requiredAuth: true }
|
//meta: { requiredAuth: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -52,6 +52,21 @@ const router = new VueRouter({
|
|||||||
// 1. 전역가드 : router.beforeEach((to, from, next) 이런식으로 전체에 대해 특정조건 (meta: { requiredAuth: true })으로 사용
|
// 1. 전역가드 : router.beforeEach((to, from, next) 이런식으로 전체에 대해 특정조건 (meta: { requiredAuth: true })으로 사용
|
||||||
// 2. 라우터 가드: 특정 Route Path아래에 직접선언-> beforeEach: function(to, from, next){}
|
// 2. 라우터 가드: 특정 Route Path아래에 직접선언-> beforeEach: function(to, from, next){}
|
||||||
// 3. 컴포넌트 가드: 특정 vue 파일내에서 바로 선언해서 사용 :// view/Mypage.vue ( Mypage Components )
|
// 3. 컴포넌트 가드: 특정 vue 파일내에서 바로 선언해서 사용 :// view/Mypage.vue ( Mypage Components )
|
||||||
|
// export default {
|
||||||
|
// name: "Mypage",
|
||||||
|
// beforeRouteEnter(to, from, next) {
|
||||||
|
// // Login 컴포넌트가 화면에 표시되기 전에 수행될 로직
|
||||||
|
// // Login 컴포넌트는 아직 생성되지 않은 시점
|
||||||
|
// },
|
||||||
|
// beforeRouteUpdate(to, from, next) {
|
||||||
|
// // 화면에 표시된 컴포넌트가 변경될 때 수행될 로직
|
||||||
|
// // `this`로 Login 컴포넌트를 접근할 수 있음
|
||||||
|
// },
|
||||||
|
// beforeRouteLeave(to, from, next) {
|
||||||
|
// // Login 컴포넌트를 화면에 표시한 url 값이 변경되기 직전의 로직
|
||||||
|
// // `this`로 Login 컴포넌트를 접근할 수 있음
|
||||||
|
// },
|
||||||
|
// }
|
||||||
// 로그인 처리 과정용
|
// 로그인 처리 과정용
|
||||||
// to : 이동할 url 정보가 담긴 라우터 객체
|
// to : 이동할 url 정보가 담긴 라우터 객체
|
||||||
// from : 현재 url 정보가 담긴 라우터 객체
|
// from : 현재 url 정보가 담긴 라우터 객체
|
||||||
@ -59,21 +74,26 @@ const router = new VueRouter({
|
|||||||
//여기에서 login은 path가 아니라 name에서 찾는다
|
//여기에서 login은 path가 아니라 name에서 찾는다
|
||||||
//router.beforeEach()를 호출하고 나면 모든 라우팅이 대기 상태가 된다
|
//router.beforeEach()를 호출하고 나면 모든 라우팅이 대기 상태가 된다
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
|
console.log('라우딩 대기')
|
||||||
//1. routes 설정에서 meta: { requiredAuth: true } 가 선언된 경우
|
//1. routes 설정에서 meta: { requiredAuth: true } 가 선언된 경우
|
||||||
if (to.matched.some((route) => route.meta.requiredAuth)) {
|
if (to.matched.some((routeRecord) => routeRecord.meta.requiredAuth)) {
|
||||||
//2. 로그인 인증 않된 경우
|
//2. 로그인 인증 않된 경우
|
||||||
//console.log(store.getters)
|
//sessionStorage Access-Token이 없으면 Login페이지로 전송
|
||||||
//console.log(store.getters['AuthStore/isAuthenticated'])
|
if (!sessionStorage.getItem(process.env.VUE_APP_SESSIONSTORAGE_JWT_NAME)) {
|
||||||
if (!store.getters['AuthStore/isAuthenticated']) {
|
console.log(from.path + ' => 3. Login 페이지 이동 => 로그인 페이지')
|
||||||
console.log(from.name + ' => 3. To[' + to.name + '] => 로그인')
|
//로그인 성공 후 이동할 URL 저장
|
||||||
next({ name: 'login', params: { return_url: to.name } })
|
sessionStorage.setItem(
|
||||||
|
process.env.VUE_APP_SESSIONSTORAGE_REDIRECT_NAME,
|
||||||
|
to.path
|
||||||
|
)
|
||||||
|
next({ name: 'login' })
|
||||||
} else {
|
} else {
|
||||||
//3. 로그인 인증완료
|
//3. 로그인 인증완료
|
||||||
console.log(from.name + ' => 2. 이미인증완료 => ' + to.name)
|
console.log(from.path + ' => 2. 이미인증완료 => ' + to.path)
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(from.name + ' => 1. 인증요구 없음 => ' + to.name)
|
console.log(from.path + ' => 1. 인증요구 없음 => ' + to.path)
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import AuthStore from './modules/auth'
|
|
||||||
import TodoStore from './modules/todo'
|
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
modules: {
|
state: {},
|
||||||
AuthStore,
|
getters: {},
|
||||||
TodoStore
|
mutations: {},
|
||||||
}
|
actions: {},
|
||||||
|
modules: {}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,97 +0,0 @@
|
|||||||
import axios from 'axios'
|
|
||||||
import jwt from './jwt'
|
|
||||||
|
|
||||||
//참조: https://yamoo9.github.io/axios/guide/interceptors.html
|
|
||||||
const authAxios = axios.create({
|
|
||||||
baseURL: process.env.VUE_APP_AUTH_HOST,
|
|
||||||
headers: { 'content-type': 'application/json' }
|
|
||||||
})
|
|
||||||
authAxios.interceptors.request.use(
|
|
||||||
(config) => jwt.getAuthorizationHeader(config),
|
|
||||||
(error) => {
|
|
||||||
// Do something with request error
|
|
||||||
Promise.reject(error)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
authAxios.defaults.headers.post['Content-Type'] =
|
|
||||||
'application/x-www-form-urlencoded'
|
|
||||||
|
|
||||||
// count state 속성 추가
|
|
||||||
const state = {
|
|
||||||
token: {
|
|
||||||
accessToken: jwt.getToken()
|
|
||||||
}, // 토큰정보
|
|
||||||
isAuthenticated: jwt.isAuthenticated()
|
|
||||||
}
|
|
||||||
const getters = {
|
|
||||||
getAccessToken: function (state) {
|
|
||||||
return state.token.accessToken
|
|
||||||
},
|
|
||||||
isAuthenticated: function (state) {
|
|
||||||
return state.isAuthenticated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mutations = {
|
|
||||||
login: function (state, payload = {}) {
|
|
||||||
state.token.accessToken = payload.accessToken
|
|
||||||
state.isAuthenticated = true
|
|
||||||
jwt.saveToken(payload.accessToken)
|
|
||||||
},
|
|
||||||
logout: function (state) {
|
|
||||||
state.token.accessToken = ''
|
|
||||||
state.isAuthenticated = false
|
|
||||||
jwt.destroyToken()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const actions = {
|
|
||||||
login: function (context, payload) {
|
|
||||||
let params = {
|
|
||||||
email: payload.email,
|
|
||||||
password: payload.password
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
authAxios
|
|
||||||
.post('/auth/login', params)
|
|
||||||
.then((response) => {
|
|
||||||
const { data } = response
|
|
||||||
context.commit('login', {
|
|
||||||
accessToken: data.accessToken
|
|
||||||
})
|
|
||||||
resolve(response)
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
logout: function (context, payload) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(function () {
|
|
||||||
context.commit('logout', payload)
|
|
||||||
resolve({})
|
|
||||||
}, 1000)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
register: function (context, payload) {
|
|
||||||
let params = {
|
|
||||||
email: payload.email,
|
|
||||||
password: payload.password,
|
|
||||||
name: payload.name
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
authAxios
|
|
||||||
.post('/user/register', params)
|
|
||||||
.then((response) => {
|
|
||||||
const { data } = response
|
|
||||||
context.commit('login', {
|
|
||||||
accessToken: data.accessToken
|
|
||||||
})
|
|
||||||
resolve(response)
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default { namespaced: true, state, getters, mutations, actions }
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
const Payload_KEY_NAME = 'access_token'
|
|
||||||
const getToken = () => {
|
|
||||||
return window.localStorage.getItem(Payload_KEY_NAME)
|
|
||||||
}
|
|
||||||
const saveToken = (token) => {
|
|
||||||
window.localStorage.setItem(Payload_KEY_NAME, token)
|
|
||||||
}
|
|
||||||
const destroyToken = () => {
|
|
||||||
window.localStorage.removeItem(Payload_KEY_NAME)
|
|
||||||
}
|
|
||||||
const isAuthenticated = () => {
|
|
||||||
return !!getToken()
|
|
||||||
}
|
|
||||||
|
|
||||||
const getAuthorizationHeader = (config) => {
|
|
||||||
//로그인이 되었는지 확인후 Request시 헤더에 로그인정보 추가하기 위함
|
|
||||||
if (isAuthenticated) {
|
|
||||||
config.headers.common['Authorization'] = getToken()
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
export default {
|
|
||||||
getToken,
|
|
||||||
saveToken,
|
|
||||||
destroyToken,
|
|
||||||
isAuthenticated,
|
|
||||||
getAuthorizationHeader
|
|
||||||
}
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
import axios from 'axios'
|
|
||||||
import jwt from './jwt'
|
|
||||||
|
|
||||||
//참조: https://yamoo9.github.io/axios/guide/interceptors.html
|
|
||||||
const todoAxios = axios.create({
|
|
||||||
baseURL: process.env.VUE_APP_BACKEND_HOST,
|
|
||||||
headers: { 'content-type': 'application/json' }
|
|
||||||
})
|
|
||||||
todoAxios.interceptors.request.use(
|
|
||||||
(config) => jwt.getAuthorizationHeader(config),
|
|
||||||
(error) => {
|
|
||||||
// Do something with request error
|
|
||||||
Promise.reject(error)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
todoAxios.defaults.headers.post['Content-Type'] =
|
|
||||||
'application/x-www-form-urlencoded'
|
|
||||||
|
|
||||||
// count state 속성 추가
|
|
||||||
const state = {
|
|
||||||
total: 0,
|
|
||||||
rows: []
|
|
||||||
}
|
|
||||||
const getters = {
|
|
||||||
getTotal: function (state) {
|
|
||||||
return state.total
|
|
||||||
},
|
|
||||||
getRows: function (state) {
|
|
||||||
return state.rows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mutations = {
|
|
||||||
setData: function (state, data) {
|
|
||||||
state.total = data.total
|
|
||||||
state.rows = data.rows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const actions = {
|
|
||||||
setData: function (context, params) {
|
|
||||||
console.log(params)
|
|
||||||
//주의 .get의 parameter는 { params: params} 처럼 보내야함
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
todoAxios
|
|
||||||
.get('/todo', { params: params })
|
|
||||||
.then((response) => {
|
|
||||||
const { data } = response
|
|
||||||
context.commit('setData', data)
|
|
||||||
resolve(response)
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default { namespaced: true, state, getters, mutations, actions }
|
|
||||||
@ -1,23 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div>
|
||||||
<!-- 참조: https://codesandbox.io/s/3v0m1?file=/src/components/board/BoardList.vue -->
|
<!-- 참조: https://codesandbox.io/s/3v0m1?file=/src/components/board/BoardList.vue -->
|
||||||
<LoginComponent />
|
<LoginComponent />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import LoginComponent from '@/components/LoginComponent.vue'
|
import LoginComponent from '@/components/common/LoginComponent.vue'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
LoginComponent
|
LoginComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
.wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 100vh;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -3,48 +3,18 @@
|
|||||||
<!-- 참조: https://codesandbox.io/s/3v0m1?file=/src/components/board/BoardList.vue -->
|
<!-- 참조: https://codesandbox.io/s/3v0m1?file=/src/components/board/BoardList.vue -->
|
||||||
<ListComponent />
|
<ListComponent />
|
||||||
<div class="justify-content-end border">
|
<div class="justify-content-end border">
|
||||||
<template v-if="isAuthenticated">
|
|
||||||
<b-button v-b-modal.inputForm variant="outline-primary">입력</b-button>
|
<b-button v-b-modal.inputForm variant="outline-primary">입력</b-button>
|
||||||
<b-modal
|
|
||||||
id="inputForm"
|
|
||||||
centered
|
|
||||||
title="입력폼"
|
|
||||||
size="lg"
|
|
||||||
:header-bg-variant="headerBgVariant"
|
|
||||||
:header-text-variant="headerTextVariant"
|
|
||||||
:body-bg-variant="bodyBgVariant"
|
|
||||||
:body-text-variant="bodyTextVariant"
|
|
||||||
:footer-bg-variant="footerBgVariant"
|
|
||||||
:footer-text-variant="footerTextVariant"
|
|
||||||
>
|
|
||||||
<InputComponent />
|
<InputComponent />
|
||||||
</b-modal>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import ListComponent from '@/components/todo/ListComponent.vue'
|
import ListComponent from '@/components/todo/ListComponent.vue'
|
||||||
import InputComponent from '@/components/todo/InputComponent.vue'
|
import InputComponent from '@/components/todo/InputComponent.vue'
|
||||||
import { createNamespacedHelpers } from 'vuex'
|
|
||||||
const authStore = createNamespacedHelpers('AuthStore')
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
InputComponent,
|
InputComponent,
|
||||||
ListComponent
|
ListComponent
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...authStore.mapGetters(['isAuthenticated'])
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
headerBgVariant: 'dark',
|
|
||||||
headerTextVariant: 'light',
|
|
||||||
bodyBgVariant: 'light',
|
|
||||||
bodyTextVariant: 'dark',
|
|
||||||
footerBgVariant: 'warning',
|
|
||||||
footerTextVariant: 'dark'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user