no message

This commit is contained in:
CN32479-詹红柱 2021-08-18 20:36:58 +08:00
parent 2f2ccf7039
commit 7e4a538f5e
7 changed files with 352 additions and 30 deletions

94
src/Api/request.js Normal file
View File

@ -0,0 +1,94 @@
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL: 'https://lean.zhanhongzhu.top' || process.env.NODE_ENV === 'production' ? window.PROD_CONFIG.BASE_URL : process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 50000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
const res = response.data
if (res.status === 400) {
Message({
message: '入参错误',
type: 'error',
duration: 5 * 1000
})
return false
}
// if the custom code is not 0, it is judged as an error.
if (res.code !== 0 && res.code !== 200) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service

68
src/Api/user.js Normal file
View File

@ -0,0 +1,68 @@
import AV from 'leancloud-storage'
// 用户登录
const login = (username, password) => {
console.log(username, password)
return new Promise((resolve, reject) => {
AV.User.logIn(username, password).then(user => {
resolve(user)
}).catch(error => {
reject(error)
})
})
}
// 用户登录
const loginEmail = (username, password) => {
console.log(username, password)
return new Promise((resolve, reject) => {
AV.User.loginWithEmail(username, password).then(user => {
resolve(user)
}).catch(error => {
reject(error)
})
})
}
// 用户登出
const logout = (username, password) => {
return new Promise((resolve, reject) => {
AV.User.logOut(username, password).then(user => {
resolve(user)
})
})
}
// 用户注册
const register = (username, password) => {
return new Promise((resolve, reject) => {
const user = new AV.User()
user.setUsername(username)
user.setPassword(password)
user.signUp().then((user) => {
resolve(user)
}, (error) => {
reject(error)
})
})
}
const getInfo = (params) => {
return new Promise((resolve, reject) => {
const user = new AV.User()
user.loginWithAuthData({
openid: params.openid,
access_token: params.access_token,
expires_in: params.expires_in
}, 'weixin').then(function (user) {
resolve(user)
}).catch(function (error) {
reject(error)
})
})
}
export default {
login,
logout,
register,
loginEmail,
getInfo
}

View File

@ -14,9 +14,10 @@
<img src="./assets/svg/add.svg" class="tool-icon" @click="add({},'add')" />
<a title="我的博客" href="https://zhanhongzhu.top" target="_blank"><img src="./assets/svg/blog.svg" class="tool-icon" /></a>
<a title="在线翻译" href="https://translate.google.cn" target="_blank"><img src="./assets/svg/translate.svg" class="tool-icon" /></a>
<a title="我的码云" href="https://gitee.com/zhanhongzhu/kestrel-bookmark" target="_blank"><img src="./assets/svg/gitee.svg" class="tool-icon" /></a>
<a title="我的github" href="https://github.com/zhanhongzhu/kestrel-bookmark" target="_blank"><img src="./assets/svg/github.svg" class="tool-icon" /></a>
<span class="login-s" @click="loginClick"><img src="./assets/svg/user.svg" class="tool-icon" /><span class="login-status" :title="userInfo.username">{{userInfo.username.slice(0, 5)}}</span></span>
</div>
<!-- userInfo.objectId?LoginOut:handleUserLogin -->
</div>
<!-- 侧边导航栏 -->
<div class="box-m">
@ -45,7 +46,6 @@
<i class="el-icon-edit" @click.stop="add(card,'modify')"></i>
<i class="el-icon-delete" @click.stop="deleteClick(card)"></i>
</span>
<span class="title">{{card.title || 'Kestrel-bookmark'}}</span>
<span class="subtitle">{{card.desc || "红隼书签-为中国 Web 前端开发人员提供优质网站导航"}}</span>
</div>
@ -69,16 +69,22 @@
</div>
</div>
</div>
<!-- 新增/修改弹窗 -->
<Dialog class="my-dialog" v-model="isDetailVisible" @closeViews="closeViews" :detail="detail" :selectType="activeIndex" @fresh="search" />
<!-- 登录弹窗 -->
<Login v-model="isLoginVisible" @closeViews="closeLoginViews" @setUser="setUsername"/>
</template>
<script>
import { reactive, toRefs } from '@vue/reactivity'
import { myData } from './assets/Json/印象笔记.js'
import { watch } from '@vue/runtime-core'
import Dialog from './components/Dialog.vue'
import Login from './components/Login.vue'
import gsap from 'gsap'
import { ElMessage } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { importBookmark, exportBookmark } from './components/utils.js'
import Cookie from 'js-cookie'
import Api from './Api/user.js'
var rowData = []
function getData(fn = () => {}) {
//
@ -93,7 +99,7 @@ function getData(fn = () => {}) {
}
getData()
export default {
components: { Dialog },
components: { Dialog, Login },
name: 'kestrel-bookmark',
setup() {
//
@ -113,9 +119,22 @@ export default {
searchVal: '',
allData: flatten(rowData),
isDetailVisible: false,
detail: {}
isLoginVisible: false,
detail: {},
userInfo: {
username: '未登录'
}
})
const setUsername = () => {
if (Cookie.get('userInfo')) {
data.userInfo = JSON.parse(Cookie.get('userInfo'))
} else {
data.userInfo = {username: '未登录'}
}
}
setUsername()
//
watch(
() => data.searchVal,
@ -150,8 +169,15 @@ export default {
}
data.isDetailVisible = true
}
//
const handleUserLogin = () => {
data.isLoginVisible = true
}
//
const closeViews = (v) => (data.isDetailVisible = v)
const closeLoginViews = (v) => (data.isLoginVisible = v)
//
const search = async () => {
@ -180,6 +206,29 @@ export default {
}
}
}
// 退
const LoginOut = () => {
ElMessageBox.confirm('确认要退出登录?', '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const params = { username: '', password: '' }
Api.logout(params.username, params.password).then((res) => {
Cookie.remove('userInfo')
setUsername()
})
ElMessage({
type: 'success',
message: '删除成功!'
})
})
}
// 退
const loginClick = () => {
data.userInfo.objectId ? LoginOut() : handleUserLogin()
}
return {
deleteClick,
...toRefs(data),
@ -187,9 +236,12 @@ export default {
navigate,
add,
closeViews,
closeLoginViews,
search,
importBookmark,
exportBookmark
exportBookmark,
loginClick,
setUsername
}
},
methods: {
@ -525,4 +577,18 @@ export default {
cursor: pointer;
}
}
.login-status {
display: inline-block;
font-size: 12px;
padding-right: 8px;
color: #999;
cursor: pointer;
}
.login-s .tool-icon {
margin-right: 5px;
}
.login-s:hover .login-status {
color: #e03b5d;
}
</style>

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -33,14 +33,13 @@
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeViews"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="closeViews" size="small"> </el-button>
<el-button type="primary" @click="submitForm" size="small"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import gsap from 'gsap'
import { reactive, ref, toRefs } from '@vue/reactivity'
import { nextTick, watch } from '@vue/runtime-core'
import { ElMessage } from 'element-plus'
@ -154,26 +153,6 @@ export default {
}
},
methods: {
beforeEnter(el) {
el.style.opacity = 0
el.style.height = 0
},
enter(el, done) {
gsap.to(el, {
opacity: 1,
height: '1.6em',
delay: el.dataset.index * 0.15,
onComplete: done
})
},
leave(el, done) {
gsap.to(el, {
opacity: 0,
height: 0,
delay: el.dataset.index * 0.15,
onComplete: done
})
}
}
}
</script>

