format codes

pull/8/head
Zhang Peng 2019-10-12 09:51:15 +08:00
parent 46c9f4f40a
commit be8034fd71
82 changed files with 1607 additions and 1534 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.dunwu</groupId>
<artifactId>JavaWebApp</artifactId>

View File

@ -1,21 +1,26 @@
package io.github.dunwu;
import java.io.File;
import org.apache.catalina.Server;
import org.apache.catalina.startup.Catalina;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.scan.Constants;
import java.io.File;
public class Main {
private static final String CONNECTOR_PORT = "8080";
// 以下设置轻易不要改动
private static final String RELATIVE_DEV_BASE_DIR = "src/main/resources/tomcat/";
private static final String RELATIVE_BASE_DIR = "WEB-INF/classes/tomcat/";
private static final String RELATIVE_DEV_DOCBASE_DIR = "src/main/webapp";
private static final String RELATIVE_DOCBASE_DIR = "";
private static final String CONTEXT_PATH = "/";
public static void main(String[] args) throws Exception {
@ -26,7 +31,8 @@ public class Main {
if (!checkFile.exists()) {
System.setProperty("catalina.base", getAbsolutePath() + RELATIVE_DEV_BASE_DIR);
System.setProperty("tomcat.context.docBase", RELATIVE_DEV_DOCBASE_DIR);
} else {
}
else {
System.setProperty("catalina.base", getAbsolutePath() + RELATIVE_BASE_DIR);
System.setProperty("tomcat.context.docBase", RELATIVE_DOCBASE_DIR);
}
@ -58,11 +64,11 @@ public class Main {
private static String getAbsolutePath() {
String path = null;
String folderPath = Main.class.getProtectionDomain().getCodeSource().getLocation()
.getPath();
String folderPath = Main.class.getProtectionDomain().getCodeSource().getLocation().getPath();
if (folderPath.indexOf("WEB-INF") > 0) {
path = folderPath.substring(0, folderPath.indexOf("WEB-INF"));
} else if (folderPath.indexOf("target") > 0) {
}
else if (folderPath.indexOf("target") > 0) {
path = folderPath.substring(0, folderPath.indexOf("target"));
}
return path;
@ -76,14 +82,8 @@ public class Main {
}
static class ExtendedTomcat extends Tomcat {
private static final String RELATIVE_SERVERXML_PATH = "/conf/server.xml";
private class ExtendedCatalina extends Catalina {
@Override
public Digester createStartDigester() {
return super.createStartDigester();
}
}
private static final String RELATIVE_SERVERXML_PATH = "/conf/server.xml";
@Override
public Server getServer() {
@ -106,13 +106,24 @@ public class Main {
// 设置catalina.base和catalna.home
this.initBaseDir();
return server;
} catch (Exception e) {
}
catch (Exception e) {
System.err.println("Error while parsing server.xml" + e.getMessage());
throw new RuntimeException("server未创建,请检查server.xml(路径:" + System.getProperty("catalina.base")
+ RELATIVE_SERVERXML_PATH + ")配置是否正确");
}
}
}
private class ExtendedCatalina extends Catalina {
@Override
public Digester createStartDigester() {
return super.createStartDigester();
}
}
}
}

View File

@ -1,29 +1,25 @@
package io.github.dunwu.filter;
import java.io.IOException;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;
/**
*
*/
public class CorsFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(CorsFilter.class);
private static final Logger logger = LoggerFactory.getLogger(CorsFilter.class);
private final String ORIGIN_KEY = "Origin";
private String regex;
private String headerKey;
private String protocol = "http";
private final String ORIGIN_KEY = "Origin";
public void init(FilterConfig filterConfig) {
// 取配置参数
@ -34,7 +30,8 @@ public class CorsFilter implements Filter {
if (StringUtils.equalsIgnoreCase("http", protocolVal)
|| StringUtils.equalsIgnoreCase("https", protocolVal)) {
protocol = protocolVal.toLowerCase();
} else {
}
else {
logger.error("CorsFilter 配置参数 protocol 非法,仍使用默认值 http");
}
}
@ -87,11 +84,11 @@ public class CorsFilter implements Filter {
httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
httpResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, DELETE");
httpResponse.addHeader("Access-Control-Allow-Headers",
"DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since," +
" Cache-Control, Content-Type, Content-Range, Range, X-CSRF-TOKEN");
"DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since,"
+ " Cache-Control, Content-Type, Content-Range, Range, X-CSRF-TOKEN");
httpResponse.addHeader("Access-Control-Expose-Headers",
"DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since," +
" Cache-Control, Content-Type, Content-Range, Range");
"DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since,"
+ " Cache-Control, Content-Type, Content-Range, Range");
if (httpRequest.getMethod().equals("OPTIONS")) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
return;
@ -99,5 +96,7 @@ public class CorsFilter implements Filter {
chain.doFilter(httpRequest, httpResponse);
}
public void destroy() {}
public void destroy() {
}
}

View File

@ -5,8 +5,10 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class IOObjectMapper extends ObjectMapper {
public IOObjectMapper() {
this.setSerializationInclusion(Include.NON_EMPTY);
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}

View File

@ -4,12 +4,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.dunwu.web.dto.BaseResponseDTO;
import io.github.dunwu.web.dto.MenuDTO;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
@ -17,65 +11,22 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* API
*
* @author zhangpeng0913
* @date 2017/8/23.
*/
@Controller
public class ApiController {
@ResponseBody
@RequestMapping(value = "/menu", method = RequestMethod.GET)
public BaseResponseDTO getAll(HttpServletRequest request) throws JsonProcessingException {
String data = request.getParameter("data");
BaseResponseDTO baseResponseDTO = new BaseResponseDTO();
baseResponseDTO.setData(getAll());
ObjectMapper om = new ObjectMapper();
System.out.println("ResponseDTO: " + om.writeValueAsString(baseResponseDTO));
return baseResponseDTO;
}
@ResponseBody
@RequestMapping(value = "/login")
public BaseResponseDTO login(@RequestBody Map<String, String> map) throws IOException {
String username = map.get("username");
String password = map.get("password");
BaseResponseDTO<Map<String, String>> baseResponseDTO = new BaseResponseDTO();
if (StringUtils.equals(username, "admin") && StringUtils.equals(password, "123456")) {
Map<String, String> result = new HashMap<String, String>();
result.put("name", "admin");
result.put("role", "ADMIN");
result.put("uid", "1");
baseResponseDTO.setData(result);
System.out.println(baseResponseDTO.toString());
return baseResponseDTO;
} else {
baseResponseDTO.setCode(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.value());
baseResponseDTO.getMessages().add(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.desc());
return baseResponseDTO;
}
}
@ResponseBody
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public BaseResponseDTO logout(HttpServletRequest request) {
BaseResponseDTO baseResponseDTO = new BaseResponseDTO();
return baseResponseDTO;
}
@ResponseBody
@RequestMapping(value = "/my", method = RequestMethod.GET)
public BaseResponseDTO my(HttpServletRequest request) {
Map<String, String> map = new HashMap<String, String>();
map.put("name", "admin");
map.put("role", "ADMIN");
map.put("uid", "1");
BaseResponseDTO baseResponseDTO = new BaseResponseDTO();
baseResponseDTO.setData(map);
return baseResponseDTO;
}
private static Set<MenuDTO> getAll() {
MenuDTO item0 = new MenuDTO("0", "首页", "home", "Item", "/pages/home");
@ -104,4 +55,57 @@ public class ApiController {
return menus;
}
@ResponseBody
@RequestMapping(value = "/menu", method = RequestMethod.GET)
public BaseResponseDTO getAll(HttpServletRequest request) throws JsonProcessingException {
String data = request.getParameter("data");
BaseResponseDTO baseResponseDTO = new BaseResponseDTO();
baseResponseDTO.setData(getAll());
ObjectMapper om = new ObjectMapper();
System.out.println("ResponseDTO: " + om.writeValueAsString(baseResponseDTO));
return baseResponseDTO;
}
@ResponseBody
@RequestMapping(value = "/login")
public BaseResponseDTO login(@RequestBody Map<String, String> map) throws IOException {
String username = map.get("username");
String password = map.get("password");
BaseResponseDTO<Map<String, String>> baseResponseDTO = new BaseResponseDTO();
if (StringUtils.equals(username, "admin") && StringUtils.equals(password, "123456")) {
Map<String, String> result = new HashMap<String, String>();
result.put("name", "admin");
result.put("role", "ADMIN");
result.put("uid", "1");
baseResponseDTO.setData(result);
System.out.println(baseResponseDTO.toString());
return baseResponseDTO;
}
else {
baseResponseDTO.setCode(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.value());
baseResponseDTO.getMessages().add(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.desc());
return baseResponseDTO;
}
}
@ResponseBody
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public BaseResponseDTO logout(HttpServletRequest request) {
BaseResponseDTO baseResponseDTO = new BaseResponseDTO();
return baseResponseDTO;
}
@ResponseBody
@RequestMapping(value = "/my", method = RequestMethod.GET)
public BaseResponseDTO my(HttpServletRequest request) {
Map<String, String> map = new HashMap<String, String>();
map.put("name", "admin");
map.put("role", "ADMIN");
map.put("uid", "1");
BaseResponseDTO baseResponseDTO = new BaseResponseDTO();
baseResponseDTO.setData(map);
return baseResponseDTO;
}
}

View File

@ -8,15 +8,19 @@ import org.springframework.web.servlet.ModelAndView;
/**
* spring mvc
*
* @author Zhang Peng
* @since 2016.07.29
*/
@Controller
@RequestMapping(value = "/hello")
public class HelloController {
/**
* <p>Spring hello.jsp
* <p>访http://localhost:8080/hello?name=张三
* <p>
* Spring hello.jsp
* <p>
* 访http://localhost:8080/hello?name=张三
*/
@RequestMapping(value = "/name", method = RequestMethod.GET)
public ModelAndView hello(@RequestParam("name") String name) {
@ -25,4 +29,5 @@ public class HelloController {
mav.setViewName("hello");
return mav;
}
}

View File

@ -14,9 +14,12 @@ import org.springframework.web.servlet.ModelAndView;
*/
@Controller
public class IndexController {
/**
* <p> ModelAndView index index.jsp
* <p>访http://localhost:8080/
* <p>
* ModelAndView index index.jsp
* <p>
* 访http://localhost:8080/
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index() {
@ -24,4 +27,5 @@ public class IndexController {
mav.setViewName("index");
return mav;
}
}

View File

@ -6,13 +6,12 @@ import java.util.List;
public class BaseResponseDTO<T> {
private Integer code = DEFAULT_RESPONSE_RESULT.SUCCESS.value();
private final List<String> messages = new ArrayList<>();
private Integer code = DEFAULT_RESPONSE_RESULT.SUCCESS.value();
private T data;
public BaseResponseDTO() {}
public BaseResponseDTO() {
}
public BaseResponseDTO(T dto) {
this.data = dto;
@ -55,16 +54,14 @@ public class BaseResponseDTO<T> {
}
public enum DEFAULT_RESPONSE_RESULT {
SUCCESS(0, "[]"), // 成功
AUTHEN_FAIL(-1, "认证失败"), // 认证失败
AUTHOR_FAIL(-2, "权限不足"), // 授权不足
PARAM_CHECK_FAIL(-3, ""), // 参数校验失败,错误信息交由业务逻辑处理
RESOURCE_NOT_EXIST(-4, "请求资源不存在"), // 请求资源不存在
SYSTEM_ERROR(-5, "系统错误"),
DATA_MALFORMAT(-6, "请求参数数据格式不正确"),
REQMETHOD_ERROR(-7, "请求方法不正确"),
TYPE_MISMATCH(-8, "请求参数类型不匹配"),
MISS_REQUEST_PARAM(-9, "请求参数缺失");
SYSTEM_ERROR(-5, "系统错误"), DATA_MALFORMAT(-6, "请求参数数据格式不正确"), REQMETHOD_ERROR(-7, "请求方法不正确"), TYPE_MISMATCH(-8,
"请求参数类型不匹配"), MISS_REQUEST_PARAM(-9, "请求参数缺失");
private final Integer value;
@ -82,6 +79,7 @@ public class BaseResponseDTO<T> {
public String desc() {
return desc;
}
}
}

View File

@ -1,27 +1,24 @@
package io.github.dunwu.web.dto;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
public class MenuDTO implements Cloneable, Comparable<MenuDTO> {
private final Set<MenuDTO> children = new TreeSet<MenuDTO>();
private String key;
private String title;
private String icon;
private String type;
private String url;
private final Set<MenuDTO> children = new TreeSet<MenuDTO>();
public MenuDTO() {}
public MenuDTO() {
}
public MenuDTO(String key, String title, String icon, String type, String url) {
this.key = key;
@ -119,4 +116,5 @@ public class MenuDTO implements Cloneable, Comparable<MenuDTO> {
return new CompareToBuilder().append(key, otherMenuDTO.getKey()).append(url, otherMenuDTO.getUrl())
.toComparison();
}
}

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context

View File

@ -15,8 +15,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>spring-embed-tomcat-demo-helloworld</display-name>

View File

@ -1,8 +1,7 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
String path = request.getContextPath();
String basePath =
request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

View File

@ -2,17 +2,17 @@
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<link href="%PUBLIC_URL%/favicon.ico" rel="shortcut icon"/>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
name="viewport"
/>
<meta name="theme-color" content="#000000" />
<meta content="#000000" name="theme-color"/>
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link href="%PUBLIC_URL%/manifest.json" rel="manifest"/>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.

View File

@ -8,7 +8,7 @@
}
.App-header {
background-color: #282c34;
background-color: #282C34;
min-height: 100vh;
display: flex;
flex-direction: column;
@ -19,7 +19,7 @@
}
.App-link {
color: #61dafb;
color: #61DAFB;
}
@keyframes App-logo-spin {

View File

@ -1,28 +1,35 @@
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import React, { Component } from 'react'
import logo from './logo.svg'
import './App.css'
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
< div
className = 'App' >
< header
className = 'App-header' >
< img
src = { logo }
className = 'App-logo'
alt = 'logo' / >
< p >
Edit < code > src / App.js < /code> and save to reload.
< /p>
< a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
className = 'App-link'
href = 'https://reactjs.org'
target = '_blank'
rel = 'noopener noreferrer'
>
Learn React
Learn
React
< /a>
< /header>
< /div>
);
)
}
}
export default App;
export default App

View File

@ -1,9 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ReactDOM from 'react-dom'
import App from './App'
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
const div = document.createElement('div')
ReactDOM.render( < App / >, div
)
ReactDOM.unmountComponentAtNode(div)
})

View File

@ -1,12 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
ReactDOM.render( < App / >, document.getElementById('root')
)
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
serviceWorker.unregister()

View File

@ -1,6 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<path
d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -18,25 +18,25 @@ const isLocalhost = Boolean(
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
)
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
return
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
checkValidServiceWorker(swUrl, config)
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
@ -44,13 +44,13 @@ export function register(config) {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit http://bit.ly/CRA-PWA'
);
});
)
})
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
registerValidSW(swUrl, config)
}
});
})
}
}
@ -59,9 +59,9 @@ function registerValidSW(swUrl, config) {
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
const installingWorker = registration.installing
if (installingWorker == null) {
return;
return
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
@ -72,30 +72,30 @@ function registerValidSW(swUrl, config) {
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
);
)
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
config.onUpdate(registration)
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
console.log('Content is cached for offline use.')
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
config.onSuccess(registration)
}
}
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
console.error('Error during service worker registration:', error)
})
}
function checkValidServiceWorker(swUrl, config) {
@ -103,7 +103,7 @@ function checkValidServiceWorker(swUrl, config) {
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
const contentType = response.headers.get('content-type')
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
@ -111,25 +111,25 @@ function checkValidServiceWorker(swUrl, config) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
window.location.reload()
})
})
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
registerValidSW(swUrl, config)
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
)
})
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
registration.unregister()
})
}
}

View File

@ -20,6 +20,6 @@ module.exports = {
/**
* 服务器的host
*/
baseURL: '/api',
baseURL: '/api'
}
}
};

View File

@ -1,9 +1,9 @@
/**
* Created by Zhang Peng on 2017/6/14.
*/
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
@ -20,16 +20,16 @@ module.exports = {
output: {
// 所有输出文件的目标路径
// 必须是绝对路径(使用 Node.js 的 path 模块)
path: path.resolve(__dirname, "../dist"),
path: path.resolve(__dirname, '../dist'),
// 「入口分块(entry chunk)」的文件名模板(出口分块?)
// filename: "bundle.min.js",
// filename: "[name].js", // 用于多个入口点(entry point)(出口点?)
// filename: "[chunkhash].js", // 用于长效缓存
filename: "[name].[hash:8].js",
filename: '[name].[hash:8].js',
// 「source map 位置」的文件名模板
sourceMapFilename: "[name].map",
sourceMapFilename: '[name].map'
},
// 关于模块配置
@ -47,13 +47,13 @@ module.exports = {
{
// 语义解释器,将 js/jsx 文件中的 es2015/react 语法自动转为浏览器可识别的 Javascript 语法
test: /\.jsx?$/,
include: path.resolve(__dirname, "../src"),
include: path.resolve(__dirname, '../src'),
exclude: /node_modules/,
// 应该应用的 loader它相对上下文解析
// 为了更清晰,`-loader` 后缀在 webpack 2 中不再是可选的
// 查看 webpack 1 升级指南。
loader: "babel-loader",
loader: 'babel-loader'
},
{
@ -87,7 +87,7 @@ module.exports = {
extensions: ['.js', '.jsx', '.json'],
alias: {
"@": path.resolve(__dirname, "../src")
'@': path.resolve(__dirname, '../src')
}
},
@ -99,15 +99,15 @@ module.exports = {
* 用于简化 HTML 文件index.html的创建提供访问 bundle 的服务
*/
new HtmlWebpackPlugin({
title: "reactapp",
template: "public/index.html",
favicon: "public/favicon.ico",
title: 'reactapp',
template: 'public/index.html',
favicon: 'public/favicon.ico'
}),
// 将多个入口起点之间共享的公共模块,生成为一些 chunk并且分离到单独的 bundle 中
new webpack.optimize.CommonsChunkPlugin({
name: "vendor" // 指定公共 bundle 的名字
}),
],
};
name: 'vendor' // 指定公共 bundle 的名字
})
]
}

View File

@ -1,11 +1,11 @@
/**
* Created by Zhang Peng on 2017/6/14.
*/
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const OpenBrowserPlugin = require('open-browser-webpack-plugin');
const baseWebpackConfig = require('./webpack.config.base');
const path = require('path')
const webpack = require('webpack')
const webpackMerge = require('webpack-merge')
const OpenBrowserPlugin = require('open-browser-webpack-plugin')
const baseWebpackConfig = require('./webpack.config.base')
module.exports = webpackMerge(baseWebpackConfig, {
// 这里应用程序开始执行
@ -14,7 +14,7 @@ module.exports = webpackMerge(baseWebpackConfig, {
entry: {
main: [
// App 入口
path.resolve(__dirname, "../src/index"),
path.resolve(__dirname, '../src/index'),
// 开启 React 代码的模块热替换(HMR)
'react-hot-loader/patch',
@ -25,13 +25,13 @@ module.exports = webpackMerge(baseWebpackConfig, {
// 为热替换(HMR)打包好代码
// only- 意味着只有成功更新运行代码才会执行热替换(HMR)
'webpack/hot/only-dev-server',
],
'webpack/hot/only-dev-server'
]
},
output: {
// 对于热替换(HMR)是必须的,让 webpack 知道在哪里载入热更新的模块(chunk)
publicPath: "/",
publicPath: '/'
},
// 关于模块配置
@ -48,7 +48,7 @@ module.exports = webpackMerge(baseWebpackConfig, {
limit: 10000,
name: 'static/images/[name].[hash:8].[ext]'
}
},
}
]
},
@ -68,8 +68,8 @@ module.exports = webpackMerge(baseWebpackConfig, {
// 自动打开浏览器
new OpenBrowserPlugin({
url: "http://localhost:9000"
}),
url: 'http://localhost:9000'
})
],
// 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试
@ -78,16 +78,16 @@ module.exports = webpackMerge(baseWebpackConfig, {
// devtool: "eval-source-map", // 将 SourceMap 嵌入到每个模块中
// devtool: "hidden-source-map", // SourceMap 不在源文件中引用
// devtool: "cheap-source-map", // 没有模块映射(module mappings)的 SourceMap 低级变体(cheap-variant)
devtool: "eval-source-map", // 有模块映射(module mappings)的 SourceMap 低级变体
devtool: 'eval-source-map', // 有模块映射(module mappings)的 SourceMap 低级变体
// devtool: "eval", // 没有模块映射,而是命名模块。以牺牲细节达到最快。
devServer: {
contentBase: [path.join(__dirname, "../dist")],
contentBase: [path.join(__dirname, '../dist')],
compress: true,
port: 9000, // 启动端口号
hot: true, // 启用 webpack 的模块热替换特性
inline: true,
publicPath: "/", // 和上文 output 的“publicPath”值保持一致
publicPath: '/', // 和上文 output 的“publicPath”值保持一致
historyApiFallback: true
}
});
})

