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

View File

@ -1,224 +1,242 @@
<template>
<el-row justify="space-between" type="flex">
<el-col>
<el-col :xs="8" :sm="4" :md="4" :xl="3" style="padding-top: 1rem;">
<a class="navbar-brand" href="/">
<img src="@/assets/rymcu.png" alt="RYMCU" class="navbar-brand-img">
<span>RYMCU</span>
</a>
</el-col>
<el-col :xs="0" :sm="12" :md="14" :xl="18" style="text-align: center;">
<el-row type="flex" justify="center">
<el-col>
<el-menu :default-active="getActiveMenu" style="margin-top: -2px;border: 0;" mode="horizontal" @select="handleSelectMenu">
<el-menu-item index="home">首页</el-menu-item>
<el-menu-item index="topic">专题</el-menu-item>
<el-menu-item index="github">开源代码</el-menu-item>
<el-menu-item index="open-source">资料下载</el-menu-item>
</el-menu>
</el-col>
</el-row>
</el-col>
<el-col :xs="16" :sm="8" :md="6" :xl="3" style="padding-top: 1rem;">
<!--<el-col :xs="24" :sm="16" :xl="12">-->
<el-col :xs="0" :sm="0" :xl="0">
<el-autocomplete
v-model="state"
size="small"
:fetch-suggestions="querySearchAsync"
placeholder="搜索帖子、标签和用户"
: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-row justify="space-between" type="flex">
<el-col>
<el-col :xs="8" :sm="4" :md="4" :xl="3" style="padding-top: 1rem;">
<a class="navbar-brand" href="/">
<img src="@/assets/rymcu.png" alt="RYMCU" class="navbar-brand-img">
<span>RYMCU</span>
</a>
</el-col>
<el-col :xs="0" :sm="12" :md="14" :xl="18" style="text-align: center;">
<el-row type="flex" justify="center">
<el-col>
<el-menu :default-active="getActiveMenu" style="margin-top: -2px;border: 0;" mode="horizontal"
@select="handleSelectMenu">
<el-menu-item index="index">首页</el-menu-item>
<el-menu-item index="topic">专题</el-menu-item>
<el-menu-item index="github">开源代码</el-menu-item>
<el-menu-item index="open-source">资料下载</el-menu-item>
</el-menu>
</el-col>
</el-row>
</el-col>
<el-col :xs="16" :sm="8" :md="6" :xl="3" style="padding-top: 1rem;">
<!--<el-col :xs="24" :sm="16" :xl="12">-->
<el-col :xs="0" :sm="0" :xl="0">
<el-autocomplete
v-model="state"
size="small"
:fetch-suggestions="querySearchAsync"
placeholder="搜索帖子、标签和用户"
:trigger-on-focus="false"
@select="handleSelect"
/>
</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>
<script>
export default {
name: "MobileHeader",
computed: {
getActiveMenu () {
return this.$store.state.activeMenu;
},
isLogin () {
return this.$store.getters.isLogin;
},
avatarURL () {
return this.$store.state.avatarURL;
},
nickname() {
return this.$store.state.nickname;
},
hasPermissions () {
return this.$store.getters.hasPermissions('blog_admin');
}
},
data() {
return {
restaurants: [],
state: '',
timeout: null,
show: false,
notifications: [],
notificationNumbers: ""
};
},
watch: {
isLogin: function () {
this.getUnreadNotifications();
}
},
methods: {
loadAll() {
return [
{ "value": "三全鲜食(北新泾店)", "address": "长宁区新渔路144号" },
{ "value": "Hot honey 首尔炸鸡(仙霞路)", "address": "上海市长宁区淞虹路661号" },
{ "value": "新旺角茶餐厅", "address": "上海市普陀区真北路988号创邑金沙谷6号楼113" }
]
},
querySearchAsync(queryString, cb) {
let restaurants = this.restaurants;
let results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants;
const Cookie = process.client ? require('js-cookie') : undefined
export default {
name: "MobileHeader",
computed: {
getActiveMenu() {
return this.$store.state.activeMenu;
},
isLogin() {
return this.$store.state.oauth;
},
avatarURL() {
return this.$store.state.oauth?.avatarURL;
},
nickname() {
return this.$store.state.oauth?.nickname;
},
hasPermissions() {
return this.$store.getters.hasPermissions('blog_admin');
}
},
data() {
return {
restaurants: [],
state: '',
timeout: null,
show: false,
notifications: [],
notificationNumbers: ""
};
},
watch: {
isLogin: function () {
this.getUnreadNotifications();
}
},
methods: {
loadAll() {
return [
{"value": "三全鲜食(北新泾店)", "address": "长宁区新渔路144号"},
{"value": "Hot honey 首尔炸鸡(仙霞路)", "address": "上海市长宁区淞虹路661号"},
{"value": "新旺角茶餐厅", "address": "上海市普陀区真北路988号创邑金沙谷6号楼113"}
]
},
querySearchAsync(queryString, cb) {
let restaurants = this.restaurants;
let results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants;
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
cb(results);
}, 3000 * Math.random());
},
createStateFilter(queryString) {
return (state) => {
return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
handleSelectMenu(item) {
let _ts = this;
let activeMenu = _ts.$store.state.activeMenu;
if (activeMenu !== item) {
this.$store.commit('setActiveMenu', item);
if(item === 'topic'){
_ts.$router.push(
{
name: item,
params: {
name: '51mcu'
}
}
)
}
if(item === 'github') {
window.open("https://github.com/Hugh-rymcu");
return false;
}
_ts.$router.push(
{
name: item
}
)
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
cb(results);
}, 3000 * Math.random());
},
createStateFilter(queryString) {
return (state) => {
return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
handleSelectMenu(item) {
let _ts = this;
let activeMenu = _ts.$store.state.activeMenu;
if (activeMenu !== item) {
if (item === 'topic') {
_ts.$router.push(
{
name: item,
params: {
name: '51mcu'
}
},
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'){
_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();
}
)
}
if (item === 'github') {
window.open("https://github.com/Hugh-rymcu");
return false;
}
_ts.$router.push(
{
name: item
}
)
}
},
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>
<style scoped>
.navbar-brand {
color: inherit;
margin-right: 1rem;
font-size: 1.25rem;
white-space: nowrap;
font-weight: 600;
padding: 0;
transition: .3s opacity;
line-height: 2rem;
}
.navbar-brand-img {
height: 2rem;
line-height: 2rem;
vertical-align: bottom;
margin-right: .5rem;
width: auto;
}
.navbar-brand {
color: inherit;
margin-right: 1rem;
font-size: 1.25rem;
white-space: nowrap;
font-weight: 600;
padding: 0;
transition: .3s opacity;
line-height: 2rem;
}
.navbar-brand-img {
height: 2rem;
line-height: 2rem;
vertical-align: bottom;
margin-right: .5rem;
width: auto;
}
</style>

View File

@ -1,27 +1,58 @@
<template>
<el-container>
<el-header>
<mobile-header/>
<header-view/>
</el-header>
<el-main>
<!-- <nuxt></nuxt>-->
<nuxt :nuxt-child-key="$route.name" />
</el-main>
<el-footer>
<mobile-footer/>
<footer-view/>
</el-footer>
</el-container>
</template>
<script>
import MobileHeader from "./header";
import MobileFooter from "./footer";
import { mapState } from 'vuex'
import HeaderView from "./header";
import FooterView from "./footer";
export default {
name: "mobileMain",
components: {MobileFooter, MobileHeader}
name: "MobileMain",
components: {
HeaderView,
FooterView
},
computed: {
...mapState('global', [])
}
}
</script>
<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>

View File

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

View File

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

View File

@ -1,4 +1,3 @@
export const meta = {
title: 'RYMCU - 嵌入式知识学习交流平台',
keywords: 'RYMCU,嵌入式,51,单片机,STM,STM8,STM32',
@ -8,11 +7,9 @@ export const meta = {
email: 'ronger@rymcu.com'
}
export const links = {
}
export const links = {}
export const friendLinks = {
}
export const friendLinks = {}
export const music = {
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
*/
modules: [
['@nuxtjs/axios', {baseURL: apiConfig.BASE}]
['@nuxtjs/axios', {baseURL: apiConfig.BASE}],
'js-cookie',
'cookieparser'
],
/*
** Build configuration

1542
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -52,9 +52,12 @@
</template>
<script>
import { mapState } from 'vuex';
import {mapState} from 'vuex';
const Cookie = process.client ? require('js-cookie') : undefined
export default {
name: "login",
middleware: 'notAuthenticated',
data() {
return {
user: {
@ -84,13 +87,19 @@
}
_ts.$axios.$post('/api/v1/console/login', data).then(function (res) {
console.log(res);
if (res.data) {
if (res.data.message) {
_ts.$message(res.data.message);
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({
name: 'index'
})
@ -132,6 +141,9 @@
}
})
}
},
mounted() {
this.$store.commit('setActiveMenu', 'login')
}
}
</script>

View File

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

View File

@ -1,28 +1,2 @@
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 = () => {
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 = {
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 = [
// 内容数据
store.dispatch('article/fetchList')
@ -13,3 +36,36 @@ export const actions = {
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;
}
}