first commit

This commit is contained in:
ronger 2020-07-03 11:04:25 +08:00
parent 4bf83cc3fe
commit 5a13c949fa
18 changed files with 1261 additions and 1214 deletions

View File

@ -1,42 +1,46 @@
<template> <template>
<el-row class="footer"> <el-row class="footer">
<el-col style="text-align: center;"> <el-col style="text-align: center;">
<el-col :xs="24" :sm="24" :xl="12"> <el-col :xs="24" :sm="24" :xl="12">
<span>{{ slogan }}</span> <span>{{ slogan }}</span>
<span>{{ slogan_en }}</span> <span>{{ slogan_en }}</span>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :xl="12"> <el-col :xs="24" :sm="24" :xl="12">
<el-col class="row align-items-center"> <el-col class="row align-items-center">
<el-col class="col-auto"> <el-col class="col-auto">
Copyright © 2020 <el-link :underline="false" href="/" style="vertical-align: baseline;"><span>{{ systemName }}</span></el-link>. Copyright © 2020
<el-link :underline="false" href="http://www.beian.miit.gov.cn/" style="vertical-align: baseline;"><span>{{ beiAn }}</span></el-link> <el-link :underline="false" href="/" style="vertical-align: baseline;"><span>{{ systemName }}</span>
</el-col> </el-link>
</el-col> .
</el-col> <el-link :underline="false" href="http://www.beian.miit.gov.cn/" style="vertical-align: baseline;"><span>{{ beiAn }}</span>
</el-link>
</el-col>
</el-col> </el-col>
</el-row> </el-col>
</el-col>
</el-row>
</template> </template>
<script> <script>
export default { export default {
name: "MobileFooter", name: "MobileFooter",
data() { data() {
return { return {
systemTitle: '\u7f57\u5409\u7f51\u0020\u002d\u0020\u5185\u5bb9\u5206\u4eab\u751f\u6001\u5e73\u53f0', systemTitle: '\u7f57\u5409\u7f51\u0020\u002d\u0020\u5185\u5bb9\u5206\u4eab\u751f\u6001\u5e73\u53f0',
systemName: 'RYMCU', systemName: 'RYMCU',
systemUrl: 'https://rymcu.com', systemUrl: 'https://rymcu.com',
slogan: 'rymcu · 嵌入式知识学习交流平台 ', slogan: 'rymcu · 嵌入式知识学习交流平台 ',
slogan_en: 'Embedded knowledge learning exchange platform', slogan_en: 'Embedded knowledge learning exchange platform',
beiAn: '沪ICP备19042611号' beiAn: '沪ICP备19042611号'
} }
}
} }
}
</script> </script>
<style scoped> <style scoped>
.footer { .footer {
font-size: 14px; font-size: 14px;
align-items: center; align-items: center;
display: flex; display: flex;
} }
</style> </style>

View File