View File

@ -1,11 +1,11 @@
/**
* Created by Zhang Peng on 2017/6/14.
*/
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const baseWebpackConfig = require('./webpack.config.base');
const path = require('path')
const webpack = require('webpack')
const webpackMerge = require('webpack-merge')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const baseWebpackConfig = require('./webpack.config.base')
module.exports = webpackMerge(baseWebpackConfig, {
// 这里应用程序开始执行
@ -14,8 +14,8 @@ module.exports = webpackMerge(baseWebpackConfig, {
entry: {
main: [
// App 入口
path.resolve(__dirname, "../src/index"),
],
path.resolve(__dirname, '../src/index')
]
},
// 关于模块配置
@ -36,18 +36,18 @@ module.exports = webpackMerge(baseWebpackConfig, {
},
{
loader: "image-webpack-loader",
loader: 'image-webpack-loader',
query: {
progressive: true,
pngquant: {
quality: "65-90",
quality: '65-90',
speed: 4
}
}
}
]
},
}
]
},
@ -68,7 +68,7 @@ module.exports = webpackMerge(baseWebpackConfig, {
// 压缩 js 插件
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false, // remove all comments
comments: false // remove all comments
},
compress: {
warnings: false
@ -76,6 +76,6 @@ module.exports = webpackMerge(baseWebpackConfig, {
}),
// 将样式文件独立打包
new ExtractTextPlugin("styles.css"),
],
});
new ExtractTextPlugin('styles.css')
]
})

View File

@ -3,8 +3,8 @@
<head>
<title><%= htmlWebpackPlugin.options.title %></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
</head>
<body>
<div id="root"></div>

View File

@ -1,4 +1,5 @@
#!/bin/bash
ln -s /app/ck-puck-front/node_modules/ node_modules
nvm use 8.1.0
npm set registry http://192.168.51.44

View File

