no message
This commit is contained in:
parent
2f2ccf7039
commit
7e4a538f5e
94
src/Api/request.js
Normal file
94
src/Api/request.js
Normal 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
68
src/Api/user.js
Normal 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
|
||||||
|
}
|
80
src/App.vue
80
src/App.vue
@ -14,9 +14,10 @@
|
|||||||
<img src="./assets/svg/add.svg" class="tool-icon" @click="add({},'add')" />
|
<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://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://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>
|
<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>
|
||||||
<a title="我的github" href="https://github.com/zhanhongzhu/kestrel-bookmark" target="_blank"><img src="./assets/svg/github.svg" class="tool-icon" /></a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- userInfo.objectId?LoginOut:handleUserLogin -->
|
||||||
</div>
|
</div>
|
||||||
<!-- 侧边导航栏 -->
|
<!-- 侧边导航栏 -->
|
||||||
<div class="box-m">
|
<div class="box-m">
|
||||||
@ -45,7 +46,6 @@
|
|||||||
<i class="el-icon-edit" @click.stop="add(card,'modify')"></i>
|
<i class="el-icon-edit" @click.stop="add(card,'modify')"></i>
|
||||||
<i class="el-icon-delete" @click.stop="deleteClick(card)"></i>
|
<i class="el-icon-delete" @click.stop="deleteClick(card)"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="title">{{card.title || 'Kestrel-bookmark'}}</span>
|
<span class="title">{{card.title || 'Kestrel-bookmark'}}</span>
|
||||||
<span class="subtitle">{{card.desc || "红隼书签-为中国 Web 前端开发人员提供优质网站导航"}}</span>
|
<span class="subtitle">{{card.desc || "红隼书签-为中国 Web 前端开发人员提供优质网站导航"}}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -69,16 +69,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 新增/修改弹窗 -->
|
||||||
<Dialog class="my-dialog" v-model="isDetailVisible" @closeViews="closeViews" :detail="detail" :selectType="activeIndex" @fresh="search" />
|
<Dialog class="my-dialog" v-model="isDetailVisible" @closeViews="closeViews" :detail="detail" :selectType="activeIndex" @fresh="search" />
|
||||||
|
<!-- 登录弹窗 -->
|
||||||
|
<Login v-model="isLoginVisible" @closeViews="closeLoginViews" @setUser="setUsername"/>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { reactive, toRefs } from '@vue/reactivity'
|
import { reactive, toRefs } from '@vue/reactivity'
|
||||||
import { myData } from './assets/Json/印象笔记.js'
|
import { myData } from './assets/Json/印象笔记.js'
|
||||||
import { watch } from '@vue/runtime-core'
|
import { watch } from '@vue/runtime-core'
|
||||||
import Dialog from './components/Dialog.vue'
|
import Dialog from './components/Dialog.vue'
|
||||||
|
import Login from './components/Login.vue'
|
||||||
import gsap from 'gsap'
|
import gsap from 'gsap'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { importBookmark, exportBookmark } from './components/utils.js'
|
import { importBookmark, exportBookmark } from './components/utils.js'
|
||||||
|
import Cookie from 'js-cookie'
|
||||||
|
import Api from './Api/user.js'
|
||||||
var rowData = []
|
var rowData = []
|
||||||
function getData(fn = () => {}) {
|
function getData(fn = () => {}) {
|
||||||
// 数据持久化
|
// 数据持久化
|
||||||
@ -93,7 +99,7 @@ function getData(fn = () => {}) {
|
|||||||
}
|
}
|
||||||
getData()
|
getData()
|
||||||
export default {
|
export default {
|
||||||
components: { Dialog },
|
components: { Dialog, Login },
|
||||||
name: 'kestrel-bookmark',
|
name: 'kestrel-bookmark',
|
||||||
setup() {
|
setup() {
|
||||||
// 扁平化数组
|
// 扁平化数组
|
||||||
@ -113,9 +119,22 @@ export default {
|
|||||||
searchVal: '',
|
searchVal: '',
|
||||||
allData: flatten(rowData),
|
allData: flatten(rowData),
|
||||||
isDetailVisible: false,
|
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(
|
watch(
|
||||||
() => data.searchVal,
|
() => data.searchVal,
|
||||||
@ -150,8 +169,15 @@ export default {
|
|||||||
}
|
}
|
||||||
data.isDetailVisible = true
|
data.isDetailVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户登录
|
||||||
|
const handleUserLogin = () => {
|
||||||
|
data.isLoginVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
// 关闭弹窗事件
|
// 关闭弹窗事件
|
||||||
const closeViews = (v) => (data.isDetailVisible = v)
|
const closeViews = (v) => (data.isDetailVisible = v)
|
||||||
|
const closeLoginViews = (v) => (data.isLoginVisible = v)
|
||||||
|
|
||||||
// 获取数据
|
// 获取数据
|
||||||
const search = async () => {
|
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 {
|
return {
|
||||||
deleteClick,
|
deleteClick,
|
||||||
...toRefs(data),
|
...toRefs(data),
|
||||||
@ -187,9 +236,12 @@ export default {
|
|||||||
navigate,
|
navigate,
|
||||||
add,
|
add,
|
||||||
closeViews,
|
closeViews,
|
||||||
|
closeLoginViews,
|
||||||
search,
|
search,
|
||||||
importBookmark,
|
importBookmark,
|
||||||
exportBookmark
|
exportBookmark,
|
||||||
|
loginClick,
|
||||||
|
setUsername
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -525,4 +577,18 @@ export default {
|
|||||||
cursor: pointer;
|
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>
|
</style>
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -33,14 +33,13 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="closeViews">取 消</el-button>
|
<el-button @click="closeViews" size="small">取 消</el-button>
|
||||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
<el-button type="primary" @click="submitForm" size="small">确 定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import gsap from 'gsap'
|
|
||||||
import { reactive, ref, toRefs } from '@vue/reactivity'
|
import { reactive, ref, toRefs } from '@vue/reactivity'
|
||||||
import { nextTick, watch } from '@vue/runtime-core'
|
import { nextTick, watch } from '@vue/runtime-core'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
@ -154,26 +153,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
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>
|
</script>
|
||||||
|
107
src/components/Login.vue
Normal file
107
src/components/Login.vue
Normal 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>
|
@ -4,6 +4,14 @@ import App from './App.vue'
|
|||||||
import ElementPlus from 'element-plus'
|
import ElementPlus from 'element-plus'
|
||||||
import 'element-plus/lib/theme-chalk/index.css'
|
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)
|
const app = createApp(App)
|
||||||
app.use(ElementPlus)
|
app.use(ElementPlus)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
Loading…
Reference in New Issue
Block a user