first commit

This commit is contained in:
ronger 2020-06-22 17:13:42 +08:00
parent 509773ccbf
commit f1f9648a06
14 changed files with 252 additions and 84 deletions

View File

@ -1,7 +1,7 @@
<template>
<el-row class="wrapper">
<el-col :xs="24" :sm="24" :xl="24" style="margin: 0 auto;">
<el-col v-for="article in articles.data" :key="article.idArticle" style="padding-bottom: 1rem;">
<el-col v-for="article in articles.articles" :key="article.idArticle" style="padding-bottom: 1rem;">
<el-card>
<div class="card-body d-flex flex-column">
<el-link @click="onRouter('article',article.articleLink)" :underline="false" style="margin-bottom: .5rem;">
@ -36,10 +36,10 @@
</el-col>
<el-col>
<div class="vertical-container text-center">
<el-pagination v-show="pagination.total > 10" v-model="pagination"
<el-pagination v-show="articles.pagination.total > 10" v-model="articles.pagination"
layout="prev, pager, next"
:current-page="pagination.currentPage"
:total="pagination.total"
:current-page="articles.pagination.currentPage"
:total="articles.pagination.total"
@current-change="currentChange">
</el-pagination>
</div>
@ -49,29 +49,32 @@
</template>
<script>
import Vue from 'vue';
import { mapState } from 'vuex';
export default Vue.extend({
name: "PcAside",
data() {
return {
export default {
name: "ArticleList",
props: {
articles: {
type: Object
}
},
computed: {
...mapState({
articles: state => state.article.list.data,
pagination: state => state.article.list.data.pagination
})
},
methods: {
currentChange(p) {
console.log(p);
currentChange(page) {
this.$emit('currentChange', page);
},
onRouter(name, data) {
if ("article" === name) {
this.$router.push({
path: data
})
} else {
this.$router.push(
{
path: '/user/' + data
}
)
}
}
},
mounted () {
}
})
}
</script>
<style scoped>

View File

@ -17,7 +17,7 @@
import MobileFooter from "./footer";
export default {
name: "moblieMain",
name: "mobileMain",
components: {MobileFooter, MobileHeader}
}
</script>

View File

@ -4,7 +4,7 @@
<header-view/>
</el-header>
<el-main>
<aside-view key="aside"/>
<nuxt :nuxt-child-key="$route.name" />
</el-main>
<el-footer>
<footer-view/>
@ -16,14 +16,12 @@
import { mapState } from 'vuex'
import HeaderView from "./header";
import FooterView from "./footer";
import AsideView from './aside/main';
export default {
name: "PcMain",
components: {
HeaderView,
FooterView,
AsideView
FooterView
},
computed: {
...mapState('global', [])

22
config/api.config.js Normal file
View File

@ -0,0 +1,22 @@
import { NODE_ENV } from '../environment'
const apisMap = {
development: {
FE: 'http://localhost:3000',
BASE: 'http://localhost:8099/vertical-console',
CDN: '',
PROXY: '/proxy',
SOCKET: 'http://localhost:3000',
GRAVATAR: '/proxy/static.rymcu.com/avatar'
},
production: {
FE: 'https://rymcu.com',
BASE: 'https://api.rymcu.com',
CDN: 'https://cdn.rymcu.com',
PROXY: 'https://cdn.rymcu.com/proxy',
SOCKET: 'https://rymcu.com',
GRAVATAR: 'https://static.rymcu.com/avatar'
}
}
export default apisMap[NODE_ENV]

36
config/app.config.js Normal file
View File

@ -0,0 +1,36 @@
export const meta = {
title: 'RYMCU - 嵌入式知识学习交流平台',
keywords: 'RYMCU,嵌入式,51,单片机,STM,STM8,STM32',
description: 'RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。',
url: 'https://rymcu.com',
author: 'rymcu',
email: 'ronger@rymcu.com'
}
export const links = {
}
export const friendLinks = {
}
export const music = {
id: '638949385'
}
export const fetch = {
delay: 888
}
export const color = {
primary: '#0088f5'
}
export default {
meta,
links,
music,
fetch,
color,
friendLinks
}

View File

@ -1,3 +1,7 @@
import appConfig from './config/app.config'
import apiConfig from './config/api.config'
import { isProdMode, isDevMode } from './environment'
export default {
/*
@ -11,22 +15,27 @@ export default {
render: {
csp: true
},
/*
** Environment variable configuration
*/
modern: true,
dev: isDevMode,
env: {
baseUrl: 'http://127.0.0.1:8099'
BASE: apiConfig.BASE,
HOST_URL: apiConfig.SOCKET
},
cache: {
max: 100,
maxAge: 1000 * 60 * 15
},
/*
** Headers of the page
** See https://nuxtjs.org/api/configuration-head
*/
head: {
title: 'RYMCU - 嵌入式知识学习交流平台',
title: appConfig.meta.title,
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
{ hid: 'keywords', name: 'keywords', content: appConfig.meta.keywords },
{ hid: 'description', name: 'description', content: appConfig.meta.description }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
@ -55,7 +64,7 @@ export default {
** Nuxt.js modules
*/
modules: [
'@nuxtjs/axios'
['@nuxtjs/axios', { baseURL: apiConfig.BASE }]
],
/*
** Build configuration
@ -63,11 +72,5 @@ export default {
*/
build: {
transpile: [/^element-ui/],
},
proxy: {
'/api': {
target: 'http://localhost:8099/vertical/',
}
}
}

8
package-lock.json generated
View File

@ -1406,7 +1406,7 @@
},
"@nuxtjs/axios": {
"version": "5.11.0",
"resolved": "https://registry.npm.taobao.org/@nuxtjs/axios/download/@nuxtjs/axios-5.11.0.tgz",
"resolved": "https://registry.npm.taobao.org/@nuxtjs/axios/download/@nuxtjs/axios-5.11.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40nuxtjs%2Faxios%2Fdownload%2F%40nuxtjs%2Faxios-5.11.0.tgz",
"integrity": "sha1-J9cpemnhHDkDm5ysrGHi4NDgDx8=",
"requires": {
"@nuxtjs/proxy": "^2.0.0",
@ -5102,7 +5102,7 @@
},
"http-proxy-middleware": {
"version": "1.0.4",
"resolved": "https://registry.npm.taobao.org/http-proxy-middleware/download/http-proxy-middleware-1.0.4.tgz?cache=0&sync_timestamp=1589915551464&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-proxy-middleware%2Fdownload%2Fhttp-proxy-middleware-1.0.4.tgz",
"resolved": "https://registry.npm.taobao.org/http-proxy-middleware/download/http-proxy-middleware-1.0.4.tgz",
"integrity": "sha1-Ql6hd5hqDNo0+cgeyWHHGa22wqk=",
"requires": {
"@types/http-proxy": "^1.17.4",
@ -5135,7 +5135,7 @@
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-4.0.2.tgz?cache=0&sync_timestamp=1588851826089&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmicromatch%2Fdownload%2Fmicromatch-4.0.2.tgz",
"resolved": "https://registry.npm.taobao.org/micromatch/download/micromatch-4.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmicromatch%2Fdownload%2Fmicromatch-4.0.2.tgz",
"integrity": "sha1-T8sJmb+fvC/L3SEvbWKbmlbDklk=",
"requires": {
"braces": "^3.0.1",
@ -5531,7 +5531,7 @@
},
"is-retry-allowed": {
"version": "1.2.0",
"resolved": "https://registry.npm.taobao.org/is-retry-allowed/download/is-retry-allowed-1.2.0.tgz",
"resolved": "https://registry.npm.taobao.org/is-retry-allowed/download/is-retry-allowed-1.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-retry-allowed%2Fdownload%2Fis-retry-allowed-1.2.0.tgz",
"integrity": "sha1-13hIi9CkZmo76KFIK58rqv7eqLQ="
},
"is-ssh": {

View File

@ -12,8 +12,11 @@
"@nuxtjs/axios": "^5.11.0",
"cross-env": "^7.0.2",
"element-ui": "^2.13.2",
"express": "^4.17.1",
"nuxt": "^2.13.0",
"vditor": "^3.3.2"
},
"devDependencies": {}
"devDependencies": {
"@nuxtjs/proxy": "^2.0.0"
}
}

View File

@ -1,7 +1,32 @@
<template>
<div>
<article-list :articles="articles" @currentChange="currentChangeArticle"></article-list>
</div>
</template>
<script>
import ArticleList from '~/components/archive/list'
export default {
name: 'Index',
fetch({store}) {
return Promise.all([
store.dispatch('article/fetchList')
])
},
components: {
ArticleList
},
computed: {
articles() {
return this.$store.state.article.list.data
}
},
methods: {
currentChangeArticle(page) {
this.$store.dispatch('article/fetchList', {page: page})
}
}
}
</script>
<style>
.el-header {

View File

@ -1,5 +1,7 @@
import apiConfig from '~/config/api.config'
export default function ({ app: { $axios, $cookies } }) {
$axios.defaults.baseURL = process.env.baseUrl
$axios.defaults.baseURL = apiConfig.BASE
$axios.defaults.timeout = 30000
$axios.interceptors.request.use(config => {
config.headers['X-Token'] = $cookies.get('token') || ''
@ -11,6 +13,16 @@ export default function ({ app: { $axios, $cookies } }) {
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
})
}

28
server/index.js Normal file
View File

@ -0,0 +1,28 @@
const { Nuxt, Builder } = require('nuxt')
const app = require('express')()
const isProd = (process.env.NODE_ENV === 'production')
const port = process.env.PORT || 3000
// 用指定的配置对象实例化 Nuxt.js
const config = require('./nuxt.config.js')
config.dev = !isProd
const nuxt = new Nuxt(config)
// 用 Nuxt.js 渲染每个路由
app.use(nuxt.render)
app.set("port", port)
// 在开发模式下启用编译构建和热加载
if (config.dev) {
new Builder(nuxt).build()
.then(listen)
} else {
listen()
}
function listen () {
// 服务端监听
app.listen(port, '0.0.0.0')
console.log('Server listening on `localhost:' + port + '`.')
}

View File

@ -1,29 +1,29 @@
import Vue from 'vue';
import { isBrowser } from '~/environment';
const ARTICLE_API_PATH = 'article';
export const ARTICLE_API_PATH = '/api/v1/console'
const getDefaultListData = () => {
return {
data: [],
pagination: {
total: 0,
currentPage: 0
articles: [],
pagination: {}
}
}
export const state = () => {
return {
list: {
fetching: false,
data: getDefaultListData()
},
detail: {
fetching: false,
data: {}
}
}
}
export const state = () => ({
list: {
fetching: false,
data: getDefaultListData()
},
detail: {
fetching: false,
data: {}
}
})
export const mutations = () => ({
export const mutations = {
// 文章列表
updateListFetching(state, action) {
state.list.fetching = action
@ -31,6 +31,10 @@ export const mutations = () => ({
updateListData(state, action) {
state.list.data = action
},
updateExistingListData(state, action) {
state.list.data.data.push(...action.data)
state.list.data.pagination = action.pagination
},
// 文章详情
updateDetailFetching(state, action) {
@ -38,32 +42,66 @@ export const mutations = () => ({
},
updateDetailData(state, action) {
state.detail.data = action
}
})
},
export const actions = () => ({
// 更新文章阅读全文状态
updateDetailRenderedState(state, action) {
Vue.set(
state.detail.data,
'isRenderedFullContent',
action == null ? true : action
)
}
}
export const actions = {
// 获取文章列表
fetchList({commit}, params = {}) {
const isRestart = !params.page || params.page === 1
const isLoadMore = params.page && params.page > 1
console.log(isRestart, isLoadMore)
// 清空已有数据
isRestart && commit('updateListData', getDefaultListData())
// commit('updateListData', getDefaultListData())
commit('updateListFetching', true)
return this.$axios
.$get(ARTICLE_API_PATH, {params})
.$get(`${ARTICLE_API_PATH}/articles`, {params})
.then(response => {
commit('updateListFetching', false)
isLoadMore
? commit('updateExistingListData', response.result)
: commit('updateListData', response.result)
if (isLoadMore && isBrowser) {
commit('updateListData', response.data)
if (isBrowser) {
Vue.nextTick(() => {
window.scrollTo(0, 0);
window.scrollTo(0,0);
})
}
})
.catch(error => commit('updateListFetching', false))
},
// 获取文章详情
fetchDetail({ commit }, params = {}) {
const delay = fetchDelay(
isBrowser && isArticleDetailRoute(window.$nuxt.$route.name) ? null : 0
)
if (isBrowser) {
Vue.nextTick(() => {
scrollTo(0, 300, { easing: Easing['ease-in'] })
})
}
commit('updateDetailFetching', true)
commit('updateDetailData', {})
return this.$axios
.$get(`${ARTICLE_API_PATH}/article/${params.article_id}`)
.then(response => {
return new Promise(resolve => {
delay(() => {
commit('updateDetailData', response.result)
commit('updateDetailFetching', false)
resolve(response)
})
})
})
.catch(error => {
commit('updateDetailFetching', false)
return Promise.reject(error)
})
}
})
}

View File

@ -8,14 +8,14 @@ export const state = () => ({
})
export const getters = () => ({
export const getters = {
isMobile: state => state.isMobile
})
}
export const mutations = () => ({
export const mutations = {
})
}
export const actions = () => ({
export const actions ={
})
}

View File

@ -1,4 +1,4 @@
export const actions = () => ({
export const actions = {
nuxtServerInit(store, {req}) {
// 初始化时的全局任务
const initFetchAppData = [
@ -7,4 +7,4 @@ export const actions = () => ({
]
return Promise.all(initFetchAppData)
}
})
}