honghaitzz11 6 tahun lalu
induk
melakukan
2265ef8c99
13 mengubah file dengan 440 tambahan dan 38 penghapusan
  1. 1 1
      config/data.json
  2. 59 0
      config/env-config.js
  3. 4 3
      package.json
  4. 2 1
      src/App.jsx
  5. 7 3
      src/App.scss
  6. 33 0
      src/api/user.jsx
  7. 56 9
      src/page/login/index.jsx
  8. 6 2
      src/page/login/index.scss
  9. 106 0
      src/util/axios.js
  10. 126 0
      src/util/http.jsx
  11. 0 7
      src/util/mm.jsx
  12. 18 0
      src/util/mutil.jsx
  13. 22 12
      webpack.config.js

+ 1 - 1
data.json → config/data.json

@@ -1,6 +1,6 @@
 {
     "statistic": {
-        "status": 0,
+        "status": 10,
         "data": {
             "userCount": 3777,
             "productCount": 3208,

+ 59 - 0
config/env-config.js

@@ -0,0 +1,59 @@
+/*
+ * @Author: Johnhong9527
+ * @Date:   2019-05-26 06:52:34
+ * @Last Modified by:   Johnhong9527
+ * @Last Modified time: 2019-05-26 09:55:03
+ */
+
+'use strict';
+/*
+
+
+    "admintest.happymmall.com",
+    "adminv2.happymmall.com"
+
+
+ */
+
+const chalk = require('chalk');
+/*
+ * 环境列表,第一个环境为默认环境
+ * envName: 指明现在使用的环境
+ * dirName: 打包的路径,只在build的时候有用
+ * baseUrl: 这个环境下面的api 请求的域名
+ * assetsPublicPath: 静态资源存放的域名,未指定则使用相对路径
+ * */
+const ENV_LIST = [
+  {
+    envName: 'dev',
+    dirName: 'dev',
+    baseUrl: 'http://adminv2.happymmall.com',
+    assetsPublicPath: './'
+  },
+  {
+    envName: 'test',
+    dirName: 'test',
+    baseUrl: 'http://192.168.xx.xx:8000/',
+    assetsPublicPath: './'
+  },
+  {
+    envName: 'pro',
+    dirName: 'pro',
+    baseUrl: 'http://webapi.xxx.com/',
+    assetsPublicPath: './'
+  }
+];
+
+//获取命令行参数 http://nodejs.cn/api/process.html#process_process_argv
+const argv = JSON.parse(process.env.npm_config_argv).original || process.argv;
+const HOST_ENV = argv[2] ? argv[2].replace(/[^a-z]+/gi, '') : '';
+//没有设置环境,则默认为第一个
+const HOST_CONF = HOST_ENV ? ENV_LIST.find(item => item.envName === HOST_ENV) : ENV_LIST[0];
+// 把环境常量挂载到process.env.HOST_ENV方便客户端使用
+process.env.BASE_URL = HOST_CONF.baseUrl;
+// log选中的变量
+console.log(chalk.green('当前环境常量:'));
+console.log(HOST_CONF);
+
+module.exports.HOST_CONF = HOST_CONF;
+module.exports.ENV_LIST = ENV_LIST;

+ 4 - 3
package.json

@@ -4,18 +4,19 @@
   "description": "",
   "main": "index.js",
   "scripts": {
-    "start": "webpack-dev-server --mode development --open",
-    "build": "webpack --mode production"
+    "start": "webpack-dev-server --dev --mode development --open",
+    "build": "webpack --pro --mode production"
   },
   "keywords": [],
   "author": "",
   "license": "ISC",
   "dependencies": {
     "antd": "^3.18.2",
+    "axios": "^0.18.0",
+    "create-react-class": "^15.6.3",
     "moment": "^2.24.0",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
-    "react-router": "^5.0.0",
     "react-router-dom": "^5.0.0"
   },
   "devDependencies": {

+ 2 - 1
src/App.jsx

@@ -1,6 +1,7 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
 import { LocaleProvider } from 'antd';
+import axios from 'axios';
 import zh_CN from 'antd/lib/locale-provider/zh_CN';
 import moment from 'moment';
 // import 'moment/locale/en-us';
@@ -16,7 +17,7 @@ import Login from 'page/login/index.jsx';
 import Product from 'page/product/index.jsx';
 import Order from 'page/order/index.jsx';
 import ProductCategory from 'page/product/category.jsx';
-
+axios.defaults.baseURL = process.env.BASE_URL;
 class App extends React.Component {
 	render() {
 		return (

+ 7 - 3
src/App.scss

@@ -1,7 +1,11 @@
 * {
-	padding: 0;
-	margin: 0;
+  padding: 0;
+  margin: 0;
+}
+body {
+  background-color: #f3f3f3;
 }
 #app {
-	// color: #fff;
+  background-color: #f3f3f3;
+  // color: #fff;
 }

+ 33 - 0
src/api/user.jsx

@@ -0,0 +1,33 @@
+/*
+ * @Author: Johnhong9527
+ * @Date:   2019-05-26 12:01:45
+ * @Last Modified by:   Johnhong9527
+ * @Last Modified time: 2019-05-26 14:17:07
+ */
+import { post, get } from 'util/http.jsx';
+export default class User {
+  login(loginInfo) {
+    return post('/manage/user/login.do', loginInfo);
+  }
+  // 检查登陆接口的数据是不是合法
+  checkLoginInfo(loginInfo) {
+    let username = `${loginInfo.username}`,
+      password = `${loginInfo.password}`;
+    if (typeof username !== 'string' || username.length === 0) {
+      return {
+        status: false,
+        msg: '用户名不能为空'
+      };
+    }
+    if (typeof password !== 'string' || password.length === 0) {
+      return {
+        status: false,
+        msg: '密码不能为空'
+      };
+    }
+    return {
+      status: true,
+      msg: '验证通过'
+    };
+  }
+}

+ 56 - 9
src/page/login/index.jsx

@@ -2,20 +2,25 @@
  * @Author: Johnhong9527
  * @Date:   2019-05-25 20:29:31
  * @Last Modified by:   Johnhong9527
- * @Last Modified time: 2019-05-25 22:26:52
+ * @Last Modified time: 2019-05-26 14:42:02
  */
 
 import React from 'react';
-import { Row, Col, PageHeader, Input, Button } from 'antd';
+import { Row, Col, PageHeader, Input, Button, message } from 'antd';
 import PageTitle from 'component/page-title/index.jsx';
-
+import User from 'api/user.jsx';
+import MUtil from 'util/mutil.jsx';
+// import axios from 'axios';
+const _user = new User();
+const _mutil = new MUtil();
 import './index.scss';
 export default class Login extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       username: 'admin',
-      password: 'admin'
+      password: 'admin',
+      redirect: _mutil.getUrlParams('redirect') || '/'
     };
   }
   componentWillMount() {
@@ -26,6 +31,40 @@ export default class Login extends React.Component {
       [e.target.name]: e.target.value
     });
   }
+
+  sublime() {
+    const loginInfo = {
+        username: this.state.username,
+        password: this.state.password
+      },
+      checkResult = _user.checkLoginInfo(loginInfo);
+    if (!checkResult.status) {
+      _mutil.errorTips(checkResult.msg);
+    } else {
+      const loading = message.loading('正在提交中!', 0);
+      _user.login(loginInfo).then(
+        res => {
+          if (res.msg === '登录成功') {
+            setTimeout(loading, 1300);
+            setTimeout(() => {
+              message.success('登陆成功,', 0.5).then(() => {
+                window.localStorage.setItem('userInfo', JSON.stringify(res));
+                message.loading('正在跳转到登录前的页面', 1.5).then(() => {
+                  this.props.history.push('/');
+                });
+              });
+            }, 1600);
+          }
+        },
+        errMsg => {
+          setTimeout(loading, 10);
+          setTimeout(() => {
+            _mutil.errorTips(errMsg);
+          }, 300);
+        }
+      );
+    }
+  }
   render() {
     return (
       <div className="login-wrapper">
@@ -33,8 +72,7 @@ export default class Login extends React.Component {
           <Col span={8} push={8}>
             <div className="login">
               {/*
- <PageHeader className="ant-page-header" style={{ textAlign: 'center' }} title="欢迎登录 - MMALL管理系统" />
-
+                <PageHeader className="ant-page-header" style={{ textAlign: 'center' }} title="欢迎登录 - MMALL管理系统" />
              */}
               <PageHeader title="欢迎登录 - MMALL管理系统" />
 
@@ -45,6 +83,8 @@ export default class Login extends React.Component {
                       placeholder="User Name"
                       type="text"
                       name="username"
+                      value={this.state.username}
+                      onPressEnter={e => this.sublime(e)}
                       onChange={e => {
                         this.onInputChange(e);
                       }}
@@ -54,14 +94,21 @@ export default class Login extends React.Component {
                 <br />
                 <Row>
                   <Col span={22} push={1}>
-                    <Input type="password" name="password" placeholder="Password" onChange={e => this.onInputChange(e)} />
+                    <Input
+                      type="password"
+                      name="password"
+                      value={this.state.password}
+                      placeholder="Password"
+                      onPressEnter={e => this.sublime(e)}
+                      onChange={e => this.onInputChange(e)}
+                    />
                   </Col>
                 </Row>
                 <br />
                 <Row>
                   <Col span={22} push={1}>
-                    <Button block type="primary">
-                      登陆1
+                    <Button block type="primary" size="large" onClick={e => this.sublime(e)}>
+                      登陆
                     </Button>
                   </Col>
                 </Row>

+ 6 - 2
src/page/login/index.scss

@@ -2,13 +2,17 @@
 * @Author: Johnhong9527
 * @Date:   2019-05-25 20:42:00
 * @Last Modified by:   Johnhong9527
-* @Last Modified time: 2019-05-25 21:52:41
+* @Last Modified time: 2019-05-26 09:30:54
 */
 .login-wrapper {
-  background-color: #ccc;
   height: 100vh;
   // margin: 12px 0;
   // padding-top: 80px;
+  .h-alert{
+    position: fixed;
+    right: 15px;
+    top: 15px;
+  }
   .ant-page-header {
     // text-align: center;
   }

+ 106 - 0
src/util/axios.js

@@ -0,0 +1,106 @@
+/*
+ * @Author: Johnhong9527
+ * @Date:   2019-05-26 07:02:21
+ * @Last Modified by:   Johnhong9527
+ * @Last Modified time: 2019-05-26 07:14:38
+ */
+
+// 引入网络请求库 https://github.com/axios/axios
+
+import axios from 'axios';
+// import store from '../store';
+// import router from '../router';
+
+// 请求列表
+const requestList = [];
+// 取消列表
+const CancelToken = axios.CancelToken;
+let sources = {};
+
+// axios.defaults.timeout = 10000
+axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
+
+axios.defaults.baseURL = process.env.BASE_URL;
+
+axios.interceptors.request.use(
+  config => {
+    const request = JSON.stringify(config.url) + JSON.stringify(config.data);
+
+    config.cancelToken = new CancelToken(cancel => {
+      sources[request] = cancel;
+    });
+
+    if (requestList.includes(request)) {
+      sources[request]('取消重复请求');
+    } else {
+      requestList.push(request);
+      // store.dispatch('changeGlobalState', { loading: true });
+    }
+
+    // const token = store.getters.userInfo.token;
+    if (token) {
+      config.headers.token = 'token';
+    }
+
+    return config;
+  },
+  function(error) {
+    return Promise.reject(error);
+  }
+);
+
+axios.interceptors.response.use(
+  function(response) {
+    const request = JSON.stringify(response.config.url) + JSON.stringify(response.config.data);
+    requestList.splice(requestList.findIndex(item => item === request), 1);
+    if (requestList.length === 0) {
+      // store.dispatch('changeGlobalState', { loading: false });
+    }
+    if (response.data.code === 900401) {
+      window.ELEMENT.Message.error('认证失效,请重新登录!', 1000);
+      // router.push('/login');
+    }
+    return response;
+  },
+  function(error) {
+    if (axios.isCancel(error)) {
+      requestList.length = 0;
+      // store.dispatch('changeGlobalState', { loading: false });
+      throw new axios.Cancel('cancel request');
+    } else {
+      window.ELEMENT.Message.error('网络请求失败', 1000);
+    }
+    return Promise.reject(error);
+  }
+);
+
+const request = function(url, params, config, method) {
+  return new Promise((resolve, reject) => {
+    axios[method](url, params, Object.assign({}, config))
+      .then(
+        response => {
+          resolve(response.data);
+        },
+        err => {
+          if (err.Cancel) {
+            console.log(err);
+          } else {
+            reject(err);
+          }
+        }
+      )
+      .catch(err => {
+        reject(err);
+      });
+  });
+};
+
+const post = (url, params, config = {}) => {
+  return request(url, params, config, 'post');
+};
+
+const get = (url, params, config = {}) => {
+  return request(url, params, config, 'get');
+};
+
+export { sources, post, get };

+ 126 - 0
src/util/http.jsx

@@ -0,0 +1,126 @@
+/*
+ * @Author: Johnhong9527
+ * @Date:   2019-05-25 17:58:36
+ * @Last Modified by:   Johnhong9527
+ * @Last Modified time: 2019-05-26 14:40:38
+ */
+import axios from 'axios';
+// 请求列表
+const requestList = [];
+// 取消列表
+const CancelToken = axios.CancelToken;
+let sources = {};
+
+// axios.defaults.timeout = 10000; //超时取消请求
+// axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
+
+axios.defaults.baseURL = process.env.BASE_URL;
+
+axios.interceptors.request.use(
+  config => {
+    const request = JSON.stringify(config.url) + JSON.stringify(config.data);
+
+    config.cancelToken = new CancelToken(cancel => {
+      sources[request] = cancel;
+    });
+
+    if (requestList.includes(request)) {
+      sources[request]('取消重复请求');
+    } else {
+      requestList.push(request);
+      // store.dispatch('changeGlobalState', { loading: true });
+    }
+
+    // const token = store.getters.userInfo.token;
+    // if (token) {
+    //   config.headers.token = 'token';
+    // }
+    // config.headers.token = 'token';
+    return config;
+  },
+  function(error) {
+    return Promise.reject(error);
+  }
+);
+
+axios.interceptors.response.use(
+  function(response) {
+    // console.log(response);
+    const request = JSON.stringify(response.config.url) + JSON.stringify(response.config.data);
+    requestList.splice(requestList.findIndex(item => item === request), 1);
+    if (requestList.length === 0) {
+      // 请求结束,取消loading
+    }
+    if (response.data.status === 0) {
+      return {
+        data: response.data.data,
+        msg: response.data.msg
+      };
+    } else if (response.data.status === 10) {
+      // window.ELEMENT.Message.error('认证失效,请重新登录!', 1000);
+      doLogin();
+      return;
+    } else {
+      return Promise.reject(response.data.msg || response.data.data);
+    }
+  },
+  function(error) {
+    if (axios.isCancel(error)) {
+      requestList.length = 0;
+      // store.dispatch('changeGlobalState', { loading: false });
+      throw new axios.Cancel('cancel request');
+    } else {
+      // window.ELEMENT.Message.error('网络请求失败', 1000);
+    }
+    return Promise.reject(error);
+  }
+);
+
+const request = function(url, params, config, method) {
+  const fd = new FormData();
+  Object.keys(params).forEach(key => {
+    fd.append(key, params[key]);
+  });
+  return new Promise((resolve, reject) => {
+    axios[method](
+      url,
+      fd,
+      Object.assign(
+        {
+          headers: {
+            'Content-Type': 'multipart/form-data'
+          }
+        },
+        config
+      )
+    )
+      .then(
+        response => {
+          resolve(response);
+        },
+        err => {
+          if (err.Cancel) {
+            console.log(err);
+          } else {
+            reject(err);
+          }
+        }
+      )
+      .catch(err => {
+        reject(err);
+      });
+  });
+};
+
+const post = (url, params, config = {}) => {
+  return request(url, params, config, 'post');
+};
+
+const get = (url, params, config = {}) => {
+  return request(url, params, config, 'get');
+};
+function doLogin() {
+  window.location.href = '/login?redirect=' + encodeURIComponent(window.location.pathname);
+}
+
+export { sources, post, get };

+ 0 - 7
src/util/mm.jsx

@@ -1,7 +0,0 @@
-/*
- * @Author: Johnhong9527
- * @Date:   2019-05-25 17:58:36
- * @Last Modified by:   Johnhong9527
- * @Last Modified time: 2019-05-25 20:22:33
- */
-export default class MUtill {}

+ 18 - 0
src/util/mutil.jsx

@@ -0,0 +1,18 @@
+/*
+ * @Author: Johnhong9527
+ * @Date:   2019-05-26 12:23:53
+ * @Last Modified by:   Johnhong9527
+ * @Last Modified time: 2019-05-26 14:15:36
+ */
+import { message } from 'antd';
+export default class MUtil {
+  getUrlParams(name) {
+    let queryString = window.location.search.split('?')[1] || '',
+      reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'),
+      result = queryString.match(reg);
+    return result ? decodeURIComponent(result[2]) : null;
+  }
+  errorTips(errMsg) {
+    message.error(`${errMsg || '好像哪里不对劲~'}`);
+  }
+}

+ 22 - 12
webpack.config.js

@@ -1,6 +1,7 @@
 const path = require('path');
 const join = path.join;
 const resolve = path.resolve;
+const webpack = require('webpack');
 const tmpdir = require('os').tmpdir;
 const HtmlWebpackPlugin = require('html-webpack-plugin');
 const htmlPlugin = new HtmlWebpackPlugin({
@@ -8,8 +9,9 @@ const htmlPlugin = new HtmlWebpackPlugin({
   filename: './index.html',
   favicon: './favicon.ico'
 });
+const config = require('./config/env-config');
 // mock data
-const appData = require('./data.json');
+const appData = require('./config/data.json');
 const statistic = appData.statistic;
 const user = appData.user;
 const category = appData.category;
@@ -19,7 +21,9 @@ module.exports = {
   resolve: {
     alias: {
       page: path.resolve(__dirname, 'src/page'),
-      component: path.resolve(__dirname, 'src/component')
+      component: path.resolve(__dirname, 'src/component'),
+      util: path.resolve(__dirname, 'src/util'),
+      api: path.resolve(__dirname, 'src/api')
     },
     modules: ['node_modules', join(__dirname, '../node_modules')],
     extensions: ['.web.tsx', '.web.ts', '.web.jsx', '.web.js', '.ts', '.tsx', '.js', '.jsx', '.json']
@@ -107,15 +111,21 @@ module.exports = {
         res.json(statistic);
       });
     },
-    // proxy: {
-    //   '/manage': {
-    //     // target: 'https://bird.ioliu.cn/v1?url=http://adminv2.happymmall.com/manage/',
-    //     target: 'http://adminv2.happymmall.com/manage/',
-    //     // target: 'https://www.baidu.com',
-    //     pathRewrite: { '^/manage': '' },
-    //     secure: false
-    //   }
-    // }
+    proxy: {
+      '/manage': {
+        // target: 'https://bird.ioliu.cn/v1?url=http://adminv2.happymmall.com/manage/',
+        target: 'http://adminv2.happymmall.com',
+        changeOrigin: true
+        // target: 'https://www.baidu.com',
+        // pathRewrite: { '^/manage': '' },
+        // secure: false
+      }
+    }
   },
-  plugins: [htmlPlugin]
+  plugins: [
+    htmlPlugin,
+    new webpack.DefinePlugin({
+      'process.env.BASE_URL': '"' + process.env.BASE_URL + '"'
+    })
+  ]
 };