@ -1,10 +1,9 @@
import React from 'react';
import { Modal } from 'antd';
import _ from 'lodash';
import { Modal } from 'antd'
import _ from 'lodash'
import { COMMON_REQUEST_ERROR } from '../../redux/constants/commonActionTypes';
import { COMMON_REQUEST_ERROR } from '../../redux/constants/commonActionTypes'
export const REQ_BASE_URL = '/api';
export const REQ_BASE_URL = '/api'
export const METHODS = {
GET: 'GET',
@ -13,29 +12,29 @@ export const METHODS = {
PUT: 'PUT',
DEL: 'DEL',
OPTIONS: 'OPTIONS',
PATCH: 'PATCH',
};
PATCH: 'PATCH'
}
export const REQ_TYPE = {
HTML: 'html',
JSON: 'json',
JSONP: 'jsonp',
};
JSONP: 'jsonp'
}
export const CACHE_TYPE = {
DEFAULT: 'default',
NO_STORE: 'no-store',
RELOAD: 'reload',
NO_CACHE: 'no-cache',
FORCE_CACHE: 'force-cache',
};
FORCE_CACHE: 'force-cache'
}
export const ERROR_HANDLER_TYPE = {
NO: 'NO', // ['NO' | undefined | false ] 不处理
SYSTEM: 'SYSTEM', // ['SYSTEM'] 只处理系统预料外的返回not json
SYSTEM_AND_AUTH: 'SYSTEM_AND_AUTH', // [true, 'SYSTEM_AND_AUTH'] 处理上一步,与 认证失败 比较常用所以单独列出用true
ALL: 'ALL', // [no errorHandler | 'ALL'] 所有
};
ALL: 'ALL' // [no errorHandler | 'ALL'] 所有
}
export const defaultOptions = {
url: null,
@ -49,32 +48,32 @@ export const defaultOptions = {
},
onError: () => {
},
cache: CACHE_TYPE.NO_CACHE,
};
cache: CACHE_TYPE.NO_CACHE
}
// 在 defaultOptions 基础上多出来的, request plan textresponse json
export const defaultJsonOptions = _.merge({}, defaultOptions, {
headers: {
Accept: 'application/json, text/plain, */*',
'Cache-Control': 'no-cache',
'Cache-Control': 'no-cache'
},
type: REQ_TYPE.JSON,
});
type: REQ_TYPE.JSON
})
// 在 defaultJsonOptions 基础上多出来的, request response 皆是 json
export const defaultBiJsonOptions = _.merge({}, defaultJsonOptions, {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'Content-Type': 'application/json;charset=UTF-8'
},
reqType: REQ_TYPE.JSON,
});
reqType: REQ_TYPE.JSON
})
// 获取真正请求的 URL
export function getRealUrl(url) {
if (!!url && !url.startsWith('http')) {
return REQ_BASE_URL + url;
return REQ_BASE_URL + url
}
return url;
return url
}
/**
@ -85,20 +84,25 @@ function _showAuthError() {
Modal.error({
title: '认证失败',
// eslint-disable-next-line react/jsx-filename-extension
content: (<p>您现在处于非认证状态<br />
如果想保留本页状态请在 <a href="/login" target="blank">新页面登陆</a> 。<br />
content: ( < p > 您现在处于非认证状态<
br / >
如果想保留本页状态请在 < a
href = '/login'
target = 'blank' > 新页面登陆 < /a> 。<br / >
{ /* 否则在 <Link to="/login" >当前页登陆</Link> 。 */ }
< /p>),
});
})
}
/**
* 防抖展示认证错误一段时间内仅一次
* @type {Function}
*/
const showAuthError = _.debounce(_showAuthError, 500, {
leading: true,
trailing: false,
});
trailing: false
})
/**
* 展示服务端错误信息
@ -107,8 +111,8 @@ const showAuthError = _.debounce(_showAuthError, 500, {
function _showServerError(e) {
Modal.error({
title: '服务端错误!',
content: `服务端错误。服务端可能未正确部署或由于其他原因响应失败!请保留现场并联系开发人员。错误信息: ${e}`,
});
content: `服务端错误。服务端可能未正确部署或由于其他原因响应失败!请保留现场并联系开发人员。错误信息: ${e}`
})
}
/**
@ -117,8 +121,8 @@ function _showServerError(e) {
*/
const showServerError = _.debounce(_showServerError, 500, {
leading: true,
trailing: false,
});
trailing: false
})
/**
* 包装错误处理所有服务端应用非业务 ret 预计错误与认证错误统一处理
@ -132,35 +136,35 @@ const showServerError = _.debounce(_showServerError, 500, {
*/
export function wrapErrorHandler(errorHandler, dispatch) {
return (e) => {
let handlerLevel = 1000; // 默认都处理
let handlerLevel = 1000 // 默认都处理
// 先看是否传入 errorHandler如果传入则执行用户 errorHandler并根据处理结果设置新的 handlerLevel
if (_.isFunction(errorHandler)) {
handlerLevel = _getErrorHandlerLevel(errorHandler(e));
handlerLevel = _getErrorHandlerLevel(errorHandler(e))
}
if (handlerLevel > 0 && e instanceof XMLHttpRequest) {
// 服务端应用(非业务)非 ret 预计错误处理,如 404400500非返回 json 错误
showServerError(e.responseText);
showServerError(e.responseText)
} else if (handlerLevel > 10 && e.ret === -1) {
// 认证失败,该登陆未登录
showAuthError();
showAuthError()
} else if (handlerLevel > 100 && dispatch) {
dispatch({ type: COMMON_REQUEST_ERROR, payload: e });
dispatch({ type: COMMON_REQUEST_ERROR, payload: e })
} else if (handlerLevel > 100) {
const msg = e.ret ? `[code]${e.ret}, [msg]${e.msg}` : JSON.stringify(e);
const msg = e.ret ? `[code]${e.ret}, [msg]${e.msg}` : JSON.stringify(e)
// eslint-disable-next-line no-console
console.error(`请求出错: ${msg}`);
console.error(`请求出错: ${msg}`)
}
}
};
}
function _getErrorHandlerLevel(type) {
if (type === ERROR_HANDLER_TYPE.SYSTEM) {
return 10;
return 10
} else if (type === ERROR_HANDLER_TYPE.SYSTEM_AND_AUTH || type === true) {
return 100;
return 100
} else if (type === ERROR_HANDLER_TYPE.ALL) {
return 1000;
return 1000
}
return 0;
return 0
}

View File

@ -1,37 +1,37 @@
const createApi = fetchFunc => options => (...args) => {
let finalOpts;
const argsName = ['options', 'successCallBack', 'errorCallBack', 'dispatch'];
let finalOpts
const argsName = ['options', 'successCallBack', 'errorCallBack', 'dispatch']
// options 可以是 url或完整的 options 对象
if (typeof options === 'string') {
finalOpts = { url: options };
finalOpts = { url: options }
} else {
finalOpts = { ...options };
finalOpts = { ...options }
}
const temArgs = {};
const temArgs = {}
if (args) {
// args 第一个参数options 可以忽略
let i = 0;
let i = 0
if (args[0] !== null && typeof args[0] === 'object') {
i = 1;
finalOpts = Object.assign(finalOpts, args[0]);
i = 1
finalOpts = Object.assign(finalOpts, args[0])
}
// eslint-disable-next-line no-plusplus
for (let j = i; j < args.length; j++) {
// eslint-disable-next-line no-mixed-operators
temArgs[argsName[j - i + 1]] = args[j];
temArgs[argsName[j - i + 1]] = args[j]
}
}
if (temArgs.successCallBack) {
finalOpts.onSuccess = temArgs.successCallBack;
finalOpts.onSuccess = temArgs.successCallBack
}
if (temArgs.errorCallBack) {
finalOpts.onError = temArgs.errorCallBack;
finalOpts.onError = temArgs.errorCallBack
}
fetchFunc(finalOpts, temArgs.dispatch)
}
fetchFunc(finalOpts, temArgs.dispatch);
};
export default createApi;
export default createApi

View File

@ -1,10 +1,10 @@
/**
* 错误处理帮助类
*/
import { Message } from 'antd';
import _ from 'lodash';
import { Message } from 'antd'
import _ from 'lodash'
import { ERROR_HANDLER_TYPE } from './index';
import { ERROR_HANDLER_TYPE } from './index'
/**
* 处理业务类型的错误(-3)通过 message 的方式展现
@ -13,14 +13,14 @@ import { ERROR_HANDLER_TYPE } from './index';
* @return {boolean}
*/
export function messageBizError(e, callBack) {
let continueHandler = true;
let continueHandler = true
if (e && e.ret === -3) {
// 业务错误
Message.error(e.msg, 4.5);
continueHandler = ERROR_HANDLER_TYPE.NO;
Message.error(e.msg, 4.5)
continueHandler = ERROR_HANDLER_TYPE.NO
}
if (_.isFunction(callBack)) {
callBack({ error: e });
callBack({ error: e })
}
return continueHandler;
return continueHandler
}

View File

@ -1,27 +1,28 @@
import 'isomorphic-fetch';
import { REQ_TYPE, defaultOptions, defaultJsonOptions, getRealUrl, wrapErrorHandler } from './ajaxCommon';
import 'isomorphic-fetch'
import { defaultJsonOptions, defaultOptions, getRealUrl, REQ_TYPE, wrapErrorHandler } from './ajaxCommon'
function handleStatus(res) {
if (res.ok) {
return res;
return res
}
throw new Error({ result: res.status });
throw new Error({ result: res.status })
}
// json 有固定的格式,所以固定处理方法
function handleJson(data) {
// noinspection JSUnresolvedVariable
if (data.ret === 0) {
return data.data;
return data.data
}
throw new Error(data);
throw new Error(data)
}
export function doFetch(options = {}, dispatch) {
const opts = {
...defaultOptions,
...options,
onError: wrapErrorHandler(options.onError, dispatch),
};
onError: wrapErrorHandler(options.onError, dispatch)
}
// 根据配置创建 Request 对象
const req = new Request(getRealUrl(opts.url), {
@ -30,23 +31,23 @@ export function doFetch(options = {}, dispatch) {
body: opts.data,
cache: opts.cache,
redirect: 'follow',
mode: 'cors',
});
mode: 'cors'
})
if (!__DEV__) {
req.credentials = 'include';
req.credentials = 'include'
}
// 请求
// FIXME 应该根据 response 类型自动判断是否 Json 请求
let tempRes = fetch(req).then(handleStatus);
let tempRes = fetch(req).then(handleStatus)
if (options.type === REQ_TYPE.JSON) {
tempRes = tempRes.then(res => res.json()).then(handleJson);
tempRes = tempRes.then(res => res.json()).then(handleJson)
}
tempRes.then(options.onSuccess).catch(options.onError);
tempRes.then(options.onSuccess).catch(options.onError)
}
export function doFetchJson(options = {}, dispatch) {
const opts = { ...defaultJsonOptions, ...options };
doFetch(opts, dispatch);
const opts = { ...defaultJsonOptions, ...options }
doFetch(opts, dispatch)
}

View File

@ -1,26 +1,26 @@
/**
* export 一个 API底层的实现可能会改切换为 reqwest/superagent/fetch
*/
import { METHODS, REQ_TYPE, CACHE_TYPE, ERROR_HANDLER_TYPE } from './ajaxCommon';
import { doFetch, doFetchJson, doBiJsonFetch } from './reqwestAJAX';
import createApi from './apiCreator';
import { CACHE_TYPE, ERROR_HANDLER_TYPE, METHODS, REQ_TYPE } from './ajaxCommon'
import { doBiJsonFetch, doFetch, doFetchJson } from './reqwestAJAX'
import createApi from './apiCreator'
/**
* 创建一个 API 函数结果可以是任何形式如果是响应是 JSON 会自动转换类似于 #createFetchJson 结果<br />
* 但是请求头不指名 Json Accept:text/javascript, text/html, application/xml, text/xml, *\/*
*/
const createFetch = createApi(doFetch);
const createFetch = createApi(doFetch)
/**
* 创建一个 API 函数明确指明函数用于获取 Json 格式数据如果结果不符合格式会转到错误处理 <br />
* 请求头Accept:application/json, text/plain, *\/*
*/
const createFetchJson = createApi(doFetchJson);
const createFetchJson = createApi(doFetchJson)
// 创建一个 API 函数, 指明客户端、服务端 内容体content body都是 Json 格式。<br />
// 在 #createFetchJson 的基础上添加Content-Type: application/json;charset=UTF-8<br />
// 同时,如果请求 data 为 Object类型会通过 JSON.stringify 转换
const createBiJsonFetch = createApi(doBiJsonFetch);
const createBiJsonFetch = createApi(doBiJsonFetch)
/**
* api 转换为返回 Promise 方式, 不处理 error 如果处理 error 请君自new
@ -28,9 +28,9 @@ const createBiJsonFetch = createApi(doBiJsonFetch);
*/
const createPromiseAPI = api => (data) => {
return new Promise((resolve) => {
api({ data }, rs => resolve(rs));
});
};
api({ data }, rs => resolve(rs))
})
}
const API = {
METHODS,
@ -42,7 +42,7 @@ const API = {
createFetch,
createFetchJson,
createBiJsonFetch,
createPromiseAPI,
};
createPromiseAPI
}
export default API;
export default API

View File