@ -1,224 +1,242 @@
<template> <template>
<el-row justify="space-between" type="flex"> <el-row justify="space-between" type="flex">
<el-col> <el-col>
<el-col :xs="8" :sm="4" :md="4" :xl="3" style="padding-top: 1rem;"> <el-col :xs="8" :sm="4" :md="4" :xl="3" style="padding-top: 1rem;">
<a class="navbar-brand" href="/"> <a class="navbar-brand" href="/">
<img src="@/assets/rymcu.png" alt="RYMCU" class="navbar-brand-img"> <img src="@/assets/rymcu.png" alt="RYMCU" class="navbar-brand-img">
<span>RYMCU</span> <span>RYMCU</span>
</a> </a>
</el-col> </el-col>
<el-col :xs="0" :sm="12" :md="14" :xl="18" style="text-align: center;"> <el-col :xs="0" :sm="12" :md="14" :xl="18" 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" @select="handleSelectMenu"> <el-menu :default-active="getActiveMenu" style="margin-top: -2px;border: 0;" mode="horizontal"
<el-menu-item index="home">首页</el-menu-item> @select="handleSelectMenu">
<el-menu-item index="topic">专题</el-menu-item> <el-menu-item index="index">首页</el-menu-item>
<el-menu-item index="github">开源代码</el-menu-item> <el-menu-item index="topic">专题</el-menu-item>
<el-menu-item index="open-source">资料下载</el-menu-item> <el-menu-item index="github">开源代码</el-menu-item>
</el-menu> <el-menu-item index="open-source">资料下载</el-menu-item>
</el-col> </el-menu>
</el-row> </el-col>
</el-col> </el-row>
<el-col :xs="16" :sm="8" :md="6" :xl="3" style="padding-top: 1rem;"> </el-col>
<!--<el-col :xs="24" :sm="16" :xl="12">--> <el-col :xs="16" :sm="8" :md="6" :xl="3" style="padding-top: 1rem;">
<el-col :xs="0" :sm="0" :xl="0"> <!--<el-col :xs="24" :sm="16" :xl="12">-->
<el-autocomplete <el-col :xs="0" :sm="0" :xl="0">
v-model="state" <el-autocomplete
size="small" v-model="state"
:fetch-suggestions="querySearchAsync" size="small"
placeholder="搜索帖子、标签和用户" :fetch-suggestions="querySearchAsync"
:trigger-on-focus="false" placeholder="搜索帖子、标签和用户"
@select="handleSelect" :trigger-on-focus="false"
/> @select="handleSelect"
</el-col> />
<!--<el-col v-if="isLogin" :xs="0" :sm="8" :xl="6">-->
<el-col v-if="isLogin">
<el-link :underline="false" style="padding-left: 10px;padding-right: 10px;" href="/post-portfolio">创建作品集</el-link>
<el-link :underline="false" style="padding-left: 10px;padding-right: 10px;" href="/post-article">发帖</el-link>
<el-link :underline="false" style="padding-left: 10px;padding-right: 10px;">
<el-dropdown trigger="click" @command="handleCommand">
<el-badge :value="notificationNumbers" class="item">
<el-link :underline="false" style="font-size: 1.4rem;" class="el-icon-bell"></el-link>
</el-badge>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="notification in notifications" :key="notification.idNotification" command="notification">{{ notification.dataSummary }}</el-dropdown-item>
<el-dropdown-item command="notification">查看所有消息</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-link>
<el-link :underline="false" style="margin-left: 10px;">
<el-dropdown trigger="click" @command="handleCommand">
<el-avatar v-if="avatarURL" size="small" :src="avatarURL"></el-avatar>
<el-avatar v-else size="small" src="https://rymcu.com/vertical/article/1578475481946.png"></el-avatar>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="user" style="align-items: center;">
<el-avatar class="mr-3" v-if="avatarURL" size="small" style="margin-top: 1rem;" :src="avatarURL"></el-avatar>
<el-avatar class="mr-3" v-else size="small" style="margin-top: 1rem;" src="https://rymcu.com/vertical/article/1578475481946.png"></el-avatar>
<el-link :underline="false" style="margin-left: 10px;margin-bottom: 1rem;">{{ nickname }}</el-link>
</el-dropdown-item>
<el-dropdown-item v-show="hasPermissions" command="admin-dashboard">系统管理</el-dropdown-item>
<el-dropdown-item command="user-info">资料与账号</el-dropdown-item>
<el-dropdown-item command="drafts">我的草稿</el-dropdown-item>
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-link>
</el-col>
<el-col v-else>
<el-link :underline="false" style="margin-left: 10px;" href="/login">登录</el-link>
<el-link :underline="false" style="margin-left: 10px;" href="/register">注册</el-link>
</el-col>
</el-col>
</el-col> </el-col>
</el-row> <!--<el-col v-if="isLogin" :xs="0" :sm="8" :xl="6">-->
<el-col v-if="isLogin">
<el-link :underline="false" style="padding-left: 10px;padding-right: 10px;" href="/post-portfolio">创建作品集
</el-link>
<el-link :underline="false" style="padding-left: 10px;padding-right: 10px;" href="/post-article">发帖</el-link>
<el-link :underline="false" style="padding-left: 10px;padding-right: 10px;">
<el-dropdown trigger="click" @command="handleCommand">
<el-badge :value="notificationNumbers" class="item">
<el-link :underline="false" style="font-size: 1.4rem;" class="el-icon-bell"></el-link>
</el-badge>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="notification in notifications" :key="notification.idNotification"
command="notification">{{ notification.dataSummary }}
</el-dropdown-item>
<el-dropdown-item command="notification">查看所有消息</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-link>
<el-link :underline="false" style="margin-left: 10px;">
<el-dropdown trigger="click" @command="handleCommand">
<el-avatar v-if="avatarURL" size="small" :src="avatarURL"></el-avatar>
<el-avatar v-else size="small" src="https://rymcu.com/vertical/article/1578475481946.png"></el-avatar>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="user" style="align-items: center;">
<el-avatar class="mr-3" v-if="avatarURL" size="small" style="margin-top: 1rem;"
:src="avatarURL"></el-avatar>
<el-avatar class="mr-3" v-else size="small" style="margin-top: 1rem;"
src="https://rymcu.com/vertical/article/1578475481946.png"></el-avatar>
<el-link :underline="false" style="margin-left: 10px;margin-bottom: 1rem;">{{ nickname }}</el-link>
</el-dropdown-item>
<el-dropdown-item v-show="hasPermissions" command="admin-dashboard">系统管理</el-dropdown-item>
<el-dropdown-item command="user-info">资料与账号</el-dropdown-item>
<el-dropdown-item command="drafts">我的草稿</el-dropdown-item>
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-link>
</el-col>
<el-col v-else>
<nuxt-link to="/login">
<el-link :underline="false" style="margin-left: 10px;">登录</el-link>
</nuxt-link>
<nuxt-link to="/register">
<el-link :underline="false" style="margin-left: 10px;">注册</el-link>
</nuxt-link>
</el-col>
</el-col>
</el-col>
</el-row>
</template> </template>
<script> <script>
export default { const Cookie = process.client ? require('js-cookie') : undefined
name: "MobileHeader", export default {
computed: { name: "MobileHeader",
getActiveMenu () { computed: {
return this.$store.state.activeMenu; getActiveMenu() {
}, return this.$store.state.activeMenu;
isLogin () { },
return this.$store.getters.isLogin; isLogin() {
}, return this.$store.state.oauth;
avatarURL () { },
return this.$store.state.avatarURL; avatarURL() {
}, return this.$store.state.oauth?.avatarURL;
nickname() { },
return this.$store.state.nickname; nickname() {
}, return this.$store.state.oauth?.nickname;
hasPermissions () { },
return this.$store.getters.hasPermissions('blog_admin'); hasPermissions() {
} return this.$store.getters.hasPermissions('blog_admin');
}, }
data() { },
return { data() {
restaurants: [], return {
state: '', restaurants: [],
timeout: null, state: '',
show: false, timeout: null,
notifications: [], show: false,
notificationNumbers: "" notifications: [],
}; notificationNumbers: ""
}, };
watch: { },
isLogin: function () { watch: {
this.getUnreadNotifications(); isLogin: function () {
} this.getUnreadNotifications();
}, }
methods: { },
loadAll() { methods: {
return [ loadAll() {
{ "value": "三全鲜食(北新泾店)", "address": "长宁区新渔路144号" }, return [
{ "value": "Hot honey 首尔炸鸡(仙霞路)", "address": "上海市长宁区淞虹路661号" }, {"value": "三全鲜食(北新泾店)", "address": "长宁区新渔路144号"},
{ "value": "新旺角茶餐厅", "address": "上海市普陀区真北路988号创邑金沙谷6号楼113" } {"value": "Hot honey 首尔炸鸡(仙霞路)", "address": "上海市长宁区淞虹路661号"},
] {"value": "新旺角茶餐厅", "address": "上海市普陀区真北路988号创邑金沙谷6号楼113"}
}, ]
querySearchAsync(queryString, cb) { },
let restaurants = this.restaurants; querySearchAsync(queryString, cb) {
let results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants; let restaurants = this.restaurants;
let results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants;
clearTimeout(this.timeout); clearTimeout(this.timeout);
this.timeout = setTimeout(() => { this.timeout = setTimeout(() => {
cb(results); cb(results);
}, 3000 * Math.random()); }, 3000 * Math.random());
}, },
createStateFilter(queryString) { createStateFilter(queryString) {
return (state) => { return (state) => {
return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0); return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
}; };
}, },
handleSelectMenu(item) { handleSelectMenu(item) {
let _ts = this; let _ts = this;
let activeMenu = _ts.$store.state.activeMenu; let activeMenu = _ts.$store.state.activeMenu;
if (activeMenu !== item) { if (activeMenu !== item) {
this.$store.commit('setActiveMenu', item); if (item === 'topic') {
if(item === 'topic'){ _ts.$router.push(
_ts.$router.push( {
{ name: item,
name: item, params: {
params: { name: '51mcu'
name: '51mcu'
}
}
)
}
if(item === 'github') {
window.open("https://github.com/Hugh-rymcu");
return false;
}
_ts.$router.push(
{
name: item
}
)
} }
}, }
handleSelect(item) { )
console.log(item) }
}, if (item === 'github') {
handleCommand(item) { window.open("https://github.com/Hugh-rymcu");
let _ts = this; return false;
if(item === 'user'){ }
_ts.$router.push({ _ts.$router.push(
path: '/user/' + _ts.$store.state.nickname {
}) name: item
}
if( item === 'user-info'){
_ts.$router.push({
name: 'account',
params: {
id: _ts.$store.state.idUser
}
})
}
if (item === 'logout'){
_ts.$store.commit('logout');
item = 'login';
}
_ts.$router.push({
name: item
})
},
getUnreadNotifications() {
let _ts = this;
_ts.axios.get('/notification/unread').then(function (res) {
if (res) {
_ts.$set(_ts, 'notifications', res.notifications);
_ts.$set(_ts, 'notificationNumbers', res.notifications.length == 0 ? "" : res.notifications.length);
}
})
}
},
mounted() {
this.restaurants = this.loadAll();
let isLogin = this.isLogin;
if (isLogin) {
this.getUnreadNotifications();
} }
)
} }
},
handleSelect(item) {
console.log(item)
},
handleCommand(item) {
let _ts = this;
if (item === 'user') {
_ts.$router.push({
path: '/user/' + _ts.$store.state.nickname
})
}
if (item === 'user-info') {
_ts.$router.push({
name: 'account',
params: {
id: _ts.$store.state.idUser
}
})
}
if (item === 'logout') {
Cookie.remove('auth')
_ts.$store.commit('setAuth', null)
item = 'login';
}
_ts.$router.push({
name: item
})
},
getUnreadNotifications() {
let _ts = this;
if (_ts.isLogin) {
_ts.$axios.$get('/api/v1/notification/unread', {
headers: {
Authorization: _ts.$store.state.oauth?.accessToken
}
}).then(function (res) {
if (res) {
_ts.$set(_ts, 'notifications', res.data.notifications);
_ts.$set(_ts, 'notificationNumbers', res.data.notifications.length == 0 ? "" : res.data.notifications.length);
}
})
}
}
},
mounted() {
this.restaurants = this.loadAll();
let isLogin = this.isLogin;
if (isLogin) {
this.getUnreadNotifications();
}
} }
}
</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;
white-space: nowrap; white-space: nowrap;
font-weight: 600; font-weight: 600;
padding: 0; padding: 0;
transition: .3s opacity; transition: .3s opacity;
line-height: 2rem; line-height: 2rem;
} }
.navbar-brand-img {
height: 2rem; .navbar-brand-img {
line-height: 2rem; height: 2rem;
vertical-align: bottom; line-height: 2rem;
margin-right: .5rem; vertical-align: bottom;
width: auto; margin-right: .5rem;
} width: auto;
}
</style> </style>

