first commit

This commit is contained in:
ronger 2020-06-19 17:10:44 +08:00
commit 08c1630a31
29 changed files with 11587 additions and 0 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

90
.gitignore vendored Normal file
View File

@ -0,0 +1,90 @@
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE / Editor
.idea
# Service worker
sw.*
# macOS
.DS_Store
# Vim swap files
*.swp

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# nebula
## Build Setup
```bash
# install dependencies
$ yarn install
# serve with hot reload at localhost:3000
$ yarn dev
# build for production and launch server
$ yarn build
$ yarn start
# generate static project
$ yarn generate
```
For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org).

7
assets/README.md Normal file
View File

@ -0,0 +1,7 @@
# ASSETS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).

BIN
assets/rymcu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

28
components/Logo.vue Normal file
View File

@ -0,0 +1,28 @@
<template>
<svg class="NuxtLogo" width="245" height="180" viewBox="0 0 452 342" xmlns="http://www.w3.org/2000/svg">
<path
d="M139 330l-1-2c-2-4-2-8-1-13H29L189 31l67 121 22-16-67-121c-1-2-9-14-22-14-6 0-15 2-22 15L5 303c-1 3-8 16-2 27 4 6 10 12 24 12h136c-14 0-21-6-24-12z"
fill="#00C58E"
/>
<path
d="M447 304L317 70c-2-2-9-15-22-15-6 0-15 3-22 15l-17 28v54l39-67 129 230h-49a23 23 0 0 1-2 14l-1 1c-6 11-21 12-23 12h76c3 0 17-1 24-12 3-5 5-14-2-26z"
fill="#108775"
/>
<path
d="M376 330v-1l1-2c1-4 2-8 1-12l-4-12-102-178-15-27h-1l-15 27-102 178-4 12a24 24 0 0 0 2 15c4 6 10 12 24 12h190c3 0 18-1 25-12zM256 152l93 163H163l93-163z"
fill="#2F495E"
/>
</svg>
</template>
<style>
.NuxtLogo {
animation: 1s appear;
margin: auto;
}
@keyframes appear {
0% {
opacity: 0;
}
}
</style>

7
components/README.md Normal file
View File

@ -0,0 +1,7 @@
# COMPONENTS
**This directory is not required, you can delete it if you don't want to use it.**
The components directory contains your Vue.js Components.
_Nuxt.js doesn't supercharge these components._

View File

@ -0,0 +1,42 @@
<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-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号'
}
}
}
</script>
<style scoped>
.footer {
font-size: 14px;
align-items: center;
display: flex;
}
</style>

View File

@ -0,0 +1,224 @@
<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-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;
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
}
)
}
},
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();
}
}
}
</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;
}
</style>

View File

@ -0,0 +1,27 @@
<template>
<el-container>
<el-header>
<mobile-header/>
</el-header>
<el-main>
<!-- <nuxt></nuxt>-->
</el-main>
<el-footer>
<mobile-footer/>
</el-footer>
</el-container>
</template>
<script>
import MobileHeader from "./header";
import MobileFooter from "./footer";
export default {
name: "moblieMain",
components: {MobileFooter, MobileHeader}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +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-col>
</el-row>
</template>
<script>
export default {
name: "PcFooter",
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;
}
</style>

View File

@ -0,0 +1,231 @@
<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-col>
</el-row>
</template>
<script>
export default {
name: "PcHeader",
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;
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
}
)
}
},
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();
}
}
}
</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;
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<el-container>
<el-header>
<header-view/>
</el-header>
<el-main>
<!-- <nuxt></nuxt>-->
</el-main>
<el-footer>
<footer-view/>
</el-footer>
</el-container>
</template>
<script>
import HeaderView from "./header";
import FooterView from "./footer";
export default {
name: "PcMain",
components: {
HeaderView,
FooterView
}
}
</script>
<style scoped>
</style>

7
layouts/README.md Normal file
View File

@ -0,0 +1,7 @@
# LAYOUTS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your Application Layouts.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts).

161
layouts/default.vue Normal file
View File

