├── src
├── components
│ ├── Layout
│ │ ├── Layout.scss
│ │ ├── index.vue
│ │ └── Layout.vue
│ ├── App
│ │ ├── images
│ │ │ ├── bg.jpg
│ │ │ ├── bg2.png
│ │ │ └── bg3.jpg
│ │ ├── index.vue
│ │ └── App.scss
│ ├── Banner
│ │ ├── images
│ │ │ ├── bg.jpg
│ │ │ ├── bg2.png
│ │ │ ├── bg3.jpg
│ │ │ ├── img01.png
│ │ │ ├── img02.jpg
│ │ │ └── img02.png
│ │ ├── Banner.scss
│ │ └── index.vue
│ ├── common
│ │ └── Toast
│ │ │ └── index.js
│ └── ProgressBar.vue
├── public
│ ├── logo-48.png
│ ├── logo-120.png
│ ├── logo-144.png
│ ├── logo-152.png
│ ├── logo-192.png
│ ├── logo-256.png
│ ├── logo-384.png
│ └── logo-512.png
├── pages
│ ├── Home
│ │ ├── Index
│ │ │ ├── images
│ │ │ │ └── wx.png
│ │ │ ├── Home.scss
│ │ │ └── index.vue
│ │ ├── List
│ │ │ ├── images
│ │ │ │ ├── a1.jpg
│ │ │ │ ├── a10.jpg
│ │ │ │ ├── a2.jpg
│ │ │ │ ├── a3.jpg
│ │ │ │ ├── a4.jpg
│ │ │ │ ├── a5.jpg
│ │ │ │ ├── a6.jpg
│ │ │ │ ├── a7.jpg
│ │ │ │ ├── a8.jpg
│ │ │ │ ├── a9.jpg
│ │ │ │ └── wx.png
│ │ │ ├── List.scss
│ │ │ └── index.vue
│ │ ├── Details
│ │ │ ├── Details.scss
│ │ │ └── index.vue
│ │ └── route.js
│ ├── Login
│ │ ├── images
│ │ │ └── notFound.jpg
│ │ ├── Login.scss
│ │ └── index.vue
│ ├── NotFoundPage
│ │ ├── images
│ │ │ ├── 404.png
│ │ │ └── notFound.jpg
│ │ ├── NotFoundPage.scss
│ │ └── index.vue
│ └── routes.js
├── store
│ ├── index.js
│ ├── login
│ │ └── index.js
│ └── home
│ │ └── index.js
├── utils
│ ├── filters.js
│ ├── title.js
│ ├── bridge.js
│ ├── util.js
│ ├── format.js
│ ├── fetchApi
│ │ ├── fetch.js
│ │ ├── fetch-client-(备份20160720).js
│ │ ├── fetch-client.js
│ │ └── fetch-server.js
│ ├── validate.js
│ └── fetch.js
└── views
│ └── index.template.html
├── server
├── env
│ ├── prd.js
│ ├── pre.js
│ ├── test.js
│ └── dev.js
├── config.js
├── error.js
├── logger.js
├── express.js
└── server.js
├── assets
├── images
│ ├── a4.jpg
│ ├── a5.jpg
│ ├── a7.jpg
│ ├── a8.jpg
│ ├── a9.jpg
│ ├── 404.png
│ ├── a10.jpg
│ ├── bg2.png
│ ├── img01.png
│ └── img02.png
├── fonts
│ ├── ionicons.eot
│ ├── ionicons.ttf
│ ├── ionicons.woff
│ └── ionicons.svg
├── public
│ ├── logo-48.png
│ ├── logo-120.png
│ ├── logo-144.png
│ ├── logo-152.png
│ ├── logo-192.png
│ ├── logo-256.png
│ ├── logo-384.png
│ └── logo-512.png
├── js
│ ├── 2.18e5bac323c205796d49.js
│ ├── manifest.6a5fd1fc2b981fe18281.js
│ ├── 4.2ba8b0ea69ab323082d9.js
│ ├── 5.95f3fcb64e74ab55624c.js
│ ├── 3.c299a5f8bda21fc21fdd.js
│ ├── 1.6e3d48efa6a1fec884fd.js
│ ├── app.387598ae874dd5716761.js
│ └── 0.d2daa19751f85de12e1d.js
├── service-worker.js
└── vue-ssr-client-manifest.json
├── .gitignore
├── .babelrc
├── .npmrc
├── app.js
├── devServer.js
├── manifest.json
├── README.md
├── bin
└── www
└── package.json
/src/components/Layout/Layout.scss:
--------------------------------------------------------------------------------
1 |
2 | .layout{
3 | max-width: 100%
4 | }
--------------------------------------------------------------------------------
/server/env/prd.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | PORT: 80,
3 | API : {
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/server/env/pre.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | PORT: 80,
3 | API : {
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/server/env/test.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | PORT: 80,
3 | API : {
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/assets/images/a4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/a4.jpg
--------------------------------------------------------------------------------
/assets/images/a5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/a5.jpg
--------------------------------------------------------------------------------
/assets/images/a7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/a7.jpg
--------------------------------------------------------------------------------
/assets/images/a8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/a8.jpg
--------------------------------------------------------------------------------
/assets/images/a9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/a9.jpg
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log
5 | yarn-error.log
6 | .idea
7 | *.iml
--------------------------------------------------------------------------------
/assets/images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/404.png
--------------------------------------------------------------------------------
/assets/images/a10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/a10.jpg
--------------------------------------------------------------------------------
/assets/images/bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/bg2.png
--------------------------------------------------------------------------------
/src/public/logo-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-48.png
--------------------------------------------------------------------------------
/assets/fonts/ionicons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/fonts/ionicons.eot
--------------------------------------------------------------------------------
/assets/fonts/ionicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/fonts/ionicons.ttf
--------------------------------------------------------------------------------
/assets/images/img01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/img01.png
--------------------------------------------------------------------------------
/assets/images/img02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/images/img02.png
--------------------------------------------------------------------------------
/assets/public/logo-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-48.png
--------------------------------------------------------------------------------
/src/public/logo-120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-120.png
--------------------------------------------------------------------------------
/src/public/logo-144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-144.png
--------------------------------------------------------------------------------
/src/public/logo-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-152.png
--------------------------------------------------------------------------------
/src/public/logo-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-192.png
--------------------------------------------------------------------------------
/src/public/logo-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-256.png
--------------------------------------------------------------------------------
/src/public/logo-384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-384.png
--------------------------------------------------------------------------------
/src/public/logo-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/public/logo-512.png
--------------------------------------------------------------------------------
/assets/fonts/ionicons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/fonts/ionicons.woff
--------------------------------------------------------------------------------
/assets/public/logo-120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-120.png
--------------------------------------------------------------------------------
/assets/public/logo-144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-144.png
--------------------------------------------------------------------------------
/assets/public/logo-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-152.png
--------------------------------------------------------------------------------
/assets/public/logo-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-192.png
--------------------------------------------------------------------------------
/assets/public/logo-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-256.png
--------------------------------------------------------------------------------
/assets/public/logo-384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-384.png
--------------------------------------------------------------------------------
/assets/public/logo-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/assets/public/logo-512.png
--------------------------------------------------------------------------------
/assets/fonts/ionicons.svg:
--------------------------------------------------------------------------------
1 | module.exports = __webpack_public_path__ + "images/ionicons.svg?621bd386841f74e0053cb8e67f8a0604";
--------------------------------------------------------------------------------
/src/components/App/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/App/images/bg.jpg
--------------------------------------------------------------------------------
/src/components/App/images/bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/App/images/bg2.png
--------------------------------------------------------------------------------
/src/components/App/images/bg3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/App/images/bg3.jpg
--------------------------------------------------------------------------------
/src/components/Banner/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/Banner/images/bg.jpg
--------------------------------------------------------------------------------
/src/pages/Home/Index/images/wx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/Index/images/wx.png
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a1.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a10.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a2.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a3.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a4.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a5.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a6.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a7.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a8.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/a9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/a9.jpg
--------------------------------------------------------------------------------
/src/pages/Home/List/images/wx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Home/List/images/wx.png
--------------------------------------------------------------------------------
/src/pages/Login/images/notFound.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/Login/images/notFound.jpg
--------------------------------------------------------------------------------
/src/components/Banner/images/bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/Banner/images/bg2.png
--------------------------------------------------------------------------------
/src/components/Banner/images/bg3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/Banner/images/bg3.jpg
--------------------------------------------------------------------------------
/src/pages/NotFoundPage/images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/NotFoundPage/images/404.png
--------------------------------------------------------------------------------
/src/components/Banner/images/img01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/Banner/images/img01.png
--------------------------------------------------------------------------------
/src/components/Banner/images/img02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/Banner/images/img02.jpg
--------------------------------------------------------------------------------
/src/components/Banner/images/img02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/components/Banner/images/img02.png
--------------------------------------------------------------------------------
/src/pages/NotFoundPage/images/notFound.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meibin08/Vue-Vuex-axios-SSR/HEAD/src/pages/NotFoundPage/images/notFound.jpg
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", { "modules": false }]
4 | ],
5 | "plugins": [
6 | "syntax-dynamic-import","transform-object-rest-spread",
7 | "transform-runtime"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/server/env/dev.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | PORT: 8081,
3 | API : {
4 |
5 | easy: {
6 | host: 'easy-mock.com/mock/59294d8e91470c0ac1fe8a4c',
7 | port: 80
8 | },
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/src/pages/Home/Index/Home.scss:
--------------------------------------------------------------------------------
1 |
2 | .home{
3 | max-width:100%;
4 | .ivu-col{
5 | margin-bottom:10px;
6 | }
7 | .mt-10{margin-top:10px;text-align:right}
8 | .img{width:50px;height:30px;}
9 | }
10 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
2 | phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
3 | electron_mirror=https://npm.taobao.org/mirrors/electron/
4 | registry=https://registry.npm.taobao.org
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 |
2 | var express = require('express');
3 | var path = require('path');
4 | var config = require('./server/config');
5 |
6 | var app = express();
7 | require('./server/express')(app);
8 | require('./server/server')(app);
9 | require('./server/error')(app);
10 | require('./bin/www')(app);
11 |
--------------------------------------------------------------------------------
/src/components/App/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/devServer.js:
--------------------------------------------------------------------------------
1 |
2 | var express = require('express');
3 | var webpack = require('webpack');
4 |
5 | const path = require('path')
6 |
7 | var app = express();
8 |
9 | require('./server/express')(app);
10 | require('./server/server')(app);
11 | require('./server/error')(app);
12 | require('./bin/www')(app);
13 |
--------------------------------------------------------------------------------
/src/pages/Login/Login.scss:
--------------------------------------------------------------------------------
1 |
2 | .login{
3 | margin:15% auto 0;
4 | text-align: center;
5 | width:320px;
6 | padding:5px;
7 | border-radius:5px;
8 | background-color:rgba(0,0,0,.5);
9 | .ivu-alert{
10 | padding:8px 16px;
11 | margin:0;
12 | }
13 | .tit{
14 | padding:10px 0 20px;
15 | text-align:center;
16 | font-size:14px;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/components/Banner/Banner.scss:
--------------------------------------------------------------------------------
1 | .app-banner{
2 | width:100%;
3 | overflow:hidden;
4 | .demo-carousel{
5 | width:100%;
6 | text-align: center;
7 | background-color: #eadcc7;
8 | height: 300px;
9 | img{
10 | max-width:100%;
11 | }
12 | &.c3{
13 | background-color: #1b9bb5;
14 | }
15 | &.c4{
16 | background-color: #b30038;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/pages/NotFoundPage/NotFoundPage.scss:
--------------------------------------------------------------------------------
1 |
2 | .error-tips{
3 | width: 666px;
4 | margin: 15% auto 0;
5 | text-align:center;
6 | .err-inner{
7 | width:550px;
8 | height:420px;
9 | padding:60% 0 0;
10 | background: url(./images/404.png) center center no-repeat;
11 | margin: 0 auto ;
12 | font-size:15px;
13 | }
14 | .a-block{
15 | display: inline-block;margin-right:30px;
16 | text-decoration: underline;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/pages/Home/List/List.scss:
--------------------------------------------------------------------------------
1 |
2 | .list{
3 | .name{
4 | color:#06c;
5 | }
6 | .a-block{
7 | display:block;
8 | color: #34495e;
9 | }
10 | .ivu-card{
11 | margin-bottom:15px;
12 | }
13 | .user-icon{
14 | width:50px;
15 | height:50px;
16 | border-radius:4px;
17 | border:1px solid #999;
18 | }
19 | .row{
20 | background:#fff;
21 | border-radius:5px;
22 | padding:5px 10px;
23 | }
24 | }
25 | .preview-img{
26 | max-width:400px;
27 | max-height: 400px;
28 | }
29 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @authors :Bin Mei
3 | * @email : meibin08@163.com
4 | * @QQ群 : 386485473 -- 技术交流群
5 | * @date :2017-07-20
6 | * @description:pc官网 -> store - store 模块
7 | */
8 |
9 | import Vue from 'vue'
10 | import Vuex from 'vuex'
11 | import home from './home/index'
12 | import login from './login/index'
13 |
14 | Vue.use(Vuex)
15 |
16 | export function createStore (){
17 | return new Vuex.Store({
18 | modules: {
19 | home,
20 | login
21 | }
22 | });
23 | } ;
--------------------------------------------------------------------------------
/server/config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var extend = require('util')._extend;
3 |
4 | var dev = require('./env/dev'),
5 | test = require('./env/test'),
6 | pre = require('./env/pre'),
7 | prd = require('./env/prd');
8 |
9 | var defaults = {
10 | root: path.normalize(__dirname + '/..')
11 | };
12 |
13 | module.exports = {
14 | dev: extend(dev, defaults),
15 | test: extend(test, defaults),
16 | pre: extend(pre, defaults),
17 | prd: extend(prd, defaults)
18 | }[process.env.DEPLOY_ENV || 'dev'];
19 |
--------------------------------------------------------------------------------
/src/pages/Home/Details/Details.scss:
--------------------------------------------------------------------------------
1 |
2 | .list{
3 | .name{
4 | color:#06c;
5 | }
6 | .label{color:#666}
7 | .a-block{
8 | display:block;
9 | color: #34495e;
10 | }
11 | .ivu-card{
12 | margin-bottom:15px;
13 | }
14 | .user-icon{
15 | width:50px;
16 | height:50px;
17 | border-radius:4px;
18 | border:1px solid #999;
19 | }
20 | .row{
21 | background:#fff;
22 | border-radius:5px;
23 | padding:5px 10px;
24 | }
25 | }
26 | .preview-img{
27 | max-width:400px;
28 | max-height: 400px;
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/filters.js:
--------------------------------------------------------------------------------
1 | export function host (url) {
2 | const host = url.replace(/^https?:\/\//, '').replace(/\/.*$/, '')
3 | const parts = host.split('.').slice(-3)
4 | if (parts[0] === 'www') parts.shift()
5 | return parts.join('.')
6 | }
7 |
8 | export function timeAgo (time) {
9 | const between = Date.now() / 1000 - Number(time)
10 | if (between < 3600) {
11 | return pluralize(~~(between / 60), ' minute')
12 | } else if (between < 86400) {
13 | return pluralize(~~(between / 3600), ' hour')
14 | } else {
15 | return pluralize(~~(between / 86400), ' day')
16 | }
17 | }
18 |
19 | function pluralize (time, label) {
20 | if (time === 1) {
21 | return time + label
22 | }
23 | return time + label + 's'
24 | }
25 |
--------------------------------------------------------------------------------
/server/error.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function (app) {
3 |
4 | // catch 404 and forward to error handler
5 | app.use(function(req, res, next) {
6 | var err = new Error('Not Found');
7 | err.status = 404;
8 | next(err);
9 | });
10 |
11 | // error handlers
12 |
13 | // development error handler
14 | // will print stacktrace
15 | if (app.get('env') === 'dev') {
16 | app.use(function(err, req, res, next) {
17 | res.status(err.status || 500);
18 | res.render('error', {
19 | message: err.message,
20 | error: err
21 | });
22 | });
23 | }
24 |
25 | // production error handler
26 | // no stacktraces leaked to user
27 | app.use(function(err, req, res, next) {
28 | res.status(err.status || 500);
29 | res.render('error', {
30 | message: err.message,
31 | error: {}
32 | });
33 | });
34 |
35 | };
--------------------------------------------------------------------------------
/src/utils/title.js:
--------------------------------------------------------------------------------
1 | function getTitle (vm) {
2 |
3 | const { meta } = (vm&&vm.$route&&vm.$route||{});
4 | const title = meta&&meta.title;
5 | return title;
6 | /*console.log()
7 | if (title) {
8 | return typeof title === 'function'
9 | ? title.call(vm)
10 | : title
11 | }*/
12 | }
13 |
14 | const serverTitleMixin = {
15 | created () {
16 | const title = getTitle(this)
17 | if (title&&this&&this.$ssrContext) {
18 | console.log(18,title,this.$ssrContext)
19 | //this.$ssrContext.title = `Vue HN 2.0 | ${title}`
20 | }
21 | }
22 | }
23 |
24 | const clientTitleMixin = {
25 | mounted () {
26 | const title = getTitle(this)
27 | if (title) {
28 | document.title = `Vue HN 2.0 | ${title}`
29 | }
30 | }
31 | }
32 |
33 | export default clientTitleMixin
34 | /*export default process.env.VUE_ENV === 'server'
35 | ? serverTitleMixin
36 | : clientTitleMixin*/
37 |
--------------------------------------------------------------------------------
/src/components/Banner/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |

10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue demo",
3 | "short_name": "Vue HN",
4 | "icons": [{
5 | "src": "/static/logo-120.png",
6 | "sizes": "120x120",
7 | "type": "image/png"
8 | }, {
9 | "src": "/static/logo-144.png",
10 | "sizes": "144x144",
11 | "type": "image/png"
12 | }, {
13 | "src": "/static/logo-152.png",
14 | "sizes": "152x152",
15 | "type": "image/png"
16 | }, {
17 | "src": "/static/logo-192.png",
18 | "sizes": "192x192",
19 | "type": "image/png"
20 | }, {
21 | "src": "/static/logo-256.png",
22 | "sizes": "256x256",
23 | "type": "image/png"
24 | }, {
25 | "src": "/static/logo-384.png",
26 | "sizes": "384x384",
27 | "type": "image/png"
28 | }, {
29 | "src": "/static/logo-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png"
32 | }],
33 | "start_url": "/",
34 | "background_color": "#f2f3f5",
35 | "display": "standalone",
36 | "theme_color": "#f60"
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/common/Toast/index.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | import Vue from 'vue'
4 |
5 | var StaticToast = new Vue({
6 | methods: {
7 | default(type,content,duration,closable){
8 | this.$Message.config({
9 | top: 180
10 | });
11 | this.$Message[type||"info"]({
12 | content: content||"提示",
13 | duration: (duration||3),
14 | closable: (closable||false)
15 | });
16 | },
17 | info (content,duration,closable) {
18 | StaticToast.default("info",content,duration,closable);
19 | },
20 | success:(content,duration,closable)=>{
21 | StaticToast.default("success",content,duration,closable);
22 | },
23 | warning:(content,duration,closable)=>{
24 | StaticToast.default("warning",content,duration,closable);
25 | },
26 | error:(content,duration,closable)=>{
27 | StaticToast.default("error",content,duration,closable);
28 | },
29 | destroy(){
30 | this.$Message.destroy();
31 | }
32 | }
33 | })
34 | /*const StaticToast= {
35 |
36 | }*/
37 | export default StaticToast;
38 |
39 |
--------------------------------------------------------------------------------
/src/pages/NotFoundPage/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 返回首页
8 | {{second}}秒后自动回到首页
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
46 |
47 |
51 |
--------------------------------------------------------------------------------
/src/utils/bridge.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * @authors :Bin Mei
4 | * @date :2017-07-20
5 | * @description:pc官网 -> bridge 设置标题
6 | */
7 |
8 |
9 |
10 | function getTitle (vm) {
11 |
12 | const { meta } = (vm&&vm.$route&&vm.$route||{});
13 | const title = meta&&meta.title;
14 | return title;
15 | /*console.log()
16 | if (title) {
17 | return typeof title === 'function'
18 | ? title.call(vm)
19 | : title
20 | }*/
21 | }
22 |
23 | const serverTitleMixin = {
24 | created () {
25 | const title = getTitle(this)
26 | if (title) {
27 | //this.$ssrContext.title = `Vue HN 2.0 | ${title}`
28 | }
29 | }
30 | }
31 | /*设置页面title*/
32 | export const clientTitleMixin = {
33 | mounted () {
34 | const title = getTitle(this)
35 | if (title) {
36 | document.title = title||"vue服务端渲染示例";
37 | }
38 | }
39 | };
40 |
41 | /*
42 | 控制每个页面进入的权限、及页面的title设置
43 | @requireAuth 页面是否需要登录进入
44 | @title 当前页面的title;
45 | */
46 | export const Bridges=(title,auth)=>{
47 | return {
48 | meta:{
49 | requireAuth: auth||false,
50 | title:title||"vue服务端渲染示例"
51 | }
52 | };
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/src/utils/util.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author monkeywang
3 | * Date: 17/3/14
4 | */
5 | import Vue from 'vue'
6 | import $http from 'vue-resource'
7 | // import { createAPI } from 'create-api'
8 | Vue.use($http)
9 |
10 | const logRequests = !!process.env.DEBUG_API
11 | const client = process.env.VUE_ENV == "client";
12 |
13 | /*const api = createAPI({
14 | version: '/v0',
15 | config: {
16 | databaseURL: 'https://easy-mock.com/mock/59294d8e91470c0ac1fe8a4c'
17 | }
18 | })*/
19 | let vm = new Vue()
20 |
21 | const configPath = client?"/zaApi/easy":'https://easy-mock.com/mock/59294d8e91470c0ac1fe8a4c';
22 | // const configPath = 'https://easy-mock.com/mock/59294d8e91470c0ac1fe8a4c';
23 |
24 | export class Utils {
25 | get (url, data = {}) {
26 | url = configPath + url;
27 |
28 | return new Promise((resolve, reject) => {
29 | vm.$http.get(url, {params: data, credentials: true}).then((response) => {
30 | //console.log(18,response);
31 | resolve(response.body)
32 | }, function (error) {
33 | console.log('接口异常')
34 | }).catch(function () {
35 | console.log("Promise Rejected");
36 | });
37 |
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/server/logger.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var log4js = require('log4js');
3 | var env = process.env.DEPLOY_ENV || 'dev';
4 | var package = require('../package.json');
5 |
6 | if (env != 'dev') {
7 | // 日志存放位置
8 | var log_dir = (env != 'dev')
9 | ? '/alidata1/admin/' + package.name
10 | : './';
11 |
12 | log4js.loadAppender('file');
13 | log4js.configure({
14 | appenders: [
15 | {
16 | type: 'file',
17 | filename: path.join(log_dir, 'logs/'+process.env.HOSTNAME+'_'+package.name+'.log'),
18 | // pattern: '_yyyy-MM-dd.log',
19 | // alwaysIncludePattern: true,
20 | category: 'info',
21 | },
22 | {
23 | type: 'file',
24 | filename: path.join(log_dir, 'logs/'+process.env.HOSTNAME+'_'+package.name+'_error.log'),
25 | // pattern: '_yyyy-MM-dd.log',
26 | // alwaysIncludePattern: true,
27 | category: 'error',
28 | }
29 | ]
30 | });
31 | }
32 |
33 | var logger_info = log4js.getLogger('info');
34 | logger_info.setLevel('INFO');
35 |
36 | var logger_error = log4js.getLogger('error');
37 | logger_error.setLevel('ERROR');
38 |
39 | module.exports = {
40 | info: function(msg) {
41 | logger_info.info(msg)
42 | },
43 | error: function(msg) {
44 | logger_error.error(msg)
45 | }
46 | };
--------------------------------------------------------------------------------
/src/views/index.template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ title }}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/server/express.js:
--------------------------------------------------------------------------------
1 |
2 | const fs = require('fs')
3 | const path = require('path')
4 | const express = require('express')
5 | const favicon = require('serve-favicon')
6 | const resolve = file => path.resolve(__dirname, file)
7 |
8 | var cookieParser = require('cookie-parser')
9 | var compression = require('compression')
10 | var config = require('./config')
11 | module.exports = function (app) {
12 | // app.set('views', config.root + '/src/views');//设置模板文件路径
13 | app.set('views', config.root + '/src/views');//设置模板文件路径
14 | // app.engine('.html', require('ejs').__express)
15 | // app.set('view engine', 'html');
16 | const isProd = process.env.NODE_ENV === 'production'
17 |
18 | /*
19 | @ maxAge 最大缓存30天
20 | */
21 | const serve = (path, cache) => express.static(resolve(path), {
22 | maxAge: cache && isProd ? 1000 * 60 * 60 * 24 * 30 : 0
23 | })
24 | app.use(cookieParser())
25 | app.use(compression({ threshold: 0 }))
26 | /*
27 | @ 设置全部静态资源访问路径
28 | @ assets 编译后的文件目录
29 | */
30 | let static =isProd?"assets":"src";
31 | app.use('/assets', serve(config.root + '/assets', true)) //
32 | app.use('/static', serve(config.root + '/'+static+'/public', true))
33 | app.use('/manifest.json', serve(config.root + '/manifest.json', true))
34 | app.use('/service-worker.js', serve(config.root + '/assets/service-worker.js'))
35 | app.use(favicon(config.root + '/'+static+'/public/logo-48.png'))
36 |
37 |
38 |
39 |
40 |
41 |
42 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vue-Vuex-axios-SRR 示例
2 |
3 | ### 示例说明
4 |
5 | - 1、该示例由官方 vue-hackernews-2.0 示例根据公司实际项目需要进行优化改进过,非原创,
6 | - 2、实现的功能点列表:
7 | - 1)、项目目录结构进行了变更,让整个项目分类看起来更一目了然,
8 | - 2)、处理了500、404等页面的跳转逻辑,
9 | - 3)、融入了axios,进行多队列请求、单个请求的回调封装逻辑处理
10 | - 4)、引入了scss的支持,页面title的修改优化,无需在每个组件内部设置,直接在路由配置页配置添加即可,
11 | - 5)、路由划分为按功能模块分类,便于维护
12 | - 6)、store的维护,变更,不同模块写在不同文件内,分开处理
13 | - 7)、引入了mock.js数据……
14 | - 8)、其他还有很多细节,有兴趣的同学自己去慢慢发现吧……
15 | - 3、如果觉得该示例不错,对您有一定的帮助,记得帮 star、star、star 哦 ^_^ ^_^ ^_^ ^_^~~
16 | - 想了解更多?——[@IT·平头哥联盟](https://honeybadger8.github.io/blog/ "@IT·平头哥联盟-首席填坑官∙苏南")
17 |
18 | ****
19 |
20 | ## 技术交流
21 | - 公众号:`honeyBadger8` 下方可扫码👇
22 | - 群:912594095、[386485473](https://shang.qq.com/wpa/qunwpa?idkey=d44baf17512787eb0e4f268849a3239d6b9675145a606e21b9a055176bd1c0e2 "技术交流群 @IT·平头哥联盟")
23 | - 博客:[@IT·平头哥联盟](https://honeybadger8.github.io/blog/ "@IT·平头哥联盟-首席填坑官∙苏南")
24 |
25 | ## 安装依赖包
26 | - npm install
27 | - 建议使用 cnpm 速度更快一些,[淘宝 NPM 镜像](https://npm.taobao.org/)
28 |
29 | ## 开发环境
30 | - npm run dev
31 | - 访问http://localhost:80/home
32 |
33 | ## 生成环境
34 | - npm run build
35 | - npm start
36 |
37 | ## 关于我
38 | - 最近在写博客了,有兴趣的同学可以关注一下我和朋友一起整的公众号,专注于分享前端/测试的一些心得总结👇👇,
39 | - 公众号:`honeyBadger8`。
40 |
41 | 
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/assets/js/2.18e5bac323c205796d49.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([2],{151:function(t,n,e){"use strict";function r(t){e(189)}Object.defineProperty(n,"__esModule",{value:!0});var i=e(192),a=e(193),o=e(60),s=r,c=o(i.a,a.a,s,null,null);n.default=c.exports},189:function(t,n,e){var r=e(190);"string"==typeof r&&(r=[[t.i,r,""]]),r.locals&&(t.exports=r.locals);e(146)("681d7cb6",r,!0)},190:function(t,n,e){n=t.exports=e(145)(void 0),n.push([t.i,".error-tips{width:666px;margin:15% auto 0;text-align:center}.error-tips .err-inner{width:550px;height:420px;padding:60% 0 0;background:url("+e(191)+") 50% no-repeat;margin:0 auto;font-size:15px}.error-tips .a-block{display:inline-block;margin-right:30px;text-decoration:underline}",""])},191:function(t,n,e){t.exports=e.p+"images/404.png?d022af973da8a895df602a976f5159cc"},192:function(t,n,e){"use strict";var r=null;n.a={name:"noFound-view",mounted:function(){this.down()},data:function(){return{second:5}},methods:{down:function(){var t=this;r=setInterval(function(){if(t.second<=0)return clearInterval(r),t.$router.replace({path:"/home"}),!1;t.second--},1e3)}}}},193:function(t,n,e){"use strict";var r=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",[e("div",{staticClass:"error-tips"},[e("Card",[e("div",{staticClass:"err-inner"},[e("p",[e("router-link",{staticClass:"a-block",attrs:{to:{path:"/home"}}},[t._v("返回首页")]),e("span",[e("strong",{staticClass:"red"},[t._v(t._s(t.second))]),t._v("秒后自动回到首页")])],1)])])],1)])},i=[],a={render:r,staticRenderFns:i};n.a=a}});
--------------------------------------------------------------------------------
/assets/js/manifest.6a5fd1fc2b981fe18281.js:
--------------------------------------------------------------------------------
1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,a,c){for(var f,u,i,d=0,s=[];d store - login 模块
7 | */
8 | import StaticToast from 'src/components/common/Toast/index';
9 | import {fetchSingle,fetchGroup} from "src/utils/fetch";
10 |
11 | /*
12 | * @ 登录模块 type 常量; 用于更新不同的操作数据
13 | */
14 | export const LOGIN = 'LOGIN';
15 |
16 |
17 | /*
18 | * @ 登录模块 initState;
19 | */
20 | const state = {
21 | userToken:""
22 | };
23 |
24 | /*
25 | * @ 登录模块 getters - 对外数据接收器
26 | */
27 | const getters = {
28 | _Token (state) {
29 | return state.userToken
30 | }
31 |
32 | };
33 |
34 | /*
35 | * @ 登录模块 actions
36 | */
37 | const actions = {
38 |
39 | submit({commit, state}, options){
40 |
41 | const {data,success,error} = options||{};
42 | // 登录成功后更新userToken
43 | return fetchSingle({url:'/api/test/userToken',type:"POST",data}).then(res=>{
44 | if(res.code == 0){
45 | commit(LOGIN, {userToken: res.data.userToken});
46 | }else{
47 | StaticToast.warning(res.message);
48 | };
49 | success&&success(res);
50 | },error=>{
51 | error&&error(error);
52 | console.log("1555login",error)
53 | });
54 | }
55 |
56 | };
57 |
58 | /*
59 | * @ 登录模块 mutations - 数据更新
60 | */
61 | const mutations = {
62 |
63 | [LOGIN](state, { userToken }){
64 |
65 | // 登录成功后更新userToken
66 | state.userToken = userToken
67 | }
68 |
69 | };
70 |
71 |
72 |
73 | export default {
74 | state,
75 | getters,
76 | actions,
77 | mutations
78 | }
79 |
--------------------------------------------------------------------------------
/src/pages/routes.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * @authors :Bin Mei
4 | * @date :2017-07-20
5 | * @description:pc官网 -> 路由对统一外出口
6 | */
7 |
8 |
9 | import Vue from 'vue'
10 | import Router from 'vue-router'
11 | import HomeRoute from "./Home/route.js" //首页模块router
12 | const NotFoundPage = () => import('./NotFoundPage/index.vue') //详情
13 | const Login = () => import('./Login/index.vue') //详情
14 | import iView from 'iview';
15 | import { createStore } from 'src/store/index.js'
16 | import format from 'src/utils/format'
17 | import 'iview/dist/styles/iview.css'; // 使用 CSS
18 |
19 | const store = createStore()
20 |
21 | Vue.use(iView);
22 | Vue.use(Router);
23 |
24 | var router = new Router({
25 | mode: 'history',
26 | scrollBehavior: () => ({ y: 0 }),
27 | routes: [
28 | ...HomeRoute,
29 |
30 |
31 | { path: '/login/:page(\\d+)?', component: Login,meta: {
32 | title:"登录页"
33 | } },
34 | { path: '/', redirect: '/home' },
35 | {
36 | path: '*', component:NotFoundPage ,
37 | meta: {
38 | requireAuth: false,title:"页面不存在"
39 | }
40 | },
41 |
42 | ]
43 | });
44 | // store.state.cookies
45 |
46 | //已在 build => entry => client 页面处理
47 | /*router.beforeEach((to, from, next) => {
48 | //页面是是否要登录进入,在该处统一处理
49 | if (to.matched.some(r => r.meta.requireAuth)) {
50 | // let format
51 |
52 | if (true) {
53 | next();
54 | }
55 | else {
56 |
57 | next({
58 | path: '/login',
59 | query: {redirect: to.fullPath}
60 | })
61 | }
62 | }
63 | else {
64 | next();
65 | }
66 | });*/
67 |
68 | export function createRouter () {
69 | return router;
70 | }
71 |
--------------------------------------------------------------------------------
/assets/js/4.2ba8b0ea69ab323082d9.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([4],{150:function(t,e,s){"use strict";function a(t){s(185)}Object.defineProperty(e,"__esModule",{value:!0});var i=s(187),r=s(188),n=s(60),o=a,l=n(i.a,r.a,o,null,null);e.default=l.exports},185:function(t,e,s){var a=s(186);"string"==typeof a&&(a=[[t.i,a,""]]),a.locals&&(t.exports=a.locals);s(146)("5c1e8767",a,!0)},186:function(t,e,s){e=t.exports=s(145)(void 0),e.push([t.i,".list .name{color:#06c}.list .label{color:#666}.list .a-block{display:block;color:#34495e}.list .ivu-card{margin-bottom:15px}.list .user-icon{width:50px;height:50px;border-radius:4px;border:1px solid #999}.list .row{background:#fff;border-radius:5px;padding:5px 10px}.preview-img{max-width:400px;max-height:400px}",""])},187:function(t,e,s){"use strict";var a=s(32),i=s.n(a),r=s(61);e.a={name:"detail-view",computed:i()({},Object(r.c)({_details:"_details"})),methods:i()({},Object(r.b)({details:"details"})),data:function(){return{currentName:this.$route.query.name}},asyncData:function(t){var e=t.store,s=t.route.params.id,a=e.state.cookies.userToken;return e.dispatch("details",{id:s,userToken:a})}}},188:function(t,e,s){"use strict";var a=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"list main"},[t._details&&Object.keys(t._details).length?s("section",[s("Alert",[s("p",[t._v("作者:"),s("strong",{staticClass:"name"},[t._v(t._s(t.currentName))]),t._v("老师 ")]),s("p",[t._v("发表时间:"+t._s(t._details.date)+" ")])]),s("Card",{attrs:{bordered:!0}},[s("p",{slot:"title"},[s("span",{staticClass:"label"},[t._v("文章标题:")]),t._v(t._s(t._details.title))]),s("section",[t._v("\n "+t._s(t._details.content)+"\n ")])])],1):s("h1",[t._v("请求出错")])])},i=[],r={render:a,staticRenderFns:i};e.a=r}});
--------------------------------------------------------------------------------
/src/pages/Home/route.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | import {Bridges} from 'src/utils/bridge.js'
4 | const Layout = () => import('src/components/Layout/index.vue') //共用部分
5 | const Home = () => import('./Index/index.vue') //首页
6 | const List = () => import('./List/index.vue') //列表
7 | const Details = () => import('./Details/index.vue') //详情
8 |
9 |
10 | // export default [
11 | // {
12 | // path:'/home',
13 | // component:Home,
14 | // name:"home",
15 | // ...Bridges("首 页",true),
16 | // //children 使用注意,内容渲染在home 内的route-view入口 内;
17 | // children:[
18 |
19 | // ],
20 |
21 | // },{
22 | // path:'/list/:page(\\d+)?',
23 | // name:"list",
24 | // component:List,
25 | // ...Bridges("列表页",true),
26 | // },{
27 | // path:'/details/:id',
28 | // name:"details",
29 | // component:Details,
30 | // ...Bridges("文章详情页",true),
31 | // }
32 | // ];
33 | // import {Bridges} from 'src/utils/bridge.js'
34 | // import Layout from "src/components/Layout/index.vue" //首页
35 | // import Home from "src/pages/Home/Index/index.vue" //首页
36 | // import List from "src/pages/Home/List/index.vue" //列表
37 | // import Details from "src/pages/Home/Details/index.vue" //详情
38 |
39 | export default [
40 | {
41 | path:'/home',
42 | component:Layout,
43 | // name:"layout",
44 | //children 使用注意,内容渲染在home 内的route-view入口 内;
45 | children:[
46 | {
47 | // name:"",
48 | path: '/',
49 | component: Home,
50 | ...Bridges("首 页"),
51 | },{
52 | path:'list',
53 | // name:"list",
54 | component:List,
55 | ...Bridges("列表页",true),
56 | },{
57 | path:'details/:id',
58 | // name:"details",
59 | component:Details,
60 | ...Bridges("文章详情页",true),
61 | }
62 | ],
63 | }
64 | ];
--------------------------------------------------------------------------------
/src/pages/Home/Details/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 作者:{{currentName}}老师
6 | 发表时间:{{_details.date}}
7 |
8 |
9 |
10 | 文章标题:{{_details.title}}
11 |
12 | {{_details.content}}
13 |
14 |
15 |
16 |
请求出错
17 |
18 |
19 |
20 |
63 |
64 |
68 |
--------------------------------------------------------------------------------
/src/components/Layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
18 |
19 |
20 | 该项目示例说明:
21 |
22 | 1、该示例由官方 vue-hackernews-2.0 示例根据公司实际项目需要进行优化改进过,非原创,
23 | 2、实现的功能点列表:
24 | 1)、项目目录结构进行了变更,让整个项目分类看起来更一目了然,
25 | 2)、处理了500、404等页面的跳转逻辑,
26 | 3)、融入了axios,进行多队列请求、单个请求的回调封装逻辑处理
27 | 4)、引入了scss的支持,页面title的修改优化,无需在每个组件内部设置,直接在路由配置页配置添加即可,
28 | 5)、路由划分为按功能模块分类,便于维护
29 | 6)、store的维护,变更,不同模块写在不同文件内,分开处理
30 | 7)、引入了mock.js数据……
31 | 8)、其他还有很多细节,有兴趣的同学自己去慢慢发现吧……
32 | 3、如果觉得该示例不错,对您有一定的帮助,记得帮 star、star、star 哦 ^_^ ^_^ ^_^ ^_^~~
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/components/Layout/Layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
18 |
19 |
20 | 该项目示例说明:
21 |
22 | 1、该示例由官方 vue-hackernews-2.0 示例根据公司实际项目需要进行优化改进过,非原创,
23 | 2、实现的功能点列表:
24 | 1)、项目目录结构进行了变更,让整个项目分类看起来更一目了然,
25 | 2)、处理了500、404等页面的跳转逻辑,
26 | 3)、融入了axios,进行多队列请求、单个请求的回调封装逻辑处理
27 | 4)、引入了scss的支持,页面title的修改优化,无需在每个组件内部设置,直接在路由配置页配置添加即可,
28 | 5)、路由划分为按功能模块分类,便于维护
29 | 6)、store的维护,变更,不同模块写在不同文件内,分开处理
30 | 7)、引入了mock.js数据……
31 | 8)、其他还有很多细节,有兴趣的同学自己去慢慢发现吧……
32 | 3、如果觉得该示例不错,对您有一定的帮助,记得帮 star、star、star 哦 ^_^ ^_^ ^_^ ^_^~~
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/pages/Home/Index/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 作者:{{item.title}}
9 | 时间:{{item.date}}
10 | 签名:{{item.content}}
11 | 共发表过{{item.sum}}文章
12 |
13 |
14 |
15 |
16 |
{{home_error}}
17 |
18 |
19 |
20 |
21 |
66 |
70 |
71 |
--------------------------------------------------------------------------------
/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 | var config = require('../server/config');
7 |
8 | var debug = require('debug')('todo:server');
9 | var http = require('http');
10 |
11 | module.exports = function (app) {
12 | var port = normalizePort(config.PORT || '8080');
13 | app.set('port', port);
14 |
15 | var server = http.createServer(app);
16 | server.listen(port);
17 | console.log('Express app http started on port ' + port);
18 | server.on('error', onError);
19 | server.on('listening', onListening);
20 |
21 | /**
22 | * Normalize a port into a number, string, or false.
23 | */
24 | function normalizePort(val) {
25 | var port = parseInt(val, 10);
26 | if (isNaN(port)) {
27 | // named pipe
28 | return val;
29 | }
30 | if (port >= 0) {
31 | // port number
32 | return port;
33 | }
34 | return false;
35 | }
36 |
37 | /**
38 | * Event listener for HTTP server "error" event.
39 | */
40 | function onError(error) {
41 | if (error.syscall !== 'listen') {
42 | throw error;
43 | }
44 | var bind = typeof port === 'string'
45 | ? 'Pipe ' + port
46 | : 'Port ' + port;
47 | // handle specific listen errors with friendly messages
48 | switch (error.code) {
49 | case 'EACCES':
50 | console.error(bind + ' requires elevated privileges');
51 | process.exit(1);
52 | break;
53 | case 'EADDRINUSE':
54 | console.error(bind + ' is already in use');
55 | process.exit(1);
56 | break;
57 | default:
58 | throw error;
59 | }
60 | }
61 |
62 | /**
63 | * Event listener for HTTP server "listening" event.
64 | */
65 | function onListening() {
66 | var addr = server.address();
67 | var bind = typeof addr === 'string'
68 | ? 'pipe ' + addr
69 | : 'port ' + addr.port;
70 | debug('Listening on ' + bind);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/assets/js/5.95f3fcb64e74ab55624c.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([5],{147:function(t,s,a){"use strict";function e(t){a(157)}Object.defineProperty(s,"__esModule",{value:!0});var r=a(159),i=a(60),o=e,n=i(null,r.a,o,null,null);s.default=n.exports},157:function(t,s,a){var e=a(158);"string"==typeof e&&(e=[[t.i,e,""]]),e.locals&&(t.exports=e.locals);a(146)("42e93068",e,!0)},158:function(t,s,a){s=t.exports=a(145)(void 0),s.push([t.i,".layout{max-width:100%}",""])},159:function(t,s,a){"use strict";var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"layout"},[a("header",{staticClass:"header"},[a("nav",{staticClass:"inner"},[a("router-link",{attrs:{to:"/",exact:""}},[a("img",{staticClass:"logo",attrs:{src:"/static/logo-48.png",alt:"logo"}})]),a("router-link",{attrs:{to:"/login"}},[t._v("登录页")]),a("router-link",{attrs:{to:"/details"}},[t._v("详情页")]),a("router-link",{attrs:{to:"/noFound"}},[t._v("错误404页")]),a("a",{staticClass:"github",attrs:{href:"https://github.com/meibin08",target:"_blank",title:"GitHub",rel:"noopener"}},[a("Icon",{attrs:{type:"social-github",size:"26",color:"#fff"}})],1)],1)]),a("transition",{attrs:{name:"fade",mode:"out-in"}},[a("router-view",{staticClass:"view"})],1),a("Alert",{staticClass:"main",attrs:{"show-icon":""}},[a("h3",[t._v("该项目示例说明:")]),a("template",{slot:"desc"},[a("p",[t._v("1、该示例由官方 vue-hackernews-2.0 示例根据公司实际项目需要进行优化改进过,非原创,")]),a("p",[t._v("2、实现的功能点列表:")]),a("p",[t._v(" 1)、项目目录结构进行了变更,让整个项目分类看起来更一目了然,")]),a("p",[t._v(" 2)、处理了500、404等页面的跳转逻辑,")]),a("p",[t._v(" 3)、融入了axios,进行多队列请求、单个请求的回调封装逻辑处理")]),a("p",[t._v(" 4)、引入了scss的支持,页面title的修改优化,无需在每个组件内部设置,直接在路由配置页配置添加即可,")]),a("p",[t._v(" 5)、路由划分为按功能模块分类,便于维护")]),a("p",[t._v(" 6)、store的维护,变更,不同模块写在不同文件内,分开处理")]),a("p",[t._v(" 7)、引入了mock.js数据……")]),a("p",[t._v(" 8)、其他还有很多细节,有兴趣的同学自己去慢慢发现吧……")]),a("p",[t._v("3、如果觉得该示例不错,对您有一定的帮助,记得帮 "),a("span",{staticClass:"red"},[t._v("star、star、star")]),t._v(" 哦 ^_^ ^_^ ^_^ ^_^~~")]),a("br"),a("h6",[t._v("想了解更多吗?"),a("strong",[a("a",{attrs:{href:"https://github.com/meibin08"}},[t._v("请猛戳我吧!")])])])])],2)],1)},r=[],i={render:e,staticRenderFns:r};s.a=i}});
--------------------------------------------------------------------------------
/assets/js/3.c299a5f8bda21fc21fdd.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([3],{152:function(t,e,n){"use strict";function o(t){n(194)}Object.defineProperty(e,"__esModule",{value:!0});var r=n(196),s=n(197),a=n(60),i=o,p=a(r.a,s.a,i,null,null);e.default=p.exports},194:function(t,e,n){var o=n(195);"string"==typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);n(146)("d9bda868",o,!0)},195:function(t,e,n){e=t.exports=n(145)(void 0),e.push([t.i,".login{margin:15% auto 0;text-align:center;width:320px;padding:5px;border-radius:5px;background-color:rgba(0,0,0,.5)}.login .ivu-alert{padding:8px 16px;margin:0}.login .tit{padding:10px 0 20px;text-align:center;font-size:14px}",""])},196:function(t,e,n){"use strict";var o=n(32),r=n.n(o),s=n(61),a=n(33),i=(n(18),n(19)),p=!1;e.a={name:"login-view",mounted:function(){},computed:r()({},Object(s.c)({_Token:"_Token"})),methods:r()({},Object(s.b)({submit:"submit"}),{login:function(){var t=this,e=this.$route.query.redirect;return this.name?this.password?!p&&(p=!0,void this.submit({data:{name:this.name,password:this.password},success:function(n){i.a.setCookie("userToken",t._Token),t.$router.replace({path:e}),p=!1}})):void a.a.warning("请输入您的密码"):void a.a.warning("请输入您的用户名")}}),data:function(){this.$route.query.name;return{modal:!1,name:"",password:""}}}},197:function(t,e,n){"use strict";var o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"login"},[n("Alert",[n("h4",{staticClass:"tit"},[t._v("登录")]),n("Form",{ref:"formInline"},[n("Form-item",{attrs:{prop:"user"}},[n("Input",{attrs:{type:"text",placeholder:"Username"},model:{value:t.name,callback:function(e){t.name=e},expression:"name"}},[n("Icon",{attrs:{type:"ios-person-outline"},slot:"prepend"})],1)],1),n("Form-item",{attrs:{prop:"password"}},[n("Input",{attrs:{type:"password",placeholder:"Password"},model:{value:t.password,callback:function(e){t.password=e},expression:"password"}},[n("Icon",{attrs:{type:"ios-locked-outline"},slot:"prepend"})],1)],1),n("p",[t._v(t._s(t._Token))]),n("Form-item",[n("Button",{attrs:{type:"primary"},on:{click:t.login}},[t._v("登录")])],1)],1)],1)],1)},r=[],s={render:o,staticRenderFns:r};e.a=s}});
--------------------------------------------------------------------------------
/src/pages/Login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
25 |
85 |
86 |
90 |
--------------------------------------------------------------------------------
/src/components/App/App.scss:
--------------------------------------------------------------------------------
1 | html,body{
2 | width:100%;
3 | height:100%;
4 | }
5 | body{
6 | background: url(./images/bg2.png) center center repeat;
7 | background-color:#f5f5f5;
8 |
9 | }
10 | .app-content{
11 |
12 | .red{
13 | color:#e42323
14 | }
15 | .main{
16 | width:1000px;
17 | max-width:1000px;
18 | margin:20px auto;
19 | overflow: hidden;
20 | }
21 | }
22 |
23 |
24 | body{
25 |
26 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
27 | font-size :15px;
28 | background-color: lighten(#eceef1, 30%);
29 | margin :0;
30 | padding-top :55px;
31 | color: #34495e;
32 | overflow-y :scroll
33 | }
34 |
35 | a{
36 | color :#34495e;
37 | text-decoration :none
38 | }
39 | .header{
40 | background-color :#333;
41 | position: fixed;
42 | z-index: 999;
43 | height :55px;
44 | top: 0;
45 | left: 0;
46 | right: 0}
47 | .inner{
48 | max-width: 800px;
49 | box-sizing: border-box;
50 | margin :0px auto;
51 | padding :15px 5px;
52 | a{
53 | color: rgba(255, 255, 255, .8);
54 | line-height: 24px;
55 | transition :color .15s ease;
56 | display :inline-block;
57 | vertical-align: middle;
58 | font-weight :300;
59 | letter-spacing :.075em;
60 | margin-right: 1.8em;
61 | &:hover{
62 | color :#fff
63 | }
64 | &.router-link-active{
65 | color :#fff;
66 | font-weight :400
67 | }
68 | &:nth-child(6){
69 | margin-right: 0
70 | }
71 | }
72 | }
73 | .github{
74 | color: #fff;
75 | font-size :.9em;
76 | margin: 0;
77 | float: right
78 | }
79 |
80 | .logo{
81 | width: 24px;
82 | margin-right: 10px;
83 | display: inline-block;
84 | vertical-align: middle
85 | }
86 |
87 | .view{
88 | max-width: 800px;
89 | margin: 0 auto;
90 | position :relative
91 | }
92 |
93 | .fade-enter-active, .fade-leave-active{
94 | transition: all .2s ease
95 | }
96 |
97 | .fade-enter, .fade-leave-active{
98 | opacity: 0
99 | }
100 |
101 | @media (max-width: 860px){
102 | .header .inner{
103 | padding :15px 30px
104 | }
105 | }
106 |
107 | @media (max-width: 600px){
108 | .header{
109 | .inner{
110 | padding: 15px}
111 | a{
112 | margin-right: 1em
113 | }
114 | .github{
115 | display: none
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/src/components/ProgressBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
88 |
89 |
103 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-ssr",
3 | "description": "A Vue.js project",
4 | "author": "Bin.Mei ",
5 | "private": true,
6 | "scripts": {
7 | "dev": "node devServer",
8 | "start": "cross-env NODE_ENV=production node app",
9 | "build": "rimraf assets && npm run build:client && npm run build:server",
10 | "build:client": "cross-env NODE_ENV=production webpack --config build/client/webpack.client.prd.config.js --progress --hide-modules",
11 | "build:server": "cross-env NODE_ENV=production webpack --config build/server/webpack.server.prd.config.js --progress --hide-modules"
12 | },
13 | "engines": {
14 | "node": ">=6.0",
15 | "npm": ">=3.0"
16 | },
17 | "dependencies": {
18 | "compression": "^1.6.2",
19 | "cookie-parser": "^1.4.3",
20 | "debug": "^2.2.0",
21 | "log4js": "^0.6.38",
22 | "morgan": "^1.7.0",
23 | "cross-env": "^4.0.0",
24 | "es6-promise": "^4.1.0",
25 | "express": "^4.15.2",
26 | "extract-text-webpack-plugin": "^2.1.0",
27 | "firebase": "^3.7.2",
28 | "lru-cache": "^4.0.2",
29 | "serve-favicon": "^2.4.1",
30 | "http-proxy": "^1.14.0",
31 | "vue": "^2.4.1",
32 | "vue-router": "^2.7.0",
33 | "vue-resource": "^1.2.1",
34 | "vue-server-renderer": "^2.4.1",
35 | "vuex": "^2.3.1",
36 | "vuex-router-sync": "^4.1.2"
37 | },
38 | "devDependencies": {
39 | "autoprefixer": "^6.7.7",
40 | "axios": "^0.16.2",
41 | "babel-core": "^6.24.1",
42 | "babel-loader": "^7.1.1",
43 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
44 | "babel-plugin-transform-object-rest-spread": "^6.23.0",
45 | "babel-plugin-transform-runtime": "^6.3.13",
46 | "babel-polyfill": "^6.22.0",
47 | "babel-preset-env": "^1.4.0",
48 | "babel-preset-es2015": "^6.0.0",
49 | "babel-preset-stage-0": "^6.5.0",
50 | "copy-webpack-plugin": "^4.0.1",
51 | "css-loader": "^0.28.0",
52 | "file-loader": "^0.11.1",
53 | "friendly-errors-webpack-plugin": "^1.6.1",
54 | "glob": "^7.1.1",
55 | "html5-history-api": "^4.2.8",
56 | "iview": "^2.0.0-rc.19",
57 | "node-sass": "^3.7.0",
58 | "rimraf": "^2.6.1",
59 | "sass-loader": "^4.1.1",
60 | "style-loader": "^0.18.2",
61 | "stylus": "^0.54.5",
62 | "stylus-loader": "^3.0.1",
63 | "sw-precache-webpack-plugin": "^0.10.1",
64 | "url-loader": "^0.5.8",
65 | "vue-loader": "^13.0.1",
66 | "vue-style-loader": "^3.0.0",
67 | "vue-template-compiler": "^2.4.1",
68 | "webpack": "^3.2.0",
69 | "webpack-dev-middleware": "^1.10.1",
70 | "webpack-hot-middleware": "^2.17.1",
71 | "webpack-merge": "^4.0.0",
72 | "webpack-node-externals": "^1.5.4"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/pages/Home/List/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
参与人:{{currentName}}老师发表的文章列表
4 |
27 |
请求出错
28 |
32 | ![]()
33 |
34 |
35 |
36 |
37 |
99 |
100 |
104 |
--------------------------------------------------------------------------------
/assets/js/1.6e3d48efa6a1fec884fd.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([1],{148:function(t,e,a){"use strict";function o(t){a(160)}Object.defineProperty(e,"__esModule",{value:!0});var s=a(162),n=a(169),r=a(60),i=o,c=r(s.a,n.a,i,null,null);e.default=c.exports},160:function(t,e,a){var o=a(161);"string"==typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);a(146)("fe28d920",o,!0)},161:function(t,e,a){e=t.exports=a(145)(void 0),e.push([t.i,".home{max-width:100%}.home .ivu-col{margin-bottom:10px}.home .mt-10{margin-top:10px;text-align:right}.home .img{width:50px;height:30px}",""])},162:function(t,e,a){"use strict";var o=a(32),s=a.n(o),n=a(61),r=a(163);e.a={name:"home-view",components:{Banner:r.a},computed:s()({},Object(n.c)({_home:"_home"}),{home_error:function(){return this.$store.state.home.home_error}}),methods:s()({},Object(n.b)({home:"home"}),{goToList:function(t){return this.$router.push({path:"/home/list",query:{name:t}})}}),asyncData:function(t){var e=t.store,a=t.route.params.id;return e.dispatch("home",{id:a})}}},163:function(t,e,a){"use strict";function o(t){a(164)}var s=a(166),n=a(60),r=o,i=n(null,s.a,r,null,null);e.a=i.exports},164:function(t,e,a){var o=a(165);"string"==typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);a(146)("18c02a52",o,!0)},165:function(t,e,a){e=t.exports=a(145)(void 0),e.push([t.i,".app-banner{width:100%;overflow:hidden}.app-banner .demo-carousel{width:100%;text-align:center;background-color:#eadcc7;height:300px}.app-banner .demo-carousel img{max-width:100%}.app-banner .demo-carousel.c3{background-color:#1b9bb5}.app-banner .demo-carousel.c4{background-color:#b30038}",""])},166:function(t,e,a){"use strict";var o=function(){var t=this,e=t.$createElement,o=t._self._c||e;return o("div",{staticClass:"app-banner"},[o("Carousel",{attrs:{autoplay:"",height:300,arrow:"never"}},[o("Carousel-item",[o("div",{staticClass:"demo-carousel"},[o("img",{attrs:{src:a(167),alt:""}})])]),o("Carousel-item",[o("div",{staticClass:"demo-carousel"},[o("img",{attrs:{src:a(168),alt:""}})])]),o("Carousel-item",[o("div",{staticClass:"demo-carousel c3"},[o("img",{attrs:{src:"http://img3.job1001.com/zhuanti/android/images/zsj/banner3.png",alt:""}})])]),o("Carousel-item",[o("div",{staticClass:"demo-carousel c4"},[o("img",{attrs:{src:"http://img3.job1001.com/zhuanti/android/images/zsj/banner1.png",alt:""}})])])],1)],1)},s=[],n={render:o,staticRenderFns:s};e.a=n},167:function(t,e,a){t.exports=a.p+"images/img01.png?96d6f287b3c6d23d6e7aebdd273ff7a8"},168:function(t,e,a){t.exports=a.p+"images/img02.png?2113fefce936df86c4ca7d27fae8b0ce"},169:function(t,e,a){"use strict";var o=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"home"},[a("banner"),a("div",{staticClass:"content main"},[t._home&&t._home.length?a("Row",{attrs:{type:"flex",gutter:10}},t._l(t._home,function(e){return a("Col",{key:e.id,attrs:{span:"8"}},[a("Card",[a("p",{slot:"title"},[t._v("作者:"+t._s(e.title))]),a("p",[t._v("时间:"+t._s(e.date))]),a("p",[t._v("签名:"+t._s(e.content))]),a("p",[t._v("共发表过"),a("span",{staticClass:"red"},[t._v(t._s(e.sum))]),t._v("文章")]),a("p",{staticClass:"mt-10"},[a("Button",{attrs:{type:"info",size:"small"},on:{click:function(a){t.goToList(e.title)}}},[t._v("查看列表")])],1)])],1)})):a("h1",[t._v(t._s(t.home_error))])],1)],1)},s=[],n={render:o,staticRenderFns:s};e.a=n}});
--------------------------------------------------------------------------------
/src/utils/format.js:
--------------------------------------------------------------------------------
1 | import { isNotEmpty, isIdCard } from './validate';
2 |
3 | const client = process.env.VUE_ENV == "client";
4 | let format = {
5 |
6 | // 格式化日期
7 | date: function (date, fmt) {
8 | if (!date || !fmt) {
9 | return date;
10 | }
11 | if (date.length == 8) {
12 | date = date.substr(0, 4) + '-' + date.substr(4, 2) + '-' + date.substr(6, 2)
13 | }
14 | date = new Date(date.toString().replace(/-/g, "/"));
15 | var o = {
16 | "M+": date.getMonth() + 1, //月份
17 | "d+": date.getDate(), //日
18 | "h+": date.getHours(), //小时
19 | "m+": date.getMinutes(), //分
20 | "s+": date.getSeconds(), //秒
21 | "q+": Math.floor((date.getMonth() + 3) / 3), //季度
22 | "S": date.getMilliseconds() //毫秒
23 | };
24 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
25 | for (var k in o)
26 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
27 | return fmt;
28 | },
29 |
30 | // 根据身份证获取出生年月
31 | getBirthdayByIdCard(idCard) {
32 | if (!isIdCard(idCard)) {
33 | return;
34 | }
35 | let tmpStr;
36 | if (idCard.length == 15) {
37 | tmpStr = idCard.substring(6, 12);
38 | tmpStr = "19" + tmpStr;
39 | tmpStr = tmpStr.substring(0, 4) + "-" + tmpStr.substring(4, 6) + "-" + tmpStr.substring(6)
40 | return tmpStr;
41 | } else {
42 | tmpStr = idCard.substring(6, 14);
43 | tmpStr = tmpStr.substring(0, 4) + "-" + tmpStr.substring(4, 6) + "-" + tmpStr.substring(6)
44 | return tmpStr;
45 | }
46 | },
47 |
48 | // 根据身份证获取性别
49 | getSexByIdCard(idCard) {
50 | if (!isIdCard(idCard)) {
51 | return;
52 | }
53 | return (parseInt(idCard.substr(16, 1)) % 2)
54 | },
55 | setCookie(name,value)
56 | {
57 | var Days = 7;
58 | var exp = new Date();
59 | exp.setTime(exp.getTime() + Days*24*60*60*1000);
60 | document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString() + ";path=/";
61 | },
62 |
63 | //读取cookies
64 | getCookie(name)
65 | {
66 | var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
67 |
68 | if(arr=document.cookie.match(reg))
69 |
70 | return unescape(arr[2]);
71 | else
72 | return null;
73 | } ,
74 | //删除cookies
75 | removeCookie(name)
76 | {
77 |
78 | var exp = new Date();
79 | exp.setTime(exp.getTime() - 1);
80 | var cval=getCookie(name);
81 | if(cval!=null) document.cookie= name + "="+cval+";expires="+exp.toGMTString() + ";path=/";
82 | } ,
83 | clientCookie(){
84 | let result = {};
85 | let cookies = document.cookie;
86 | if(!cookies){
87 | return result;
88 | };
89 | let str = cookies.split(";");
90 | for(var i=0;i store - home 模块
7 | */
8 | import StaticToast from 'src/components/common/Toast/index';
9 | import {fetchSingle,fetchGroup} from "src/utils/fetch";
10 |
11 | /*
12 | * @ home 模块 type 常量; 用于更新不同的操作数据
13 | */
14 | export const LOGIN = 'LOGIN';
15 | export const SET_HOME = 'SET_HOME';
16 | export const SET_LIST = 'SET_LIST';
17 | export const SET_DETAILS = 'SET_DETAILS';
18 | export const SET_ERROR = 'SET_ERROR';
19 |
20 |
21 | /*
22 | * @ home 模块 initState;
23 | */
24 | const state = {
25 | home:[],
26 | home_error:"请求出错啦",
27 | list:[],
28 | details:{}
29 | };
30 |
31 | /*
32 | * @ home 模块 getters - 对外数据接收器 function 格式 以 _ 开头
33 | */
34 | const getters = {
35 | _home (state) {
36 | /*
37 | * @ home页面数据
38 | */
39 | return state.home
40 | },
41 | _list(state){
42 | /*
43 | * @ home -> list 页面数据
44 | */
45 | return state.list;
46 | },
47 | _details(state){
48 | /*
49 | * @ home -> list -> detail 页面数据
50 | */
51 | return state.details;
52 | }
53 |
54 | };
55 |
56 | /*
57 | * @ home 模块 actions
58 | */
59 | const actions = {
60 |
61 |
62 | home: ({commit, state}) =>{
63 | /*
64 | * @ 首页初始数据
65 | */
66 | return fetchSingle({url:'/api/test/homeList', data:{city: state.city}}).then(res=>{
67 | // console.log(32,'首页初始数据',res);
68 | if(res.code == 0){
69 | commit(SET_HOME, {home: res.data});
70 | }else{
71 | commit(SET_ERROR, {message: res.message,"key":"home_error"});
72 | };
73 | },error=>{
74 | console.log(1555,error)
75 | });
76 | },
77 |
78 | list:({commit, state},{name,userToken})=>{
79 | /*
80 | * @ 文章列表页初始数据
81 | */
82 | return fetchSingle({url:'/api/test/sectionList',data:{name,userToken},type:"POST"}).then(res=>{
83 | // console.log(32,res);
84 | if(res.code == 0){
85 | commit(SET_LIST, {list: res.data});
86 | }else{
87 | commit(SET_ERROR, {message: res.message,"key":"list_error"});
88 | };
89 | },error=>{
90 | console.log(35,error)
91 | });
92 | return ;
93 | return fetchGroup([
94 | {url:'/api/test/section_list', data:{name},type:"POST"},
95 | {url:'/api/test/list', data:{city: state.city}},
96 | ]).then(res=>{
97 | if(res[0].code == 0){
98 | commit(SET_LIST, {list: res[0].data.list});
99 | }else{
100 |
101 | commit(SET_LIST, {list: res.data,"key":"list_error"});
102 | }
103 | },error=>{
104 | console.log(35,error);
105 | });
106 | },
107 |
108 | details: ({commit, state},{id,userToken}) =>{
109 | /*
110 | * @ 文章详情页数据
111 | */
112 | return fetchSingle({url:`/api/test/details/${id}`,type:"POST",data:{id,userToken}}).then(res=>{
113 | if(res.code == 0){
114 | // console.log(48,res)
115 | commit(SET_DETAILS, {details: res.data});
116 | }else{
117 | commit(SET_ERROR, {message: res.message,"key":"home_error"});
118 | };
119 | },error=>{
120 | console.log(1555,error)
121 | });;
122 | }
123 |
124 | };
125 |
126 | /*
127 | * @ home 模块 mutations - 数据更新
128 | */
129 | const mutations = {
130 | [SET_HOME](state, { home }) {
131 | state.home = home
132 | },
133 | [SET_LIST](state, { list }) {//console.log("setHome",home);
134 | state.list = list
135 | },
136 | [SET_DETAILS](state, { details }) {//console.log("setHome",home);
137 | state.details = details
138 | },
139 | [SET_ERROR](state, { message,key }) {
140 | state.home_error = message;
141 | console.log("sssetHome",state);
142 | }
143 |
144 | };
145 |
146 |
147 | export default {
148 | state,
149 | getters,
150 | actions,
151 | mutations
152 | }
153 |
--------------------------------------------------------------------------------
/src/utils/fetchApi/fetch.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author monkeywang
3 | * Date: 17/3/14
4 | */
5 | import Vue from 'vue'
6 | import axios from 'axios'
7 | // import { createApp } from 'src/app'
8 | import { createRouter } from 'src/pages/routes'
9 | const router = createRouter()
10 | // const { app, router, store } = createApp();
11 |
12 | const client = process.env.VUE_ENV == "client";
13 |
14 | axios.defaults.timeout = 5000;
15 | axios.defaults.baseURL = client?"/zaApi/easy":'https://easy-mock.com/mock/59294d8e91470c0ac1fe8a4c';;
16 |
17 | // http request 拦截器
18 | axios.interceptors.request.use(
19 | config => {
20 | let token = localStorage.getItem("token");
21 | if (token) {
22 | config.headers.Authorization = `token ${token}`;
23 | }
24 | return config;
25 | },
26 | err => {
27 | return Promise.reject(err);
28 | });
29 |
30 | // http response 拦截器
31 | axios.interceptors.response.use(
32 | response => {
33 | return response;
34 | },
35 | error => {
36 | if (error.response) {
37 | switch (error.response.status) {
38 | case 401:
39 | console.log(error);
40 | router.replace({
41 | path: 'login',
42 | query: {redirect: router.currentRoute.fullPath}
43 | })
44 | break;
45 | case 404:
46 | case 500:
47 | router.replace({
48 | path: 'notFound',
49 | query: {redirect: router.currentRoute.fullPath}
50 | })
51 | break;
52 |
53 | }
54 | };
55 |
56 | // console.log(JSON.stringify(error));//console : Error: Request failed with status code 402
57 | return Promise.reject(error.response.data)
58 | });
59 |
60 | const fetch =(options)=>{
61 | let { url, type, data, ...others } = options;
62 | let opts = {
63 | ...others,
64 | method: (type || 'get').toUpperCase(),
65 | // credentials: 'include',
66 | data,
67 | url,
68 | headers: {
69 | 'Accept': 'application/json',
70 | 'Content-Type': 'application/json'
71 | }
72 | }
73 | return axios(opts);
74 | }
75 |
76 | export const fetchJson = (options)=>{
77 |
78 | fetch(options).then(resData => toJson(resData, options))
79 | .then(resData => resHandler(resData, options))
80 | };
81 | export const fetchJsonAll = (queue)=>{
82 | var promises = (queue||[]).map(function(item){
83 | return fetch(item);
84 | });
85 | axios.all(promises)
86 | .then(axios.spread((res1, res2)=>{
87 | console.log(res1)
88 | console.log(res2)
89 | })).catch(err=>{ console.log(err) })
90 |
91 |
92 | };
93 |
94 |
95 |
96 |
97 | function toJson(resp, options) {
98 | if (resp.status >= 400) {
99 | return errorHandler(null, options, resp.status)
100 | }
101 | return resp;
102 | }
103 |
104 | // 请求成功处理
105 | function resHandler(resData, options) {
106 | // Loading(false);
107 | if (resData.status && resData.status != 200) {
108 | return errorHandler(resData.error, options, resData.status);
109 | }
110 | if (!resData || (resData.data&& resData.data.code > 20000)) {
111 | // options.error && options.error(resData.data);
112 | /*router.replace({
113 | path: 'login',
114 | query: {redirect: router.currentRoute.fullPath}
115 | });*/
116 | return ;
117 | // StaticToast.error(resData.message);
118 | } else {
119 | options.success && options.success(resData.data);
120 | };
121 |
122 | }
123 |
124 | // 异常处理
125 | function errorHandler(error, options, status) {
126 | // Loading(false);
127 | options.error && options.error(error);
128 | console.log(`网络异常,请稍后重试(${status})`);
129 | // ErrorLogs(options._url,{status,error});
130 | }
131 |
132 |
133 |
134 |
135 | export default axios;
136 |
--------------------------------------------------------------------------------
/src/utils/fetchApi/fetch-client-(备份20160720).js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * @authors :Bin Mei
4 | * @date :2017-07-20
5 | * @description:pc官网 -> api请求 -客户端
6 | */
7 |
8 | import Vue from 'vue'
9 | import axios from 'axios'
10 | // import { createApp } from 'src/app'
11 | import { createRouter } from 'src/pages/routes'
12 | const router = createRouter()
13 | // const { app, router, store } = createApp();
14 |
15 | const client = process.env.VUE_ENV == "client";
16 |
17 | axios.defaults.timeout = 5000;
18 | axios.defaults.baseURL = client?"/zaApi/easy":'https://easy-mock.com/mock/59294d8e91470c0ac1fe8a4c';;
19 |
20 | // http request 拦截器
21 | axios.interceptors.request.use(
22 | config => {
23 | let token = "dsfdsagfdsgfdsgfdsgfdg";//localStorage.getItem("token");
24 | if (token) {
25 | config.headers.Authorization = `token ${token}`;
26 | }
27 | return config;
28 | },
29 | err => {
30 | return Promise.reject(err);
31 | });
32 |
33 | // http response 拦截器
34 | axios.interceptors.response.use(
35 | response => {
36 |
37 | if (response.status >= 200 && response.status < 300) {
38 | return response;
39 | }
40 | return Promise.reject(response);
41 | },
42 | error => {
43 |
44 | if (error.response) {
45 | switch (error.response.status) {
46 | case 401:
47 | console.log(error);
48 | router.replace({
49 | path: 'login',
50 | query: {redirect: router.currentRoute.fullPath}
51 | })
52 | break;
53 | case 404:
54 | case 500:
55 | //以提示的方式处理
56 |
57 | /*router.replace({
58 | path: 'notFound',
59 | query: {redirect: router.currentRoute.fullPath}
60 | })*/
61 | break;
62 |
63 | }
64 | };
65 |
66 | // console.log(JSON.stringify(error));//console : Error: Request failed with status code 402
67 | return Promise.reject(error.response)
68 | });
69 |
70 | const fetch =(options)=>{
71 | let { url, type, data, ...others } = options;
72 | let opts = {
73 | ...others,
74 | method: (type || 'get').toUpperCase(),
75 | // credentials: 'include',
76 | data,
77 | url,
78 | headers: {
79 | 'Accept': 'application/json',
80 | 'Content-Type': 'application/json'
81 | }
82 | }
83 |
84 | return new Promise((resolve, reject)=>{
85 | axios(opts)
86 | .then(resData =>{
87 |
88 | resolve(resData)
89 | }).catch((error) => {
90 | reject(error);
91 | });
92 | });
93 | // return axios(opts).then(resData => resData);
94 | }
95 |
96 | export const fetchJson = (options)=>{
97 | return fetch(options).then(res=>{
98 |
99 | return resHandler(res, options);
100 | },(err) =>{
101 | console.log(121,err)
102 | return errorHandler(err, options, err.status);
103 | });
104 | // return fetch(options).then(res=>resHandler(res, options),(err) =>resHandler(err, options));
105 | // fetch(options).then(resData => toJson(resData, options)).then(resData => resHandler(resData, options))
106 | };
107 | export const fetchJsonAll = (queue)=>{
108 | var promises = (queue||[]).map(function(item){
109 | return fetch(item);
110 | });
111 | axios.all(promises)
112 | .then(axios.spread((res1, res2)=>{
113 | console.log(res1)
114 | console.log(res2)
115 | })).catch(err=>{ console.log(err) })
116 |
117 |
118 | };
119 |
120 |
121 |
122 |
123 | function toJson(resp, options) {
124 | if (resp.status >= 400) {
125 | return errorHandler(null, options, resp.status)
126 | }
127 | return resp;
128 | }
129 |
130 | // 请求成功处理
131 | function resHandler(resData, options) {
132 |
133 | // Loading(false);
134 | if (resData.status && resData.status != 200) {
135 | return errorHandler(resData.data, options, resData.status);
136 | }
137 | if (!resData || (resData.data&& resData.data.code > 20000)) {
138 | // options.error && options.error(resData.data);
139 | router.replace({
140 | path: 'login',
141 | query: {redirect: router.currentRoute.fullPath}
142 | });
143 | return ;
144 | // StaticToast.error(resData.message);
145 | } else {
146 | options.success && options.success(resData.data);
147 | };
148 |
149 | }
150 |
151 | // 异常处理
152 | function errorHandler(error, options, status) {
153 | // Loading(false);
154 | options.error && options.error(error.data);
155 | console.log(`网络异常,请稍后重试(${status})`);
156 | // ErrorLogs(options._url,{status,error});
157 | }
158 |
159 |
160 |
161 |
162 | export default axios;
163 |
--------------------------------------------------------------------------------
/src/utils/validate.js:
--------------------------------------------------------------------------------
1 |
2 | const MOBILE_REG = /^1[3|4|5|8|7|9][0-9]\d{8}$/,
3 | EMAIL_REG = /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/,
4 | MONEY_REG = /^([1-9][\d]{0,7}|0)(\.[\d]{1,2})?$/,
5 | NAME_REG = /^([\u4e00-\u9fa5]+|[a-zA-Z0-9]+)$/,
6 | CHINESE_REG = /^[\u4e00-\u9fa5]+$/,
7 | BANKNO_REG=/^\d{16,19}$/,
8 | PWD_REG = /(\d(?!\d{5})|[A-Za-z](?![A-Za-z]{5})){6}/;
9 |
10 | function isRule(regText, value) {
11 | if (!value || value.length == 0)
12 | return true
13 |
14 | const reg = new RegExp(regText)
15 | if (!reg.test(value)) {
16 | return false
17 | }
18 | return true
19 | }
20 |
21 | module.exports = {
22 |
23 | isFromWeixin: () => {
24 | let ua = window.navigator.userAgent.toLowerCase();
25 | if (ua.match(/MicroMessenger/i) == "micromessenger") {
26 | return true;
27 | } else {
28 | return false;
29 | }
30 | },
31 | isIos(){
32 | let userAgent= navigator.userAgent;
33 | let IsiOS = !!userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
34 | return IsiOS;
35 | },
36 | isMobile: (mobile) => {
37 | return isRule(MOBILE_REG, mobile)
38 | },
39 |
40 | isEmail: (email) => {
41 | return isRule(EMAIL_REG, email)
42 | },
43 |
44 | isMoney: (money) => {
45 | return isRule(MONEY_REG, money)
46 | },
47 |
48 | isUsername: (name) => {
49 | return isRule(NAME_REG, name)
50 | },
51 | isChinese: (name) => {
52 | return isRule(CHINESE_REG, name)
53 | },
54 | isBankNo: (name) => {
55 | return isRule(BANKNO_REG, name)
56 | },
57 |
58 | isNotEmpty: (data) => {
59 | return data && (data.length > 0)
60 | },
61 |
62 | isPwd: (pwd) => {
63 | return isRule(PWD_REG, pwd)
64 | },
65 | isSame: (data1, data2) => {
66 | return data1 === data2
67 | },
68 | isIdCard: (card) => {
69 | if (!card) return true;
70 | var num = card.toUpperCase();
71 | //身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。
72 | if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(num))) {
73 | return false;
74 | }
75 | //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
76 | //下面分别分析出生日期和校验位
77 | var len, re;
78 | var birthday,sex;
79 | len = num.length;
80 | if (len == 15) {
81 |
82 | //获取出生日期
83 | birthday = '19' + card.substring(6, 8) + "-" + card.substring(8, 10) + "-" + card.substring(10, 12);
84 | //获取性别
85 | sex = parseInt(card.substr(14, 1)) % 2 == 1 ? 'M' : 'F';
86 |
87 | re = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/);
88 | var arrSplit = num.match(re);
89 |
90 | //检查生日日期是否正确
91 | var dtmBirth = new Date('19' + arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4]);
92 | var bGoodDay;
93 | bGoodDay = (dtmBirth.getYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]));
94 | if (!bGoodDay) {
95 | return false;
96 | } else {
97 | //将15位身份证转成18位
98 | //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
99 | var valnum;
100 | var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
101 | var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
102 | var nTemp = 0,
103 | i;
104 |
105 | num = num.substr(0, 6) + '19' + num.substr(6, num.length - 6);
106 | for (i = 0; i < 17; i++) {
107 | nTemp += num.substr(i, 1) * arrInt[i];
108 | }
109 | num += arrCh[nTemp % 11];
110 | }
111 | } else if (len == 18) {
112 |
113 | //获取出生日期
114 | birthday = card.substring(6, 10) + "-" + card.substring(10, 12) + "-" + card.substring(12, 14);
115 | //获取性别
116 | sex = parseInt(card.substr(16, 1)) % 2 == 1 ? 'M' : 'F';
117 |
118 | re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
119 | var arrSplit = num.match(re);
120 |
121 | //检查生日日期是否正确
122 | var dtmBirth = new Date(arrSplit[2] + "/" + arrSplit[3] + "/" + arrSplit[4]);
123 | var bGoodDay;
124 | bGoodDay = (dtmBirth.getFullYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]));
125 | if (!bGoodDay) {
126 | return false;
127 | } else {
128 | //检验18位身份证的校验码是否正确。
129 | //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
130 | var valnum;
131 | var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
132 | var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
133 | var nTemp = 0,
134 | i;
135 | for (i = 0; i < 17; i++) {
136 | nTemp += num.substr(i, 1) * arrInt[i];
137 | }
138 | valnum = arrCh[nTemp % 11];
139 | if (valnum != num.substr(17, 1)) {
140 | return false;
141 | }
142 | }
143 | }
144 | return {
145 | birthday: birthday,
146 | sex: sex
147 | }
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/src/utils/fetchApi/fetch-client.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * @authors :Bin Mei
4 | * @date :2017-07-20
5 | * @description:pc官网 -> api请求 -客户端
6 | */
7 |
8 | import Vue from 'vue'
9 | import axios from 'axios'
10 | // import { createApp } from 'src/app'
11 | import { createRouter } from 'src/pages/routes'
12 | import { createStore } from 'src/store'
13 | const router = createRouter()
14 | const store = createStore()
15 |
16 | const client = process.env.VUE_ENV == "client";
17 |
18 | //取客户端cookie;
19 | const getCookie = cookies => {
20 | let cookie = ''
21 | Object.keys(cookies).forEach(item => {
22 | cookie+= item + '=' + cookies[item] + '; '
23 | })
24 | return cookie;
25 | }
26 |
27 |
28 |
29 | axios.defaults.timeout = 5000;
30 | axios.defaults.baseURL = client?"/zaApi/easy":'https://easy-mock.com/mock/59294d8e91470c0ac1fe8a4c';
31 |
32 | // http request 拦截器
33 | axios.interceptors.request.use(
34 | config => {
35 | let token = "dsfdsagfdsgfdsgfdsgfdg";//localStorage.getItem("token");
36 |
37 | //把取到的cookie设置在请求头部;
38 | if (store.state.cookies &&!client) {
39 | config.headers.cookie =getCookie(store.state.cookies);
40 | };
41 | return config;
42 | },
43 | err => {
44 | return Promise.reject(err);
45 | });
46 |
47 | // http response 拦截器
48 | axios.interceptors.response.use(
49 | response => {
50 |
51 | if (response.status >= 200 && response.status < 300) {
52 | return response;
53 | }
54 | return Promise.reject(response);
55 | },
56 | error => {
57 | // console.log("57======================",error);
58 |
59 |
60 | //单个、多个队列请求可统一在这里处理 登录失效等逻辑
61 | if (error.response) {
62 | switch (error.response.status) {
63 | case 401:
64 | console.log(error);
65 | router.replace({
66 | path: 'login',
67 | query: {redirect: router.currentRoute.fullPath}
68 | })
69 | break;
70 | case 404:
71 | case 500:
72 | //以提示的方式处理
73 |
74 | /*router.replace({
75 | path: 'notFound',
76 | query: {redirect: router.currentRoute.fullPath}
77 | })*/
78 | break;
79 |
80 | }
81 | };
82 |
83 | // console.log(JSON.stringify(error));//console : Error: Request failed with status code 402
84 | return Promise.reject(error)
85 | });
86 |
87 | const fetch =(options)=>{
88 | let { url, type, data, ...others } = options;
89 | let opts = {
90 | ...others,
91 | method: (type || 'get').toUpperCase(),
92 | data,
93 | url,
94 | headers: {
95 | 'Accept': 'application/json',
96 | 'Content-Type': 'application/json'
97 | }
98 | }
99 |
100 | return new Promise((resolve, reject)=>{
101 | axios(opts)
102 | .then(resData =>{
103 | resolve(resData)
104 | }).catch((error) => {
105 | reject((error||{message: '网络异常,请刷新重试', type: 1}));
106 | });
107 | });
108 | }
109 |
110 | export const fetchJson = (options)=>{
111 | return fetch(options).then(res=>resHandler(res),(err) =>errorHandler(err, err.status));
112 | // return fetch(options).then(res=>resHandler(res, options),(err) =>resHandler(err, options));
113 | // fetch(options).then(resData => toJson(resData, options)).then(resData => resHandler(resData, options))
114 | };
115 | export const fetchJsonAll = (queue)=>{
116 | var promises = (queue||[]).map(function(item){
117 | return fetch(item);
118 | });
119 | return axios.all(promises)
120 | .then(res=>{
121 | //多个队列请求,只安第一个返回的结果处理 未登录状态;
122 | let firstItem = res[0];
123 | if (firstItem && firstItem.data&& firstItem.data.code > 20000) {
124 | router.replace({
125 | path: 'login',
126 | query: {redirect: router.currentRoute.fullPath}
127 | });
128 | return ;
129 | } ;
130 | let result = (res||[]).map((item)=>{
131 | return item.data;
132 | })
133 | return Promise.resolve(result);
134 | },(err) =>errorHandler(err.data||err, err.status))
135 | };
136 |
137 |
138 |
139 |
140 | function toJson(resp, options) {
141 | if (resp.status >= 400) {
142 | return errorHandler(null, options, resp.status)
143 | }
144 | return resp;
145 | }
146 |
147 | // 请求成功处理
148 | function resHandler(resData, options) {
149 |
150 | if (resData.status && resData.status != 200) {
151 | return errorHandler(resData.data||resData, resData.status);
152 | }
153 | if (!resData || (resData.data&& resData.data.code > 20000)) {
154 | router.replace({
155 | path: 'login',
156 | query: {redirect: router.currentRoute.fullPath}
157 | });
158 | return ;
159 | } else {
160 | return Promise.resolve(resData.data);
161 | };
162 | }
163 | // 异常处理
164 | function errorHandler(error, status) {
165 | console.log(`网络异常,请稍后重试(${status})`);
166 | return Promise.reject(error.data||error);
167 | }
168 |
169 |
170 |
171 |
172 |
173 | export default axios;
174 |
--------------------------------------------------------------------------------
/src/utils/fetch.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * @authors :Bin Mei
4 | * @date :2017-07-20
5 | * @description:pc官网 -> api请求 -客户、服务端都共用引起页面逻辑
6 | */
7 |
8 | import Vue from 'vue'
9 | import axios from 'axios'
10 | import format from 'src/utils/format'
11 | import { createRouter } from 'src/pages/routes'
12 | import { createStore } from 'src/store/index.js'
13 | const router = createRouter()
14 | const store = createStore()
15 |
16 | const client = process.env.VUE_ENV == "client";
17 |
18 |
19 |
20 | axios.defaults.timeout = 5000;
21 | axios.defaults.baseURL = client?"/zaApi/easy":'https://easy-mock.com/mock/59294d8e91470c0ac1fe8a4c';
22 |
23 | // http request 拦截器
24 | axios.interceptors.request.use(
25 | config => {
26 |
27 | if (client) {
28 | //config.headers.cookie =getCookie(format.getAllCookies());
29 | };
30 |
31 | return config;
32 | },
33 | err => {
34 | return Promise.reject(err);
35 | });
36 |
37 | // http response 拦截器
38 | axios.interceptors.response.use(
39 | response => {
40 |
41 | if (response.status >= 200 && response.status < 300) {
42 | return response;
43 | }
44 | return Promise.reject(response);
45 | },
46 | error => {
47 | console.log("57======================",error);
48 |
49 |
50 | //单个、多个队列请求可统一在这里处理 登录失效等逻辑
51 | if (error.response) {
52 | switch (error.response.status) {
53 | case 401:
54 | console.log(error);
55 | router.replace({
56 | path: 'login',
57 | query: {redirect: router.currentRoute.fullPath}
58 | })
59 | break;
60 | case 404:
61 | case 500:
62 | //以提示的方式处理
63 |
64 | /*router.replace({
65 | path: 'notFound',
66 | query: {redirect: router.currentRoute.fullPath}
67 | })*/
68 | break;
69 |
70 | }
71 | };
72 |
73 | // console.log(JSON.stringify(error));//console : Error: Request failed with status code 402
74 | return Promise.reject(error)
75 | });
76 |
77 | const fetch =(options)=>{
78 | /*
79 |
80 | * @ 数据请求
81 | * @ options - url 接口url 结果== baseUrl + url;
82 | * @ options - type 请求类型 post\get等;
83 | * @ options - data 请求数据 object类型;
84 | * @ options - others 其他参数;
85 | @ options - userToken 用户token 服务端 初始化数据方法,请手动传入,客户端会自动带上;
86 | */
87 | let { url, type, data,userToken, ...others } = options;
88 | let opts = {
89 | ...others,
90 | method: (type || 'get').toUpperCase(),
91 | data,
92 | url,
93 | headers: {
94 | 'Accept': 'application/json',
95 | 'Content-Type': 'application/json'
96 |
97 | }
98 | };
99 |
100 | return new Promise((resolve, reject)=>{
101 | axios(opts)
102 | .then(resData =>{
103 | resolve(resData)
104 | }).catch((error) => {
105 | reject((error||{message: '网络异常,请刷新重试', type: 1}));
106 | });
107 | });
108 | }
109 |
110 |
111 |
112 | export const fetchSingle = (options)=>{
113 |
114 | /*
115 | * @ 单个数据请求
116 | * @ options -- 请参考 fetch 方法
117 | */
118 | return fetch(options).then(res=>resHandler(res),(err) =>errorHandler(err, err.status));
119 | };
120 | export const fetchGroup = (queue)=>{
121 | var promises = (queue||[]).map(function(item){
122 | return fetch(item);
123 | });
124 | return axios.all(promises)
125 | .then(res=>{
126 | //多个队列请求,只安第一个返回的结果处理 未登录状态;
127 | let firstItem = res[0];
128 | if (firstItem && firstItem.data&& firstItem.data.code > 20000) {
129 | router.push({
130 | path: '/login',
131 | query: {redirect: router.currentRoute.fullPath}
132 | });
133 | return ;
134 | } ;
135 | let result = (res||[]).map((item)=>{
136 | return item.data;
137 | })
138 | return Promise.resolve(result);
139 | },(err) =>errorHandler(err.data||err, err.status))
140 | };
141 |
142 |
143 |
144 |
145 | function toJson(resp, options) {
146 | if (resp.status >= 400) {
147 | return errorHandler(resp, resp.status)
148 | }
149 | return resp;
150 | }
151 |
152 | function resHandler(resData, options) {
153 |
154 | /*
155 |
156 | * @ 请求成功处理
157 | * @ status -- 当前请求的状态
158 | * @ data -- 业务接口返回的数据
159 | * @ code -- 业务接口状态码
160 |
161 | */
162 | if (resData.status && resData.status != 200) {
163 | return errorHandler(resData.data||resData, resData.status);
164 | }
165 | if (!resData || (resData.data&& resData.data.code > 20000)) {
166 | router.push({
167 | path: '/login',
168 | query: {redirect: router.currentRoute.fullPath}
169 | });
170 | return ;
171 | } else {
172 | return Promise.resolve(resData.data);
173 | };
174 | }
175 |
176 | function errorHandler(error, status) {
177 |
178 | /*
179 | * @ 异常处理
180 | * @ status -- 当前请求的状态
181 | * @ error||error.data -- 业务接口返回的数据
182 |
183 | */
184 | console.log(`网络异常,请稍后重试(${status})`);
185 | return Promise.reject(error.data||error);
186 | }
187 |
188 |
189 | axios.prototype.fetchSingle = fetchSingle;
190 | axios.prototype.fetchGroup = fetchGroup;
191 |
192 | export default axios;
193 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 |
2 | const fs = require('fs')
3 | const path = require('path')
4 | const resolve = file => path.resolve(__dirname, file)
5 | const httpProxy = require('http-proxy');
6 | const LRU = require('lru-cache')
7 | const config = require('./config');
8 | const logger = require('./logger');
9 |
10 | module.exports = function (app) {
11 |
12 | var insuranceServers = config.INSURANCE_SERVER;
13 | var apiServers = config.API;
14 |
15 | var proxy = httpProxy.createProxyServer();
16 |
17 | proxy.on('error', function(e) {
18 | logger.error(e);
19 | });
20 |
21 | /*
22 | *接口代理
23 | */
24 |
25 | app.all('/zaApi/*', function (req, res) {//接口API代理
26 | var url = req.url;
27 | console.log('req:', url)
28 | var regExp = /\/zaApi\/(.*?)\//,
29 | hostkey = req.url.match(regExp)[1],
30 | target = '';
31 | req.url = req.url.replace(regExp, '/');
32 | target = 'http://' + apiServers[hostkey].host;
33 | console.log('zaApi:', target + req.url);
34 | console.log('-------------------------');
35 | proxy.web(req, res, {
36 | target: target,
37 | changeOrigin: true
38 | });
39 | });
40 |
41 |
42 | /**
43 | *html输出
44 | *
45 | */
46 | const { createBundleRenderer } = require('vue-server-renderer')
47 | const isProd = process.env.NODE_ENV === 'production'
48 | const useMicroCache = process.env.MICRO_CACHE !== 'false'
49 | const serverInfo =
50 | `express/${require('express/package.json').version} ` +
51 | `vue-server-renderer/${require('vue-server-renderer/package.json').version}`
52 |
53 | const template = fs.readFileSync(resolve('../src/views/index.template.html'), 'utf-8')
54 |
55 | function createRenderer (bundle, options) {
56 |
57 | return createBundleRenderer(bundle, Object.assign(options, {
58 | template,
59 | // for component caching
60 | cache: LRU({
61 | max: 1000,
62 | maxAge: 1000 * 60 * 15
63 | }),
64 | // this is only needed when vue-server-renderer is npm-linked
65 | basedir: resolve('./assets'),
66 | // recommended for performance
67 | runInNewContext: false
68 | }))
69 | }
70 |
71 | let renderer
72 | let readyPromise
73 | //线上环境
74 | if (isProd) {
75 | // In production: create server renderer using built server bundle.
76 | // The server bundle is generated by vue-ssr-webpack-plugin.
77 | const bundle = require('../assets/vue-ssr-server-bundle.json')
78 | // The client manifests are optional, but it allows the renderer
79 | // to automatically infer preload/prefetch links and directly add