update
1. add login action 2. add user info getter 3. add top menu ui
This commit is contained in:
parent
b8a9e43033
commit
e2de8f5d85
9
jsconfig.json
Normal file
9
jsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"moduleResolution": "classic",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@": ["src/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,15 +2,18 @@
|
|||||||
<div id="app">
|
<div id="app">
|
||||||
<router-view/>
|
<router-view/>
|
||||||
<Loading />
|
<Loading />
|
||||||
|
<Dialog />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Loading from '@/components/Loading'
|
import Loading from '@/components/Loading'
|
||||||
|
import Dialog from '@/components/Dialog'
|
||||||
export default {
|
export default {
|
||||||
name: 'root-view',
|
name: 'root-view',
|
||||||
components: {
|
components: {
|
||||||
Loading
|
Loading,
|
||||||
|
Dialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
14
src/components/ControlPanel/channelList/index.vue
Normal file
14
src/components/ControlPanel/channelList/index.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<sui-container>
|
||||||
|
|
||||||
|
</sui-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ChannelList',
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
36
src/components/ControlPanel/index.vue
Normal file
36
src/components/ControlPanel/index.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div class='cp-div'>
|
||||||
|
<TopMenu />
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.cp-div {
|
||||||
|
padding-top: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TopMenu from './topMenu'
|
||||||
|
import {mapActions} from 'vuex'
|
||||||
|
export default {
|
||||||
|
name: 'ControlPanel',
|
||||||
|
components: {
|
||||||
|
TopMenu
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.checkSession((flag) => {
|
||||||
|
if (flag === false) {
|
||||||
|
this.$router.replace('/')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(['checkSession'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
22
src/components/ControlPanel/topMenu.vue
Normal file
22
src/components/ControlPanel/topMenu.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<sui-menu fluid borderless fixed='top'>
|
||||||
|
<sui-container>
|
||||||
|
<sui-menu-menu position='right'>
|
||||||
|
<sui-menu-item>User: {{userInfo.name}}</sui-menu-item>
|
||||||
|
</sui-menu-menu>
|
||||||
|
</sui-container>
|
||||||
|
</sui-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {mapGetters} from 'vuex'
|
||||||
|
export default {
|
||||||
|
name: 'TopMenu',
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['userInfo'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
38
src/components/Dialog/index.vue
Normal file
38
src/components/Dialog/index.vue
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<sui-modal v-model="openModal">
|
||||||
|
<sui-modal-content>
|
||||||
|
{{msg}}
|
||||||
|
</sui-modal-content>
|
||||||
|
<sui-modal-actions>
|
||||||
|
<sui-button @click.native="closeDialog">OK</sui-button>
|
||||||
|
</sui-modal-actions>
|
||||||
|
</sui-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {mapGetters, mapMutations} from 'vuex'
|
||||||
|
export default {
|
||||||
|
name: 'Dialog',
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(['removeDialog']),
|
||||||
|
closeDialog: function () {
|
||||||
|
if (typeof this.dialogMsg.act === 'function') this.dialogMsg.act()
|
||||||
|
this.removeDialog()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['dialogMsg']),
|
||||||
|
msg: function () {
|
||||||
|
if (this.dialogMsg === null) return ''
|
||||||
|
return this.dialogMsg.msg
|
||||||
|
},
|
||||||
|
openModal: function () {
|
||||||
|
if (this.dialogMsg === null) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -8,7 +8,7 @@
|
|||||||
<input placeholder="Account" v-model="account">
|
<input placeholder="Account" v-model="account">
|
||||||
</sui-form-field>
|
</sui-form-field>
|
||||||
<sui-form-field>
|
<sui-form-field>
|
||||||
<input placeholder="Password" v-model="password">
|
<input placeholder="Password" type="password" v-model="password">
|
||||||
</sui-form-field>
|
</sui-form-field>
|
||||||
<sui-button type="submit" fluid color='teal'>Login</sui-button>
|
<sui-button type="submit" fluid color='teal'>Login</sui-button>
|
||||||
<sui-button type="button" @click="go_oauth" class="twitch-button" fluid color='violet'>Login with Twitch</sui-button>
|
<sui-button type="button" @click="go_oauth" class="twitch-button" fluid color='violet'>Login with Twitch</sui-button>
|
||||||
@ -49,18 +49,22 @@ export default {
|
|||||||
this.checkSession((flag) => {
|
this.checkSession((flag) => {
|
||||||
// check login session
|
// check login session
|
||||||
// true === isLogin
|
// true === isLogin
|
||||||
console.log(flag)
|
if (flag === true) {
|
||||||
|
this.$router.push('/cp')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(['toggleLoading']),
|
...mapMutations(['toggleLoading']),
|
||||||
...mapActions(['checkSession']),
|
...mapActions(['checkSession', 'sendLogin']),
|
||||||
login: function () {
|
login: function () {
|
||||||
console.log('login submit')
|
console.log('login submit')
|
||||||
this.toggleLoading(1)
|
this.sendLogin({
|
||||||
setTimeout(() => {
|
account: this.account,
|
||||||
this.toggleLoading(0)
|
password: this.password
|
||||||
}, 1000)
|
}, () => {
|
||||||
|
this.$router.push('/cp')
|
||||||
|
})
|
||||||
},
|
},
|
||||||
go_oauth: function () {
|
go_oauth: function () {
|
||||||
window.location.href = apiUrl.replace(/\/$/, '') + '/twitch/login?tourl=' + encodeURIComponent(window.location.href)
|
window.location.href = apiUrl.replace(/\/$/, '') + '/twitch/login?tourl=' + encodeURIComponent(window.location.href)
|
||||||
|
@ -2,6 +2,8 @@ import Vue from 'vue'
|
|||||||
import Router from 'vue-router'
|
import Router from 'vue-router'
|
||||||
// import HelloWorld from '@/components/HelloWorld'
|
// import HelloWorld from '@/components/HelloWorld'
|
||||||
import Login from '@/components/Login'
|
import Login from '@/components/Login'
|
||||||
|
import ControlPanel from '@/components/ControlPanel'
|
||||||
|
import ChannelList from '@/components/ControlPanel/channelList'
|
||||||
|
|
||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
|
|
||||||
@ -13,6 +15,23 @@ export default new Router({
|
|||||||
path: '/',
|
path: '/',
|
||||||
name: 'Login',
|
name: 'Login',
|
||||||
component: Login
|
component: Login
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/cp',
|
||||||
|
name: 'ControlPanel',
|
||||||
|
component: ControlPanel,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'channels',
|
||||||
|
alias: '',
|
||||||
|
name: 'ChannelList',
|
||||||
|
component: ChannelList
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '*',
|
||||||
|
redirect: 'channels'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import {apiUrl} from '@/tools'
|
import {apiUrl, chkObject} from '@/tools'
|
||||||
|
|
||||||
const client = axios.create({
|
const client = axios.create({
|
||||||
baseURL: apiUrl,
|
baseURL: apiUrl,
|
||||||
@ -11,15 +11,52 @@ export default {
|
|||||||
commit('toggleLoading', true)
|
commit('toggleLoading', true)
|
||||||
let flag = false
|
let flag = false
|
||||||
try {
|
try {
|
||||||
await client({
|
let result = await client({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/api/session'
|
url: '/api/session'
|
||||||
})
|
})
|
||||||
|
if ('data' in result) {
|
||||||
|
commit('setUserInfo', {
|
||||||
|
name: result.data.user.name || '',
|
||||||
|
type: result.data.user.type || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
flag = true
|
flag = true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
flag = false
|
flag = false
|
||||||
}
|
}
|
||||||
if (typeof cb === 'function') cb(flag)
|
if (typeof cb === 'function') cb(flag)
|
||||||
commit('toggleLoading', false)
|
commit('toggleLoading', false)
|
||||||
|
},
|
||||||
|
async sendLogin ({commit}, {account, password}, cb = null) {
|
||||||
|
let chk = chkObject.bind({body: {account, password}})
|
||||||
|
if (!chk('account', 'string') || !chk('password', 'string')) {
|
||||||
|
commit('addDialog', {
|
||||||
|
msg: '帳號密碼不能留空'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let data = {
|
||||||
|
account,
|
||||||
|
password
|
||||||
|
}
|
||||||
|
commit('toggleLoading', true)
|
||||||
|
try {
|
||||||
|
await client({
|
||||||
|
method: 'post',
|
||||||
|
url: '/api/login',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
if (typeof cb === 'function') cb()
|
||||||
|
} catch (err) {
|
||||||
|
let msg = ''
|
||||||
|
if ('response' in err && 'data' in err.response && 'message' in err.response.data) {
|
||||||
|
msg = err.response.data.message
|
||||||
|
} else {
|
||||||
|
msg = 'unknown error'
|
||||||
|
}
|
||||||
|
commit('addDialog', {msg})
|
||||||
|
}
|
||||||
|
commit('toggleLoading', false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1,3 @@
|
|||||||
export const getLoading = state => !!state.loading
|
export const getLoading = state => !!state.loading
|
||||||
|
export const dialogMsg = state => state.dialog[0] || null
|
||||||
|
export const userInfo = state => state.user
|
||||||
|
@ -6,10 +6,17 @@ import * as getters from './getters'
|
|||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
loading: false,
|
||||||
|
dialog: [],
|
||||||
|
user: {
|
||||||
|
name: '',
|
||||||
|
type: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state,
|
||||||
loading: false
|
|
||||||
},
|
|
||||||
mutations,
|
mutations,
|
||||||
getters,
|
getters,
|
||||||
actions
|
actions
|
||||||
|
@ -1,5 +1,23 @@
|
|||||||
export default {
|
export default {
|
||||||
toggleLoading (state, loading = null) {
|
toggleLoading (state, loading = null) {
|
||||||
state.loading = !!loading
|
state.loading = !!loading
|
||||||
|
},
|
||||||
|
setUserInfo (state, {name, type}) {
|
||||||
|
if (typeof name !== 'string' || name.trim().length === 0) return
|
||||||
|
if (typeof type !== 'string' || type.trim().length === 0) return
|
||||||
|
name = name.trim()
|
||||||
|
type = type.trim()
|
||||||
|
state.user = {
|
||||||
|
...state.user,
|
||||||
|
name,
|
||||||
|
type
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addDialog (state, {msg, act = null}) {
|
||||||
|
if (typeof msg !== 'string' || msg.trim().length === 0) return
|
||||||
|
state.dialog = [...state.dialog, {msg, act}]
|
||||||
|
},
|
||||||
|
removeDialog (state) {
|
||||||
|
state.dialog = state.dialog.slice(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
40
src/tools.js
40
src/tools.js
@ -1 +1,39 @@
|
|||||||
export const apiUrl = 'https://bot.trj.tw'
|
export const apiUrl = 'https://bot.trj.tw'
|
||||||
|
|
||||||
|
export const chkObject = function (key = '', type = '', empty = false) {
|
||||||
|
const uuidChk = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
||||||
|
if (!(key in this.body)) return false
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'string':
|
||||||
|
if (typeof this.body[key] !== 'string' || (!empty && !this.body[key].trim())) return false
|
||||||
|
break
|
||||||
|
case 'number':
|
||||||
|
if (!isFinite(this.body[key])) return false
|
||||||
|
break
|
||||||
|
case 'boolean':
|
||||||
|
if (typeof this.body[key] !== 'boolean') return false
|
||||||
|
break
|
||||||
|
case 'array':
|
||||||
|
if (!Array.isArray(this.body[key]) || (!empty && this.body[key].length === 0)) return false
|
||||||
|
break
|
||||||
|
case 'uuid':
|
||||||
|
if (typeof this.body[key] !== 'string') return false
|
||||||
|
if (!empty && this.body[key] === '') return false
|
||||||
|
if (!empty && !uuidChk.test(this.body[key])) return false
|
||||||
|
break
|
||||||
|
case 'object':
|
||||||
|
if (typeof this.body[key] !== 'object') return false
|
||||||
|
try {
|
||||||
|
let str = JSON.stringify(this.body[key])
|
||||||
|
JSON.parse(str)
|
||||||
|
} catch (err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user