@ -0,0 +1,161 @@
<template>
<div>
<nuxt />
</div>
</template>
<style>
body {
margin: 0;
display: block;
overflow-wrap: break-word;
-webkit-font-smoothing: antialiased;
background-color: rgb(246, 247, 248);
overflow-x: hidden;
}
a, li {
text-decoration:none !important;
}
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, .h1 a, .h2 a, .h3 a, .h4 a, .h5 a, .h6 a {
color: inherit;
}
h4, .h4 {
font-size: 1.125rem;
}
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
margin-bottom: 0.66em;
font-family: inherit;
font-weight: 600;
line-height: 1.1;
color: inherit;
}
p {
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
}
.avatar-md {
width: 2.5rem;
height: 2.5rem;
line-height: 2.5rem;
font-size: 1rem;
}
.avatar {
width: 2rem;
height: 2rem;
line-height: 2rem;
border-radius: 50%;
display: inline-block;
background: #ced4da no-repeat center/cover;
position: relative;
text-align: center;
color: #868e96;
font-weight: 600;
vertical-align: bottom;
font-size: .875rem;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.pt-5, .py-5 {
padding-top: 1.5rem !important;
}
.text-default {
color: #495057 !important;
}
.text-muted {
color: #9aa0ac !important;
}
.d-block {
display: block !important;
}
.article-summary-md {
position:relative;
line-height:1.4em;
/* 3 times the line-height to show 3 lines */
height:4.2em;
overflow:hidden;
}
.article-summary-md::after {
content:"...";
font-weight:bold;
position:absolute;
bottom:0;
right:0;
padding:0 20px 1px 45px;
/*background:url(http://newimg88.b0.upaiyun.com/newimg88/2014/09/ellipsis_bg.png) repeat-y;*/
}
.article-summary-sd {
position:relative;
line-height:1.4em;
/* 1 times the line-height to show 1 lines */
height:1.4em;
overflow:hidden;
}
.article-summary-sd::after {
content:"...";
font-weight:bold;
position:absolute;
bottom:0;
right:0;
padding:0 20px 1px 45px;
/*background:url(http://newimg88.b0.upaiyun.com/newimg88/2014/09/ellipsis_bg.png) repeat-y;*/
}
.text-center {
text-align: center !important;
}
.wrapper {
max-width: 980px;
margin: 0 auto;
display: block;
padding-left: 1rem;
padding-right: 1rem;
box-sizing: border-box;
float: none;
}
.mr-3, .mx-3 {
margin-right: 0.75rem !important;
}
.navbar-brand-img {
height: 2rem;
line-height: 2rem;
vertical-align: bottom;
margin-right: .5rem;
width: auto;
}
.topic-brand-img {
height: 4rem;
line-height: 2rem;
vertical-align: bottom;
margin-right: .5rem;
width: auto;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
</style>

8
middleware/README.md Normal file
View File

@ -0,0 +1,8 @@
# MIDDLEWARE
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your application middleware.
Middleware let you define custom functions that can be run before rendering either a page or a group of pages.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware).

54
nuxt.config.js Normal file
View File

@ -0,0 +1,54 @@
export default {
/*
** Nuxt rendering mode
** See https://nuxtjs.org/api/configuration-mode
*/
mode: 'universal',
/*
** Headers of the page
** See https://nuxtjs.org/api/configuration-head
*/
head: {
title: process.env.npm_package_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
/*
** Global CSS
*/
css: [
'element-ui/lib/theme-chalk/index.css'
],
/*
** Plugins to load before mounting the App
** https://nuxtjs.org/guide/plugins
*/
plugins: [
'@/plugins/element-ui',
'@/plugins/axios'
],
/*
** Nuxt.js dev-modules
*/
buildModules: [
],
/*
** Nuxt.js modules
*/
modules: [
],
/*
** Build configuration
** See https://nuxtjs.org/api/configuration-build/
*/
build: {
transpile: [/^element-ui/],
}
}

10247
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "nebula",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate"
},
"dependencies": {
"axios": "^0.19.2",
"element-ui": "^2.13.2",
"nuxt": "^2.13.0",
"vditor": "^3.3.2",
"vue-axios": "^2.1.5"
},
"devDependencies": {}
}

6
pages/README.md Normal file
View File

@ -0,0 +1,6 @@
# PAGES
This directory contains your Application Views and Routes.
The framework reads all the `*.vue` files inside this directory and creates the router of your application.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing).

54
pages/index.vue Normal file
View File

@ -0,0 +1,54 @@
<template>
<div>
<pc-main-view v-if="!isMobile"/>
<mobile-main-view v-else/>
</div>
</template>
<script>
import PcMainView from '~/components/layouts/pc/main.vue'
import MobileMainView from '~/components/layouts/mobile/main.vue'
export default {
components: {
PcMainView,
MobileMainView
},
computed: {
theme() {
return this.$store.state.theme
},
isMobile() {
return this.$store.state.isMobile
}
}
}
</script>
<style>
.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>

7
plugins/README.md Normal file
View File

@ -0,0 +1,7 @@
# PLUGINS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).

88
plugins/axios.js Normal file
View File

