Merge branch 'rymcu:master' into master

This commit is contained in:
Zeeland 2022-10-30 22:46:03 +08:00 committed by GitHub
commit 2856fa3296
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 7376 additions and 7606 deletions

View File

@ -10,7 +10,7 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-link target="_blank" :href="'/user/' + user.account" class="text-default"> <el-link target="_blank" :href="'/user/' + user.account" class="text-default">
<span style="font-size: 20px;font-weight: bold;">{{ user.nickname }}</span> <span style="font-size: 20px;font-weight: bold;" v-html="user.nickname"></span>
</el-link> </el-link>
</el-col> </el-col>
<el-col :span="24" style="padding: 1rem 0;"> <el-col :span="24" style="padding: 1rem 0;">
@ -48,7 +48,7 @@ export default {
name: "UserList", name: "UserList",
computed: { computed: {
...mapState({ ...mapState({
userInfo: state => state.oauth userInfo: state => state.auth.user
}) })
}, },
props: { props: {

View File

@ -9,7 +9,7 @@
<el-col :xs="0" :sm="12" :md="8" :xl="8" style="text-align: center;"> <el-col :xs="0" :sm="12" :md="8" :xl="8" style="text-align: center;">
<el-row type="flex" justify="center"> <el-row type="flex" justify="center">
<el-col> <el-col>
<el-menu :default-active="getActiveMenu" style="margin-top: -2px;border: 0;" mode="horizontal" <el-menu :default-active="activeMenu" style="margin-top: -2px;border: 0;" mode="horizontal"
@select="handleSelectMenu"> @select="handleSelectMenu">
<el-menu-item index="index">首页</el-menu-item> <el-menu-item index="index">首页</el-menu-item>
<el-menu-item index="topic">专题</el-menu-item> <el-menu-item index="topic">专题</el-menu-item>
@ -19,8 +19,9 @@
</el-col> </el-col>
<el-col :xs="16" :sm="8" :md="6" :xl="3" style="padding-top: 1rem;"> <el-col :xs="16" :sm="8" :md="6" :xl="3" style="padding-top: 1rem;">
<client-only> <client-only>
<el-col v-if="user" style="text-align: right;"> <el-col v-if="loggedIn" style="text-align: right;">
<el-link rel="nofollow" :underline="false" style="padding-left: 10px;padding-right: 10px;" href="/article/post">发帖 <el-link rel="nofollow" :underline="false" style="padding-left: 10px;padding-right: 10px;"
href="/article/post">发帖
</el-link> </el-link>
<el-link rel="nofollow" :underline="false" style="padding-left: 10px;padding-right: 10px;"> <el-link rel="nofollow" :underline="false" style="padding-left: 10px;padding-right: 10px;">
<el-dropdown trigger="click" @command="handleCommand"> <el-dropdown trigger="click" @command="handleCommand">
@ -37,15 +38,17 @@
</el-link> </el-link>
<el-link rel="nofollow" :underline="false" style="margin-left: 10px;"> <el-link rel="nofollow" :underline="false" style="margin-left: 10px;">
<el-dropdown trigger="click" @command="handleCommand"> <el-dropdown trigger="click" @command="handleCommand">
<el-avatar v-if="avatarURL" size="small" :src="avatarURL"></el-avatar> <el-avatar v-if="loggedIn" size="small" :src="user.avatarUrl"></el-avatar>
<el-avatar v-else size="small" src="https://static.rymcu.com/article/1578475481946.png"></el-avatar> <el-avatar v-else size="small" src="https://static.rymcu.com/article/1578475481946.png"></el-avatar>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="user" style="align-items: center;"> <el-dropdown-item command="user" style="align-items: center;">
<el-avatar class="mr-3" v-if="avatarURL" size="small" style="margin-top: 1rem;" <el-avatar class="mr-3" v-if="user.avatarUrl" size="small" style="margin-top: 1rem;"
:src="avatarURL"></el-avatar> :src="loggedIn"></el-avatar>
<el-avatar class="mr-3" v-else size="small" style="margin-top: 1rem;" <el-avatar class="mr-3" v-else size="small" style="margin-top: 1rem;"
src="https://static.rymcu.com/article/1578475481946.png"></el-avatar> src="https://static.rymcu.com/article/1578475481946.png"></el-avatar>
<el-link rel="nofollow" :underline="false" style="margin-left: 10px;margin-bottom: 1rem;">{{ nickname }}</el-link> <el-link rel="nofollow" :underline="false" style="margin-left: 10px;margin-bottom: 1rem;">
{{ user.nickname }}
</el-link>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-if="hasPermissions" command="admin-dashboard">系统管理</el-dropdown-item> <el-dropdown-item v-if="hasPermissions" command="admin-dashboard">系统管理</el-dropdown-item>
<el-dropdown-item command="user-info">资料与账号</el-dropdown-item> <el-dropdown-item command="user-info">资料与账号</el-dropdown-item>
@ -70,56 +73,18 @@
</template> </template>
<script> <script>
import { isBrowser } from '~/environment' import {mapState} from 'vuex';
const Cookie = process.client ? require('js-cookie') : undefined export default {
export default {
name: "MobileHeader", name: "MobileHeader",
computed: { computed: {
getActiveMenu() { ...mapState({
return this.$store.state.activeMenu; activeMenu: state => state.activeMenu,
}, user: state => state.auth.user,
user() { loggedIn: state => state.auth.loggedIn
return this.$store.state.oauth; }),
},
avatarURL() {
let _ts = this;
if (isBrowser) {
if (!_ts.$store.state.userInfo) {
let user = localStorage.getItem('user');
if (user) {
_ts.$store.commit('setUser', JSON.parse(user))
}
}
}
return _ts.$store.state.userInfo?.avatarURL;
},
nickname() {
let _ts = this;
if (isBrowser) {
if (!_ts.$store.state.userInfo) {
let user = localStorage.getItem('user');
if (user) {
_ts.$store.commit('setUser', JSON.parse(user))
}
}
}
return _ts.$store.state.userInfo?.nickname;
},
account() {
let _ts = this;
if (isBrowser) {
if (!_ts.$store.state.userInfo) {
let user = localStorage.getItem('user');
if (user) {
_ts.$store.commit('setUser', JSON.parse(user))
}
}
}
return _ts.$store.state.userInfo?.account;
},
hasPermissions() { hasPermissions() {
return this.$store.getters.hasPermissions('blog_admin'); return this.$auth.hasScope('blog_admin');
} }
}, },
data() { data() {
@ -166,7 +131,7 @@
switch (item) { switch (item) {
case 'user': case 'user':
_ts.$router.push({ _ts.$router.push({
path: '/user/' + _ts.account path: '/user/' + _ts.user.account
}) })
break; break;
case 'user-info': case 'user-info':
@ -175,8 +140,8 @@
}) })
break; break;
case 'logout': case 'logout':
Cookie.remove('auth') _ts.$auth.reset()
_ts.$store.commit('setAuth', null) item = 'login';
item = 'login'; item = 'login';
break; break;
default: default:
@ -205,14 +170,14 @@
ctx.font = "14px 'Arial'"; ctx.font = "14px 'Arial'";
ctx.textBaseline = "rymcu"; ctx.textBaseline = "rymcu";
ctx.fillStyle = "#f60"; ctx.fillStyle = "#f60";
ctx.fillRect(125,1,62,20); ctx.fillRect(125, 1, 62, 20);
ctx.fillStyle = "#069"; ctx.fillStyle = "#069";
ctx.fillText(txt, 2, 15); ctx.fillText(txt, 2, 15);
ctx.fillStyle = "rgba(102, 204, 0, 0.7)"; ctx.fillStyle = "rgba(102, 204, 0, 0.7)";
ctx.fillText(txt, 4, 17); ctx.fillText(txt, 4, 17);
let b64 = canvas.toDataURL().replace("data:image/png;base64,",""); let b64 = canvas.toDataURL().replace("data:image/png;base64,", "");
let bin = atob(b64); let bin = atob(b64);
let fingerprint = _ts.bin2hex(bin.slice(-16,-12)); let fingerprint = _ts.bin2hex(bin.slice(-16, -12));
_ts.$store.commit('setFingerprint', fingerprint); _ts.$store.commit('setFingerprint', fingerprint);
}, },
bin2hex(str) { bin2hex(str) {
@ -247,11 +212,11 @@
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
.navbar-brand { .navbar-brand {
color: inherit; color: inherit;
margin-right: 1rem; margin-right: 1rem;
font-size: 1.25rem; font-size: 1.25rem;
@ -260,13 +225,13 @@
padding: 0; padding: 0;
transition: .3s opacity; transition: .3s opacity;
line-height: 2rem; line-height: 2rem;
} }
.navbar-brand-img { .navbar-brand-img {
height: 2rem; height: 2rem;
line-height: 2rem; line-height: 2rem;
vertical-align: bottom; vertical-align: bottom;
margin-right: .5rem; margin-right: .5rem;
width: auto; width: auto;
} }
</style> </style>

View File

@ -20,7 +20,7 @@
<el-col :md="10" :span="10" :xs="16" style="line-height: 60px"> <el-col :md="10" :span="10" :xs="16" style="line-height: 60px">
<client-only> <client-only>
<el-col style="text-align: right;" v-if="user"> <el-col style="text-align: right;" v-if="loggedIn">
<el-popover <el-popover
@show="handleShowPopover" @show="handleShowPopover"
placement="bottom" placement="bottom"
@ -76,17 +76,17 @@
</el-link> </el-link>
<el-link :underline="false" rel="nofollow" style="margin-left: 10px;"> <el-link :underline="false" rel="nofollow" style="margin-left: 10px;">
<el-dropdown @command="handleCommand" trigger="click"> <el-dropdown @command="handleCommand" trigger="click">
<el-avatar :src="avatarURL" size="small" v-if="avatarURL"></el-avatar> <el-avatar :src="user.avatarUrl" size="small" v-if="user.avatarUrl"></el-avatar>
<el-avatar size="small" src="https://static.rymcu.com/article/1578475481946.png" v-else></el-avatar> <el-avatar size="small" src="https://static.rymcu.com/article/1578475481946.png" v-else></el-avatar>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item style="align-items: center;"> <el-dropdown-item style="align-items: center;">
<el-avatar :src="avatarURL" class="mr-3" size="small" style="margin-top: 1rem;" <el-avatar :src="user.avatarUrl" class="mr-3" size="small" style="margin-top: 1rem;"
v-if="avatarURL"></el-avatar> v-if="user.avatarUrl"></el-avatar>
<el-avatar class="mr-3" size="small" src="https://static.rymcu.com/article/1578475481946.png" <el-avatar class="mr-3" size="small" src="https://static.rymcu.com/article/1578475481946.png"
style="margin-top: 1rem;" style="margin-top: 1rem;"
v-else></el-avatar> v-else></el-avatar>
<el-link :underline="false" rel="nofollow" style="margin-left: 10px;margin-bottom: 1rem;"> <el-link :underline="false" rel="nofollow" style="margin-left: 10px;margin-bottom: 1rem;">
{{ nickname }} {{ user.nickname }}
</el-link> </el-link>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item command="user">个人中心</el-dropdown-item> <el-dropdown-item command="user">个人中心</el-dropdown-item>
@ -138,56 +138,19 @@
</template> </template>
<script> <script>
import {mapState} from 'vuex'; import {mapState} from 'vuex';
import {isBrowser} from '~/environment'; // import sockClient from '~/plugins/sockjs';
// import sockClient from '~/plugins/sockjs';
const Cookie = process.client ? require('js-cookie') : undefined export default {
export default {
name: "PcHeader", name: "PcHeader",
computed: { computed: {
...mapState({ ...mapState({
activeMenu: state => state.activeMenu, activeMenu: state => state.activeMenu,
user: state => state.oauth user: state => state.auth.user,
loggedIn: state => state.auth.loggedIn
}), }),
avatarURL() {
let _ts = this;
if (isBrowser) {
if (!_ts.$store.state.userInfo) {
let user = localStorage.getItem('user');
if (user) {
_ts.$store.commit('setUser', JSON.parse(user))
}
}
}
return _ts.$store.state.userInfo?.avatarURL;
},
nickname() {
let _ts = this;
if (isBrowser) {
if (!_ts.$store.state.userInfo) {
let user = localStorage.getItem('user');
if (user) {
_ts.$store.commit('setUser', JSON.parse(user))
}
}
}
return _ts.$store.state.userInfo?.nickname;
},
account() {
let _ts = this;
if (isBrowser) {
if (!_ts.$store.state.userInfo) {
let user = localStorage.getItem('user');
if (user) {
_ts.$store.commit('setUser', JSON.parse(user))
}
}
}
return _ts.$store.state.userInfo?.account;
},
hasPermissions() { hasPermissions() {
return this.$store.getters.hasPermissions('blog_admin'); return this.$auth.hasScope('admin') || this.$auth.hasScope('blog_admin');
} }
}, },
data() { data() {
@ -264,7 +227,7 @@
switch (item) { switch (item) {
case 'user': case 'user':
_ts.$router.push({ _ts.$router.push({
path: '/user/' + _ts.account path: '/user/' + _ts.user.account
}) })
break; break;
case 'user-info': case 'user-info':
@ -273,8 +236,7 @@
}) })
break; break;
case 'logout': case 'logout':
Cookie.remove('auth') _ts.$auth.logout()
_ts.$store.commit('setAuth', null)
item = 'login'; item = 'login';
break; break;
default: default:
@ -348,7 +310,7 @@
_ts.getUnreadNotifications(); _ts.getUnreadNotifications();
_ts.$store.dispatch('follow/fetchUserFollowerList'); _ts.$store.dispatch('follow/fetchUserFollowerList');
_ts.$store.dispatch('follow/fetchUserFollowingList'); _ts.$store.dispatch('follow/fetchUserFollowingList');
// sockClient.initSocket(this.$store.state.userInfo); // sockClient.initSocket(this.$store.state.auth.user);
} }
let fingerprint = _ts.$store.state.fingerprint let fingerprint = _ts.$store.state.fingerprint
if (!fingerprint) { if (!fingerprint) {
@ -356,11 +318,11 @@
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
.navbar-brand { .navbar-brand {
color: inherit; color: inherit;
margin-right: 1rem; margin-right: 1rem;
font-size: 1.25rem; font-size: 1.25rem;
@ -369,20 +331,20 @@
padding: 0; padding: 0;
transition: .3s opacity; transition: .3s opacity;
line-height: 3rem; line-height: 3rem;
} }
.navbar-brand-img { .navbar-brand-img {
height: 3rem; height: 3rem;
line-height: 3rem; line-height: 3rem;
vertical-align: top; vertical-align: top;
width: auto; width: auto;
} }
.search-result-box { .search-result-box {
min-width: 20vw !important; min-width: 20vw !important;
} }
.search-result-type { .search-result-type {
padding-right: 5px; padding-right: 5px;
} }
</style> </style>

View File

@ -1,6 +0,0 @@
export default function ({ store, redirect }) {
// If the user is not authenticated
if (!store.state.oauth) {
return redirect('/login')
}
}

View File

@ -1,6 +0,0 @@
export default function ({ store, redirect }) {
// If the user is authenticated redirect to home page
if (store.state.oauth) {
return redirect('/')
}
}

View File

@ -70,9 +70,44 @@ export default {
modules: [ modules: [
'@nuxtjs/axios', '@nuxtjs/axios',
'@nuxtjs/proxy', '@nuxtjs/proxy',
'js-cookie', '@nuxtjs/auth-next'
'cookieparser'
], ],
auth: {
redirect: {
login: '/login',
logout: false,
home: false
},
strategies: {
local: {
// scope: true,
scheme: 'refresh',
token: {
property: 'token',
global: true,
maxAge: 60 * 15,
// required: true,
type: false
},
refreshToken: {
property: 'refreshToken',
data: 'refreshToken',
maxAge: 60 * 60 * 2
},
user: {
property: 'user',
autoFetch: false
},
endpoints: {
login: { url: '/api/auth/login', method: 'post' },
logout: { url: '/api/auth/logout', method: 'post' },
refresh: { url: '/api/auth/refresh-token', method: 'post' },
user: { url: '/api/auth/user', method: 'get' }
},
autoLogout: false
}
}
},
axios: { axios: {
proxy: true // 开启proxy proxy: true // 开启proxy
}, },

View File

@ -11,13 +11,12 @@
}, },
"dependencies": { "dependencies": {
"@chenfengyuan/vue-qrcode": "^1.0.2", "@chenfengyuan/vue-qrcode": "^1.0.2",
"@nuxtjs/auth-next": "^5.0.0-1648802546.c9880dc",
"@nuxtjs/axios": "^5.13.1", "@nuxtjs/axios": "^5.13.1",
"babel-plugin-lodash": "^3.3.4", "babel-plugin-lodash": "^3.3.4",
"cookieparser": "^0.1.0",
"echarts": "^4.9.0", "echarts": "^4.9.0",
"element-ui": "^2.15.8", "element-ui": "^2.15.8",
"express": "^4.18.1", "express": "^4.18.1",
"js-cookie": "^2.2.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"net": "^1.0.2", "net": "^1.0.2",
"nuxt": "^2.15.8", "nuxt": "^2.15.8",

View File

@ -45,6 +45,7 @@ import _ from 'lodash'
export default { export default {
name: "Admin", name: "Admin",
middleware: 'auth',
data() { data() {
return { return {
menus: [ menus: [
@ -144,7 +145,7 @@ export default {
return this.$store.state.activeMenu; return this.$store.state.activeMenu;
}, },
hasPermissions() { hasPermissions() {
return this.$store.getters.hasPermissions('blog_admin'); return this.$auth.hasScope('admin') || this.$auth.hasScope('blog_admin');
} }
}, },
methods: { methods: {

View File

@ -107,6 +107,7 @@ import EditTags from '~/components/widget/tags';
export default { export default {
name: "articles", name: "articles",
middleware: 'auth',
components: { components: {
EditTags EditTags
}, },

View File

@ -75,6 +75,7 @@ import Records from "../../components/common/bank/account/records";
export default { export default {
name: "bank-accounts", name: "bank-accounts",
middleware: 'auth',
components: {Records}, components: {Records},
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context

View File

@ -87,6 +87,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "banks", name: "banks",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -97,6 +97,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "comments", name: "comments",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -81,6 +81,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "currency-rules", name: "currency-rules",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -248,6 +248,7 @@ import EditTags from '~/components/widget/tags';
Vue.prototype.$echarts = echarts; Vue.prototype.$echarts = echarts;
export default { export default {
name: "Dashboard", name: "Dashboard",
middleware: 'auth',
components: { components: {
EditTags EditTags
}, },

View File

@ -80,6 +80,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "products", name: "products",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -91,6 +91,7 @@
export default { export default {
name: "roles", name: "roles",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -126,6 +126,7 @@ import apiConfig from '~/config/api.config';
export default { export default {
name: "PostTag", name: "PostTag",
middleware: 'auth',
components: { components: {
VueCropper VueCropper
}, },

View File

@ -48,6 +48,7 @@
export default { export default {
name: "tags", name: "tags",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -71,6 +71,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "adminTopicDetail", name: "adminTopicDetail",
middleware: 'auth',
validate({params, store}) { validate({params, store}) {
if (typeof params.topic_uri === 'undefined') { if (typeof params.topic_uri === 'undefined') {
return true; return true;
@ -94,7 +95,7 @@ export default {
tags: state => state.topic.tags.data tags: state => state.topic.tags.data
}), }),
hasPermissions() { hasPermissions() {
return this.$store.getters.hasPermissions('topic'); return this.$auth.hasScope('topic');
} }
}, },
methods: { methods: {

View File

@ -53,6 +53,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "adminTopicBindTag", name: "adminTopicBindTag",
middleware: 'auth',
fetch({store, params, error}) { fetch({store, params, error}) {
let _ts = this; let _ts = this;
return Promise.all([ return Promise.all([

View File

@ -124,6 +124,7 @@ import apiConfig from '~/config/api.config';
export default { export default {
name: "adminTopicPost", name: "adminTopicPost",
middleware: 'auth',
components: { components: {
VueCropper VueCropper
}, },

View File

@ -39,6 +39,7 @@
export default { export default {
name: "topics", name: "topics",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -119,6 +119,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "users", name: "users",
middleware: 'auth',
fetch() { fetch() {
let {store, params, error} = this.$nuxt.context let {store, params, error} = this.$nuxt.context
return Promise.all([ return Promise.all([

View File

@ -62,6 +62,7 @@ import {mapState} from 'vuex';
export default { export default {
name: "answer", name: "answer",
middleware: 'auth',
fetch({store, params, error}) { fetch({store, params, error}) {
return Promise.all([ return Promise.all([
store store

View File

@ -82,7 +82,7 @@
<el-col v-if="article.portfolios && article.portfolios.length > 0"> <el-col v-if="article.portfolios && article.portfolios.length > 0">
<portfolios-widget :portfolios="article.portfolios"></portfolios-widget> <portfolios-widget :portfolios="article.portfolios"></portfolios-widget>
</el-col> </el-col>
<el-col v-if="user"> <el-col v-if="loggedIn">
<el-tooltip class="item" effect="dark" content="酷" placement="top-start"> <el-tooltip class="item" effect="dark" content="酷" placement="top-start">
<el-button type="text" style="font-size: 1.2rem;" @click="thumbsUp"> <el-button type="text" style="font-size: 1.2rem;" @click="thumbsUp">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
@ -192,11 +192,12 @@ export default {
article: state => state.article.detail.data, article: state => state.article.detail.data,
isFetching: state => state.article.detail.fetching, isFetching: state => state.article.detail.fetching,
isMobile: state => state.global.isMobile, isMobile: state => state.global.isMobile,
user: state => state.oauth, loggedIn: state => state.auth.loggedIn,
avatar: state => state.userInfo?.avatarURL user: state => state.auth.user,
avatar: state => state.auth.user.avatarUrl
}), }),
hasPermissions() { hasPermissions() {
let account = this.$store.state.userInfo?.nickname; let account = this.$store.state.auth.user?.nickname;
if (account) { if (account) {
if (account === this.article.articleAuthor.userNickname) { if (account === this.article.articleAuthor.userNickname) {
return true; return true;
@ -205,7 +206,7 @@ export default {
return false; return false;
}, },
isAdmin() { isAdmin() {
return this.$store.getters.hasPermissions('blog_admin'); return this.$auth.hasScope('admin') || this.$auth.hasScope('blog_admin');
}, },
routeArticleId() { routeArticleId() {
return Number(this.$route.params.article_id); return Number(this.$route.params.article_id);

View File

@ -63,6 +63,7 @@
export default { export default {
name: "PostArticle", name: "PostArticle",
middleware: 'auth',
validate({params, store}) { validate({params, store}) {
if (typeof params.article_id === 'undefined') { if (typeof params.article_id === 'undefined') {
return true; return true;
@ -80,7 +81,7 @@
article: state => state.article.detail.data article: state => state.article.detail.data
}), }),
hasPermissions() { hasPermissions() {
let account = this.$store.state.userInfo?.nickname; let account = this.$store.state.auth.user?.nickname;
if (account) { if (account) {
if (this.$route.params.article_id) { if (this.$route.params.article_id) {
if (account === this.article.articleAuthor.userNickname) { if (account === this.article.articleAuthor.userNickname) {
@ -90,7 +91,7 @@
return true; return true;
} }
} }
return this.$store.getters.hasPermissions('blog_admin'); return this.$auth.hasScope('blog_admin');
} }
}, },
data() { data() {

View File

@ -45,7 +45,7 @@ export default {
name: "Chat", name: "Chat",
computed: { computed: {
...mapState({ ...mapState({
user: state => state.userInfo user: state => state.auth.user
}) })
}, },
data() { data() {

View File

@ -71,6 +71,7 @@
export default { export default {
name: "DraftDetail", name: "DraftDetail",
middleware: 'auth',
validate({params, store}) { validate({params, store}) {
return params.draft_id && !isNaN(Number(params.draft_id)) return params.draft_id && !isNaN(Number(params.draft_id))
}, },
@ -86,17 +87,17 @@
article: state => state.draft.detail.data, article: state => state.draft.detail.data,
isFetching: state => state.draft.detail.fetching, isFetching: state => state.draft.detail.fetching,
isMobile: state => state.global.isMobile, isMobile: state => state.global.isMobile,
user: state => state.oauth, user: state => state.auth.user,
avatar: state => state.userInfo?.avatarURL avatar: state => state.auth.user?.avatarURL
}), }),
hasPermissions() { hasPermissions() {
let account = this.$store.state.userInfo?.nickname; let account = this.$store.state.auth.user?.nickname;
if (account) { if (account) {
if (account === this.article?.articleAuthor?.userNickname) { if (account === this.article?.articleAuthor?.userNickname) {
return true; return true;
} }
} }
return this.$store.getters.hasPermissions('blog_admin'); return this.$auth.hasScope('blog_admin');
}, },
routeArticleId() { routeArticleId() {
return Number(this.$route.params.draft_id) return Number(this.$route.params.draft_id)

View File

@ -13,6 +13,7 @@
export default { export default {
name: "Drafts", name: "Drafts",
middleware: 'auth',
components: { components: {
DraftList DraftList
}, },
@ -27,7 +28,7 @@
computed: { computed: {
...mapState({ ...mapState({
articles: state => state.draft.list.data, articles: state => state.draft.list.data,
user: state => state.oauth user: state => state.auth.user
}) })
}, },
mounted() { mounted() {

View File

@ -54,10 +54,9 @@
<script> <script>
import {mapState} from 'vuex'; import {mapState} from 'vuex';
const Cookie = process.client ? require('js-cookie') : undefined
export default { export default {
name: "login", name: "login",
middleware: 'notAuthenticated', middleware: 'auth',
data() { data() {
return { return {
user: { user: {
@ -81,40 +80,17 @@ export default {
methods: { methods: {
login() { login() {
let _ts = this; let _ts = this;
_ts.$refs.user.validate((valid) => { _ts.$refs.user.validate(async (valid) => {
if (valid) { if (valid) {
_ts.$set(_ts, 'loginLoading', true); _ts.$set(_ts, 'loginLoading', true);
setTimeout(function () {
_ts.$set(_ts, 'loginLoading', false);
}, 10000);
let data = { let data = {
account: _ts.user.account, account: _ts.user.account,
password: _ts.user.password password: _ts.user.password
} }
try {
_ts.$axios.$post('/api/console/login', data).then(function (res) { let response = await _ts.$auth.loginWith('local', {data: data})
_ts.$set(_ts, 'loginLoading', false); if (response.success) {
if (res) { _ts.$auth.setUserToken(response.data.token, response.data.refreshToken);
if (res.message) {
_ts.$message(res.message);
return false;
}
let auth = {
accessToken: res.token,
idUser: res.idUser,
role: res.weights
}
let user = {
nickname: res.nickname,
avatarURL: res.avatarUrl || 'https://static.rymcu.com/article/1578475481946.png',
account: res.account
}
_ts.$store.commit('setAuth', auth) // mutating to store for client rendering
localStorage.setItem('user', JSON.stringify(user))
_ts.$store.commit('setUser', user) // mutating to store for client rendering
Cookie.set('auth', auth, { expires: 7 })
if (_ts.historyUrl) { if (_ts.historyUrl) {
window.location.href = _ts.historyUrl window.location.href = _ts.historyUrl
} else { } else {
@ -123,9 +99,11 @@ export default {
}) })
} }
} }
},functions(error) {
_ts.$set(_ts, 'loginLoading', false); _ts.$set(_ts, 'loginLoading', false);
}) } catch (err) {
_ts.$set(_ts, 'loginLoading', false);
console.log(err)
}
} else { } else {
return false; return false;
} }

View File

@ -13,7 +13,7 @@
export default { export default {
name: "Notification", name: "Notification",
middleware: 'authenticated', middleware: 'auth',
components: { components: {
NotificationList NotificationList
}, },
@ -33,7 +33,7 @@
computed: { computed: {
...mapState({ ...mapState({
notifications: state => state.notification.list.data, notifications: state => state.notification.list.data,
user: state => state.oauth user: state => state.auth.user
}) })
}, },
methods: { methods: {

View File

@ -83,11 +83,11 @@ export default {
articles: state => state.portfolio.articles, articles: state => state.portfolio.articles,
isFetching: state => state.portfolio.detail.fetching, isFetching: state => state.portfolio.detail.fetching,
isMobile: state => state.global.isMobile, isMobile: state => state.global.isMobile,
user: state => state.oauth, user: state => state.auth.user,
avatar: state => state.userInfo?.avatarURL avatar: state => state.auth.user?.avatarURL
}), }),
isAuthor() { isAuthor() {
let account = this.$store.state.userInfo?.nickname; let account = this.$store.state.auth.user?.nickname;
if (account) { if (account) {
if (account === this.portfolio.portfolioAuthor.userNickname) { if (account === this.portfolio.portfolioAuthor.userNickname) {
return true; return true;

View File

@ -78,7 +78,7 @@
portfolio: state => state.portfolio.detail.data portfolio: state => state.portfolio.detail.data
}), }),
isAuthor() { isAuthor() {
let account = this.$store.state.userInfo?.nickname; let account = this.$store.state.auth.user?.nickname;
if (account) { if (account) {
if (account === this.portfolio.portfolioAuthorName) { if (account === this.portfolio.portfolioAuthorName) {
return true; return true;

View File

@ -125,7 +125,7 @@ export default {
return {'X-Upload-Token': state.uploadHeaders} return {'X-Upload-Token': state.uploadHeaders}
}, },
isAuthor() { isAuthor() {
let account = this.$store.state.userInfo?.nickname; let account = this.$store.state.auth.user?.nickname;
if (account) { if (account) {
if (this.$route.params.portfolio_id) { if (this.$route.params.portfolio_id) {
if (account === this.portfolioDetail.portfolioAuthorName) { if (account === this.portfolioDetail.portfolioAuthorName) {
@ -334,7 +334,7 @@ export default {
if (res) { if (res) {
_ts.$set(_ts, 'notificationFlag', false); _ts.$set(_ts, 'notificationFlag', false);
_ts.$router.push({ _ts.$router.push({
path: '/user/' + _ts.$store.state.userInfo?.account path: '/user/' + _ts.$store.state.auth.user?.account
}) })
} }
}) })

View File

@ -61,8 +61,8 @@
</el-link> </el-link>
</el-popover> </el-popover>
</div> </div>
<div v-if="oauth"> <div v-if="auth.user">
<div v-if="oauth.idUser !== user.idUser"> <div v-if="auth.user.idUser !== user.idUser">
<el-button type="primary" v-if="isFollow" @click="cancelFollowUser(user.idUser)" plain>取消关注</el-button> <el-button type="primary" v-if="isFollow" @click="cancelFollowUser(user.idUser)" plain>取消关注</el-button>
<el-button type="primary" v-else @click="followUser(user.idUser)" plain>关注</el-button> <el-button type="primary" v-else @click="followUser(user.idUser)" plain>关注</el-button>
<el-button v-show="false" @click="gotoChats" plain>聊天</el-button> <el-button v-show="false" @click="gotoChats" plain>聊天</el-button>
@ -176,7 +176,7 @@ export default {
portfolios: state => state.user.portfolios, portfolios: state => state.user.portfolios,
followers: state => state.user.followers, followers: state => state.user.followers,
followings: state => state.user.followings, followings: state => state.user.followings,
oauth: state => state.oauth auth: state => state.auth.user
}) })
}, },
data() { data() {
@ -227,7 +227,7 @@ export default {
}, },
followUser(idUser) { followUser(idUser) {
let _ts = this; let _ts = this;
if (_ts.oauth) { if (_ts.auth) {
_ts.$axios.$post('/api/follow', { _ts.$axios.$post('/api/follow', {
followingId: idUser, followingId: idUser,
followingType: 0 followingType: 0
@ -241,7 +241,7 @@ export default {
}, },
cancelFollowUser(idUser) { cancelFollowUser(idUser) {
let _ts = this; let _ts = this;
if (_ts.oauth) { if (_ts.auth) {
_ts.$axios.$post('/api/follow/cancel-follow', { _ts.$axios.$post('/api/follow/cancel-follow', {
followingId: idUser, followingId: idUser,
followingType: 0 followingType: 0
@ -265,7 +265,7 @@ export default {
mounted() { mounted() {
let _ts = this; let _ts = this;
this.$store.commit('setActiveMenu', 'user'); this.$store.commit('setActiveMenu', 'user');
if (_ts.oauth) { if (_ts.auth) {
_ts.$axios.$get('/api/follow/is-follow', { _ts.$axios.$get('/api/follow/is-follow', {
params: { params: {
followingId: _ts.user.idUser, followingId: _ts.user.idUser,

View File

@ -47,12 +47,13 @@
<script> <script>
export default { export default {
name: "Settings", name: "Settings",
middleware: 'auth',
computed: { computed: {
getActiveMenu () { getActiveMenu () {
return this.$store.state.activeMenu; return this.$store.state.activeMenu;
}, },
isLogin () { isLogin () {
return this.$store.state.oauth; return this.$store.state.auth.user;
} }
}, },
data() { data() {

View File

@ -65,9 +65,10 @@
export default { export default {
name: "account", name: "account",
middleware: 'auth',
computed: { computed: {
...mapState({ ...mapState({
idUser: state => state.oauth.idUser idUser: state => state.auth.user.idUser
}) })
}, },
data() { data() {

View File

@ -81,6 +81,7 @@ import 'cropperjs/dist/cropper.css';
const {generateRandomAvatar} = require('~/plugins/avataaars/generator/generateAvatar'); const {generateRandomAvatar} = require('~/plugins/avataaars/generator/generateAvatar');
export default { export default {
name: "avatar", name: "avatar",
middleware: 'auth',
components: { components: {
Avataaars, Avataaars,
VueCropper VueCropper
@ -90,7 +91,7 @@ export default {
uploadHeaders: state => { uploadHeaders: state => {
return {'X-Upload-Token': state.uploadHeaders} return {'X-Upload-Token': state.uploadHeaders}
}, },
idUser: state => state.oauth.idUser idUser: state => state.auth.user.idUser
}) })
}, },
data() { data() {

View File

@ -12,10 +12,11 @@ import LoginRecords from "@/components/common/user/login-records";
export default { export default {
name: "loginRecord", name: "loginRecord",
middleware: 'auth',
components: {LoginRecords}, components: {LoginRecords},
computed: { computed: {
...mapState({ ...mapState({
idUser: state => state.oauth.idUser idUser: state => state.auth.user.idUser
}) })
}, },
data() { data() {

View File

@ -79,7 +79,7 @@ export default {
name: "security", name: "security",
computed: { computed: {
...mapState({ ...mapState({
idUser: state => state.oauth.idUser idUser: state => state.auth.user.idUser
}) })
}, },
data() { data() {

View File

@ -1,5 +1,6 @@
<template> <template>
<el-row class="wrapper"> <el-row class="wrapper">
<el-col v-if="bankAccount">
<el-col> <el-col>
<h1>账户信息</h1> <h1>账户信息</h1>
</el-col> </el-col>
@ -13,6 +14,10 @@
<el-col> <el-col>
<records :records="records" :bankAccount="bankAccount.bankAccount" @currentChange="handleCurrentChange" @searchTransactionRecord="searchTransactionRecord"></records> <records :records="records" :bankAccount="bankAccount.bankAccount" @currentChange="handleCurrentChange" @searchTransactionRecord="searchTransactionRecord"></records>
</el-col> </el-col>
</el-col>
<el-col v-else style="text-align: center;margin-top: 10vh;">
<el-button type="primary">开通钱包账号</el-button>
</el-col>
</el-row> </el-row>
</template> </template>
@ -26,10 +31,10 @@ export default {
fetch({store, error}) { fetch({store, error}) {
return Promise.all([ return Promise.all([
store store
.dispatch('wallet/fetchDetail', {idUser: store.state.oauth.idUser}) .dispatch('wallet/fetchDetail')
.catch(err => error({statusCode: 404})), .catch(err => error({statusCode: 404})),
store store
.dispatch('wallet/fetchTransactionRecordList', {idUser: store.state.oauth.idUser}) .dispatch('wallet/fetchTransactionRecordList')
.catch(err => error({statusCode: 404})) .catch(err => error({statusCode: 404}))
]) ])
}, },
@ -47,7 +52,7 @@ export default {
handleCurrentChange(search) { handleCurrentChange(search) {
let _ts = this; let _ts = this;
_ts.$store.dispatch('wallet/fetchTransactionRecordList', { _ts.$store.dispatch('wallet/fetchTransactionRecordList', {
idUser: _ts.$store.state.oauth.idUser, idUser: _ts.$store.state.auth.user.idUser,
startDate: search.startDate, startDate: search.startDate,
endDate: search.endDate, endDate: search.endDate,
page: search.page page: search.page
@ -58,7 +63,7 @@ export default {
let startDate = dates[0] let startDate = dates[0]
let endDate = dates[1] let endDate = dates[1]
_ts.$store.dispatch('wallet/fetchTransactionRecordList', { _ts.$store.dispatch('wallet/fetchTransactionRecordList', {
idUser: _ts.$store.state.oauth.idUser, idUser: _ts.$store.state.auth.user.idUser,
startDate: startDate, startDate: startDate,
endDate: endDate endDate: endDate
}) })

View File

@ -1,18 +1,11 @@
import {Message} from 'element-ui' import {Message} from 'element-ui'
const Cookie = process.client ? require('js-cookie') : undefined
export default function ({app, $axios, store, redirect}) { export default function ({app, $axios, store, redirect}) {
$axios.onRequest(config => { $axios.onRequest(config => {
let fingerprint = store.state.fingerprint; let fingerprint = store.state.fingerprint;
if (fingerprint) { if (fingerprint) {
config.headers['fingerprint'] = fingerprint config.headers['fingerprint'] = fingerprint
} }
let token = store.state.oauth?.accessToken;
if (token) {
// if (!(config.url.indexOf('console') > -1 || config.url.indexOf('comments') > -1)) {
// }
config.headers['Authorization'] = token
}
}) })
$axios.onResponse(response => { $axios.onResponse(response => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -29,13 +22,9 @@ export default function ({app, $axios, store, redirect}) {
if (response.data.code === 0) { if (response.data.code === 0) {
Message.error(message ? message : '服务异常') Message.error(message ? message : '服务异常')
} else if (response.data.code === 401) { } else if (response.data.code === 401) {
Cookie.remove('auth'); app.$auth.logout()
store.commit('setAuth', null);
window.location.reload()
} else if (response.data.code === 402) { } else if (response.data.code === 402) {
Cookie.remove('auth'); app.$auth.strategy.token.reset()
store.commit('setAuth', null);
window.location.reload()
} else if (response.data.code === 404) { } else if (response.data.code === 404) {
Message.error('操作失败,请稍后再试......') Message.error('操作失败,请稍后再试......')
} else if (response.data.code === 500) { } else if (response.data.code === 500) {
@ -47,6 +36,7 @@ export default function ({app, $axios, store, redirect}) {
reject(response); reject(response);
}) })
}); });
$axios.onError(error => { $axios.onError(error => {
const code = parseInt(error.response && error.response.status) const code = parseInt(error.response && error.response.status)
if (code === 400) { if (code === 400) {

View File

@ -26,7 +26,6 @@ export const mutations = {
state.list.fetching = action state.list.fetching = action
}, },
updateListData(state, action) { updateListData(state, action) {
console.log(action)
state.list.data = action state.list.data = action
}, },
// 文章详情 // 文章详情

View File

@ -1,7 +1,5 @@
import { isServer } from '~/environment' import { isServer } from '~/environment'
const cookieParser = isServer ? require('cookieparser') : undefined
export const state = () => { export const state = () => {
return { return {
activeMenu: 'index', activeMenu: 'index',
@ -14,28 +12,12 @@ export const state = () => {
} }
export const mutations = { export const mutations = {
setAuth (state, auth) {
state.oauth = auth
},
setUser (state, data) {
state.userInfo = data
},
setActiveMenu (state, activeMenu) { setActiveMenu (state, activeMenu) {
state.activeMenu = activeMenu state.activeMenu = activeMenu
}, },
setUploadHeaders(state, data){ setUploadHeaders(state, data){
state.uploadHeaders = data state.uploadHeaders = data
}, },
setUserInfo(state, data) {
state.userInfo.avatarURL = data.avatarUrl;
state.userInfo.nickname = data.nickname;
let user = {
nickname: data.nickname,
avatarURL: data.avatarUrl,
account: this.state.userInfo.account
}
localStorage.setItem('user', JSON.stringify(user))
},
setFingerprint (state, fingerprint) { setFingerprint (state, fingerprint) {
state.fingerprint = fingerprint state.fingerprint = fingerprint
} }
@ -65,17 +47,6 @@ export const actions = {
// 移动端 // 移动端
store.commit('global/updateMobileState', true) store.commit('global/updateMobileState', true)
} }
let auth = null
if (req.headers.cookie) {
const parsed = cookieParser.parse(req.headers.cookie)
try {
auth = JSON.parse(parsed.auth)
} catch (err) {
// No valid cookie found
console.log(err);
}
store.commit('setAuth', auth)
}
const initFetchAppData = [ const initFetchAppData = [
// 内容数据 // 内容数据
@ -86,36 +57,3 @@ export const actions = {
return Promise.all(initFetchAppData) return Promise.all(initFetchAppData)
} }
} }
export const getters = {
hasPermissions: (state) => (scenes) => {
let hasPermissions = false;
const role = state.oauth?.role
if (role) {
switch (scenes) {
case 'user':
hasPermissions = role < 5;
break;
case 'role':
hasPermissions = role < 2;
break;
case 'topic':
hasPermissions = role < 3;
break;
case 'tag':
hasPermissions = role < 3;
break;
case 'admin':
hasPermissions = role < 2;
break;
case 'blog_admin':
hasPermissions = role < 3;
break;
default:
hasPermissions = false;
this.commit('logout');
}
}
return hasPermissions;
}
}

View File

@ -42,7 +42,7 @@ export const mutations = {
state.detail.fetching = action state.detail.fetching = action
}, },
updateDetailData(state, action) { updateDetailData(state, action) {
state.detail.data = action.product state.detail.data = action
}, },
// 更新作品集阅读全文状态 // 更新作品集阅读全文状态
updateDetailRenderedState(state, action) { updateDetailRenderedState(state, action) {

View File

@ -39,10 +39,10 @@ export const mutations = {
export const actions = { export const actions = {
// 获取账户详情 // 获取账户详情
fetchDetail({commit}, params = {}) { fetchDetail({commit}) {
commit('updateDetailFetching', true) commit('updateDetailFetching', true)
return this.$axios return this.$axios
.$get(`${WALLET_API_PATH}/${params.idUser}`) .$get(`${WALLET_API_PATH}/detail`)
.then(response => { .then(response => {
return new Promise(resolve => { return new Promise(resolve => {
commit('updateDetailData', response) commit('updateDetailData', response)
@ -64,7 +64,6 @@ export const actions = {
return this.$axios return this.$axios
.$get(`${WALLET_API_PATH}/transaction-records`, { .$get(`${WALLET_API_PATH}/transaction-records`, {
params: { params: {
idUser: params.idUser,
startDate: params.startDate, startDate: params.startDate,
endDate: params.endDate, endDate: params.endDate,
page: params.page || 1 page: params.page || 1

13913
yarn.lock

File diff suppressed because it is too large Load Diff