Authored by htoooth

merge

import Vue from 'vue';
import iView from 'iview';
import VueCookie from 'vue-cookie';
import Router from 'vue-router';
import App from './pages/app';
import Routers from './pages';
import routerHook from 'router-hook';
import yohoPlugin from './plugins/yoho-plugin';
import yohoPluginCore from './plugins/yoho-plugin-core';
import yohoPluginPurview from './plugins/yoho-plugin-purview';
import yohoPluginUser from './plugins/yoho-plugin-user';
import './filters';
import './directives';
import 'iview/dist/styles/iview.css';
import 'common.scss';
import config from 'config';
Vue.use(Router);
Vue.use(iView);
Vue.use(VueCookie);
Vue.use(yohoPlugin, {
config,
apiDomains: config.apiDomains
});
let router = new Router({routes: Routers});
routerHook.auth(router);
Vue.use(yohoPluginCore, {router});
Vue.use(yohoPluginPurview);
Vue.use(yohoPluginUser);
Vue.use(VueCookie);
let vue = new Vue({
new Vue({
el: '#app',
router,
template: '<App/>',
components: {App}
});
routerHook.emit(router, vue);
... ...
... ... @@ -16,12 +16,7 @@ module.exports = {
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
vue$: 'vue/dist/vue.esm.js',
'echarts-lib': 'echarts/lib/echarts',
'echarts-tooltip': 'echarts/lib/component/tooltip',
'echarts-legend': 'echarts/lib/component/legend',
'echarts-line': 'echarts/lib/chart/line',
'echarts-pie': 'echarts/lib/chart/pie'
vue$: 'vue/dist/vue.esm.js'
},
modules: [
util.resolve('components'),
... ...
... ... @@ -7,7 +7,6 @@
<script>
import _ from 'lodash';
export default {
name: 'breadcrumb',
data() {
... ... @@ -18,11 +17,15 @@ export default {
};
},
created() {
this.$root.$on('route-change', (to) => {
this.showBreadcrumb = false;
this.$nextTick(() => { // Breadcrumb更新子组件的separator,如果不手动重建Breadcrumb周期,子组件separator不会得到更新
this.render(to);
_.remove(this.$router.beforeHooks, hook => hook.name === 'breadcrumb');
let that = this;
this.$router.beforeEach(function breadcrumb(to, from, next) {
that.showBreadcrumb = false;
that.$nextTick(() => { // Breadcrumb更新子组件的separator,如果不手动重建Breadcrumb周期,子组件separator不会得到更新
that.render(to);
});
return next();
});
this.render();
},
... ... @@ -33,7 +36,7 @@ export default {
let purviews = this.$config.purviews;
let routeName = to && to.name || this.$router.history.current.name;
let routes = _.split(routeName, '.');
_.each(routes, route => {
let findRoute = _.get(purviews, route);
... ...
import menus from './menus';
import breadcrumb from './breadcrumb';
import userInfo from './user-info';
export default [menus, breadcrumb];
export default [menus, breadcrumb, userInfo];
... ...
<template>
<Row class="layout-header">
<Col :span="12" class="brand-title">{{userInfo.currentShop.shopName}}</Col>
<Col :span="12" class="shop-info">
<span class="name">{{userInfo.name}}</span>
<a href="javascript:;" @click="logout">[退出]</a>
</Col>
</Row>
</template>
<script>
import Vue from 'vue';
export default {
name: 'user-info',
data() {
return {
userInfo: this.$user
};
},
created() {
},
methods: {
logout() {
Vue.logout();
}
}
};
</script>
<style lang="scss">
</style>
... ...
// api调用列表
let domainApis = {
login: '/login',
brand: '/SellerProductController/getSellerBrandInfo',
category: '/SellerProductController/getSellerSortInfo'
};
export default domainApis;
import axios from 'axios';
import apiDomains from './api-domain';
import purviews from './purview';
axios.defaults.baseURL = 'http://localhost:6008';
axios.defaults.responseType = 'json';
export default {
purviews,
apiDomains
userKey: '_user',
purviews
};
... ...
... ... @@ -5,6 +5,7 @@ export default {
name: 'login',
component: home,
meta: {
authPass: true
authPass: true,
loginPass: true
}
};
... ...
... ... @@ -30,8 +30,7 @@
</template>
<script>
const request = require('axios');
import Vue from 'vue';
export default {
name: 'login',
... ... @@ -39,26 +38,19 @@ export default {
handleSubmit(name) {
this.$refs[name].validate((valid) => {
if (valid) {
this.$Message.success('提交成功!');
this.login(this.formInline.user, this.formInline.password).then((result) => {
let userInfo = result.data;
if (userInfo.code !== 200) {
this.$Message.error('用户名或密码错误');
}
this.$cookie.set('USER_NAME', userInfo.data.name);
this.$cookie.set('SHOP_ID', userInfo.data.shop.shopId);
this.$cookie.set('SHOP_NAME', userInfo.data.shop.shopName);
this.$router.push('/');
});
this.login(this.formInline.user, this.formInline.password);
} else {
this.$Message.error('表单验证失败!');
}
});
},
login(username, password) {
return request.post(this.$api.login, {username, password})
Vue.passport.local(username, password).then((result) => {
this.$cookie.set('SHOP_ID', result.currentShop.id);
this.$router.push('/');
}, (error) => {
this.$Message.error(error.message);
});
}
},
data() {
... ...
... ... @@ -5,13 +5,7 @@
<purview-menu></purview-menu>
</Col>
<Col :span="18" class="layout-menu-right">
<Row class="layout-header">
<Col :span="12" class="brand-title">速写旗舰店</Col>
<Col :span="12" class="shop-info">
<span class="name">江南布衣供应商</span>
<a href="javascript:;">[退出]</a>
</Col>
</Row>
<user-info></user-info>
<div class="layout-breadcrumb">
<breadcrumb></breadcrumb>
</div>
... ...
let apiUrl = {
brand: '/SellerProductController/getSellerBrandInfo',
category: '/SellerProductController/getSellerSortInfo',
color: '/SellerProductController/querySellerProductColors',
size: '/SellerSortSizeController/querySortSize'
brand: '/platform/getSellerBrandInfo',
sort: '/platform/getSellerSortInfo',
color: '/platform/querySellerProductColors',
size: '/platform/querySortSize'
};
const request = require('axios');
... ... @@ -27,7 +27,7 @@ function getSort(shopId, brandId, level , sortId) {
Object.assign(opts, {sortId});
}
return request.get(apiUrl.category, {
return request.get(apiUrl.sort, {
params: opts
}).then((result) => result.data);
}
... ... @@ -36,10 +36,10 @@ function getColor() {
return request.get(apiUrl.color).then((result) => result.data)
}
function getSize(smalSortId) {
function getSize(smallSortId) {
return request.get(apiUrl.size, {
params: {
sortId: smalSortId
sortId: smallSortId
}
}).then(result => result.data)
}
... ...
/**
* 插件
*/
import iView from 'iview';
import Router from 'vue-router';
import store from 'yoho-store';
import components from '../components/common';
import axios from 'axios';
import config from 'config';
const plugin = {
install(Vue, options) {
// 加载核心插件
Vue.use(iView);
Vue.use(Router);
// 附加Vue原型属性
if (config) {
Vue.prototype.$config = config;
}
if (options && options.router) {
Vue.$router = options.router;
}
Vue.$store = store;
Vue.prototype.$store = store;
// 加载核心组件
components.forEach(component => {
Vue.component(component.name, component);
});
// 设置axios默认参数
axios.defaults.baseURL = 'http://localhost:6008';
axios.defaults.responseType = 'json';
}
};
export default plugin;
... ...
import purviews from './purview';
/**
* 权限插件
*/
import _ from 'lodash';
import axios from 'axios';
import purviews from 'purview';
const hooks = {
auth: router => {
router.beforeEach((to, from, next) => {
console.log(`${from.path}=>${to.path}`);
// TODO 获取权限
if (to) {
const plugin = {
install(Vue) {
// 路由权限
Vue.mixin({
beforeRouteEnter(to, from, next) {
// TODO 获取权限
if (to.matched && to.matched.length > 0) {
let authPass = _.get(_.last(to.matched), 'meta.authPass', false);
... ... @@ -24,14 +27,20 @@ const hooks = {
}
}
});
},
emit: (router, vue) => {
router.beforeEach((to, from, next) => {
vue.$root.$emit('route-change', {name: to.name, path: to.path});
return next();
});
// 接口权限
axios.defaults.validateStatus = (status) => {
if (status >= 200 && status < 300) {
return true;
}
if (status === 401) {
Vue.logout();
return false;
}
Vue.$Message.error('接口异常');
return false;
};
}
};
export default hooks;
export default plugin;
... ...
/**
* 权限插件
*/
import axios from 'axios';
import config from 'config';
import _ from 'lodash';
const plugin = {
install(Vue) {
// 登录验证权限
Vue.mixin({
beforeRouteEnter(to, from, next) {
if (to.matched && to.matched.length > 0) {
let loginPass = _.get(_.last(to.matched), 'meta.loginPass', false);
let userInfo = Vue.$store.get(config.userKey);
if (!loginPass && !Vue.isLogin && !userInfo) {
return next('/login');
}
if (to.name === 'auth.login' && userInfo) {
return next('/');
}
if (!Vue.prototype.$user) {
Vue.prototype.$user = userInfo;
}
}
return next();
}
});
Vue.passport = {
local: (username, password) => {
return axios.post('/login', {username, password}).then((res) => {
let code = _.get(res, 'data.code', 0);
return new Promise((resolve, reject) => {
if (code === 200) {
Vue.prototype.$user = res.data.data;
Vue.isLogin = true;
Vue.$store.set(config.userKey, res.data.data);
resolve(res.data.data);
}
reject(res.data);
});
});
}
};
Vue.logout = () => {
Vue.$store.remove(config.userKey);
Vue.$router.push('/login');
axios.post('/logout');
};
}
};
export default plugin;
... ...
/**
* 插件
*/
import components from '../components/common';
const yohoPlugin = {
install(Vue, options) {
if (options.apiDomains) {
Vue.prototype.$api = options.apiDomains;
}
if (options.config) {
Vue.prototype.$config = options.config;
}
components.forEach(component => {
Vue.component(component.name, component);
});
}
};
export default yohoPlugin;
import config from 'config';
import axios from 'axios';
const overviewFlow = (url, params) => {
return axios.get(`${config.apiURL}/${url}`, {
params
}).then(result => {
return result.data.data;
});
};
export {
overviewFlow
};
export default {
};
... ...
... ... @@ -34,7 +34,8 @@
"vue-template-compiler": "^2.2.6",
"webpack-dev-server": "^2.4.2",
"yoho-md5": "^2.0.0",
"yoho-node-lib": "^0.2.18"
"yoho-node-lib": "^0.2.18",
"yoho-store": "^1.3.20"
},
"devDependencies": {
"autoprefixer": "^6.7.2",
... ...
... ... @@ -9,7 +9,6 @@ const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const Express = require('express');
const session = require('express-session');
const cookieSession = require('cookie-session')
const favicon = require('serve-favicon');
const path = require('path');
... ... @@ -29,12 +28,9 @@ global.yoho = {
co: global.Promise.coroutine
};
app.use(cookieSession({
app.use(session({
name: 'yoho-shop',
secret: 'yoho!shop@manage',
cookie: {
maxAge: 24 * 60 * 60 * 1000
}
secret: 'yoho!shop@manage'
}));
app.use(favicon(path.join(__dirname, '/favicon.ico')));
... ...
const blacklist = ['platform.queryShopsByAdminPid'];
module.exports = blacklist;
... ...
const _ = require('lodash');
// api调用列表
let domainApis = {
erp: {
login: '/erp-gateway-web/account/profile/login'
},
platform: {
queryShopsByAdminPid: '/SellerShopController/queryShopsByAdminPid',
getSellerBrandInfo: '/SellerProductController/getSellerBrandInfo',
getSellerSortInfo: '/SellerProductController/getSellerSortInfo',
querySellerProductColors: '/SellerProductController/querySellerProductColors',
querySortSize: '/SellerSortSizeController/querySortSize'
}
};
// 域名列表
const domains = {
erp: 'http://192.168.13.180',
platform: 'http://192.168.102.210:8088/platform'
};
_.each(domainApis, (apis, domainName) => {
_.each(apis, (url, api) => {
apis[api] = _.get(domains, domainName, '') + url;
});
});
module.exports = domainApis;
... ...
const Context = require('./context');
const request = require('request');
const qs = require('querystring');
const _ = require('lodash');
const config = global.yoho.config;
const logger = global.yoho.logger;
const API_ERROR = {
... ... @@ -16,11 +13,7 @@ const API_INTERNAL_ERROR = {
};
class Api extends Context {
constructor() {
super();
}
get(url, data, headers) {
this.logGet(url, data);
return this.parse(() => {
return request.get({
url,
... ... @@ -29,37 +22,31 @@ class Api extends Context {
});
});
}
logGet(url, data) {
logger.info('api call [GET]', url + '?' + qs.stringify(data));
}
post(url, data, headers) {
this.logPost(url, data);
let defaultHeader = {
'Content-Type': 'application/json'
};
return this.parse(() => {
return request.post({
url,
form: data,
headers
body: JSON.stringify(data),
headers: Object.assign(defaultHeader, headers)
});
});
}
logPost(url, data) {
if (_.isString(data)) {
logger.info('api call [POST]', url + '?' + data);
} else {
logger.info('api call [POST]', url + '?' + qs.stringify(data));
}
}
upload() {
}
download() {
}
parse(req) {
return new Promise((resolve, reject) => {
let buffers = [], response;
let buffers = [];
req()
.on('error', error => {
if (error) {
logger.error(error);
return reject(API_ERROR);
}
})
... ... @@ -67,10 +54,9 @@ class Api extends Context {
buffers.push(chunk);
})
.on('response', (res) => {
response = res;
logger.info(`api call ${res.statusCode} [${res.request.method}] ${res.request.href} ${res.request.body}`); // eslint-disable-line
})
.on('end', () => {
console.log(response.length);
if (buffers) {
// TODO 判断文件
try {
... ...
const _ = require('lodash');
// 域名列表
const domains = {
auth: 'http://serve.yohobuy.com',
shop: 'http://192.168.102.210:8088/platform'
};
// api调用列表
let domainApis = {
auth: {
login: {
path: '/service/account/v1/Profile/login'
}
},
shop: {
profile: {
path: '/SellerShopController/queryShopsByAdminPid'
},
brand: {
path: '/SellerProductController/getSellerBrandInfo'
},
sort: {
path: '/SellerProductController/getSellerSortInfo'
},
color: {
path: '/SellerProductController/querySellerProductColors'
},
size: {
path: '/SellerSortSizeController/querySortSize'
}
}
};
_.each(domainApis, (apis, domainName) => {
_.each(apis, (uri, api) => {
apis[api].url = domains[domainName] + uri.path;
});
});
module.exports = domainApis;
... ... @@ -6,7 +6,7 @@
'use strict';
const _ = require('lodash');
const apiDomain = require('./apiDomain');
const apiDomain = require('./api-domain');
const isProd = process.env.NODE_ENV === 'production';
const isTest = process.env.NODE_ENV === 'test';
... ... @@ -15,6 +15,7 @@ const isTest = process.env.NODE_ENV === 'test';
const config = {
app: 'shop-manage',
appVersion: '0.0.1', // 调用api的版本
platform: 2,
port: 6007,
siteUrl: '//shop.yohobuy.com',
assetUrl: '//127.0.0.1:5001',
... ...
... ... @@ -9,52 +9,52 @@ const Context = require('../common/context');
const UserService = require('../service/user-service');
const _ = require('lodash');
const config = global.yoho.config;
class UserController extends Context {
constructor() {
super();
this.userService = this.instance(UserService);
}
login(req, res, next) {
this.instance(UserService).login(req.body.username, req.body.password).then(result => {
if (result.code === 200) {
this.syncSession(req, res, result.data);
return res.json({
code: 200,
data: {
name: result.data.account,
shop: {
shopId: req.session.CURRENT_SHOP.shopsId,
shopName: req.session.CURRENT_SHOP.shopName
this.userService.login(req.body.username, req.body.password).then(user => {
this.userService.getShops(user.pid).then(result => {
if (result.code === 200) {
this.syncSession(req, Object.assign(user, {
shops: result.data
}));
let currentShop = _.first(result.data);
return res.json({
code: 200,
data: {
name: user.account,
email: user.email,
createDate: user.create_date,
currentShop: {
shopName: currentShop.shopName,
id: currentShop.id
}
}
}
});
} else {
return res.json({
code: 400,
message: '登录错误'
});
}
});
} else {
return res.json(result);
}
});
}, err => {
return res.json(err);
}).catch(next);
}
logout(req, res) {
delete res.session.LOGIN_UID;
delete res.session.USER;
res.clearCookie('USER_NAME');
return res.json({
code: 200,
data: '登出成功'
});
}
syncSession(req, res, user) {
syncSession(req, user) {
req.session.USER = user;
req.session.LOGIN_UID = user.pid; // pid 为用户名
req.session.CURRENT_SHOP = _.first(user.allowedShops); // 取第一个为当前进入的店铺
res.cookie('USER_NAME', user.account, {
domain: config.cookieDomain
});
req.session.CURRENT_SHOP = _.first(user.shops); // 取第一个为当前进入的店铺
}
}
... ...
... ... @@ -6,7 +6,7 @@
module.exports = (req, res, next) => {
if (!req.user.uid) {
return res.json({
return res.status(401).json({
code: 401,
message: '抱歉,您暂未登录!',
data: {
... ...
... ... @@ -17,9 +17,7 @@ module.exports = (req, res, next) => {
yoho.clientIp = util.getClientIp(req);
if (req.session && req.session.LOGIN_UID) {
req.user.uid = req.session.LOGIN_UID;
let userData = _.get(req.session, 'USER', {});
_.merge(req.user, userData);
_.merge(req.user, _.get(req.session, 'USER', {}));
}
// 当前选择的店铺
... ...
... ... @@ -4,21 +4,11 @@
* @date: 2017/04/13
*/
const Api = require('../common/api');
const allowdUrls = global.yoho.apiDomain;
const _ = require('lodash');
const Fn = require('lodash/fp');
const blacklist = require('../common/api-blacklist');
const apiDomain = global.yoho.apiDomain;
const logger = global.yoho.logger;
function _matchUrl(path, api) {
return api.path.toLowerCase() === path.toLowerCase();
}
function allowed(path) {
return _.flow(_.toPairs, Fn.find((api) => {
return _matchUrl(path, api[1])
}))(allowdUrls.shop);
}
module.exports = (req, res, next) => {
let api = new Api();
... ... @@ -26,26 +16,30 @@ module.exports = (req, res, next) => {
req,
res
});
let apiMap = req.path.split('/').filter(node => node).join('.');
let allowApi = allowed(req.path);
if (!allowApi) {
logger.error(`proxy [${req.method}] failed`, `${req.path} can't find proxy url`);
return next();
if (_.some(blacklist, n => n === apiMap)) {
return res.status(401).json({
code: 401,
message: '无权限访问的接口'
});
}
logger.info(`proxy [${req.method}] successfully`, `[${req.path}] => [${allowApi[1].url}]`);
let apiUrl = _.get(apiDomain, apiMap);
if (req.method.toLowerCase() === 'get') {
return api.get(allowApi[1].url, req.query).then(data => {
res.json(data);
}).catch(next);
if (!apiUrl) {
logger.error(`proxy [${req.method}] fail`, `${req.path} can't find proxy url`);
return res.status(400).json({
code: 400,
message: '无权限访问的接口'
});
}
let params = Object.assign(req.query, req.body, {
shopsId: _.get(req.user, 'currentShop.shopsId')
});
if (req.method.toLowerCase() === 'post') {
return api.post(allowApi[1].url, req.body).then(data => {
res.json(data);
}).catch(next);
}
return api[req.method.toLowerCase()](apiUrl, params).then(data => {
res.json(data);
}).catch(next);
};
... ...
... ... @@ -4,38 +4,42 @@
'use strict';
const _ = require('lodash');
const md5 = require('yoho-md5');
const Context = require('../common/context');
const Api = require('../common/api');
const apiDomain = global.yoho.apiDomain;
const co = global.yoho.co;
class loginModel extends Context {
login(username, password) {
let self = this;
return co(function * () {
let userInfo = yield self.instance(Api).post(
apiDomain.auth.login.url,
JSON.stringify([username, password, 2])
);
const config = global.yoho.config;
class UserService extends Context {
constructor() {
super();
this.api = this.instance(Api);
}
login(account, password) {
return this.api.post(apiDomain.erp.login, {
account,
password,
platform: config.platform
}).then(userInfo => {
if (userInfo.code !== 200 || !userInfo.data.pid) {
return Promise.reject({code: 500, message: '登录服务器错误'});
return Promise.reject({code: 500, message: '用户名密码错误'});
}
return userInfo.data;
});
}
let shopInfo = yield self.profile(userInfo.data.pid)
if (shopInfo.code !== 200) {
return Promise.reject({code: 500, message: '用户获取店铺错误'});
getShops(pid) {
return this.api.get(apiDomain.platform.queryShopsByAdminPid, {
userId: pid
}).then(result => {
if (result.code === 200) {
_.each(result.data, shop => {
shop.id = md5(shop.shopName);
});
}
let user = Object.assign(userInfo.data, {allowedShops: shopInfo.data});
return {
code: 200,
data: user
};
})();
return result;
});
}
profile(pid) {
... ... @@ -44,4 +48,4 @@ class loginModel extends Context {
}
module.exports = loginModel;
module.exports = UserService;
... ...