@ -1,58 +1,58 @@
import reqwest from 'reqwest';
import _ from 'lodash';
import reqwest from 'reqwest'
import _ from 'lodash'
import {
REQ_TYPE,
METHODS,
defaultOptions,
defaultJsonOptions,
defaultBiJsonOptions,
defaultJsonOptions,
defaultOptions,
getRealUrl,
wrapErrorHandler,
} from './ajaxCommon';
METHODS,
REQ_TYPE,
wrapErrorHandler
} from './ajaxCommon'
function _doFetch(options = {}, dispatch, defaultMergeOption = {}) {
const opts = _.merge({}, defaultMergeOption, options, {
url: getRealUrl(options.url),
error: wrapErrorHandler(options.onError, dispatch),
});
error: wrapErrorHandler(options.onError, dispatch)
})
const method = opts.method && opts.method.toUpperCase();
const data = opts.data;
const method = opts.method && opts.method.toUpperCase()
const data = opts.data
if (METHODS.GET === method && opts.processData !== false && !_.isString(data)) {
// get 请求,配置 processData 不为否data 不为 String 则预处理
const newData = { ...data, ts: new Date().getTime() }; // 加入时间戳,防止浏览器缓存
opts.data = reqwest.toQueryString(newData, true); // traditional 方式,保证数组符合 spring mvc 的传参方式。
const newData = { ...data, ts: new Date().getTime() } // 加入时间戳,防止浏览器缓存
opts.data = reqwest.toQueryString(newData, true) // traditional 方式,保证数组符合 spring mvc 的传参方式。
}
opts.success = (res) => {
const doSuc = options.onSuccess ? options.onSuccess : defaultOptions.onSuccess; // reqwest 名字不同
const doSuc = options.onSuccess ? options.onSuccess : defaultOptions.onSuccess // reqwest 名字不同
if (opts.type === REQ_TYPE.JSON || typeof res === 'object') {
// noinspection JSUnresolvedVariable
if (res.result === 0 || res.ret === 0) {
doSuc(res.data);
doSuc(res.data)
} else {
opts.error(res);
opts.error(res)
}
} else {
doSuc(res);
doSuc(res)
}
}
};
reqwest(opts);
reqwest(opts)
}
export function doFetch(options = {}, dispatch) {
_doFetch(options, dispatch, defaultOptions);
_doFetch(options, dispatch, defaultOptions)
}
export function doFetchJson(options = {}, dispatch) {
_doFetch(options, dispatch, defaultJsonOptions);
_doFetch(options, dispatch, defaultJsonOptions)
}
export function doBiJsonFetch(options = {}, dispatch) {
let opts = options;
let opts = options
if (typeof opts.data === 'object') {
opts = { ...options, data: JSON.stringify(opts.data) };
opts = { ...options, data: JSON.stringify(opts.data) }
}
_doFetch(opts, dispatch, defaultBiJsonOptions);
_doFetch(opts, dispatch, defaultBiJsonOptions)
}

View File

@ -4,8 +4,8 @@
*/
/****************************** 布局组件 ******************************/
export { default as Header } from './layout/Header/Header';
export { default as Sidebar } from './layout/Sidebar/Sidebar';
export { default as Content } from './layout/Content/Content';
export { default as Footer } from './layout/Footer/Footer';
export { default as Breadcrumb } from './layout/Breadcrumb/Breadcrumb';
export { default as Header } from './layout/Header/Header'
export { default as Sidebar } from './layout/Sidebar/Sidebar'
export { default as Content } from './layout/Content/Content'
export { default as Footer } from './layout/Footer/Footer'
export { default as Breadcrumb } from './layout/Breadcrumb/Breadcrumb'

View File

@ -5,10 +5,10 @@
* @see https://ant.design/components/breadcrumb-cn/
* @see https://ant.design/components/icon-cn/
*/
import { Breadcrumb, Icon } from 'antd';
import PropTypes from 'prop-types';
import React from 'react';
import './Breadcrumb.less';
import { Breadcrumb, Icon } from 'antd'
import PropTypes from 'prop-types'
import React from 'react'
import './Breadcrumb.less'
/**
* 面包屑组件
@ -17,14 +17,14 @@ import './Breadcrumb.less';
class CustomBreadcrumb extends React.PureComponent {
static propTypes = {
data: PropTypes.array
};
}
static defaultProps = {
data: []
};
}
render() {
const { data } = this.props;
const { data } = this.props
const breadcrumbItems = data.map((item) => {
return (
<Breadcrumb.Item key={'bc-' + item.key}>
@ -32,7 +32,7 @@ class CustomBreadcrumb extends React.PureComponent {
<span>{item.title}</span>
</Breadcrumb.Item>
)
});
})
return (
<div className="ant-layout-breadcrumb">
@ -47,4 +47,5 @@ class CustomBreadcrumb extends React.PureComponent {
)
}
}
export default CustomBreadcrumb;
export default CustomBreadcrumb

View File

@ -1,6 +1,7 @@
.ant-layout-breadcrumb {
z-index: 200;
line-height: 64px;
.ant-breadcrumb-link {
font-size: 16px;
}

View File

@ -4,12 +4,12 @@
* @see https://ant.design/components/layout-cn/
* @see https://ant.design/components/card-cn/
*/
import { Card, Layout } from 'antd';
import React from 'react';
import { Card, Layout } from 'antd'
import React from 'react'
import './Content.less';
import './Content.less'
const { Content } = Layout;
const { Content } = Layout
/**
* 内容布局组件
@ -30,4 +30,5 @@ class CustomContent extends React.PureComponent {
)
}
}
export default CustomContent;
export default CustomContent

View File

@ -3,12 +3,12 @@
* @author Zhang Peng
* @see https://ant.design/components/layout-cn/
*/
import { Layout } from 'antd';
import React from 'react';
import { Layout } from 'antd'
import React from 'react'
import './index.less';
import './index.less'
const { Footer } = Layout;
const { Footer } = Layout
/**
* 底部布局组件
@ -23,4 +23,5 @@ class CustomFooter extends React.PureComponent {
)
}
}
export default CustomFooter;
export default CustomFooter

View File

@ -3,18 +3,18 @@
* @author Zhang Peng
* @see https://ant.design/components/layout-cn/
*/
import { Avatar, Badge, Col, Dropdown, Icon, Layout, Menu, Popover, Row } from 'antd';
import React from 'react';
import { Link, withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Avatar, Badge, Col, Dropdown, Icon, Layout, Menu, Popover, Row } from 'antd'
import React from 'react'
import { Link, withRouter } from 'react-router-dom'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import './Header.less';
import Breadcrumb from '../Breadcrumb/Breadcrumb';
import { fetchProfile, logout } from '../../../redux/actions/auth';
import './Header.less'
import Breadcrumb from '../Breadcrumb/Breadcrumb'
import { fetchProfile, logout } from '../../../redux/actions/auth'
const { Header } = Layout;
const { Header } = Layout
const content = (
<div>
@ -24,19 +24,19 @@ const content = (
<p>Content</p>
<p>Content</p>
</div>
);
)
const mapStateToProps = (state) => {
const { auth, menu } = state;
const { auth, menu } = state
return {
auth: auth ? auth : null,
navpath: menu.navpath
};
};
}
}
const mapDispatchToProps = (dispatch) => {
return { actions: bindActionCreators({ fetchProfile, logout }, dispatch) };
};
return { actions: bindActionCreators({ fetchProfile, logout }, dispatch) }
}
/**
* 顶部布局组件
@ -47,28 +47,28 @@ class CustomHeader extends React.PureComponent {
auth: PropTypes.object,
actions: PropTypes.object,
navpath: PropTypes.array
};
}
static defaultProps = {
auth: null,
actions: null,
navpath: []
};
}
componentWillMount() {
const { actions } = this.props;
actions.fetchProfile();
const { actions } = this.props
actions.fetchProfile()
}
handleLogOut = () => {
const { actions } = this.props;
const { actions } = this.props
actions.logout().payload.promise.then(() => {
this.props.history.replace('/login');
});
};
this.props.history.replace('/login')
})
}
render() {
const { auth, navpath } = this.props;
let username = '';
const { auth, navpath } = this.props
let username = ''
if (auth.user) {
if (auth.user.data) {
username = auth.user.data.name
@ -88,7 +88,7 @@ class CustomHeader extends React.PureComponent {
<a onClick={this.handleLogOut}>注销</a>
</Menu.Item>
</Menu>
);
)
return (
<Header className="ant-layout-header">
@ -124,5 +124,6 @@ class CustomHeader extends React.PureComponent {
)
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CustomHeader));
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CustomHeader))

View File

@ -10,6 +10,7 @@
.header-icon {
margin: 0 15px;
i {
font-size: 20px;
}

View File

@ -3,19 +3,19 @@
* @author Zhang Peng
* @see https://ant.design/components/layout-cn/
*/
import {Icon, Layout, Menu} from "antd";
import PropTypes from "prop-types";
import React from "react";
import {connect} from "react-redux";
import {matchPath, withRouter} from "react-router";
import {Link} from "react-router-dom";
import {bindActionCreators} from "redux";
import { Icon, Layout, Menu } from 'antd'
import PropTypes from 'prop-types'
import React from 'react'
import { connect } from 'react-redux'
import { matchPath, withRouter } from 'react-router'
import { Link } from 'react-router-dom'
import { bindActionCreators } from 'redux'
import "./Sidebar.less";
import logoImg from "./antd.svg";
import {refreshMenu, refreshNavPath} from "../../../redux/actions/menu";
import './Sidebar.less'
import logoImg from './antd.svg'
import { refreshMenu, refreshNavPath } from '../../../redux/actions/menu'
const {Sider} = Layout;
const { Sider } = Layout
const isActive = (path, history) => {
return matchPath(path, {
@ -23,7 +23,7 @@ const isActive = (path, history) => {
exact: true,
strict: false
})
};
}
/**
* 侧边导航栏组件侧边栏采用的响应式布局方式页面大小收缩到一定程度侧边栏会隐藏
@ -32,16 +32,16 @@ const isActive = (path, history) => {
class CustomSidebar extends React.PureComponent {
static propTypes = {
items: PropTypes.array
};
}
static defaultProps = {
items: []
};
}
state = {
openKey: "sub0",
activeKey: "menu0",
mode: 'inline',
};
openKey: 'sub0',
activeKey: 'menu0',
mode: 'inline'
}
componentDidMount() {
this.props.getAllMenu()
@ -57,25 +57,25 @@ class CustomSidebar extends React.PureComponent {
})
}
})
});
})
}
menuClickHandle = (item) => {
this.setState({
activeKey: item.key
});
})
this.props.updateNavPath(item.keyPath, item.key)
};
}
render() {
const {items, history} = this.props;
let {activeKey, openKey} = this.state;
const { items, history } = this.props
let { activeKey, openKey } = this.state
const _menuProcess = (nodes, pkey) => {
return Array.isArray(nodes) && nodes.map((item, i) => {
const menu = _menuProcess(item.children, item.key);
const menu = _menuProcess(item.children, item.key)
if (item.url && isActive(item.url, history)) {
activeKey = 'menu' + item.key;
activeKey = 'menu' + item.key
openKey = 'sub' + pkey
}
@ -89,7 +89,7 @@ class CustomSidebar extends React.PureComponent {
>
{menu}
</Menu.SubMenu>
);
)
case 'ItemGroup':
return (
<Menu.ItemGroup
@ -98,11 +98,11 @@ class CustomSidebar extends React.PureComponent {
>
{menu}
</Menu.ItemGroup>
);
)
case 'Divider':
return (
<Menu.Divider key={item.key}/>
);
)
case 'Item':
default:
return (
@ -112,13 +112,13 @@ class CustomSidebar extends React.PureComponent {
<span>{item.icon && <Icon type={item.icon}/>}{item.title}</span>
}
</Menu.Item>
);
break;
)
break
}
})
}
});
};
const menu = _menuProcess(items);
const menu = _menuProcess(items)
return (
/**

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="160px" viewBox="0 0 102 102" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<svg xmlns:sketch="http://www.bohemiancoding.com/sketch/ns" width="160px" viewBox="0 0 102 102" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
<title>a</title>
<desc>Created with Sketch.</desc>
@ -23,10 +24,16 @@
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="a" sketch:type="MSLayerGroup">
<g id="Group" sketch:type="MSShapeGroup">
<path d="M54.172,2.025 L73.631,21.484 C75.458,23.311 75.458,26.272 73.631,28.098 L73.631,28.098 C71.804,29.925 68.843,29.925 67.017,28.098 L54.172,15.254 C52.345,13.427 49.384,13.427 47.558,15.254 L15.254,47.558 C13.427,49.385 13.427,52.346 15.254,54.172 L47.558,86.476 C49.385,88.303 52.346,88.303 54.172,86.476 L67.017,73.631 C68.844,71.804 71.805,71.804 73.631,73.631 L73.631,73.631 C75.458,75.458 75.458,78.419 73.631,80.245 L54.172,99.704 C52.345,101.531 49.384,101.531 47.558,99.704 L2.025,54.172 C0.198,52.345 0.198,49.384 2.025,47.558 L47.557,2.026 C49.384,0.199 52.346,0.199 54.172,2.025 L54.172,2.025 Z" id="Shape" fill="url(#linearGradient-1)"></path>
<path d="M80.246,34.713 L80.246,34.713 C82.073,32.886 85.034,32.886 86.86,34.713 L99.705,47.558 C101.532,49.385 101.532,52.346 99.705,54.172 L86.86,67.017 C85.033,68.844 82.072,68.844 80.246,67.017 L80.246,67.017 C78.419,65.19 78.419,62.229 80.246,60.403 L86.476,54.173 C88.303,52.346 88.303,49.385 86.476,47.559 L80.246,41.329 C78.419,39.501 78.419,36.54 80.246,34.713 L80.246,34.713 Z" id="Shape" fill="url(#linearGradient-2)"></path>
<path
d="M54.172,2.025 L73.631,21.484 C75.458,23.311 75.458,26.272 73.631,28.098 L73.631,28.098 C71.804,29.925 68.843,29.925 67.017,28.098 L54.172,15.254 C52.345,13.427 49.384,13.427 47.558,15.254 L15.254,47.558 C13.427,49.385 13.427,52.346 15.254,54.172 L47.558,86.476 C49.385,88.303 52.346,88.303 54.172,86.476 L67.017,73.631 C68.844,71.804 71.805,71.804 73.631,73.631 L73.631,73.631 C75.458,75.458 75.458,78.419 73.631,80.245 L54.172,99.704 C52.345,101.531 49.384,101.531 47.558,99.704 L2.025,54.172 C0.198,52.345 0.198,49.384 2.025,47.558 L47.557,2.026 C49.384,0.199 52.346,0.199 54.172,2.025 L54.172,2.025 Z"
id="Shape" fill="url(#linearGradient-1)"></path>
<path
d="M80.246,34.713 L80.246,34.713 C82.073,32.886 85.034,32.886 86.86,34.713 L99.705,47.558 C101.532,49.385 101.532,52.346 99.705,54.172 L86.86,67.017 C85.033,68.844 82.072,68.844 80.246,67.017 L80.246,67.017 C78.419,65.19 78.419,62.229 80.246,60.403 L86.476,54.173 C88.303,52.346 88.303,49.385 86.476,47.559 L80.246,41.329 C78.419,39.501 78.419,36.54 80.246,34.713 L80.246,34.713 Z"
id="Shape" fill="url(#linearGradient-2)"></path>
</g>
<path d="M50.865,65.678 C59.046,65.678 65.678,59.046 65.678,50.865 C65.678,42.684 59.046,36.052 50.865,36.052 C42.684,36.052 36.052,42.684 36.052,50.865 C36.052,59.046 42.684,65.678 50.865,65.678 L50.865,65.678 Z M50.865,58.564 C46.613,58.564 43.166,55.117 43.166,50.865 C43.166,46.613 46.613,43.166 50.865,43.166 C55.117,43.166 58.564,46.613 58.564,50.865 C58.564,55.117 55.117,58.564 50.865,58.564 L50.865,58.564 Z" id="Shape" fill="url(#linearGradient-3)" sketch:type="MSShapeGroup"></path>
<path
d="M50.865,65.678 C59.046,65.678 65.678,59.046 65.678,50.865 C65.678,42.684 59.046,36.052 50.865,36.052 C42.684,36.052 36.052,42.684 36.052,50.865 C36.052,59.046 42.684,65.678 50.865,65.678 L50.865,65.678 Z M50.865,58.564 C46.613,58.564 43.166,55.117 43.166,50.865 C43.166,46.613 46.613,43.166 50.865,43.166 C55.117,43.166 58.564,46.613 58.564,50.865 C58.564,55.117 55.117,58.564 50.865,58.564 L50.865,58.564 Z"
id="Shape" fill="url(#linearGradient-3)" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -3,14 +3,14 @@
* @author Zhang Peng
* @see https://ant.design/components/layout-cn/
*/
import { Layout } from 'antd';
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
import { Layout } from 'antd'
import React from 'react'
import { Redirect, Route } from 'react-router-dom'
import './CoreContainer.less';
import { authHOC } from '../../utils';
import { ChildRoutes } from '../../routes';
import { Content, Footer, Header, Sidebar } from '../../components';
import './CoreContainer.less'
import { authHOC } from '../../utils'
import { ChildRoutes } from '../../routes'
import { Content, Footer, Header, Sidebar } from '../../components'
/**
* 应用的核心容器组件
@ -35,7 +35,8 @@ class CoreContainer extends React.PureComponent {
<Footer/>
</Layout>
</Layout>
);
)
}
}
export default CoreContainer;
export default CoreContainer

View File

@ -5,12 +5,12 @@
* @see https://github.com/gaearon/redux-devtools-dock-monitor
* @see https://github.com/gaearon/redux-devtools-log-monitor
*/
import React from 'react';
import React from 'react'
// Exported from redux-devtools
import { createDevTools } from 'redux-devtools';
import { createDevTools } from 'redux-devtools'
// Monitors are separate packages, and you can make a custom one
import LogMonitor from 'redux-devtools-log-monitor';
import DockMonitor from 'redux-devtools-dock-monitor';
import LogMonitor from 'redux-devtools-log-monitor'
import DockMonitor from 'redux-devtools-dock-monitor'
/**
* Redux 开发工具组件
@ -27,5 +27,5 @@ const ReduxDevTools = createDevTools(
defaultIsVisible={true}>
<LogMonitor theme='tomorrow'/>
</DockMonitor>
);
export default ReduxDevTools;
)
export default ReduxDevTools

View File

@ -3,14 +3,15 @@
* @author Zhang Peng
* @see http://gaearon.github.io/react-hot-loader/getstarted/
*/
import React from 'react';
import { Provider } from 'react-redux';
import { HashRouter as Router } from 'react-router-dom';
import React from 'react'
import { Provider } from 'react-redux'
import { HashRouter as Router } from 'react-router-dom'
import Routes from '../../routes';
import ReduxDevTools from './ReduxDevTools';
import configureStore from '../../redux/store/configureStore';
const store = configureStore();
import Routes from '../../routes'
import ReduxDevTools from './ReduxDevTools'
import configureStore from '../../redux/store/configureStore'
const store = configureStore()
/**
* 开发环境的 Root 容器会包含 Redux 的开发工具
@ -18,7 +19,7 @@ const store = configureStore();
*/
class RootContainer extends React.PureComponent {
render() {
if (!this.routes) this.routes = Routes;
if (!this.routes) this.routes = Routes
return (
<Provider store={store}>
<div>
@ -26,7 +27,8 @@ class RootContainer extends React.PureComponent {
<ReduxDevTools/>
</div>
</Provider>
);
)
}
}
export default RootContainer;
export default RootContainer