@ -0,0 +1,88 @@
import axios from 'axios'
import VueAxios from 'vue-axios'
import Vue from 'vue'
// eslint-disable-next-line no-unused-vars
export default (ctx) => {
const customAxios = axios.create({
baseURL: '/api',
timeout:'10000',
withCredentials: true
});
customAxios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
customAxios.defaults.headers.common['x-requested-with'] = 'XMLHttpRequest';
Vue.use(VueAxios, customAxios);
customAxios.interceptors.request.use((config) => {
if(config.url){
let token = localStorage.getItem("x-auth-token");
if (token) { // 判断是否存在token如果存在的话则每个http header都加上token
if (!(config.url.indexOf('console') > -1)){
config.headers.Authorization = `${token}`;
}
}
} else {
config.url = '/console/heartbeat'
}
// clear cache
// if (config.method === 'get') {
// let char = '?'
// if (config.url.split('?').length > 1) {
// char = '&'
// }
// config.url += `${char}${(new Date()).getTime()}`
// }
return config
}, function (error) {
return Promise.reject(error);
});
customAxios.interceptors.response.use((response) => {
let message;
if (typeof(response.data.data) !== 'undefined') {
message = response.data.data.message
} else if (typeof(response.data) !== 'undefined') {
message = response.data.message
}
if (response.data.success) {
return response.data.data
} else {
if(response.data.code === 0){
window.app.$message(message);
}else if(response.data.code === 401){
window.app.$store.commit('logout');
window.app.$router.push({
name: 'login',
query: {
historyUrl: window.location.href
}
})
}else if(response.data.code === 402){
window.app.$store.commit('logout');
window.app.$router.push({
name: 'login',
query: {
historyUrl: window.location.href
}
})
}else if(response.data.code === 404){
window.app.$message('操作失败,请稍后再试......')
}else if(response.data.code === 500){
window.app.$message('服务器正在开小差,请稍后再试......')
}
return false
}
}, (error) => {
/*console.log(ctx.app.store.state.locale)
ctx.store.commit('setSnackBar', {
snackBar: true,
snackMsg: ctx.app.i18n.t('requestError', ctx.app.store.state.locale)
})*/
return Promise.reject(error)
})
return customAxios
}

5
plugins/element-ui.js Normal file
View File

@ -0,0 +1,5 @@
import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(Element, { locale })

11
static/README.md Normal file
View File

@ -0,0 +1,11 @@
# STATIC
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your static files.
Each file inside this directory is mapped to `/`.
Thus you'd want to delete this README.md before deploying to production.
Example: `/static/robots.txt` is mapped as `/robots.txt`.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

3
static/robots.txt Normal file
View File

@ -0,0 +1,3 @@
User-agent: *
Disallow: /api/
Disallow: /admin/

10
store/README.md Normal file
View File

@ -0,0 +1,10 @@
# STORE
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your Vuex Store files.
Vuex Store option is implemented in the Nuxt.js framework.
Creating a file in this directory automatically activates the option in the framework.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).

142
store/index.js Normal file
View File

@ -0,0 +1,142 @@
export const state = () => ({
locale: 'zh_CN',
version: '1.0.0',
isInit: false,
isLogin: false,
token: '',
nickname: '',
idUser: '',
blogTitle: '',
avatarURL: '',
blogURL: '/',
role: 0, // 0-no login, 1-admin, 2-blog admin, 3-blog author, 4-blog user, 5-visitor
blogs: [{
title: '',
id: ''
}],
snackMsg: '',
snackBar: false,
snackModify: 'error',
menu: [],
tagsItems: [],
bodySide: '',
login: false,
activeMenu: 'home',
activeAdminMenu: 'admin-dashboard',
activeTopic: '51mcu',
activeTag: 'news',
uploadHeaders: '',
theme: '',
isMobile: false
})
export const mutations = () => ({
setLogin(state, data) {
state.login = data
},
setActiveMenu(state, data) {
state.activeMenu = data
},
setActiveAdminMenu(state, data) {
state.activeAdminMenu = data
},
setActiveTopic(state, data) {
state.activeTopic = data
},
setActiveTag(state, data) {
state.activeTag = data
},
setUserInfo(state, data) {
state.avatarURL = data.avatarUrl;
state.nickname = data.nickname;
localStorage.setItem('avatarURL', data.avatarUrl);
localStorage.setItem('nickname', data.nickname);
},
initLogin(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;
localStorage.setItem('isLogin', 'true');
localStorage.setItem('avatarURL', data.avatarUrl);
localStorage.setItem('nickname', data.nickname);
localStorage.setItem('account', data.account);
localStorage.setItem('idUser', data.idUser);
localStorage.setItem('x-auth-token', data.token);
localStorage.setItem('role', data.weights);
},
logout(state) {
state.isLogin = false;
state.avatarURL = '';
state.nickname = '';
state.token = '';
state.account = '';
state.role = '';
state.idUser = '';
localStorage.removeItem('isLogin');
localStorage.removeItem('avatarURL');
localStorage.removeItem('nickname');
localStorage.removeItem('account');
localStorage.removeItem('idUser');
localStorage.removeItem('x-auth-token');
localStorage.removeItem('role');
},
setUploadHeaders(state, data) {
state.uploadHeaders = data
}
})
export const actions = () => ({})
export const getters = () => ({
uploadHeaders(state) {
return state.uploadHeaders;
},
isLogin(state) {
if (!state.isLogin) {
state.isLogin = localStorage.getItem('isLogin'); //从localStorage中读取状态
state.nickname = localStorage.getItem('nickname');
state.avatarURL = localStorage.getItem('avatarURL') !== 'undefined' ? localStorage.getItem('avatarURL') : "";
state.token = localStorage.getItem('x-auth-token');
state.account = localStorage.getItem('account');
state.idUser = localStorage.getItem('idUser');
state.role = Number(localStorage.getItem('role'));
}
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;
window.app.$store.commit('logout');
}
}
return hasPermissions;
},
isAuthor: (state) => (scenes) => {
return state.nickname === scenes ? true : false;
}
})