增加注册、登录

master
pan 3 years ago
parent f00c70b44d
commit fd1c8a6693
  1. 89
      mock/test.ts
  2. 5
      package.json
  3. 24
      src/App.vue
  4. 28
      src/components/AsyncComponent.vue
  5. 12
      src/components/Config.vue
  6. 22
      src/components/Email.vue
  7. 73
      src/components/Login.vue
  8. 23
      src/components/Password.vue
  9. 53
      src/components/Register.vue
  10. 13
      src/components/TelegramBot.vue
  11. 2
      src/global.ts
  12. 13
      src/interface.ts
  13. 38
      src/request.ts
  14. 40
      src/router.ts
  15. 8
      src/store.ts
  16. 4
      src/validate.ts

@ -1,5 +1,6 @@
import {MockMethod} from 'vite-plugin-mock';
import {changeEmailApi, changePwdApi, sendCodeApi, telegramBotApi} from "../src/interface";
import {changeEmailApi, changePwdApi, checkAdminApi, loginApi, sendCodeApi, telegramBotApi} from "../src/interface";
import {JSONResponse} from "../src/request";
const Mock = require('mockjs')
@ -9,10 +10,10 @@ export default [
url: sendCodeApi,
method: 'post',
response: ({query}) => {
const result = Mock.mock({
const result: JSONResponse = Mock.mock({
'result': /OK|FAIL/,
})
if (result.result === 'OK') {
if (result.result === "OK") {
result.message = '验证码发送成功'
} else {
result.message = '验证码发送失败'
@ -24,7 +25,7 @@ export default [
url: changeEmailApi,
method: 'post',
response: ({query}) => {
const result = Mock.mock({
const result: JSONResponse = Mock.mock({
'result': /OK|FAIL/,
})
@ -45,10 +46,9 @@ export default [
url: changePwdApi,
method: 'post',
response: ({query}) => {
debugger
const result = Mock.mock({
'result': /OK|FAIL/,
})
const result: JSONResponse = {
result: Math.random() < 0.9 ? 'OK' : "FAIL",
}
if (result.result === 'OK') {
result.message = '修改密码成功'
@ -66,15 +66,16 @@ export default [
url: telegramBotApi,
method: 'get',
response: ({query}) => {
debugger
const result = Mock.mock({
'result': Math.random() < 0.9 ? 'OK' : "FAIL",
})
const result: JSONResponse = {
result: Math.random() < 0.9 ? 'OK' : "FAIL",
}
if (result.result === 'OK') {
result.message = '获取机器人信息成功'
result.bot = Mock.mock({
name: /\w{5}/
result.body = Mock.mock({
bot: {
name: /\w{5}/
}
})
return result
} else {
@ -90,13 +91,13 @@ export default [
url: telegramBotApi,
method: 'post',
response: ({body}) => {
debugger
const result = Mock.mock({
'result': Math.random() < 0.9 ? 'OK' : "FAIL",
})
const result: JSONResponse = {
result: Math.random() < 0.9 ? 'OK' : "FAIL",
}
if (result.res === 'OK') {
if (result.result === 'OK') {
result.message = '机器人绑定成功'
return result
} else {
return {
...result, ...Mock.mock({
@ -105,5 +106,55 @@ export default [
}
}
}
},
{
url: loginApi,
method: "post",
response: ({body}) => {
const result: JSONResponse = {
result: Math.random() < 0.9 ? 'OK' : "FAIL",
}
if (result.result === 'OK') {
return {
...result,
...Mock.mock({
'message': '登陆成功',
'body': {
'token': /[a-zA-Z0-9]{32}/,
'userEmail': body['userEmail']
}
})
}
} else {
return {
...result,
...Mock.mock({
'message': /登陆失败,(邮箱或密码错误)/
})
}
}
}
},
{
url: checkAdminApi,
method: "get",
response: ({query}) => {
const result: JSONResponse = {
result: Math.random() < 0.9 ? 'OK' : "FAIL",
}
if (result.result === 'OK') {
return {
...Boolean(Math.round(Math.random())) ? {
message: '管理员已存在',
body: true
} : {
message: '管理员不存在',
body: false
}, ...result
}
} else {
return {message: '查询管理员失败'}
}
}
}
] as MockMethod[];

@ -3,10 +3,11 @@
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vuedx-typecheck . && vite build",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"crumbsjs": "^0.2.1",
"element3": "^0.0.39",
"vue": "^3.0.5",
"vue-router": "4",
@ -15,8 +16,6 @@
"devDependencies": {
"@vitejs/plugin-vue": "^1.1.4",
"@vue/compiler-sfc": "^3.0.5",
"@vuedx/typecheck": "^0.6.0",
"@vuedx/typescript-plugin-vue": "^0.6.0",
"cross-env": "^7.0.3",
"mockjs": "^1.1.0",
"node-sass": "^5.0.0",

@ -3,12 +3,10 @@
<el-header>
<el-row>
<el-col :span="4">
<h1>直播间状态通知</h1>
<h1>直播间开播通知</h1>
</el-col>
<el-col :span="20">
<el-col :span="20" v-if="![loginPath,registerPath].includes($route.fullPath)">
<el-menu mode="horizontal" :router="true" :default-active="store.state.route">
<el-submenu index="1">
<template v-slot:title>推送配置</template>
<el-menu-item index="/config">当前配置</el-menu-item>
@ -19,15 +17,14 @@
<template v-slot:title>个人信息</template>
<el-menu-item index="/password">修改密码</el-menu-item>
<el-menu-item index="/email">修改邮箱</el-menu-item>
<el-menu-item index="/">退出登录</el-menu-item>
<el-menu-item @click="logout">退出登录</el-menu-item>
</el-submenu>
</el-menu>
</el-col>
</el-row>
</el-header>
<el-main>
<Config v-if="$route.fullPath==='/'"/>
<router-view v-else/>
<router-view/>
</el-main>
</el-container>
@ -37,15 +34,24 @@
import {defineComponent} from 'vue'
import Config from "./components/Config.vue";
import {useStore} from "vuex";
import {loginPath, registerPath} from "./router";
//@ts-ignore
import crumbs from 'crumbsjs';
import {useRouter} from "vue-router";
export default defineComponent({
name: 'App',
components: {Config},
setup() {
const store = useStore()
const router = useRouter()
const logout = () => {
crumbs.deleteAll()
router.replace(loginPath)
}
return {store}
return {store, loginPath, registerPath, logout}
}
})
</script>

@ -1,28 +0,0 @@
<template>
<h1>一个异步组件</h1>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
function sleep(timeout: number | undefined){
return new Promise(resolve => setTimeout(resolve,timeout))
}
export default defineComponent({
name: "AsyncComponent",
props:{
timeout:{
type:Number,
required:true
}
},
async setup(props){
await sleep(props.timeout)
}
})
</script>
<style scoped>
</style>

@ -1,3 +1,4 @@
<!--推送配置-->
<template>
<el-row type="flex" justify="center">
<el-col :span="8">
@ -11,7 +12,10 @@
<script lang="ts">
import {defineComponent, onMounted, ref} from "vue";
import {useStore} from "vuex";
import {getTelegramBot, message} from "../request";
import {getTelegramBot, JSONResponse, message} from "../request";
import {email_cookie_key} from "../global";
//@ts-ignore
import crumbs from 'crumbsjs';
export default defineComponent({
name: "Config",
@ -25,10 +29,10 @@ export default defineComponent({
const botName = ref('')
getTelegramBot(store.state.user.email).then(res => res.json())
.then(res => {
getTelegramBot(crumbs.get(email_cookie_key)).then(res => res.json())
.then((res: JSONResponse) => {
if (res.result === 'OK') {
botName.value = res.bot.name
botName.value = res.body.bot.name
} else {
message(res)
}

@ -1,3 +1,4 @@
<!--修改邮箱-->
<template>
<el-row type="flex" justify="center">
<el-col :span="8">
@ -38,10 +39,13 @@
<script lang="ts">
import {computed, defineComponent, ref} from "vue";
import {changeEmail as _changeEmail, message, sendCode as _sendCode} from "../request";
import {useStore} from "vuex";
import {changeEmail as _changeEmail, JSONResponse, message, sendCode as _sendCode} from "../request";
import {updateRoute} from "../router";
import {useRouter} from "vue-router";
import {emailRegexp} from "../validate";
// @ts-ignore
import crumbs from 'crumbsjs';
import {email_cookie_key} from "../global";
export default defineComponent({
name: 'Email',
@ -51,20 +55,21 @@ export default defineComponent({
const second = ref<number>(0)
const store = useStore()
const router = useRouter()
const userEmail = crumbs.get(email_cookie_key)
const sendCode = () => {
second.value = 10
_sendCode(store.state.user.email).then(res => res.json()).then(res => {
_sendCode(userEmail).then(res => res.json()).then((res: JSONResponse) => {
message(res)
if (res.result === 'OK') {
console.info('发送验证码成功')
const t = setInterval(function () {
if(second.value===0){
if (second.value === 0) {
clearInterval(t)
} else {
second.value--
@ -76,7 +81,7 @@ export default defineComponent({
})
}
const changeEmail = () => _changeEmail(store.state.user.email, newEmail.value, code.value).then(res => res.json()).then(
const changeEmail = () => _changeEmail(userEmail, newEmail.value, code.value).then(res => res.json()).then(
res => {
message(res)
if (res.result === 'OK') {
@ -85,9 +90,8 @@ export default defineComponent({
}
)
const userEmail = computed(() => store.state.user.email)
const allowSendCode = computed<boolean>(() => second.value === 0 && userEmail !== newEmail.value && /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/.test(newEmail.value))
const allowSendCode = computed<boolean>(() => second.value === 0 && userEmail !== newEmail.value && emailRegexp.test(newEmail.value))
const sendCodeTip = computed<string>(() => second.value > 0 ? second.value + '秒后重发' : '发送验证码')

@ -0,0 +1,73 @@
<!--登录-->
<template>
<el-row justify="center" type="flex">
<el-col :span="8"><h1>后台登陆</h1></el-col>
</el-row>
<el-row justify="center" type="flex">
<el-col :span="8">
<el-input v-model="user">
<template v-slot:prepend>管理员邮箱</template>
</el-input>
<span v-if="user===''">邮箱不能为空</span>
<span v-else-if="!checkUser">邮箱不合法</span>
</el-col>
</el-row>
<el-row type="flex" justify="center" class="mt-1">
<el-col :span="8">
<span>密码必须包含数字字母6-10</span>
<el-input v-model="password" show-password>
<template v-slot:prepend>密码</template>
</el-input>
<span v-if="password===''">密码不能为空</span>
<span v-else-if="!checkPwd">密码不合法</span>
</el-col>
</el-row>
<el-row type="flex" justify="center" class="mt-1">
<el-col :span="8">
<el-button type="primary" class="btn-block" :disabled="user===''||password===''" @click="requestLogin">登录
</el-button>
</el-col>
</el-row>
</template>
<script lang="ts">
import {computed, defineComponent, ref} from "vue";
import {emailRegexp, passwordRegexp} from "../validate";
import {JSONResponse, login, message} from "../request";
//@ts-ignore
import crumbs from 'crumbsjs';
import {useRouter} from "vue-router";
import {email_cookie_key, token_cookie_key} from "../global";
export default defineComponent({
name: "Login",
setup() {
const user = ref<string>('')
const password = ref<string>('')
const checkUser = computed<boolean>(() => emailRegexp.test(user.value))
const checkPwd = computed<boolean>(() => passwordRegexp.test(password.value))
const router = useRouter()
const requestLogin = () => {
login(user.value, password.value).then(res => res.json())
.then((res: JSONResponse) => {
message(res)
if (res.result === 'OK') {
crumbs.set(token_cookie_key, res.body.token)
crumbs.set(email_cookie_key, res.body.userEmail)
router.replace('/')
}
})
}
return {user, password, checkUser, checkPwd, requestLogin}
}
})
</script>
<style scoped>
</style>

@ -1,7 +1,8 @@
<!--修改密码-->
<template>
<el-row type="flex" justify="center">
<el-col :span="8">
<span>密码只能由数字和英文字母组成长度最小{{ min }}最大{{ max }}</span>
<span>密码必须包含数字字母6-10</span>
<el-input v-model="password" show-password>
<template v-slot:prepend>新密码</template>
</el-input>
@ -32,13 +33,12 @@
<script lang="ts">
import {computed, defineComponent, ref} from "vue"
import {updateRoute} from "../router";
import {changePwd, message} from "../request";
import {changePwd, JSONResponse, message} from "../request";
import {useRoute, useRouter} from "vue-router";
import {useStore} from "vuex";
const min = 5
const max = 10
const pwdRegExp = new RegExp(`^[0-9a-zA-Z]{5,10}$`)
import {passwordRegexp} from "../validate";
// @ts-ignore
import crumbs from 'crumbsjs';
import {email_cookie_key} from "../global";
export default defineComponent({
name: "Password",
@ -47,12 +47,11 @@ export default defineComponent({
const newPassword = ref<string>('')
const route = useRoute()
const router = useRouter()
const store = useStore()
const checkPwd = computed<boolean>(() => pwdRegExp.test(password.value))
const checkPwd = computed<boolean>(() => passwordRegexp.test(password.value))
const requestChangePwd = () => changePwd(store.state.user.email, password.value).then(res => res.json())
.then(res => {
const requestChangePwd = () => changePwd(crumbs.get(email_cookie_key), password.value).then(res => res.json())
.then((res: JSONResponse) => {
message(res)
if (res.result === 'OK') {
router.replace('/config')
@ -61,7 +60,7 @@ export default defineComponent({
updateRoute()
return {password, newPassword, checkPwd, min, max, requestChangePwd}
return {password, newPassword, checkPwd, requestChangePwd}
}
})
</script>

@ -0,0 +1,53 @@
<!--注册-->
<template>
<template v-if="step===1">
<el-row justify="center" type="flex">
<el-col :span="8">
<h1>欢迎使用直播间开播通知应用请完成管理员注册操作</h1>
</el-col>
</el-row>
<el-row type="flex" justify="center">
<el-col :span="8">
<el-button type="info" class="btn-block" @click="step=2">开始注册</el-button>
</el-col>
</el-row>
</template>
<template v-else-if="step===2">
<el-row type="flex" justify="center">
<el-col :span="8">
<h1>注册管理员</h1>
</el-col>
</el-row>
<el-row type="flex" justify="center">
<el-col :span="8">
<el-input v-model="userEmail">
<template v-slot:prepend>管理员邮箱</template>
</el-input>
</el-col>
</el-row>
<el-row type="flex" justify="center" class="mt-1">
<el-col :span="8">
<el-input v-model="code" placeholder="请输入验证码"/>
</el-col>
</el-row>
</template>
</template>
<script lang="ts">
import {defineComponent, ref} from "vue";
export default defineComponent({
name: "Register",
setup() {
const step = ref<number>(1)
const userEmail = ref<string>('')
const code = ref<string>('')
return {step, userEmail, code}
}
})
</script>
<style scoped>
</style>

@ -1,3 +1,4 @@
<!--telegram bot-->
<template>
<el-row type="flex" justify="center">
<el-col :span="12">
@ -32,9 +33,11 @@
<script lang="ts">
import {defineComponent, ref} from "vue";
import {updateRoute} from "../router";
import {bindTelegramBot, message, testTelegramBot} from "../request";
import {useStore} from "vuex";
import {bindTelegramBot, JSONResponse, message, testTelegramBot} from "../request";
import {useRouter} from "vue-router";
//@ts-ignore
import crumbs from 'crumbsjs';
import {email_cookie_key} from "../global";
export default defineComponent({
name: "TelegramBot",
@ -50,7 +53,7 @@ export default defineComponent({
const openBot = () => {
fullscreenLoading.value = true
testTelegramBot(newBotToken.value)
.then(res => res.json()).then(res => {
.then(res => res.json()).then((res: JSONResponse) => {
fullscreenLoading.value = false
if (res.ok) {
botName.value = res.result.username
@ -60,10 +63,10 @@ export default defineComponent({
})
}
const store = useStore()
const router = useRouter()
const bindBot = () => bindTelegramBot(store.state.user.email, newBotToken.value)
const bindBot = () => bindTelegramBot(crumbs.get(email_cookie_key), newBotToken.value)
.then(res => res.json())
.then(res => {
message(res)

@ -0,0 +1,2 @@
export const token_cookie_key = 'token'
export const email_cookie_key = 'user_email'

@ -1,5 +1,8 @@
export const sendCodeApi = '/api/change/email/code'
export const changeEmailApi = '/api/change/email'
export const changePwdApi = '/api/change/pwd'
export const telegramBotApi = '/api/telegram/bot'
export const testTelegramBotApi = (token: string) => `https://api.telegram.org/bot${token}/getMe`
const prefix = '/api/backend'
export const sendCodeApi = `${prefix}/change/email/code`
export const changeEmailApi = `${prefix}/change/email`
export const changePwdApi = `${prefix}/change/pwd`
export const telegramBotApi = `${prefix}/telegram/bot`
export const testTelegramBotApi = (token: string) => `https://api.telegram.org/bot${token}/getMe`
export const checkAdminApi = `${prefix}/checkAdmin`
export const loginApi = `${prefix}/login`

@ -1,4 +1,12 @@
import {changeEmailApi, changePwdApi, sendCodeApi, telegramBotApi, testTelegramBotApi} from "./interface";
import {
changeEmailApi,
changePwdApi,
checkAdminApi,
loginApi,
sendCodeApi,
telegramBotApi,
testTelegramBotApi
} from "./interface";
// @ts-ignore
import {Message} from 'element3/src/components/Message'
@ -38,18 +46,42 @@ export function getTelegramBot(userEmail: string) {
}
/**
* token
* telegram bot token
* @param token
*/
export function testTelegramBot(token: string) {
return fetch(new Request(testTelegramBotApi(token)))
}
/**
* telegram bot
* @param userEmail
* @param token
*/
export function bindTelegramBot(userEmail: string, token: string) {
return fetch(new Request(telegramBotApi), {method: 'POST', body: JSON.stringify({userEmail, token})})
}
export function message(res: any) {
/**
*
*/
export function checkAdmin() {
return fetch(new Request(checkAdminApi), {method: 'GET'})
}
export function login(userEmail: string, password: string) {
return fetch(new Request(loginApi), {method: 'POST', body: JSON.stringify({userEmail, password})})
}
export type Result = 'OK' | 'FAIL'
export interface JSONResponse {
result: Result,
body?: any,
message?: string
}
export function message(res: JSONResponse) {
new Message({
showClose: true,
duration: 3000,

@ -5,13 +5,24 @@ import {useStore} from "vuex";
import {onMounted} from "vue";
import Password from "./components/Password.vue";
import TelegramBot from "./components/TelegramBot.vue";
import Login from "./components/Login.vue";
import Register from "./components/Register.vue";
import {checkAdmin, JSONResponse} from "./request";
// @ts-ignore
import crumbs from 'crumbsjs';
import {token_cookie_key} from "./global";
export const registerPath = '/register'
export const loginPath = '/login'
const routes = [
{path: '/', redirect: '/config'},
{path: registerPath, component: Register},
{path: '/config', component: Config},
{path: '/config/telegram', component: TelegramBot},
{path: '/email', component: Email},
{path: '/password', component: Password}
{path: '/password', component: Password},
{path: loginPath, component: Login}
]
@ -19,7 +30,33 @@ export const router = createRouter({
history: createWebHashHistory(),
routes
})
//路由导航守卫
router.beforeEach(async (to, from) => {
let res: JSONResponse = await checkAdmin().then(res => res.json())
if (![registerPath, loginPath].includes(to.fullPath)) {
if (res.body && crumbs.get(token_cookie_key)) {
return true
} else if (res.body) {
alert('请登录')
return loginPath
} else {
alert('请进行应用初始化操作')
return registerPath
}
} else if (to.fullPath === loginPath && crumbs.get(token_cookie_key)) {
return '/'
} else if (to.fullPath === loginPath && !res.body) {
return registerPath
} else if (to.fullPath === registerPath && res.body) {
return loginPath
} else {
return true
}
})
//更新状态里的路由
export function updateRoute() {
const store = useStore()
const route = useRoute()
@ -28,3 +65,4 @@ export function updateRoute() {
store.commit('updateRoute', route.fullPath)
})
}

@ -2,16 +2,10 @@ import {createStore} from "vuex";
export const store = createStore({
state: () => ({
user: {
email: '1029559041@qq.com'
},
//默认
route: '/config'
}),
mutations: {
setUser(state, user) {
// @ts-ignore
state.user = user
},
updateRoute(state, route) {
state.route = route
}

@ -0,0 +1,4 @@
//邮箱校验
export const emailRegexp = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/
//密码校验,必须包含数字、字母,6-10位
export const passwordRegexp = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,10}$/
Loading…
Cancel
Save