View File

@ -3,10 +3,10 @@
* @author Zhang Peng
* @see http://gaearon.github.io/react-hot-loader/getstarted/
*/
if (process.env.NODE_ENV === "development") {
module.exports = require('./RootContainer.dev');
console.log('[development] Root.dev started.');
if (process.env.NODE_ENV === 'development') {
module.exports = require('./RootContainer.dev')
console.log('[development] Root.dev started.')
} else {
module.exports = require('./RootContainer.prod');
console.log('[production] Root.prod started.');
module.exports = require('./RootContainer.prod')
console.log('[production] Root.prod started.')
}

View File

@ -3,13 +3,14 @@
* @author Zhang Peng
* @see http://gaearon.github.io/react-hot-loader/getstarted/
*/
import React from 'react';
import { Provider } from 'react-redux';
import { HashRouter as Router } from 'react-router-dom';
import React from 'react'
import { Provider } from 'react-redux'
import { HashRouter as Router } from 'react-router-dom'
import Routes from '../../routes';
import configureStore from '../../redux/store/configureStore';
const store = configureStore();
import Routes from '../../routes'
import configureStore from '../../redux/store/configureStore'
const store = configureStore()
/**
* 生产环境的 Root 容器
@ -17,12 +18,13 @@ const store = configureStore();
*/
class RootContainer extends React.PureComponent {
render() {
if (!this.routes) this.routes = Routes;
if (!this.routes) this.routes = Routes
return (
<Provider store={store}>
<Router children={this.routes}/>
</Provider>
);
)
}
}
export default RootContainer;
export default RootContainer

View File

@ -3,12 +3,12 @@
* @author Zhang Peng
* @see http://gaearon.github.io/react-hot-loader/getstarted/
*/
import 'react-hot-loader/patch';
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import 'react-hot-loader/patch'
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import RootContainer from './containers/Root/RootContainer';
import RootContainer from './containers/Root/RootContainer'
const render = Component => {
ReactDOM.render(
@ -16,16 +16,16 @@ const render = Component => {
<Component/>
</AppContainer>,
document.getElementById('root')
);
};
)
}
// App
render(RootContainer);
render(RootContainer)
// App
if (module.hot) {
module.hot.accept('./containers/Root/RootContainer', () => {
const NextRootContainer = require('./containers/Root/RootContainer');
const NextRootContainer = require('./containers/Root/RootContainer')
render(NextRootContainer)
});
})
}

View File

@ -1,11 +1,11 @@
const webapi = require('../../webapi');
import { FETCH_PROFILE, LOGIN, LOGOUT, UID_NOT_FOUND } from '../constants/authActionType';
const webapi = require('../../webapi')
import { FETCH_PROFILE, LOGIN, LOGOUT, UID_NOT_FOUND } from '../constants/authActionType'
export const fetchProfile = () => {
let uid = window.localStorage.getItem('uid');
let uid = window.localStorage.getItem('uid')
if (uid === undefined) {
return { type: UID_NOT_FOUND };
return { type: UID_NOT_FOUND }
}
return {
@ -14,7 +14,7 @@ export const fetchProfile = () => {
promise: webapi.get('/my')
}
}
};
}
export const login = (username, password) => {
return {
@ -26,7 +26,7 @@ export const login = (username, password) => {
})
}
}
};
}
export const logout = () => {
return {
@ -35,4 +35,4 @@ export const logout = () => {
promise: webapi.get('/logout')
}
}
};
}

View File

@ -1,5 +1,5 @@
const webapi = require('../../webapi');
import { REFRESH_MENU, REFRESH_NAVPATH } from '../constants/menuActionType';
const webapi = require('../../webapi')
import { REFRESH_MENU, REFRESH_NAVPATH } from '../constants/menuActionType'
export const refreshNavPath = (path, key) => {
return {
@ -9,7 +9,7 @@ export const refreshNavPath = (path, key) => {
key: key
}
}
};
}
export const refreshMenu = () => {
return {
@ -18,4 +18,4 @@ export const refreshMenu = () => {
promise: webapi.get('/menu')
}
}
};
}

View File

@ -1,16 +1,16 @@
export const LOGIN = 'LOGIN';
export const LOGOUT = 'LOGOUT';
export const FETCH_PROFILE = 'FETCH_PROFILE';
export const UID_NOT_FOUND = 'UID_NOT_FOUND';
export const LOGIN = 'LOGIN'
export const LOGOUT = 'LOGOUT'
export const FETCH_PROFILE = 'FETCH_PROFILE'
export const UID_NOT_FOUND = 'UID_NOT_FOUND'
export const LOGIN_PENDING = 'LOGIN_PENDING';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_FAILED = 'LOGIN_FAILED';
export const LOGIN_PENDING = 'LOGIN_PENDING'
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'
export const LOGIN_FAILED = 'LOGIN_FAILED'
export const LOGOUT_PENDING = 'LOGOUT_PENDING';
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const LOGOUT_FAILED = 'LOGOUT_FAILED';
export const LOGOUT_PENDING = 'LOGOUT_PENDING'
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'
export const LOGOUT_FAILED = 'LOGOUT_FAILED'
export const FETCH_PROFILE_PENDING = 'FETCH_PROFILE_PENDING';
export const FETCH_PROFILE_SUCCESS = 'FETCH_PROFILE_SUCCESS';
export const FETCH_PROFILE_FAILED = 'FETCH_PROFILE_FAILED';
export const FETCH_PROFILE_PENDING = 'FETCH_PROFILE_PENDING'
export const FETCH_PROFILE_SUCCESS = 'FETCH_PROFILE_SUCCESS'
export const FETCH_PROFILE_FAILED = 'FETCH_PROFILE_FAILED'