View File

@ -1,27 +1,58 @@
<template> <template>
<el-container> <el-container>
<el-header> <el-header>
<mobile-header/> <header-view/>
</el-header> </el-header>
<el-main> <el-main>
<!-- <nuxt></nuxt>--> <nuxt :nuxt-child-key="$route.name" />
</el-main> </el-main>
<el-footer> <el-footer>
<mobile-footer/> <footer-view/>
</el-footer> </el-footer>
</el-container> </el-container>
</template> </template>
<script> <script>
import MobileHeader from "./header"; import { mapState } from 'vuex'
import MobileFooter from "./footer"; import HeaderView from "./header";
import FooterView from "./footer";
export default { export default {
name: "mobileMain", name: "MobileMain",
components: {MobileFooter, MobileHeader} components: {
HeaderView,
FooterView
},
computed: {
...mapState('global', [])
}
} }
</script> </script>
<style scoped> <style scoped>
.el-header {
padding-bottom: 1rem;
background: #fff;
border-bottom: 1px solid rgba(0, 40, 100, 0.12);
z-index: 80;
}
.el-main {
padding: 20px 0;
background-attachment: fixed;
min-height: 280px;
margin-bottom: 60px;
overflow-x: hidden;
}
.el-footer {
position: fixed;
bottom: 0;
width: 100%;
padding-top: 1rem;
padding-bottom: 1rem;
background: #fff;
border-top: 1px solid rgba(0, 40, 100, 0.12);
z-index: 80;
}
</style> </style>