107
src/components/Login.vue Normal file
View File

@ -0,0 +1,107 @@
<template>
<el-dialog custom-class="my-dialog" title="用户登录" :visible="isLoginVisible" width="400px">
<el-form status-icon ref="refruleForm" :rules="rules" :model="ruleForm" label-width="80px" size="small">
<el-row>
<el-col :span="24">
<el-form-item label="邮箱" prop="email">
<el-input v-model="ruleForm.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="密码" prop="password">
<el-input v-model="ruleForm.password" show-password placeholder="请输入密码"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeViews" size="small"> </el-button>
<el-button type="primary" @click="submitForm" size="small"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import Cookie from 'js-cookie'
import { reactive, ref, toRefs } from '@vue/reactivity'
import { ElMessage } from 'element-plus'
import Api from '../Api/user.js' // register
export default {
model: {
value: 'isLoginVisible',
events: 'closeViews'
},
props: {
isLoginVisible: {
type: Boolean,
default: false
}
},
setup(props, context) {
const form = reactive({
ruleForm: {
username: '',
password: ''
}
})
//
// :rules
const rules = {
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
email: [{type: 'email', required: true, message: '请输入邮箱', trigger: 'blur' }]
}
const refruleForm = ref(null)
//
const submitForm = () => {
refruleForm.value.validate((valid) => {
if (valid) {
const formData = { ...form.ruleForm }
Api.loginEmail(formData.email, formData.password)
.then((res) => {
// token
Cookie.set('userInfo', JSON.stringify(res))
ElMessage.success('登记成功')
closeViews()
})
.catch(() => {
Api.register(formData.email, formData.password).then((res) => {
Cookie.set('userInfo', JSON.stringify(res))
context.emit('setUser')
ElMessage.success('注册成功')
closeViews()
})
})
}
})
}
//
function closeViews() {
refruleForm.value.resetFields()
context.emit('closeViews', false)
}
return {
...toRefs(form),
closeViews,
submitForm,
refruleForm,
rules
}
},
methods: {}
}
</script>
<style scoped lang="scss">
.my-dialog {
background: red;
}
.my-dialog /deep/.el-dialog__header {
border-bottom: 1px solid #eee !important;
}
.my-dialog /deep/.el-dialog__title {
font-size: 16px;
color: #e03b5d;
}
</style>

View File

@ -4,6 +4,14 @@ import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
// 接入了Leancloud
import AV from 'leancloud-storage'
AV.init({
appId: 'BwLrCgdVyLs52mJO1HcrXakI-gzGzoHsz',
appKey: '25gNwzw4dV7IAh7i0IzDnYvV',
serverURL: 'https://bwlrcgdv.lc-cn-n1-shared.com' // 临时域名
})
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')