View File

@ -4,27 +4,27 @@
* 如果无 dispatch console.log error
* @type {string}
*/
export const COMMON_REQUEST_ERROR = 'COMMON_REQUEST_ERROR';
export const COMMON_REQUEST_ERROR = 'COMMON_REQUEST_ERROR'
/**
* 公共的 SpinModal action用于控制统一的过度形式的模态框展示
* 各类型配合 payload 中的 type 等字段控制
* @type {string}
*/
export const COMMON_SPIN_MODAL = 'COMMON_SPIN_MODAL';
export const COMMON_SPIN_MODAL = 'COMMON_SPIN_MODAL'
/**
* 公共的 SpinModal action用于控制统一的过度形式的模态框消失
* @type {string}
*/
export const COMMON_SPIN_MODAL_DIS = 'COMMON_SPIN_MODAL_DIS';
export const COMMON_SPIN_MODAL_DIS = 'COMMON_SPIN_MODAL_DIS'
// 校验
export const COMMON_VALIDATE_FAIL = 'COMMON_VALIDATE_FAIL';
export const COMMON_VALIDATE_FAIL = 'COMMON_VALIDATE_FAIL'
/**
* 公共的页面离开跳转确认功能开关
* @type {string}
*/
export const COMMON_LEAVE_CONFIRM_ON = 'COMMON_LEAVE_CONFIRM_ON';
export const COMMON_LEAVE_CONFIRM_OFF = 'COMMON_LEAVE_CONFIRM_OFF';
export const COMMON_LEAVE_CONFIRM_ON = 'COMMON_LEAVE_CONFIRM_ON'
export const COMMON_LEAVE_CONFIRM_OFF = 'COMMON_LEAVE_CONFIRM_OFF'

View File

@ -1,4 +1,4 @@
export const REFRESH_MENU = 'REFRESH_MENU';
export const REFRESH_NAVPATH = 'REFRESH_NAVPATH';
export const REFRESH_MENU_SUCCESS = 'REFRESH_MENU_SUCCESS';
export const REFRESH_MENU_FAILED = 'REFRESH_MENU_FAILED';
export const REFRESH_MENU = 'REFRESH_MENU'
export const REFRESH_NAVPATH = 'REFRESH_NAVPATH'
export const REFRESH_MENU_SUCCESS = 'REFRESH_MENU_SUCCESS'
export const REFRESH_MENU_FAILED = 'REFRESH_MENU_FAILED'

View File

@ -1,25 +1,25 @@
const defaultTypes = ['PENDING', 'FULFILLED', 'REJECTED'];
const defaultTypes = ['PENDING', 'FULFILLED', 'REJECTED']
const isPromise = (value) => {
if (value !== null && typeof value === 'object') {
return value.promise && typeof value.promise.then === 'function';
return value.promise && typeof value.promise.then === 'function'
}
}
};
function createPromiseMiddleware(config = {}) {
const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypes;
const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypes
return (_ref) => {
const dispatch = _ref.dispatch;
const dispatch = _ref.dispatch
return next => action => {
if (!isPromise(action.payload)) {
return next(action);
return next(action)
}
const { type, payload, meta } = action;
const { promise, data } = payload;
const [PENDING, FULFILLED, REJECTED] = (meta || {}).promiseTypeSuffixes || promiseTypeSuffixes;
const { type, payload, meta } = action
const { promise, data } = payload
const [PENDING, FULFILLED, REJECTED] = (meta || {}).promiseTypeSuffixes || promiseTypeSuffixes
/**
* Dispatch the first async handler. This tells the
@ -29,15 +29,15 @@ function createPromiseMiddleware(config = {}) {
type: `${type}_${PENDING}`,
...!!data ? { payload: data } : {},
...!!meta ? { meta } : {}
});
})
const isAction = resolved => resolved && (resolved.meta || resolved.payload);
const isThunk = resolved => typeof resolved === 'function';
const isAction = resolved => resolved && (resolved.meta || resolved.payload)
const isThunk = resolved => typeof resolved === 'function'
const getResolveAction = isError => ({
type: `${type}_${isError ? REJECTED : FULFILLED}`,
...!!meta ? { meta } : {},
...!!isError ? { error: true } : {}
});
})
/**
* Re-dispatch one of:
@ -47,29 +47,29 @@ function createPromiseMiddleware(config = {}) {
*/
action.payload.promise = promise.then(
(resolved = {}) => {
const resolveAction = getResolveAction();
const resolveAction = getResolveAction()
return dispatch(isThunk(resolved) ? resolved.bind(null, resolveAction) : {
...resolveAction,
...isAction(resolved) ? resolved : {
...!!resolved && { payload: resolved }
}
});
})
},
(rejected = {}) => {
const resolveAction = getResolveAction(true);
const resolveAction = getResolveAction(true)
return dispatch(isThunk(rejected) ? rejected.bind(null, resolveAction) : {
...resolveAction,
...isAction(rejected) ? rejected : {
...!!rejected && { payload: rejected }
}
});
},
);
})
}
)
return action;
};
};
return action
}
}
}
const promise = createPromiseMiddleware({ promiseTypeSuffixes: ['PENDING', 'SUCCESS', 'FAILED'] });
export default promise;
const promise = createPromiseMiddleware({ promiseTypeSuffixes: ['PENDING', 'SUCCESS', 'FAILED'] })
export default promise

View File

@ -4,52 +4,52 @@ import {
LOGIN_PENDING,
LOGIN_SUCCESS,
LOGOUT_SUCCESS
} from '../constants/authActionType';
} from '../constants/authActionType'
const initialState = {
user: null,
loggingIn: false,
loggingOut: false,
message: null
};
}
const auth = (state = initialState, action = {}) => {
switch (action.type) {
case LOGIN_PENDING:
return Object.assign({}, state, {
loggingIn: true
});
})
case LOGIN_SUCCESS:
let user = action.payload.data;
window.localStorage.setItem('uid', user.uid);
let user = action.payload.data
window.localStorage.setItem('uid', user.uid)
return Object.assign({}, state, {
user: user,
loggingIn: false,
message: null
});
})
case LOGIN_FAILED:
return {
...state,
loggingIn: false,
user: null,
message: action.payload.response.data.message
};
}
case LOGOUT_SUCCESS:
window.localStorage.removeItem('uid');
window.localStorage.removeItem('uid')
return {
...state,
loggingOut: false,
user: null,
message: null
};
}
case FETCH_PROFILE_SUCCESS:
return Object.assign({}, state, {
user: action.payload.data,
loggingIn: false,
message: null
});
})
default:
return state;
return state
}
};
export default auth;
}
export default auth

View File

@ -1,12 +1,12 @@
/**
* Created by Zhang Peng on 2017/7/6.
*/
import { combineReducers } from 'redux';
import auth from './auth';
import menu from './menu';
import { combineReducers } from 'redux'
import auth from './auth'
import menu from './menu'
const rootReducer = combineReducers({
auth,
menu
});
export default rootReducer;
})
export default rootReducer

View File

@ -1,49 +1,49 @@
import _ from 'lodash';
import _ from 'lodash'
import { REFRESH_MENU_SUCCESS, REFRESH_NAVPATH } from '../constants/menuActionType';
import { REFRESH_MENU_SUCCESS, REFRESH_NAVPATH } from '../constants/menuActionType'
const initialState = {
items: [],
navpath: []
};
}
const menu = (state = initialState, action = {}) => {
switch (action.type) {
case REFRESH_MENU_SUCCESS:
return Object.assign({}, initialState, {
items: action.payload.data.data
});
})
case REFRESH_NAVPATH:
let navpath = [], tmpOb, tmpKey, children;
let navpath = [], tmpOb, tmpKey, children
if (Array.isArray(action.payload.data)) {
action.payload.data.reverse().map((item) => {
if (item.indexOf('sub') !== -1) {
tmpKey = item.replace('sub', '');
tmpKey = item.replace('sub', '')
tmpOb = _.find(state.items, function(o) {
return o.key == tmpKey;
});
children = tmpOb.children;
return o.key == tmpKey
})
children = tmpOb.children
navpath.push({
key: tmpOb.key,
title: tmpOb.title,
icon: tmpOb.icon,
type: tmpOb.type,
url: tmpOb.url,
url: tmpOb.url
})
}
if (item.indexOf('menu') !== -1) {
tmpKey = item.replace('menu', '');
tmpKey = item.replace('menu', '')
if (children) {
tmpOb = _.find(children, function(o) {
return o.key == tmpKey;
});
return o.key == tmpKey
})
navpath.push({
key: tmpOb.key,
title: tmpOb.title,
icon: tmpOb.icon,
type: tmpOb.type,
url: tmpOb.url,
});
url: tmpOb.url
})
}
}
})
@ -51,9 +51,9 @@ const menu = (state = initialState, action = {}) => {
return Object.assign({}, state, {
currentIndex: action.payload.key * 1,
navpath: navpath
});
})
default:
return state;
return state
}
};
export default menu;
}
export default menu

View File

@ -4,14 +4,14 @@
* @see https://github.com/gaearon/redux-devtools/blob/master/docs/Walkthrough.md
*/
import { applyMiddleware, compose, createStore } from 'redux';
import { persistState } from 'redux-devtools';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import { applyMiddleware, compose, createStore } from 'redux'
import { persistState } from 'redux-devtools'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
import DevTools from '../../containers/Root/ReduxDevTools';
import promise from '../middlewares/promiseMiddleware';
import reducers from '../reducers';
import DevTools from '../../containers/Root/ReduxDevTools'
import promise from '../middlewares/promiseMiddleware'
import reducers from '../reducers'
const enhancer = compose(
// Middleware you want to use in development:
@ -20,13 +20,13 @@ const enhancer = compose(
DevTools.instrument(),
// Optional. Lets you write ?debug_session=<key> in address bar to persist debug sessions
persistState(getDebugSessionKey())
);
)
function getDebugSessionKey() {
// You can write custom logic here!
// By default we try to read the key from ?debug_session=<key> in the address bar
const matches = window.location.href.match(/[?&]debug_session=([^&]+)\b/);
return (matches && matches.length > 0) ? matches[1] : null;
const matches = window.location.href.match(/[?&]debug_session=([^&]+)\b/)
return (matches && matches.length > 0) ? matches[1] : null
}
/**
@ -37,15 +37,16 @@ function getDebugSessionKey() {
function configureStore(initialState) {
// Note: only Redux >= 3.1.0 supports passing enhancer as third argument.
// See https://github.com/reactjs/redux/releases/tag/v3.1.0
const store = createStore(reducers, initialState, enhancer);
const store = createStore(reducers, initialState, enhancer)
// Hot reload reducers (requires Webpack or Browserify HMR to be enabled)
if (module.hot) {
module.hot.accept('../reducers', () =>
store.replaceReducer(require('../reducers'))
);
)
}
return store;
return store
}
export default configureStore;
export default configureStore

View File

@ -6,7 +6,7 @@
// Use DefinePlugin (Webpack) or loose-envify (Browserify)
// together with Uglify to strip the dev branch in prod build.
if (process.env.NODE_ENV === 'development') {
module.exports = require('./configureStore.dev').default;
module.exports = require('./configureStore.dev').default
} else {
module.exports = require('./configureStore.prod').default;
module.exports = require('./configureStore.prod').default
}

View File

@ -4,13 +4,13 @@
* @see https://github.com/gaearon/redux-devtools/blob/master/docs/Walkthrough.md
*/
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { applyMiddleware, createStore } from 'redux'
import thunk from 'redux-thunk'
import promise from '../middlewares/promiseMiddleware';
import reducers from '../reducers';
import promise from '../middlewares/promiseMiddleware'
import reducers from '../reducers'
const enhancer = applyMiddleware(thunk, promise);
const enhancer = applyMiddleware(thunk, promise)
/**
* 生产环境的 Store 构造方法
@ -18,6 +18,7 @@ const enhancer = applyMiddleware(thunk, promise);
* @returns {Store<S>} Redux 的状态容器一个应用只有一个
*/
function configureStore(initialState) {
return createStore(reducers, initialState, enhancer);
return createStore(reducers, initialState, enhancer)
}
export default configureStore;
export default configureStore