View File

@ -84,6 +84,7 @@
</template> </template>
<script> <script>
const Cookie = process.client ? require('js-cookie') : undefined
export default { export default {
name: "PcHeader", name: "PcHeader",
computed: { computed: {
@ -91,16 +92,16 @@
return this.$store.state.activeMenu; return this.$store.state.activeMenu;
}, },
isLogin() { isLogin() {
return this.$store.getters['auth/isLogin']; return this.$store.state.oauth;
}, },
avatarURL() { avatarURL() {
return this.$store.state['auth/avatarURL']; return this.$store.state.oauth?.avatarURL;
}, },
nickname() { nickname() {
return this.$store.state['auth/nickname']; return this.$store.state.oauth?.nickname;
}, },
hasPermissions() { hasPermissions() {
return this.$store.getters['auth/hasPermissions(\'blog_admin\')']; return this.$store.getters.hasPermissions('blog_admin');
} }
}, },
data() { data() {
@ -184,7 +185,8 @@
}) })
} }
if (item === 'logout') { if (item === 'logout') {
_ts.$store.commit('logout'); Cookie.remove('auth')
_ts.$store.commit('setAuth', null)
item = 'login'; item = 'login';
} }
_ts.$router.push({ _ts.$router.push({
@ -193,12 +195,18 @@
}, },
getUnreadNotifications() { getUnreadNotifications() {
let _ts = this; let _ts = this;
_ts.$axios.$get('/api/v1/notification/unread').then(function (res) { if (_ts.isLogin) {
if (res) { _ts.$axios.$get('/api/v1/notification/unread', {
_ts.$set(_ts, 'notifications', res.data.notifications); headers: {
_ts.$set(_ts, 'notificationNumbers', res.data.notifications.length == 0 ? "" : res.notifications.length); Authorization: _ts.$store.state.oauth?.accessToken
} }
}) }).then(function (res) {
if (res) {
_ts.$set(_ts, 'notifications', res.data.notifications);
_ts.$set(_ts, 'notificationNumbers', res.data.notifications.length == 0 ? "" : res.data.notifications.length);
}
})
}
} }
}, },
mounted() { mounted() {

View File

@ -1,4 +1,4 @@
import { NODE_ENV } from '../environment' import {NODE_ENV} from '../environment'
const apisMap = { const apisMap = {
development: { development: {

View File

@ -1,4 +1,3 @@
export const meta = { export const meta = {
title: 'RYMCU - 嵌入式知识学习交流平台', title: 'RYMCU - 嵌入式知识学习交流平台',
keywords: 'RYMCU,嵌入式,51,单片机,STM,STM8,STM32', keywords: 'RYMCU,嵌入式,51,单片机,STM,STM8,STM32',
@ -8,11 +7,9 @@ export const meta = {
email: 'ronger@rymcu.com' email: 'ronger@rymcu.com'
} }
export const links = { export const links = {}
}
export const friendLinks = { export const friendLinks = {}
}
export const music = { export const music = {
id: '638949385' id: '638949385'

View File

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

View File

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

View File

@ -63,7 +63,9 @@ export default {
** Nuxt.js modules ** Nuxt.js modules
*/ */
modules: [ modules: [
['@nuxtjs/axios', {baseURL: apiConfig.BASE}] ['@nuxtjs/axios', {baseURL: apiConfig.BASE}],
'js-cookie',
'cookieparser'
], ],
/* /*
** Build configuration ** Build configuration

1542
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,11 +10,13 @@
}, },
"dependencies": { "dependencies": {
"@nuxtjs/axios": "^5.11.0", "@nuxtjs/axios": "^5.11.0",
"cookieparser": "^0.1.0",
"cross-env": "^7.0.2", "cross-env": "^7.0.2",
"element-ui": "^2.13.2", "element-ui": "^2.13.2",
"express": "^4.17.1", "express": "^4.17.1",
"nuxt": "^2.13.0", "js-cookie": "^2.2.1",
"vditor": "^3.3.2" "nuxt": "^2.13.3",
"vditor": "^3.3.3"
}, },
"devDependencies": { "devDependencies": {
"@nuxtjs/proxy": "^2.0.0", "@nuxtjs/proxy": "^2.0.0",

View File

@ -13,12 +13,14 @@
</el-col> </el-col>
<el-col :xs="9" :sm="11" :xl="11"> <el-col :xs="9" :sm="11" :xl="11">
<div style="margin-left: 1rem;"> <div style="margin-left: 1rem;">
<el-link @click="onRouter('user', article.articleAuthorName)" :underline="false" class="text-default" >{{ article.articleAuthorName }}</el-link> <el-link @click="onRouter('user', article.articleAuthorName)" :underline="false"
class="text-default">{{ article.articleAuthorName }}
</el-link>
<small class="d-block text-muted">{{ article.timeAgo }}</small> <small class="d-block text-muted">{{ article.timeAgo }}</small>
</div> </div>
</el-col> </el-col>
<el-col :xs="12" :sm="12" :xl="12" v-if="isLogin" class="text-right"> <el-col :xs="12" :sm="12" :xl="12" v-if="isLogin" class="text-right">
<el-dropdown trigger="click" @command="handleCommand"> <el-dropdown trigger="click" @command="handleCommand">
<el-link :underline="false"><i class="el-icon-more"></i></el-link> <el-link :underline="false"><i class="el-icon-more"></i></el-link>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit" v-if="hasPermissions">编辑</el-dropdown-item> <el-dropdown-item command="edit" v-if="hasPermissions">编辑</el-dropdown-item>
@ -27,7 +29,8 @@
</el-dropdown> </el-dropdown>
</el-col> </el-col>
<el-col class="text-right"> <el-col class="text-right">
<el-link :underline="false" title="总浏览数"><i class="el-icon-s-data"></i><span style="color: red;">{{ article.articleViewCount }}</span></el-link> <el-link :underline="false" title="总浏览数"><i class="el-icon-s-data"></i><span style="color: red;">{{ article.articleViewCount }}</span>
</el-link>
</el-col> </el-col>
<el-col style="margin: 1rem 0;"> <el-col style="margin: 1rem 0;">
<el-tag <el-tag
@ -49,29 +52,32 @@
<el-avatar :size="24" :src="portfolio.headImgUrl"></el-avatar> <el-avatar :size="24" :src="portfolio.headImgUrl"></el-avatar>
</el-col> </el-col>
<el-col :xs="20" :sm="20" :xl="20"> <el-col :xs="20" :sm="20" :xl="20">
<el-link @click="onRouter('portfolio', portfolio.idPortfolio)" :underline="false" class="text-default">{{ portfolio.portfolioTitle }}</el-link> <el-link @click="onRouter('portfolio', portfolio.idPortfolio)" :underline="false"
class="text-default">{{ portfolio.portfolioTitle }}
</el-link>
</el-col> </el-col>
</el-col> </el-col>
</el-col> </el-col>
</el-col> </el-col>
<!-- <el-col v-if="isShare" style="margin-bottom: 1rem;">--> <!-- <el-col v-if="isShare" style="margin-bottom: 1rem;">-->
<!-- <el-input v-model="shareData.shareUrl">--> <!-- <el-input v-model="shareData.shareUrl">-->
<!-- <el-popover slot="append"--> <!-- <el-popover slot="append"-->
<!-- placement="bottom"--> <!-- placement="bottom"-->
<!-- width="20"--> <!-- width="20"-->
<!-- trigger="hover">--> <!-- trigger="hover">-->
<!-- <el-col>--> <!-- <el-col>-->
<!-- <qrcode :value="shareWeiXin(shareData.shareUrl)" :options="{ width: 20 }"></qrcode>--> <!-- <qrcode :value="shareWeiXin(shareData.shareUrl)" :options="{ width: 20 }"></qrcode>-->
<!-- </el-col>--> <!-- </el-col>-->
<!-- <el-col class="text-center">--> <!-- <el-col class="text-center">-->
<!-- <span>扫码分享至微信</span>--> <!-- <span>扫码分享至微信</span>-->
<!-- </el-col>--> <!-- </el-col>-->
<!-- <el-button slot="reference"><el-image style="width: 14px;height: 14px;" :src="weiXin" fit="cover"></el-image></el-button>--> <!-- <el-button slot="reference"><el-image style="width: 14px;height: 14px;" :src="weiXin" fit="cover"></el-image></el-button>-->
<!-- </el-popover>--> <!-- </el-popover>-->
<!-- </el-input>--> <!-- </el-input>-->
<!-- </el-col>--> <!-- </el-col>-->
</el-row> </el-row>
<div class="pt-7 pipe-content__reset vditor-reset" id="articleContent" v-html="article.articleContent" style="overflow: hidden;"></div> <div class="pt-7 pipe-content__reset vditor-reset" id="articleContent" v-html="article.articleContent"
style="overflow: hidden;"></div>
</div> </div>
</div> </div>
</el-card> </el-card>
@ -83,25 +89,25 @@
<el-col :xs="22" :sm="23" :xl="23" style="padding-left: 1rem;"> <el-col :xs="22" :sm="23" :xl="23" style="padding-left: 1rem;">
<el-input @click.native="showComment" placeholder="请输入回帖内容"></el-input> <el-input @click.native="showComment" placeholder="请输入回帖内容"></el-input>
</el-col> </el-col>
<!-- <el-col>--> <!-- <el-col>-->
<!-- <el-drawer--> <!-- <el-drawer-->
<!-- :visible.sync="drawer"--> <!-- :visible.sync="drawer"-->
<!-- :direction="direction"--> <!-- :direction="direction"-->
<!-- size="40%">--> <!-- size="40%">-->
<!-- <el-col slot="title">--> <!-- <el-col slot="title">-->
<!-- <el-col>--> <!-- <el-col>-->
<!-- <el-avatar v-if="commentAuthorAvatar" :src="commentAuthorAvatar"></el-avatar>--> <!-- <el-avatar v-if="commentAuthorAvatar" :src="commentAuthorAvatar"></el-avatar>-->
<!-- <span class="text-default" style="padding-left: 1rem;">{{ title }}</span>--> <!-- <span class="text-default" style="padding-left: 1rem;">{{ title }}</span>-->
<!-- </el-col>--> <!-- </el-col>-->
<!-- </el-col>--> <!-- </el-col>-->
<!-- <el-col>--> <!-- <el-col>-->
<!-- <div id="contentEditor"></div>--> <!-- <div id="contentEditor"></div>-->
<!-- </el-col>--> <!-- </el-col>-->
<!-- <el-col style="margin-top: 1rem;padding-right:3rem;text-align: right;">--> <!-- <el-col style="margin-top: 1rem;padding-right:3rem;text-align: right;">-->
<!-- <el-button type="primary" :loading="loading" @click="postComment">发布</el-button>--> <!-- <el-button type="primary" :loading="loading" @click="postComment">发布</el-button>-->
<!-- </el-col>--> <!-- </el-col>-->
<!-- </el-drawer>--> <!-- </el-drawer>-->
<!-- </el-col>--> <!-- </el-col>-->
</el-col> </el-col>
<el-col v-else class="text-center" style="margin-top: 1rem;"> <el-col v-else class="text-center" style="margin-top: 1rem;">
<el-button type="primary" size="medium" @click="gotoLogin">登录</el-button> <el-button type="primary" size="medium" @click="gotoLogin">登录</el-button>
@ -119,7 +125,7 @@
<script> <script>
import Vue from 'vue'; import Vue from 'vue';
import { mapState } from 'vuex'; import {mapState} from 'vuex';
export default { export default {
name: "ArticleDetail", name: "ArticleDetail",
@ -139,11 +145,22 @@
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,
}) isLogin: state => state.oauth,
avatar: state => state.oauth?.avatarURL,
}),
hasPermissions() {
let account = this.$store.state.oauth?.nickname;
if (account) {
if (account === this.article.articleAuthor.userNickname) {
return true;
}
}
return this.$store.getters.hasPermissions('blog_admin');
}
}, },
head () { head() {
return { return {
title: this.article.articleTitle||'RYMCU - 嵌入式知识学习交流平台', title: this.article.articleTitle || 'RYMCU - 嵌入式知识学习交流平台',
meta: [ meta: [
{ {
name: 'keywords', name: 'keywords',
@ -184,14 +201,12 @@
return { return {
isShow: true, isShow: true,
loading: false, loading: false,
isLogin: false,
isShare: false, isShare: false,
shareData: {}, shareData: {},
avatar: ''
} }
}, },
methods: { methods: {
onRouter (name, data) { onRouter(name, data) {
this.$router.push( this.$router.push(
{ {
name: name, name: name,
@ -227,21 +242,22 @@
}, },
mounted() { mounted() {
Vue.nextTick(() => { Vue.nextTick(() => {
const previewElement = document.getElementById("articleContent"); this.$store.commit('setActiveMenu', 'articleDetail')
// //const outLineElement = document.getElementById("articleToC"); const previewElement = document.getElementById("articleContent");
// VditorPreview.setContentTheme('light'); // //const outLineElement = document.getElementById("articleToC");
// VditorPreview.setContentTheme('light');
Vue.VditorPreview.codeRender(previewElement, 'zh_CN'); Vue.VditorPreview.codeRender(previewElement, 'zh_CN');
Vue.VditorPreview.highlightRender({"enable":true,"lineNumber":false,"style":"github"}, previewElement); Vue.VditorPreview.highlightRender({"enable": true, "lineNumber": false, "style": "github"}, previewElement);
Vue.VditorPreview.mathRender(previewElement, { Vue.VditorPreview.mathRender(previewElement, {
math: {"engine":"KaTeX","inlineDigit":false,"macros":{}}, math: {"engine": "KaTeX", "inlineDigit": false, "macros": {}},
}); });
Vue.VditorPreview.mermaidRender(previewElement, ".language-mermaid"); Vue.VditorPreview.mermaidRender(previewElement, ".language-mermaid");
Vue.VditorPreview.graphvizRender(previewElement); Vue.VditorPreview.graphvizRender(previewElement);
Vue.VditorPreview.chartRender(previewElement); Vue.VditorPreview.chartRender(previewElement);
Vue.VditorPreview.mindmapRender(previewElement); Vue.VditorPreview.mindmapRender(previewElement);
Vue.VditorPreview.abcRender(previewElement); Vue.VditorPreview.abcRender(previewElement);
Vue.VditorPreview.mediaRender(previewElement); Vue.VditorPreview.mediaRender(previewElement);
//VditorPreview.outlineRender(previewElement, outLineElement); //VditorPreview.outlineRender(previewElement, outLineElement);
}) })
} }
@ -250,6 +266,7 @@
<style lang="scss"> <style lang="scss">
@import "~vditor/src/assets/scss/index.scss"; @import "~vditor/src/assets/scss/index.scss";
.article__wrapper { .article__wrapper {
max-width: 980px; max-width: 980px;
margin: 0 auto; margin: 0 auto;

View File

@ -5,6 +5,7 @@
</template> </template>
<script> <script>
import ArticleList from '~/components/archive/list' import ArticleList from '~/components/archive/list'
export default { export default {
name: 'Index', name: 'Index',
fetch({store}) { fetch({store}) {
@ -24,6 +25,9 @@
currentChangeArticle(page) { currentChangeArticle(page) {
this.$store.dispatch('article/fetchList', {page: page}) this.$store.dispatch('article/fetchList', {page: page})
} }
},
mounted() {
this.$store.commit('setActiveMenu', 'index')
} }
} }
</script> </script>

View File

@ -52,9 +52,12 @@
</template> </template>
<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',
data() { data() {
return { return {
user: { user: {
@ -84,13 +87,19 @@
} }
_ts.$axios.$post('/api/v1/console/login', data).then(function (res) { _ts.$axios.$post('/api/v1/console/login', data).then(function (res) {
console.log(res);
if (res.data) { if (res.data) {
if (res.data.message) { if (res.data.message) {
_ts.$message(res.data.message); _ts.$message(res.data.message);
return false; return false;
} }
_ts.$store.dispatch('auth/initLogin', res.data.user); let auth = {
accessToken: res.data.user.token,
nickname: res.data.user.nickname,
avatarURL: res.data.user.avatarUrl,
role: res.data.user.weights
}
_ts.$store.commit('setAuth', auth) // mutating to store for client rendering
Cookie.set('auth', auth)
_ts.$router.push({ _ts.$router.push({
name: 'index' name: 'index'
}) })
@ -132,6 +141,9 @@
} }
}) })
} }
},
mounted() {
this.$store.commit('setActiveMenu', 'login')
} }
} }
</script> </script>

View File

@ -69,7 +69,9 @@
if (response.data) { if (response.data) {
_ts.$message(response.data.message) _ts.$message(response.data.message)
} }
}).catch(error=>{ console.log(error) }) }).catch(error => {
console.log(error)
})
}, },
register() { register() {
let _ts = this; let _ts = this;
@ -107,6 +109,9 @@
} }
) )
} }
},
mounted() {
this.$store.commit('setActiveMenu', 'register')
} }
} }
</script> </script>

View File

@ -1,28 +1,2 @@
import apiConfig from '~/config/api.config' import apiConfig from '~/config/api.config'
export default function ({ app: { $axios, $cookies } }) {
$axios.defaults.baseURL = apiConfig.BASE
$axios.defaults.timeout = 30000
$axios.interceptors.request.use(config => {
config.headers['X-Token'] = $cookies.get('token') || ''
config.headers['X-Device-Id'] = $cookies.get('clientId') || ''
config.headers['X-Uid'] = $cookies.get('userId') || ''
return config
})
$axios.interceptors.response.use(response => {
if (/^[4|5]/.test(response.status)) {
return Promise.reject(response.statusText)
}
let message;
if (typeof(response.data.data) !== 'undefined') {
message = response.data.data.message
} else if (typeof(response.data) !== 'undefined') {
message = response.data.message
}
console.log(message);
if (response.data.success) {
return response.data.data
}
return response.data
})
}

View File

@ -1,83 +0,0 @@
export const state = () => {
return {
isLogin: false,
token: '',
nickname: '',
idUser: '',
avatarURL: '',
role: 0, // 0-no login, 1-admin, 2-blog admin, 3-blog author, 4-blog user, 5-visitor
login: false
}
}
export const mutations = {
updateUserInfo(state, data) {
state.isLogin = true;
state.avatarURL = data.avatarUrl;
state.nickname = data.nickname;
state.token = data.token;
state.account = data.account;
state.role = data.weights;
state.idUser = data.idUser;
}
}
export const actions = {
setLogin(state, data){
state.login = data
},
setUserInfo(state, data) {
state.avatarURL = data.avatarUrl;
state.nickname = data.nickname;
},
initLogin({commit}, data = {}){
commit('updateUserInfo', data)
},
logout(state){
state.isLogin = false;
state.avatarURL = '';
state.nickname = '';
state.token = '';
state.account = '';
state.role = '';
state.idUser = '';
}
}
export const getters = {
isLogin(state){
return state.isLogin
},
hasPermissions:(state)=>(scenes)=>{
let hasPermissions = false;
if (state.role) {
switch (scenes) {
case 'user':
hasPermissions = state.role < 5;
break;
case 'role':
hasPermissions = state.role < 2;
break;
case 'topic':
hasPermissions = state.role < 3;
break;
case 'tag':
hasPermissions = state.role < 3;
break;
case 'admin':
hasPermissions = state.role < 2;
break;
case 'blog_admin':
hasPermissions = state.role < 3;
break;
default:
hasPermissions = false;
this.commit('logout');
}
}
return hasPermissions;
},
isAuthor: (state)=>(scenes)=> {
return state.nickname === scenes ? true : false;
}
}

View File

@ -1,11 +1,34 @@
const cookieparser = process.server ? require('cookieparser') : undefined
export const state = () => { export const state = () => {
return { return {
activeMenu: 'index' activeMenu: 'index',
oauth: null
} }
} }
export const mutations = {
setAuth (state, auth) {
state.oauth = auth
},
setActiveMenu (state, activeMenu) {
state.activeMenu = activeMenu
}
}
export const actions = { export const actions = {
nuxtServerInit(store, {req}) { nuxtServerInit(store, {req}) {
// 初始化时的全局任务 // 初始化时的全局任务
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
}
store.commit('setAuth', auth)
}
const initFetchAppData = [ const initFetchAppData = [
// 内容数据 // 内容数据
store.dispatch('article/fetchList') store.dispatch('article/fetchList')
@ -13,3 +36,36 @@ 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;
}
}