View File

@ -5,11 +5,11 @@
* @see https://reacttraining.com/react-router/
* @see https://reacttraining.cn/
*/
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import CoreContainer from '../containers/Core';
import Login from '../views/pages/login/Login';
import CoreContainer from '../containers/Core'
import Login from '../views/pages/login/Login'
/**
* 子路由表
@ -28,7 +28,7 @@ export const ChildRoutes = [
'path': '/pages/user',
'component': require('../views/pages/user/User').default
}
];
]
/**
* 默认路由
@ -39,5 +39,5 @@ const Routes = (
<Route path="/login" component={Login}/>
<Route path="/" component={CoreContainer}/>
</Switch>
);
export default Routes;
)
export default Routes

View File

@ -4,34 +4,40 @@
* @see https://segmentfault.com/a/1190000009820646
*/
import React from 'react';
import React from 'react'
let Component = null;
let Component = null
export const asyncLoadHOC = loadComponent => (
class AsyncComponent extends React.Component {
static hasLoadedComponent() {
return Component !== null;
return Component !== null
}
componentWillMount() {
if (AsyncComponent.hasLoadedComponent()) {
return;
return
}
loadComponent().then(
module => module.default
).then((comp) => {
Component = comp;
Component = comp
}).catch((err) => {
console.error(`Cannot load component in <AsyncComponent />`);
throw err;
});
console.error(`Cannot load component in <AsyncComponent />`)
throw err
})
}
render() {
return (Component) ? <Component {...this.props} /> : null;
return (Component) ?
<
Component
{...
this.props
}
/> : null;
}
}
);
)

View File

@ -5,8 +5,8 @@
* @see https://zhuanlan.zhihu.com/p/24776678
* @see https://segmentfault.com/a/1190000004598113
*/
import React from 'react';
import { withRouter } from 'react-router-dom';
import React from 'react'
import { withRouter } from 'react-router-dom'
/**
* 校验方法
@ -14,12 +14,12 @@ import { withRouter } from 'react-router-dom';
* @param props {PropsType<S>} 组件的props
*/
const validate = props => {
const { history } = props;
const isLoggedIn = !!window.localStorage.getItem("uid");
if (!isLoggedIn && history.location.pathname !== "/login") {
history.replace("/login");
const { history } = props
const isLoggedIn = !!window.localStorage.getItem('uid')
if (!isLoggedIn && history.location.pathname !== '/login') {
history.replace('/login')
}
}
};
/**
* 对组件进行认证的方法
@ -30,19 +30,20 @@ const validate = props => {
const authHOC = WrappedComponent => {
class Authenticate extends React.Component {
componentWillMount() {
validate(this.props);
validate(this.props)
}
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
validate(nextProps);
validate(nextProps)
}
}
render() {
return <WrappedComponent {...this.props} />;
return <WrappedComponent {...this.props} />
}
}
return withRouter(Authenticate);
};
export default authHOC;
return withRouter(Authenticate)
}
export default authHOC

View File

@ -5,18 +5,18 @@
* @see http://www.jianshu.com/p/df464b26ae58
*/
const axios = require('axios');
const qs = require('qs');
const axios = require('axios')
const qs = require('qs')
import config from '../../config/app.config';
import config from '../../config/app.config'
// 本项目中 axios 的默认全局配置
axios.defaults.timeout = config.http.timeout;
axios.defaults.baseURL = config.http.baseURL;
axios.defaults.timeout = config.http.timeout
axios.defaults.baseURL = config.http.baseURL
axios.defaults.headers.get['Content-Type'] = 'application/json';
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.headers.put['Content-Type'] = 'application/json';
axios.defaults.headers.get['Content-Type'] = 'application/json'
axios.defaults.headers.post['Content-Type'] = 'application/json'
axios.defaults.headers.put['Content-Type'] = 'application/json'
// 本项目的默认配置
const defaultConfig = {
@ -37,8 +37,8 @@ const defaultConfig = {
transformRequest: [function(data) {
// 序列化
if (data) {
console.log("[request after stringify] data: ", JSON.stringify(data));
return JSON.stringify(data);
console.log('[request after stringify] data: ', JSON.stringify(data))
return JSON.stringify(data)
}
}],
@ -46,8 +46,8 @@ const defaultConfig = {
transformResponse: [function(data) {
// 反序列化
if (data) {
console.log("[response after parse] data: ", JSON.parse(data));
return JSON.parse(data);
console.log('[response after parse] data: ', JSON.parse(data))
return JSON.parse(data)
}
}],
@ -63,9 +63,9 @@ const defaultConfig = {
//`paramsSerializer`是一个可选的函数起作用是让参数params序列化
//例如(https://www.npmjs.com/package/qs,http://api.jquery.com/jquery.param)
paramsSerializer: function(params) {
const content = qs.stringify(params, { arrayFormat: 'brackets' });
console.log("[http] params 序列化后:", content);
return content;
const content = qs.stringify(params, { arrayFormat: 'brackets' })
console.log('[http] params 序列化后:', content)
return content
},
//`data`选项是作为一个请求体而需要被发送的数据
@ -120,8 +120,8 @@ const defaultConfig = {
//`validateStatus`定义了是否根据http相应状态码来resolve或者reject promise
//如果`validateStatus`返回true(或者设置为`null`或者`undefined`),那么promise的状态将会是resolved,否则其状态就是rejected
validateStatus: function(status) {
return status >= 200 && status < 300;//default
},
return status >= 200 && status < 300//default
}
//`maxRedirects`定义了在nodejs中重定向的最大数量
// maxRedirects: 5,//default
@ -147,7 +147,7 @@ const defaultConfig = {
//详见cancelation部分
// cancelToken: new CancelToken(function (cancel) {
// })
};
}
// 使用默认配置初始化的请求
const http = axios.create(defaultConfig);
export default http;
const http = axios.create(defaultConfig)
export default http

View File

@ -5,4 +5,4 @@
* @author Zhang Peng
*/
export { default as authHOC } from './authHOC';
export { default as authHOC } from './authHOC'

View File

@ -1,15 +1,14 @@
/**
* Created by Zhang Peng on 2017/7/21.
*/
import React from 'react';
import {Carousel, Col, Row} from 'antd';
import './Home.less';
import React from 'react'
import './Home.less'
import logo from './logo.svg';
import logo from './logo.svg'
export default class Home extends React.Component {
static propTypes = {};
static defaultProps = {};
static propTypes = {}
static defaultProps = {}
render() {
return (
@ -22,6 +21,6 @@ export default class Home extends React.Component {
REACT ADMIN is developing
</p>
</div>
);
)
}
}

View File

@ -24,6 +24,10 @@
}
@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@ -1,6 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<path
d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,95 +1,96 @@
import { Button, Card, Col, Form, Icon, Input, message, Row } from 'antd';
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import { Button, Card, Col, Form, Icon, Input, message, Row } from 'antd'
import PropTypes from 'prop-types'
import React from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import { bindActionCreators } from 'redux'
import { login } from '../../../redux/actions/auth';
import loginLogo from './login-logo.png';
import { login } from '../../../redux/actions/auth'
import loginLogo from './login-logo.png'
import './Login.less';
import './Login.less'
const FormItem = Form.Item;
const FormItem = Form.Item
const propTypes = {
user: PropTypes.object,
loggingIn: PropTypes.bool,
message: PropTypes.string
};
}
function hasErrors(fieldsError) {
return Object.keys(fieldsError).some(field => fieldsError[field]);
return Object.keys(fieldsError).some(field => fieldsError[field])
}
class Login extends React.Component {
constructor(props) {
super(props);
super(props)
this.state = {
loading: false,
loading: false
}
}
componentDidMount() {
// To disabled submit button at the beginning.
this.props.form.validateFields();
this.props.form.validateFields()
}
handleSubmit(e) {
e.preventDefault();
e.preventDefault()
this.setState({
loading: true
});
})
const data = this.props.form.getFieldsValue();
const data = this.props.form.getFieldsValue()
this.props.login(data.user, data.password).payload.promise.then(response => {
this.setState({
loading: false
});
})
if (response.error) {
console.warn('login failed: ', response.payload.message);
console.warn('login failed: ', response.payload.message)
} else {
let result = response.payload.data;
console.log("login result:", result);
let result = response.payload.data
console.log('login result:', result)
if (result) {
if (0 !== result.code) {
let str = '';
let str = ''
if (Array.isArray(result.messages)) {
result.messages.map((item) => {
str = str + item + '\n';
str = str + item + '\n'
})
}
message.error('登录失败: \n'+ str);
message.error('登录失败: \n' + str)
} else {
console.info('[Login] res.payload.data: ', result);
message.success('欢迎你,' + result.data.name);
this.props.history.replace('/');
console.info('[Login] res.payload.data: ', result)
message.success('欢迎你,' + result.data.name)
this.props.history.replace('/')
}
}
}
}).catch(err => {
console.error('[Login] err: ', err);
console.error('[Login] err: ', err)
this.setState({
loading: false
});
});
})
})
this.props.form.validateFields((err, values) => {
if (!err) {
console.info('提交表单信息', values);
console.info('提交表单信息', values)
} else {
console.error(err);
console.error(err)
}
});
})
}
render() {
const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched, setFieldsValue } = this.props.form;
const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched, setFieldsValue } = this.props.form
// Only show error after a field is touched.
const userNameError = isFieldTouched('userName') && getFieldError('userName');
const passwordError = isFieldTouched('password') && getFieldError('password');
const userNameError = isFieldTouched('userName') && getFieldError('userName')
const passwordError = isFieldTouched('password') && getFieldError('password')
return (
<Row className="login-row" type="flex" justify="space-around" align="middle">
@ -110,7 +111,7 @@ class Login extends React.Component {
<FormItem validateStatus={userNameError ? 'error' : ''}
help={userNameError || ''}>
{getFieldDecorator('user', {
rules: [{ required: true, message: 'Please input your username!' }],
rules: [{ required: true, message: 'Please input your username!' }]
})(
<Input
className="input"
@ -123,7 +124,7 @@ class Login extends React.Component {
<FormItem validateStatus={passwordError ? 'error' : ''}
help={passwordError || ''}>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your password!' }],
rules: [{ required: true, message: 'Please input your password!' }]
})(
<Input className="input" size="large"
prefix={<Icon type="lock" style={{ fontSize: 18 }}/>}
@ -144,17 +145,17 @@ class Login extends React.Component {
}
}
Login.propTypes = propTypes;
Login.propTypes = propTypes
Login = Form.create()(Login);
Login = Form.create()(Login)
function mapStateToProps(state) {
const { auth } = state;
const { auth } = state
if (auth.user) {
return { user: auth.user, loggingIn: auth.loggingIn, message: '' };
return { user: auth.user, loggingIn: auth.loggingIn, message: '' }
}
return { user: null, loggingIn: auth.loggingIn, message: auth.message };
return { user: null, loggingIn: auth.loggingIn, message: auth.message }
}
function mapDispatchToProps(dispatch) {

View File

@ -7,6 +7,7 @@
.login-form {
background: #F3F9F9;
border-radius: 18px;
.input {
width: 300px;
size: 18px;
@ -17,13 +18,16 @@
transition: color 0.3s;
font-size: 12px;
}
.anticon-close-circle:hover {
color: #999;
}
.anticon-close-circle:active {
color: #666;
}
}
.btn-login {
width: 300px;
}

View File

@ -1,42 +1,42 @@
import { Table } from 'antd';
import React from 'react';
import { Table } from 'antd'
import React from 'react'
const columns = [{
title: 'Name',
dataIndex: 'name',
dataIndex: 'name'
}, {
title: 'Age',
dataIndex: 'age',
dataIndex: 'age'
}, {
title: 'Address',
dataIndex: 'address',
}];
dataIndex: 'address'
}]
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
address: 'New York No. 1 Lake Park'
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
address: 'London No. 1 Lake Park'
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
address: 'Sidney No. 1 Lake Park'
}, {
key: '4',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
address: 'Sidney No. 1 Lake Park'
}, {
key: '5',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
address: 'Sidney No. 1 Lake Park'
}]
export default class MailboxPage extends React.Component {
render() {
@ -44,6 +44,6 @@ export default class MailboxPage extends React.Component {
<div title="Mailbox Page">
<Table columns={columns} dataSource={data} size="small"/>
</div>
);
)
}
}

View File

@ -1,75 +1,76 @@
import React, {PropTypes} from "react";
import {Alert, Button, Col, Input, Row, Select, Table} from "antd";
import "./User.less";
const {Option, OptGroup} = Select;
import React from 'react'
import { Alert, Button, Col, Input, Row, Select, Table } from 'antd'
import './User.less'
const { Option, OptGroup } = Select
const columns = [{
title: 'Name',
dataIndex: 'name',
filters: [{
text: 'Joe',
value: 'Joe',
value: 'Joe'
}, {
text: 'Jim',
value: 'Jim',
value: 'Jim'
}, {
text: 'Submenu',
value: 'Submenu',
children: [{
text: 'Green',
value: 'Green',
value: 'Green'
}, {
text: 'Black',
value: 'Black',
}],
value: 'Black'
}]
}],
// specify the condition of filtering result
// here is that finding the name started with `value`
onFilter: (value, record) => record.name.indexOf(value) === 0,
sorter: (a, b) => a.name.length - b.name.length,
sorter: (a, b) => a.name.length - b.name.length
}, {
title: 'Age',
dataIndex: 'age',
sorter: (a, b) => a.age - b.age,
sorter: (a, b) => a.age - b.age
}, {
title: 'Address',
dataIndex: 'address',
filters: [{
text: 'London',
value: 'London',
value: 'London'
}, {
text: 'New York',
value: 'New York',
value: 'New York'
}],
filterMultiple: false,
onFilter: (value, record) => record.address.indexOf(value) === 0,
sorter: (a, b) => a.address.length - b.address.length,
}];
sorter: (a, b) => a.address.length - b.address.length
}]
const data = [{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
address: 'New York No. 1 Lake Park'
}, {
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
address: 'London No. 1 Lake Park'
}, {
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
address: 'Sidney No. 1 Lake Park'
}, {
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
}];
address: 'London No. 2 Lake Park'
}]
function onChange(pagination, filters, sorter) {
console.log('params', pagination, filters, sorter);
console.log('params', pagination, filters, sorter)
}
export default class UserView extends React.Component {
@ -138,6 +139,6 @@ export default class UserView extends React.Component {
<Table columns={columns} dataSource={data} onChange={onChange}/>
</div>
</div>
);
)
}
}

View File

@ -1,22 +1,22 @@
const axios = require('axios');
const MockAdapter = require('axios-mock-adapter');
const mockAxios = axios.create();
const axios = require('axios')
const MockAdapter = require('axios-mock-adapter')
const mockAxios = axios.create()
// mock 数据
const mock = new MockAdapter(mockAxios);
const mock = new MockAdapter(mockAxios)
mock.onPut('/login').reply(config => {
let postData = JSON.parse(config.data);
console.info('[mock]', postData);
let postData = JSON.parse(config.data)
console.info('[mock]', postData)
if (postData.username === 'admin' && postData.password === '123456') {
let result = require('./user');
console.info('[mock result]', result);
return [200, result];
let result = require('./user')
console.info('[mock result]', result)
return [200, result]
} else {
return [500, { message: "Incorrect user or password" }];
return [500, { message: 'Incorrect user or password' }]
}
});
mock.onGet('/logout').reply(200, {});
mock.onGet('/my').reply(200, require('./user'));
mock.onGet('/menu').reply(200, require('./menu'));
})
mock.onGet('/logout').reply(200, {})
mock.onGet('/my').reply(200, require('./user'))
mock.onGet('/menu').reply(200, require('./menu'))
export default mockAxios;
export default mockAxios

View File

@ -1,92 +1,92 @@
module.exports = {
"code": 0,
"messages": [
"成功"
'code': 0,
'messages': [
'成功'
],
"data": [
'data': [
{
"key": 0,
"title": "Home",
"icon": "home",
"type": "Item",
"url": "/pages/home",
"children": []
'key': 0,
'title': 'Home',
'icon': 'home',
'type': 'Item',
'url': '/pages/home',
'children': []
},
{
"key": 1,
"title": "Pages",
"icon": "user",
"type": "SubMenu",
"url": null,
"children": [
'key': 1,
'title': 'Pages',
'icon': 'user',
'type': 'SubMenu',
'url': null,
'children': [
{
"key": 11,
"title": "Mailbox",
"icon": "mail",
"type": "Item",
"url": "/pages/mailbox",
"children": []
'key': 11,
'title': 'Mailbox',
'icon': 'mail',
'type': 'Item',
'url': '/pages/mailbox',
'children': []
},
{
"key": 12,
"title": "User",
"icon": "user",
"type": "Item",
"url": "/pages/user",
"children": []
'key': 12,
'title': 'User',
'icon': 'user',
'type': 'Item',
'url': '/pages/user',
'children': []
}
]
},
{
"key": 2,
"title": "Others",
"icon": "coffee",
"type": "SubMenu",
"url": null,
"children": [
'key': 2,
'title': 'Others',
'icon': 'coffee',
'type': 'SubMenu',
'url': null,
'children': [
{
"key": 21,
"title": "Group1",
"icon": "windows-o",
"type": "ItemGroup",
"url": null,
"children": [
'key': 21,
'title': 'Group1',
'icon': 'windows-o',
'type': 'ItemGroup',
'url': null,
'children': [
{
"key": 22,
"title": "Group1-1",
"icon": null,
"type": "Item",
"url": "/pages/home",
"children": []
'key': 22,
'title': 'Group1-1',
'icon': null,
'type': 'Item',
'url': '/pages/home',
'children': []
}
]
},
{
"key": 23,
"title": "Divider",
"icon": null,
"type": "Divider",
"url": null,
"children": []
'key': 23,
'title': 'Divider',
'icon': null,
'type': 'Divider',
'url': null,
'children': []
},
{
"key": 24,
"title": "Group2",
"icon": "apple-o",
"type": "ItemGroup",
"url": null,
"children": [
'key': 24,
'title': 'Group2',
'icon': 'apple-o',
'type': 'ItemGroup',
'url': null,
'children': [
{
"key": 25,
"title": "Group2-1",
"icon": null,
"type": "Item",
"url": "/pages/home",
"children": []
'key': 25,
'title': 'Group2-1',
'icon': null,
'type': 'Item',
'url': '/pages/home',
'children': []
}
]
}
]
}
]
};
}

View File

@ -1,5 +1,5 @@
module.exports = {
code: 0,
messages: ["成功"],
data: { uid: "1", role: "ADMIN", name: "admin" }
};
messages: ['成功'],
data: { uid: '1', role: 'ADMIN', name: 'admin' }
}

View File

@ -1,5 +1,5 @@
if (process.env.NODE_ENV === 'development') {
module.exports = require('./mock').default;
module.exports = require('./mock').default
} else {
module.exports = require('../utils/http').default;
module.exports = require('../utils/http').default
}

View File

@ -3,14 +3,14 @@
<head>
<meta charset="UTF-8"/>
<title>Nginx Tutorial</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Nginx Tutorial" />
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/>
<meta content="Nginx Tutorial" name="description"/>
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
name="viewport"
/>
<link rel="icon" href="http://dunwu.test.upcdn.net/images/others/zp_50_50.png" type="image/x-icon" />
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="vue" />
<link href="http://dunwu.test.upcdn.net/images/others/zp_50_50.png" rel="icon" type="image/x-icon"/>
<link href="//unpkg.com/docsify/lib/themes/vue.css" rel="stylesheet" title="vue"/>
<style>
h1 + ul {
display: block !important;
@ -28,20 +28,20 @@
.sidebar-toggle,
body,
.search input {
color: #6b615f !important;
background-color: #fff4e6 !important;
color: #6B615F !important;
background-color: #FFF4E6 !important;
}
.content strong,
.sidebar strong,
body strong {
color: #5c5869 !important;
color: #5C5869 !important;
}
</style>
<style>
.cover-main .anchor span {
text-align: center;
background-image: -webkit-linear-gradient(left, #ffdcb4, #b96972 25%, #e88a57 50%, #804170 75%, #a596cd);
background-image: -webkit-linear-gradient(left, #FFDCB4, #B96972 25%, #E88A57 50%, #804170 75%, #A596CD);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-background-size: 200% 100%;
@ -51,17 +51,17 @@
}
.cover-main blockquote p {
color: #5c5869;
color: #5C5869;
font-family: "Arial", 隶书, serif;
}
.cover-main ul a:hover {
color: #fe4165 !important;
color: #FE4165 !important;
}
.cover-main p a:hover {
text-align: center;
background-image: -webkit-linear-gradient(left, #ffdcb4, #b96972 25%, #e88a57 50%, #804170 75%, #a596cd);
background-image: -webkit-linear-gradient(left, #FFDCB4, #B96972 25%, #E88A57 50%, #804170 75%, #A596CD);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-background-size: 200% 100%;
@ -71,13 +71,13 @@
/* content 样式内容 */
.sidebar a,
.content a {
color: #399ab2 !important;
color: #399AB2 !important;
text-decoration: none !important;
}
.sidebar a:hover,
.content a:hover {
color: #fe4165 !important;
color: #FE4165 !important;
text-decoration: underline !important;
}
@ -86,7 +86,7 @@
.content h3 :hover,
.content h4 :hover {
text-align: center;
background-image: -webkit-linear-gradient(left, #ffdcb4, #b96972 25%, #e88a57 50%, #804170 75%, #a596cd);
background-image: -webkit-linear-gradient(left, #FFDCB4, #B96972 25%, #E88A57 50%, #804170 75%, #A596CD);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-background-size: 200% 100%;
@ -110,14 +110,14 @@
.content h1 a,
.content h1 span {
color: #399ab2 !important;
color: #399AB2 !important;
font-size: 30px;
text-shadow: 2px 2px 5px grey;
}
.content h2 a,
.content h2 span {
color: #60497c !important;
color: #60497C !important;
font-size: 26px;
text-shadow: 2px 2px 5px grey;
}
@ -132,7 +132,7 @@
.content h4 a,
.content h4 span {
font-size: 18px;
color: #78943a;
color: #78943A;
text-shadow: 2px 2px 5px grey;
}
@ -151,8 +151,8 @@
.content blockquote {
display: block;
padding: 0 16px;
border-left: 8px solid #dddfe4;
background: #fff2c9;
border-left: 8px solid #DDDFE4;
background: #FFF2C9;
overflow: auto;
}
@ -160,7 +160,7 @@
padding-left: 0 !important;
padding-right: 0 !important;
border-radius: 8px;
box-shadow: 1px 1px 20px 3px #dddddd !important;
box-shadow: 1px 1px 20px 3px #DDDDDD !important;
}
.content code {
@ -173,13 +173,13 @@
display: table;
padding-left: 0 !important;
padding-right: 0 !important;
box-shadow: 2px 2px 20px 6px #dddddd !important;
box-shadow: 2px 2px 20px 6px #DDDDDD !important;
}
.content th {
font-weight: bold;
font-size: 16px;
background-color: #cce6b6;
background-color: #CCE6B6;
}
</style>
<style>
@ -218,22 +218,22 @@
<div id="app">正在加载...</div>
<script>
window.$docsify = {
name: "Nginx Tutorial",
repo: "https://github.com/dunwu/nginx-tutorial",
logo: "http://dunwu.test.upcdn.net/images/others/zp_100_100.png",
name: 'Nginx Tutorial',
repo: 'https://github.com/dunwu/nginx-tutorial',
logo: 'http://dunwu.test.upcdn.net/images/others/zp_100_100.png',
auto2top: true,
coverpage: "coverpage.md",
coverpage: 'coverpage.md',
maxLevel: 4,
subMaxLevel: 4,
formatUpdated: "{MM}/{DD} {HH}:{mm}",
formatUpdated: '{MM}/{DD} {HH}:{mm}',
search: {
maxAge: 86400000,
paths: ["/"],
placeholder: "🔍 搜索",
noData: "没有结果!",
paths: ['/'],
placeholder: '🔍 搜索',
noData: '没有结果!',
depth: 4
}
};
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/emoji.js"></script>