format codes
parent
46c9f4f40a
commit
be8034fd71
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -36,7 +42,7 @@ public class Main {
|
|||
}
|
||||
if (isBlank(System.getProperty("tomcat.server.shutdownPort"))) {
|
||||
System.setProperty("tomcat.server.shutdownPort",
|
||||
String.valueOf(Integer.valueOf(System.getProperty("tomcat.connector.port")) + 10000));
|
||||
String.valueOf(Integer.valueOf(System.getProperty("tomcat.connector.port")) + 10000));
|
||||
}
|
||||
if (isBlank(System.getProperty("tomcat.context.path"))) {
|
||||
System.setProperty("tomcat.context.path", CONTEXT_PATH);
|
||||
|
@ -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() {
|
||||
|
@ -94,7 +94,7 @@ public class Main {
|
|||
System.setProperty("catalina.useNaming", "false");
|
||||
ExtendedCatalina extendedCatalina = new ExtendedCatalina();
|
||||
|
||||
//覆盖默认的skip和scan jar包配置
|
||||
// 覆盖默认的skip和scan jar包配置
|
||||
System.setProperty(Constants.SKIP_JARS_PROPERTY, "");
|
||||
System.setProperty(Constants.SCAN_JARS_PROPERTY, "");
|
||||
|
||||
|
@ -102,17 +102,28 @@ public class Main {
|
|||
digester.push(extendedCatalina);
|
||||
try {
|
||||
server = ((ExtendedCatalina) digester
|
||||
.parse(new File(System.getProperty("catalina.base") + RELATIVE_SERVERXML_PATH))).getServer();
|
||||
.parse(new File(System.getProperty("catalina.base") + RELATIVE_SERVERXML_PATH))).getServer();
|
||||
// 设置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 + ")配置是否正确");
|
||||
+ RELATIVE_SERVERXML_PATH + ")配置是否正确");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class ExtendedCatalina extends Catalina {
|
||||
|
||||
@Override
|
||||
public Digester createStartDigester() {
|
||||
return super.createStartDigester();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,103 +1,102 @@
|
|||
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 String regex;
|
||||
private String headerKey;
|
||||
private String protocol = "http";
|
||||
private final String ORIGIN_KEY = "Origin";
|
||||
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";
|
||||
|
||||
public void init(FilterConfig filterConfig) {
|
||||
// 取配置参数
|
||||
regex = filterConfig.getInitParameter("regex");
|
||||
headerKey = filterConfig.getInitParameter("headerKey");
|
||||
String protocolVal = filterConfig.getInitParameter("protocol");
|
||||
if (StringUtils.isNotBlank(protocolVal)) {
|
||||
if (StringUtils.equalsIgnoreCase("http", protocolVal)
|
||||
|| StringUtils.equalsIgnoreCase("https", protocolVal)) {
|
||||
protocol = protocolVal.toLowerCase();
|
||||
} else {
|
||||
logger.error("CorsFilter 配置参数 protocol 非法,仍使用默认值 http");
|
||||
}
|
||||
}
|
||||
}
|
||||
public void init(FilterConfig filterConfig) {
|
||||
// 取配置参数
|
||||
regex = filterConfig.getInitParameter("regex");
|
||||
headerKey = filterConfig.getInitParameter("headerKey");
|
||||
String protocolVal = filterConfig.getInitParameter("protocol");
|
||||
if (StringUtils.isNotBlank(protocolVal)) {
|
||||
if (StringUtils.equalsIgnoreCase("http", protocolVal)
|
||||
|| StringUtils.equalsIgnoreCase("https", protocolVal)) {
|
||||
protocol = protocolVal.toLowerCase();
|
||||
}
|
||||
else {
|
||||
logger.error("CorsFilter 配置参数 protocol 非法,仍使用默认值 http");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
if (StringUtils.isBlank(regex) || StringUtils.isBlank(headerKey)) {
|
||||
throw new ServletException("读取跨域过滤器的配置参数失败");
|
||||
}
|
||||
if (StringUtils.isBlank(regex) || StringUtils.isBlank(headerKey)) {
|
||||
throw new ServletException("读取跨域过滤器的配置参数失败");
|
||||
}
|
||||
|
||||
// 读取请求地址的域
|
||||
String domain = httpRequest.getHeader(headerKey);
|
||||
String origin = httpRequest.getHeader(ORIGIN_KEY);
|
||||
// 读取请求地址的域
|
||||
String domain = httpRequest.getHeader(headerKey);
|
||||
String origin = httpRequest.getHeader(ORIGIN_KEY);
|
||||
|
||||
if (StringUtils.isBlank(origin)) {
|
||||
logger.debug("origin 为空, 跳过检查");
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(origin)) {
|
||||
logger.debug("origin 为空, 跳过检查");
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(domain)) {
|
||||
logger.debug("domain 为空, 跳过检查");
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(domain)) {
|
||||
logger.debug("domain 为空, 跳过检查");
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (origin.toLowerCase().contains(domain.toLowerCase())) {
|
||||
// 判断请求方和应答方是否同为 http 或 https
|
||||
// 如果相同,这里视为同源;否则,视为跨域
|
||||
if (origin.startsWith(protocol)) {
|
||||
logger.debug("domain={}, origin={}, 二者协议相同,且域名同源,跳过检查", domain, origin);
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (origin.toLowerCase().contains(domain.toLowerCase())) {
|
||||
// 判断请求方和应答方是否同为 http 或 https
|
||||
// 如果相同,这里视为同源;否则,视为跨域
|
||||
if (origin.startsWith(protocol)) {
|
||||
logger.debug("domain={}, origin={}, 二者协议相同,且域名同源,跳过检查", domain, origin);
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
if (!pattern.matcher(origin).matches()) {
|
||||
logger.warn("客户端域 origin={} 不在跨域白名单中", origin);
|
||||
httpResponse.sendError(403, "客户端域不在跨域白名单中");
|
||||
throw new ServletException("客户端域不在跨域白名单中");
|
||||
}
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
if (!pattern.matcher(origin).matches()) {
|
||||
logger.warn("客户端域 origin={} 不在跨域白名单中", origin);
|
||||
httpResponse.sendError(403, "客户端域不在跨域白名单中");
|
||||
throw new ServletException("客户端域不在跨域白名单中");
|
||||
}
|
||||
|
||||
logger.debug("对 origin={} 放开跨域限制", origin);
|
||||
httpResponse.addHeader("Access-Control-Allow-Origin", origin);
|
||||
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");
|
||||
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");
|
||||
if (httpRequest.getMethod().equals("OPTIONS")) {
|
||||
httpResponse.setStatus(HttpServletResponse.SC_OK);
|
||||
return;
|
||||
}
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
}
|
||||
logger.debug("对 origin={} 放开跨域限制", origin);
|
||||
httpResponse.addHeader("Access-Control-Allow-Origin", origin);
|
||||
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");
|
||||
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");
|
||||
if (httpRequest.getMethod().equals("OPTIONS")) {
|
||||
httpResponse.setStatus(HttpServletResponse.SC_OK);
|
||||
return;
|
||||
}
|
||||
chain.doFilter(httpRequest, httpResponse);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public void destroy() {}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
public IOObjectMapper() {
|
||||
this.setSerializationInclusion(Include.NON_EMPTY);
|
||||
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,91 +11,101 @@ 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;
|
||||
}
|
||||
private static Set<MenuDTO> getAll() {
|
||||
MenuDTO item0 = new MenuDTO("0", "首页", "home", "Item", "/pages/home");
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
MenuDTO subMenu1 = new MenuDTO("1", "业务", "bars", "SubMenu", null);
|
||||
MenuDTO item11 = new MenuDTO("11", "Mailbox", "mail", "Item", "/pages/mailbox");
|
||||
MenuDTO item12 = new MenuDTO("12", "用户列表", "user", "Item", "/pages/user");
|
||||
subMenu1.addChild(item11);
|
||||
subMenu1.addChild(item12);
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "/logout", method = RequestMethod.GET)
|
||||
public BaseResponseDTO logout(HttpServletRequest request) {
|
||||
BaseResponseDTO baseResponseDTO = new BaseResponseDTO();
|
||||
return baseResponseDTO;
|
||||
}
|
||||
MenuDTO subMenu2 = new MenuDTO("2", "Others", "coffee", "SubMenu", null);
|
||||
MenuDTO itemGroup1 = new MenuDTO("21", "Group1", "windows-o", "ItemGroup", null);
|
||||
MenuDTO item22 = new MenuDTO("22", "Group1-1", null, "Item", null);
|
||||
MenuDTO divider = new MenuDTO("23", "Divider1", null, "Divider", null);
|
||||
MenuDTO itemGroup2 = new MenuDTO("24", "Group2", "apple-o", "ItemGroup", null);
|
||||
MenuDTO item25 = new MenuDTO("25", "Group2-1", null, "Item", null);
|
||||
itemGroup1.addChild(item22);
|
||||
itemGroup2.addChild(item25);
|
||||
subMenu2.addChild(itemGroup1);
|
||||
subMenu2.addChild(divider);
|
||||
subMenu2.addChild(itemGroup2);
|
||||
|
||||
@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;
|
||||
}
|
||||
Set<MenuDTO> menus = new TreeSet<MenuDTO>();
|
||||
menus.add(item0);
|
||||
menus.add(subMenu1);
|
||||
menus.add(subMenu2);
|
||||
|
||||
private static Set<MenuDTO> getAll() {
|
||||
MenuDTO item0 = new MenuDTO("0", "首页", "home", "Item", "/pages/home");
|
||||
return menus;
|
||||
}
|
||||
|
||||
MenuDTO subMenu1 = new MenuDTO("1", "业务", "bars", "SubMenu", null);
|
||||
MenuDTO item11 = new MenuDTO("11", "Mailbox", "mail", "Item", "/pages/mailbox");
|
||||
MenuDTO item12 = new MenuDTO("12", "用户列表", "user", "Item", "/pages/user");
|
||||
subMenu1.addChild(item11);
|
||||
subMenu1.addChild(item12);
|
||||
@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;
|
||||
}
|
||||
|
||||
MenuDTO subMenu2 = new MenuDTO("2", "Others", "coffee", "SubMenu", null);
|
||||
MenuDTO itemGroup1 = new MenuDTO("21", "Group1", "windows-o", "ItemGroup", null);
|
||||
MenuDTO item22 = new MenuDTO("22", "Group1-1", null, "Item", null);
|
||||
MenuDTO divider = new MenuDTO("23", "Divider1", null, "Divider", null);
|
||||
MenuDTO itemGroup2 = new MenuDTO("24", "Group2", "apple-o", "ItemGroup", null);
|
||||
MenuDTO item25 = new MenuDTO("25", "Group2-1", null, "Item", null);
|
||||
itemGroup1.addChild(item22);
|
||||
itemGroup2.addChild(item25);
|
||||
subMenu2.addChild(itemGroup1);
|
||||
subMenu2.addChild(divider);
|
||||
subMenu2.addChild(itemGroup2);
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
Set<MenuDTO> menus = new TreeSet<MenuDTO>();
|
||||
menus.add(item0);
|
||||
menus.add(subMenu1);
|
||||
menus.add(subMenu2);
|
||||
@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;
|
||||
}
|
||||
|
||||
return menus;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,82 +6,80 @@ 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;
|
||||
|
||||
private final List<String> messages = new ArrayList<>();
|
||||
public BaseResponseDTO() {
|
||||
}
|
||||
|
||||
private T data;
|
||||
public BaseResponseDTO(T dto) {
|
||||
this.data = dto;
|
||||
}
|
||||
|
||||
public BaseResponseDTO() {}
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public BaseResponseDTO(T dto) {
|
||||
this.data = dto;
|
||||
}
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
public void addError(String error) {
|
||||
this.messages.add(error);
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
public void addErrors(String[] errors) {
|
||||
this.addErrors(Arrays.asList(errors));
|
||||
}
|
||||
|
||||
public void addError(String error) {
|
||||
this.messages.add(error);
|
||||
}
|
||||
public void addErrors(List<String> errorList) {
|
||||
this.messages.addAll(errorList);
|
||||
}
|
||||
|
||||
public void addErrors(String[] errors) {
|
||||
this.addErrors(Arrays.asList(errors));
|
||||
}
|
||||
public void removeError(String error) {
|
||||
this.messages.remove(error);
|
||||
}
|
||||
|
||||
public void addErrors(List<String> errorList) {
|
||||
this.messages.addAll(errorList);
|
||||
}
|
||||
public List<String> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public void removeError(String error) {
|
||||
this.messages.remove(error);
|
||||
}
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public List<String> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
public enum DEFAULT_RESPONSE_RESULT {
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
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, "请求参数缺失");
|
||||
|
||||
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, "请求参数缺失");
|
||||
private final Integer value;
|
||||
|
||||
private final Integer value;
|
||||
private final String desc;
|
||||
|
||||
private final String desc;
|
||||
DEFAULT_RESPONSE_RESULT(int value, String desc) {
|
||||
this.value = value;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
DEFAULT_RESPONSE_RESULT(int value, String desc) {
|
||||
this.value = value;
|
||||
this.desc = desc;
|
||||
}
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public String desc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,122 +1,120 @@
|
|||
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 String key;
|
||||
private final Set<MenuDTO> children = new TreeSet<MenuDTO>();
|
||||
private String key;
|
||||
private String title;
|
||||
private String icon;
|
||||
private String type;
|
||||
private String url;
|
||||
|
||||
private String title;
|
||||
public MenuDTO() {
|
||||
}
|
||||
|
||||
private String icon;
|
||||
public MenuDTO(String key, String title, String icon, String type, String url) {
|
||||
this.key = key;
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.type = type;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
private String type;
|
||||
public MenuDTO clone() throws CloneNotSupportedException {
|
||||
super.clone();
|
||||
MenuDTO menuDTO = new MenuDTO();
|
||||
menuDTO.setType(type);
|
||||
menuDTO.setKey(key);
|
||||
menuDTO.setTitle(title);
|
||||
menuDTO.setIcon(icon);
|
||||
menuDTO.setUrl(url);
|
||||
menuDTO.setUrl(url);
|
||||
return menuDTO;
|
||||
}
|
||||
|
||||
private String url;
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
private final Set<MenuDTO> children = new TreeSet<MenuDTO>();
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public MenuDTO() {}
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public MenuDTO(String key, String title, String icon, String type, String url) {
|
||||
this.key = key;
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.type = type;
|
||||
this.url = url;
|
||||
}
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public MenuDTO clone() throws CloneNotSupportedException {
|
||||
super.clone();
|
||||
MenuDTO menuDTO = new MenuDTO();
|
||||
menuDTO.setType(type);
|
||||
menuDTO.setKey(key);
|
||||
menuDTO.setTitle(title);
|
||||
menuDTO.setIcon(icon);
|
||||
menuDTO.setUrl(url);
|
||||
menuDTO.setUrl(url);
|
||||
return menuDTO;
|
||||
}
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
public Set<MenuDTO> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public void addChild(MenuDTO child) {
|
||||
this.children.add(child);
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
public void addChildren(Set<MenuDTO> children) {
|
||||
this.children.addAll(children);
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
public void addChildren(MenuDTO[] children) {
|
||||
this.children.addAll(Arrays.asList(children));
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
boolean equals = false;
|
||||
if (obj instanceof MenuDTO) {
|
||||
MenuDTO menuDTO = (MenuDTO) obj;
|
||||
equals = (new EqualsBuilder().append(url, menuDTO.getUrl())).isEquals();
|
||||
}
|
||||
return equals;
|
||||
}
|
||||
|
||||
public Set<MenuDTO> getChildren() {
|
||||
return children;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37).append(url).toHashCode();
|
||||
}
|
||||
|
||||
public void addChild(MenuDTO child) {
|
||||
this.children.add(child);
|
||||
}
|
||||
@Override
|
||||
public int compareTo(MenuDTO otherMenuDTO) {
|
||||
return new CompareToBuilder().append(key, otherMenuDTO.getKey()).append(url, otherMenuDTO.getUrl())
|
||||
.toComparison();
|
||||
}
|
||||
|
||||
public void addChildren(Set<MenuDTO> children) {
|
||||
this.children.addAll(children);
|
||||
}
|
||||
|
||||
public void addChildren(MenuDTO[] children) {
|
||||
this.children.addAll(Arrays.asList(children));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
boolean equals = false;
|
||||
if (obj instanceof MenuDTO) {
|
||||
MenuDTO menuDTO = (MenuDTO) obj;
|
||||
equals = (new EqualsBuilder().append(url, menuDTO.getUrl())).isEquals();
|
||||
}
|
||||
return equals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37).append(url).toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MenuDTO otherMenuDTO) {
|
||||
return new CompareToBuilder().append(key, otherMenuDTO.getKey()).append(url, otherMenuDTO.getUrl())
|
||||
.toComparison();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/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"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
<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
|
||||
http://www.springframework.org/schema/context/spring-context.xsd
|
||||
|
@ -21,10 +21,10 @@
|
|||
</bean>
|
||||
|
||||
<bean id="jacksonObjectMapper" name="jacksonObjectMapper"
|
||||
class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
|
||||
<property name="indentOutput" value="true" />
|
||||
class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
|
||||
<property name="indentOutput" value="true"/>
|
||||
<property name="objectMapper">
|
||||
<bean class="io.github.dunwu.util.IOObjectMapper" />
|
||||
<bean class="io.github.dunwu.util.IOObjectMapper"/>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
|
|
|
@ -6,24 +6,24 @@
|
|||
<Service name="Catalina">
|
||||
|
||||
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
|
||||
maxThreads="300" minSpareThreads="25"/>
|
||||
maxThreads="300" minSpareThreads="25"/>
|
||||
|
||||
<Connector port="${tomcat.connector.port}" protocol="HTTP/1.1" connectionTimeout="30000" acceptCount="500"
|
||||
executor="tomcatThreadPool"
|
||||
processorCache="300" bindOnInit="false"/>
|
||||
executor="tomcatThreadPool"
|
||||
processorCache="300" bindOnInit="false"/>
|
||||
|
||||
<Engine name="localhost" defaultHost="localhost">
|
||||
<Host name="localhost" createDirs="false" appBase="${tomcat.host.appBase}" unpackWARs="false"
|
||||
autoDeploy="false"
|
||||
deployOnStartup="false" failCtxIfServletStartFails="true">
|
||||
autoDeploy="false"
|
||||
deployOnStartup="false" failCtxIfServletStartFails="true">
|
||||
<Context path="${tomcat.context.path}" docBase="${tomcat.context.docBase}" reloadable="false"
|
||||
logEffectiveWebXml="false"
|
||||
privileged="false"
|
||||
swallowOutput="false" workDir="${catalina.base}/work">
|
||||
logEffectiveWebXml="false"
|
||||
privileged="false"
|
||||
swallowOutput="false" workDir="${catalina.base}/work">
|
||||
<JarScanner>
|
||||
<JarScanFilter pluggabilitySkip="*.jar" pluggabilityScan=""
|
||||
defaultPluggabilityScan="true" tldSkip="*.jar"
|
||||
tldScan="" defaultTldScan="true"/>
|
||||
defaultPluggabilityScan="true" tldSkip="*.jar"
|
||||
tldScan="" defaultTldScan="true"/>
|
||||
</JarScanner>
|
||||
</Context>
|
||||
</Host>
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
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"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
<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">
|
||||
version="3.1">
|
||||
|
||||
<!-- ======================== Introduction ============================== -->
|
||||
<!-- This document defines default values for *all* web applications -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?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"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
|
||||
<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>
|
||||
|
||||
<!-- SERVLET BEGIN -->
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<%@ 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 path = request.getContextPath();
|
||||
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">
|
||||
<html>
|
||||
<head>
|
||||
<title>HelloController</title>
|
||||
<title>HelloController</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>${message}</h1>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%
|
||||
String domain = request.getScheme() + "://" + request.getServerName() + request.getContextPath();
|
||||
String host = request.getRemoteHost();
|
||||
// int port = request.getServerPort();
|
||||
Integer port = Integer.valueOf(System.getProperty("tomcat.connector.port"));
|
||||
String domain = request.getScheme() + "://" + request.getServerName() + request.getContextPath();
|
||||
String host = request.getRemoteHost();
|
||||
// int port = request.getServerPort();
|
||||
Integer port = Integer.valueOf(System.getProperty("tomcat.connector.port"));
|
||||
|
||||
|
||||
%>
|
||||
|
@ -11,16 +11,16 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>spring-embed-tomcat-demo</title>
|
||||
<title>spring-embed-tomcat-demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>spring-embed-tomcat-demo</h1>
|
||||
<h2><%out.print("当前服务器信息:");%></h2>
|
||||
<ul>
|
||||
<li><%out.print("domain:" + domain);%></li>
|
||||
<li><%out.print("host:" + host);%></li>
|
||||
<li><%out.print("port:" + port);%></li>
|
||||
<li><%out.print("domain:" + domain);%></li>
|
||||
<li><%out.print("host:" + host);%></li>
|
||||
<li><%out.print("port:" + port);%></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<style>
|
||||
<title>Error</title>
|
||||
<style>
|
||||
body {
|
||||
width: 35em;
|
||||
margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||
width: 35em;
|
||||
margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>An error occurred.</h1>
|
||||
<p>Sorry, the page you are looking for is currently unavailable.<br/>
|
||||
Please try again later.</p>
|
||||
Please try again later.</p>
|
||||
<p>If you are the system administrator of this resource then you should check
|
||||
the <a href="http://nginx.org/r/error_log">error log</a> for details.</p>
|
||||
the <a href="http://nginx.org/r/error_log">error log</a> for details.</p>
|
||||
<p><em>Faithfully yours, nginx.</em></p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to nginx!</title>
|
||||
<style>
|
||||
<title>Welcome to nginx!</title>
|
||||
<style>
|
||||
body {
|
||||
width: 35em;
|
||||
margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||
width: 35em;
|
||||
margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to nginx!</h1>
|
||||
<p>If you see this page, the nginx web server is successfully installed and
|
||||
working. Further configuration is required.</p>
|
||||
working. Further configuration is required.</p>
|
||||
|
||||
<p>For online documentation and support please refer to
|
||||
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
||||
Commercial support is available at
|
||||
<a href="http://nginx.com/">nginx.com</a>.</p>
|
||||
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
||||
Commercial support is available at
|
||||
<a href="http://nginx.com/">nginx.com</a>.</p>
|
||||
|
||||
<p><em>Thank you for using nginx.</em></p>
|
||||
</body>
|
||||
|
|
|
@ -1,41 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
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" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link href="%PUBLIC_URL%/favicon.ico" rel="shortcut icon"/>
|
||||
<meta
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
name="viewport"
|
||||
/>
|
||||
<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 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.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" />
|
||||
<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"
|
||||
>
|
||||
Learn React
|
||||
</a>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
< 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'
|
||||
>
|
||||
Learn
|
||||
React
|
||||
< /a>
|
||||
< /header>
|
||||
< /div>
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -2,13 +2,13 @@ body {
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
monospace;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<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"/>
|
||||
<circle cx="420.9" cy="296.5" r="45.7"/>
|
||||
<path d="M520.5 78.1z"/>
|
||||
</g>
|
||||
<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"/>
|
||||
<circle cx="420.9" cy="296.5" r="45.7"/>
|
||||
<path d="M520.5 78.1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -12,124 +12,124 @@
|
|||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||
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.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit http://bit.ly/CRA-PWA'
|
||||
);
|
||||
});
|
||||
'worker. To learn more, visit http://bit.ly/CRA-PWA'
|
||||
)
|
||||
})
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
registerValidSW(swUrl, config)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl, config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
|
||||
);
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing
|
||||
if (installingWorker == null) {
|
||||
return
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
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);
|
||||
}
|
||||
} 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.');
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
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.')
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration)
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error)
|
||||
})
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl, config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl)
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
);
|
||||
});
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type')
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@ module.exports = {
|
|||
/**
|
||||
* 服务器的host
|
||||
*/
|
||||
baseURL: '/api',
|
||||
baseURL: '/api'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 的名字
|
||||
})
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
});
|
||||
})
|
||||
|
|
|
@ -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')
|
||||
]
|
||||
})
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 text,response 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 />
|
||||
{ /* 否则在 <Link to="/login" >当前页登陆</Link> 。 */ }
|
||||
</p>),
|
||||
});
|
||||
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 预计错误处理,如 404,400,500,非返回 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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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,28 +17,28 @@ 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}>
|
||||
<Icon type={item.icon} />
|
||||
<Icon type={item.icon}/>
|
||||
<span>{item.title}</span>
|
||||
</Breadcrumb.Item>
|
||||
)
|
||||
});
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="ant-layout-breadcrumb">
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item key='bc-0'>
|
||||
<Icon type="home" />
|
||||
<Icon type="home"/>
|
||||
<span>Home</span>
|
||||
</Breadcrumb.Item>
|
||||
{breadcrumbItems}
|
||||
|
@ -47,4 +47,5 @@ class CustomBreadcrumb extends React.PureComponent {
|
|||
)
|
||||
}
|
||||
}
|
||||
export default CustomBreadcrumb;
|
||||
|
||||
export default CustomBreadcrumb
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.ant-layout-breadcrumb {
|
||||
z-index: 200;
|
||||
line-height: 64px;
|
||||
|
||||
.ant-breadcrumb-link {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,30 +47,30 @@ 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) {
|
||||
if (auth.user.data) {
|
||||
username = auth.user.data.name
|
||||
}
|
||||
}
|
||||
|
@ -83,30 +83,30 @@ class CustomHeader extends React.PureComponent {
|
|||
<Menu.Item key="2">
|
||||
选项2
|
||||
</Menu.Item>
|
||||
<Menu.Divider />
|
||||
<Menu.Divider/>
|
||||
<Menu.Item key="logout">
|
||||
<a onClick={this.handleLogOut}>注销</a>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
)
|
||||
|
||||
return (
|
||||
<Header className="ant-layout-header">
|
||||
<Row type="flex" align="middle">
|
||||
<Col xs={12} sm={12} md={12} lg={12} xl={12}>
|
||||
<Breadcrumb data={navpath} />
|
||||
<Breadcrumb data={navpath}/>
|
||||
</Col>
|
||||
<Col xs={0} sm={2} md={4} lg={8} xl={8} />
|
||||
<Col xs={0} sm={2} md={4} lg={8} xl={8}/>
|
||||
<Col xs={0} sm={6} md={6} lg={4} xl={4}>
|
||||
<Badge className="header-icon" count={5}>
|
||||
<Link to="/pages/mailbox">
|
||||
<Icon type="mail" />
|
||||
<Icon type="mail"/>
|
||||
</Link>
|
||||
</Badge>
|
||||
<Popover content={content} title="Title" trigger="click">
|
||||
<Badge className="header-icon" dot>
|
||||
<a href="#">
|
||||
<Icon type="notification" />
|
||||
<Icon type="notification"/>
|
||||
</a>
|
||||
</Badge>
|
||||
</Popover>
|
||||
|
@ -115,7 +115,7 @@ class CustomHeader extends React.PureComponent {
|
|||
<Avatar shape="circle" style={{ verticalAlign: 'middle', backgroundColor: '#00a2ae' }} size="large">
|
||||
{username}
|
||||
</Avatar>
|
||||
<Icon type="down" />
|
||||
<Icon type="down"/>
|
||||
</a>
|
||||
</Dropdown>
|
||||
</Col>
|
||||
|
@ -124,5 +124,6 @@ class CustomHeader extends React.PureComponent {
|
|||
)
|
||||
}
|
||||
}
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CustomHeader));
|
||||
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CustomHeader))
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
.header-icon {
|
||||
margin: 0 15px;
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
|
|
@ -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,68 +57,68 @@ 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);
|
||||
if (item.url && isActive(item.url, history)) {
|
||||
activeKey = 'menu' + item.key;
|
||||
openKey = 'sub' + pkey
|
||||
}
|
||||
const menu = _menuProcess(item.children, item.key)
|
||||
if (item.url && isActive(item.url, history)) {
|
||||
activeKey = 'menu' + item.key
|
||||
openKey = 'sub' + pkey
|
||||
}
|
||||
|
||||
switch (item.type) {
|
||||
switch (item.type) {
|
||||
|
||||
case 'SubMenu':
|
||||
return (
|
||||
<Menu.SubMenu
|
||||
key={item.key}
|
||||
title={<span><Icon type={item.icon}/><span className="nav-text">{item.title}</span></span>}
|
||||
>
|
||||
{menu}
|
||||
</Menu.SubMenu>
|
||||
);
|
||||
case 'ItemGroup':
|
||||
return (
|
||||
<Menu.ItemGroup
|
||||
key={item.key}
|
||||
title={<span><Icon type={item.icon}/><span className="nav-text">{item.title}</span></span>}
|
||||
>
|
||||
{menu}
|
||||
</Menu.ItemGroup>
|
||||
);
|
||||
case 'Divider':
|
||||
return (
|
||||
<Menu.Divider key={item.key} />
|
||||
);
|
||||
case 'Item':
|
||||
default:
|
||||
return (
|
||||
<Menu.Item className="ant-menu-item" key={item.key}>
|
||||
{
|
||||
item.url ? <Link to={item.url}>{item.icon && <Icon type={item.icon}/>}{item.title}</Link> :
|
||||
<span>{item.icon && <Icon type={item.icon}/>}{item.title}</span>
|
||||
}
|
||||
</Menu.Item>
|
||||
);
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
case 'SubMenu':
|
||||
return (
|
||||
<Menu.SubMenu
|
||||
key={item.key}
|
||||
title={<span><Icon type={item.icon}/><span className="nav-text">{item.title}</span></span>}
|
||||
>
|
||||
{menu}
|
||||
</Menu.SubMenu>
|
||||
)
|
||||
case 'ItemGroup':
|
||||
return (
|
||||
<Menu.ItemGroup
|
||||
key={item.key}
|
||||
title={<span><Icon type={item.icon}/><span className="nav-text">{item.title}</span></span>}
|
||||
>
|
||||
{menu}
|
||||
</Menu.ItemGroup>
|
||||
)
|
||||
case 'Divider':
|
||||
return (
|
||||
<Menu.Divider key={item.key}/>
|
||||
)
|
||||
case 'Item':
|
||||
default:
|
||||
return (
|
||||
<Menu.Item className="ant-menu-item" key={item.key}>
|
||||
{
|
||||
item.url ? <Link to={item.url}>{item.icon && <Icon type={item.icon}/>}{item.title}</Link> :
|
||||
<span>{item.icon && <Icon type={item.icon}/>}{item.title}</span>
|
||||
}
|
||||
</Menu.Item>
|
||||
)
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const menu = _menuProcess(items);
|
||||
const menu = _menuProcess(items)
|
||||
|
||||
return (
|
||||
/**
|
||||
|
|
|
@ -1,32 +1,39 @@
|
|||
<?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">
|
||||
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>a</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<linearGradient x1="121.870767%" y1="50.0000623%" x2="-8.13548721%" y2="50.0000623%" id="linearGradient-1">
|
||||
<stop stop-color="#47B4E0" offset="0%"></stop>
|
||||
<stop stop-color="#1588E0" offset="17.18%"></stop>
|
||||
<stop stop-color="#6EB4E0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.9981983%" y1="99.9981453%" x2="49.9981983%" y2="0.00156952896%" id="linearGradient-2">
|
||||
<stop stop-color="#F0776F" offset="3.22%"></stop>
|
||||
<stop stop-color="#F0656F" offset="50.32%"></stop>
|
||||
<stop stop-color="#F0606F" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.9999999%" y1="0.000675229319%" x2="49.9999999%" y2="99.9996626%" id="linearGradient-3">
|
||||
<stop stop-color="#F0776F" offset="3.22%"></stop>
|
||||
<stop stop-color="#F0656F" offset="50.32%"></stop>
|
||||
<stop stop-color="#F0606F" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<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>
|
||||
</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>
|
||||
</g>
|
||||
<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>
|
||||
<defs>
|
||||
<linearGradient x1="121.870767%" y1="50.0000623%" x2="-8.13548721%" y2="50.0000623%" id="linearGradient-1">
|
||||
<stop stop-color="#47B4E0" offset="0%"></stop>
|
||||
<stop stop-color="#1588E0" offset="17.18%"></stop>
|
||||
<stop stop-color="#6EB4E0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.9981983%" y1="99.9981453%" x2="49.9981983%" y2="0.00156952896%" id="linearGradient-2">
|
||||
<stop stop-color="#F0776F" offset="3.22%"></stop>
|
||||
<stop stop-color="#F0656F" offset="50.32%"></stop>
|
||||
<stop stop-color="#F0606F" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="49.9999999%" y1="0.000675229319%" x2="49.9999999%" y2="99.9996626%" id="linearGradient-3">
|
||||
<stop stop-color="#F0776F" offset="3.22%"></stop>
|
||||
<stop stop-color="#F0656F" offset="50.32%"></stop>
|
||||
<stop stop-color="#F0606F" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<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>
|
||||
</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>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.1 KiB |
|
@ -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'
|
||||
|
||||
/**
|
||||
* 应用的核心容器组件
|
||||
|
@ -21,21 +21,22 @@ class CoreContainer extends React.PureComponent {
|
|||
render() {
|
||||
return (
|
||||
<Layout className="ant-layout-has-sider">
|
||||
<Sidebar />
|
||||
<Sidebar/>
|
||||
<Layout>
|
||||
<Header />
|
||||
<Header/>
|
||||
<Layout className="ant-layout-container">
|
||||
<Content>
|
||||
<Redirect to="/pages/home" />
|
||||
<Redirect to="/pages/home"/>
|
||||
{ChildRoutes.map((route, index) => (
|
||||
<Route key={index} path={route.path} component={authHOC(route.component)} exactly={route.exactly} />
|
||||
<Route key={index} path={route.path} component={authHOC(route.component)} exactly={route.exactly}/>
|
||||
))}
|
||||
</Content>
|
||||
</Layout>
|
||||
<Footer />
|
||||
<Footer/>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
export default CoreContainer;
|
||||
|
||||
export default CoreContainer
|
||||
|
|
|
@ -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 开发工具组件
|
||||
|
@ -25,7 +25,7 @@ const ReduxDevTools = createDevTools(
|
|||
<DockMonitor toggleVisibilityKey='ctrl-h'
|
||||
changePositionKey='ctrl-q'
|
||||
defaultIsVisible={true}>
|
||||
<LogMonitor theme='tomorrow' />
|
||||
<LogMonitor theme='tomorrow'/>
|
||||
</DockMonitor>
|
||||
);
|
||||
export default ReduxDevTools;
|
||||
)
|
||||
export default ReduxDevTools
|
||||
|
|
|
@ -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,15 +19,16 @@ 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>
|
||||
<Router children={this.routes} />
|
||||
<ReduxDevTools />
|
||||
<Router children={this.routes}/>
|
||||
<ReduxDevTools/>
|
||||
</div>
|
||||
</Provider>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
export default RootContainer;
|
||||
|
||||
export default RootContainer
|
||||
|
|
|
@ -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.')
|
||||
}
|
||||
|
|
|
@ -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} />
|
||||
<Router children={this.routes}/>
|
||||
</Provider>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
export default RootContainer;
|
||||
|
||||
export default RootContainer
|
||||
|
|
|
@ -3,29 +3,29 @@
|
|||
* @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(
|
||||
<AppContainer>
|
||||
<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)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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', '');
|
||||
tmpOb = _.find(state.items, function (o) {
|
||||
return o.key == tmpKey;
|
||||
});
|
||||
children = tmpOb.children;
|
||||
tmpKey = item.replace('sub', '')
|
||||
tmpOb = _.find(state.items, function(o) {
|
||||
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;
|
||||
});
|
||||
tmpOb = _.find(children, function(o) {
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
];
|
||||
]
|
||||
|
||||
/**
|
||||
* 默认路由
|
||||
|
@ -36,8 +36,8 @@ export const ChildRoutes = [
|
|||
*/
|
||||
const Routes = (
|
||||
<Switch>
|
||||
<Route path="/login" component={Login} />
|
||||
<Route path="/" component={CoreContainer} />
|
||||
<Route path="/login" component={Login}/>
|
||||
<Route path="/" component={CoreContainer}/>
|
||||
</Switch>
|
||||
);
|
||||
export default Routes;
|
||||
)
|
||||
export default Routes
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
@ -34,20 +34,20 @@ const defaultConfig = {
|
|||
//该选项只适用于以下请求方式:`put/post/patch`
|
||||
//数组里面的最后一个函数必须返回一个字符串、-一个`ArrayBuffer`或者`Stream`
|
||||
|
||||
transformRequest: [function (data) {
|
||||
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)
|
||||
}
|
||||
}],
|
||||
|
||||
//`transformResponse` 选项允许我们在数据传送到`then/catch`方法之前对数据进行改动
|
||||
transformResponse: [function (data) {
|
||||
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)
|
||||
}
|
||||
}],
|
||||
|
||||
|
@ -62,10 +62,10 @@ 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;
|
||||
paramsSerializer: function(params) {
|
||||
const content = qs.stringify(params, { arrayFormat: 'brackets' })
|
||||
console.log('[http] params 序列化后:', content)
|
||||
return content
|
||||
},
|
||||
|
||||
//`data`选项是作为一个请求体而需要被发送的数据
|
||||
|
@ -107,11 +107,11 @@ const defaultConfig = {
|
|||
xsrfHeaderName: 'X-XSRF-TOKEN',//default
|
||||
|
||||
//`onUploadProgress`上传进度事件
|
||||
onUploadProgress: function (progressEvent) {
|
||||
onUploadProgress: function(progressEvent) {
|
||||
},
|
||||
|
||||
//下载进度的事件
|
||||
onDownloadProgress: function (progressEvent) {
|
||||
onDownloadProgress: function(progressEvent) {
|
||||
},
|
||||
|
||||
//相应内容的最大值
|
||||
|
@ -119,9 +119,9 @@ const defaultConfig = {
|
|||
|
||||
//`validateStatus`定义了是否根据http相应状态码,来resolve或者reject promise
|
||||
//如果`validateStatus`返回true(或者设置为`null`或者`undefined`),那么promise的状态将会是resolved,否则其状态就是rejected
|
||||
validateStatus: function (status) {
|
||||
return status >= 200 && status < 300;//default
|
||||
},
|
||||
validateStatus: function(status) {
|
||||
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
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
* @author Zhang Peng
|
||||
*/
|
||||
|
||||
export { default as authHOC } from './authHOC';
|
||||
export { default as authHOC } from './authHOC'
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
/**
|
||||
* 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 (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<img src={logo} className="App-logo" alt="logo"/>
|
||||
<h1 className="App-title">Welcome to REACT ADMIN</h1>
|
||||
</header>
|
||||
<p className="App-intro">
|
||||
REACT ADMIN is developing。。。
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 |
|
@ -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,11 +111,11 @@ 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"
|
||||
prefix={<Icon type="user" style={{ fontSize: 18 }} />}
|
||||
prefix={<Icon type="user" style={{ fontSize: 18 }}/>}
|
||||
ref={node => this.userNameInput = node}
|
||||
placeholder="admin"
|
||||
/>
|
||||
|
@ -123,12 +124,12 @@ 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 }} />}
|
||||
prefix={<Icon type="lock" style={{ fontSize: 18 }}/>}
|
||||
type='password'
|
||||
placeholder='123456' />
|
||||
placeholder='123456'/>
|
||||
)}
|
||||
</FormItem>
|
||||
<p>
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
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() {
|
||||
return (
|
||||
<div title="Mailbox Page">
|
||||
<Table columns={columns} dataSource={data} size="small" />
|
||||
<Table columns={columns} dataSource={data} size="small"/>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -86,7 +87,7 @@ export default class UserView extends React.Component {
|
|||
<Col span={7}>
|
||||
<Select
|
||||
defaultValue="lucy"
|
||||
style={{width: 200}}
|
||||
style={{ width: 200 }}
|
||||
>
|
||||
<OptGroup label="Manager">
|
||||
<Option value="jack">Jack</Option>
|
||||
|
@ -106,7 +107,7 @@ export default class UserView extends React.Component {
|
|||
<Col span={7}>
|
||||
<Select
|
||||
defaultValue="lucy"
|
||||
style={{width: 200}}
|
||||
style={{ width: 200 }}
|
||||
>
|
||||
</Select>
|
||||
</Col>
|
||||
|
@ -138,6 +139,6 @@ export default class UserView extends React.Component {
|
|||
<Table columns={columns} dataSource={data} onChange={onChange}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
.user-view-row {
|
||||
padding-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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': []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module.exports = {
|
||||
code: 0,
|
||||
messages: ["成功"],
|
||||
data: { uid: "1", role: "ADMIN", name: "admin" }
|
||||
};
|
||||
messages: ['成功'],
|
||||
data: { uid: '1', role: 'ADMIN', name: 'admin' }
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
478
docs/index.html
478
docs/index.html
|
@ -1,250 +1,250 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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
|
||||
name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
||||
/>
|
||||
<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" />
|
||||
<style>
|
||||
h1 + ul {
|
||||
display: block !important;
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Nginx Tutorial</title>
|
||||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/>
|
||||
<meta content="Nginx Tutorial" name="description"/>
|
||||
<meta
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
|
||||
name="viewport"
|
||||
/>
|
||||
<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;
|
||||
}
|
||||
|
||||
.content img,
|
||||
.sidebar img {
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 8px grey;
|
||||
}
|
||||
|
||||
.content,
|
||||
.sidebar,
|
||||
.sidebar-toggle,
|
||||
body,
|
||||
.search input {
|
||||
color: #6B615F !important;
|
||||
background-color: #FFF4E6 !important;
|
||||
}
|
||||
|
||||
.content strong,
|
||||
.sidebar strong,
|
||||
body strong {
|
||||
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);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-background-size: 200% 100%;
|
||||
-webkit-animation: masked-animation 1.5s infinite linear;
|
||||
font-family: "Brush Script MT", 隶书, serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.cover-main blockquote p {
|
||||
color: #5C5869;
|
||||
font-family: "Arial", 隶书, serif;
|
||||
}
|
||||
|
||||
.cover-main ul a:hover {
|
||||
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);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-background-size: 200% 100%;
|
||||
-webkit-animation: masked-animation 1.5s infinite linear;
|
||||
}
|
||||
|
||||
/* content 样式内容 */
|
||||
.sidebar a,
|
||||
.content a {
|
||||
color: #399AB2 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.sidebar a:hover,
|
||||
.content a:hover {
|
||||
color: #FE4165 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.content h1 :hover,
|
||||
.content h2 :hover,
|
||||
.content h3 :hover,
|
||||
.content h4 :hover {
|
||||
text-align: center;
|
||||
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%;
|
||||
-webkit-animation: masked-animation 1.5s infinite linear;
|
||||
font-family: "微软雅黑", serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@-webkit-keyframes masked-animation {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*.cover-main {*/
|
||||
/*text-shadow: 2px 2px 5px grey;*/
|
||||
/*}*/
|
||||
|
||||
.content h1 a,
|
||||
.content h1 span {
|
||||
color: #399AB2 !important;
|
||||
font-size: 30px;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
.content h2 a,
|
||||
.content h2 span {
|
||||
color: #60497C !important;
|
||||
font-size: 26px;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
.content h3 a,
|
||||
.content h3 span {
|
||||
color: #346093 !important;
|
||||
font-size: 22px;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
.content h4 a,
|
||||
.content h4 span {
|
||||
font-size: 18px;
|
||||
color: #78943A;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
img.emoji {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.content > p {
|
||||
font-size: 16px !important;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.content blockquote {
|
||||
display: block;
|
||||
padding: 0 16px;
|
||||
border-left: 8px solid #DDDFE4;
|
||||
background: #FFF2C9;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.content pre {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
border-radius: 8px;
|
||||
box-shadow: 1px 1px 20px 3px #DDDDDD !important;
|
||||
}
|
||||
|
||||
.content code {
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
box-shadow: 1px 1px 1px whitesmoke;
|
||||
}
|
||||
|
||||
.content table {
|
||||
display: table;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-shadow: 2px 2px 20px 6px #DDDDDD !important;
|
||||
}
|
||||
|
||||
.content th {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
background-color: #CCE6B6;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
@media (min-width: 600px) {
|
||||
.markdown-section pre > code {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.markdown-section pre > code {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.content img,
|
||||
.sidebar img {
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 8px grey;
|
||||
pre:after {
|
||||
content: "" !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content,
|
||||
.sidebar,
|
||||
.sidebar-toggle,
|
||||
body,
|
||||
.search input {
|
||||
color: #6b615f !important;
|
||||
background-color: #fff4e6 !important;
|
||||
@media (min-width: 600px) {
|
||||
pre code {
|
||||
padding-left: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content strong,
|
||||
.sidebar strong,
|
||||
body strong {
|
||||
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);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-background-size: 200% 100%;
|
||||
-webkit-animation: masked-animation 1.5s infinite linear;
|
||||
font-family: "Brush Script MT", 隶书, serif;
|
||||
font-weight: 600;
|
||||
@media (max-width: 600px) {
|
||||
pre {
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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',
|
||||
auto2top: true,
|
||||
coverpage: 'coverpage.md',
|
||||
maxLevel: 4,
|
||||
subMaxLevel: 4,
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
search: {
|
||||
maxAge: 86400000,
|
||||
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>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
|
||||
.cover-main blockquote p {
|
||||
color: #5c5869;
|
||||
font-family: "Arial", 隶书, serif;
|
||||
}
|
||||
|
||||
.cover-main ul a:hover {
|
||||
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);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-background-size: 200% 100%;
|
||||
-webkit-animation: masked-animation 1.5s infinite linear;
|
||||
}
|
||||
|
||||
/* content 样式内容 */
|
||||
.sidebar a,
|
||||
.content a {
|
||||
color: #399ab2 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.sidebar a:hover,
|
||||
.content a:hover {
|
||||
color: #fe4165 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.content h1 :hover,
|
||||
.content h2 :hover,
|
||||
.content h3 :hover,
|
||||
.content h4 :hover {
|
||||
text-align: center;
|
||||
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%;
|
||||
-webkit-animation: masked-animation 1.5s infinite linear;
|
||||
font-family: "微软雅黑", serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@-webkit-keyframes masked-animation {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*.cover-main {*/
|
||||
/*text-shadow: 2px 2px 5px grey;*/
|
||||
/*}*/
|
||||
|
||||
.content h1 a,
|
||||
.content h1 span {
|
||||
color: #399ab2 !important;
|
||||
font-size: 30px;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
.content h2 a,
|
||||
.content h2 span {
|
||||
color: #60497c !important;
|
||||
font-size: 26px;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
.content h3 a,
|
||||
.content h3 span {
|
||||
color: #346093 !important;
|
||||
font-size: 22px;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
.content h4 a,
|
||||
.content h4 span {
|
||||
font-size: 18px;
|
||||
color: #78943a;
|
||||
text-shadow: 2px 2px 5px grey;
|
||||
}
|
||||
|
||||
img.emoji {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.content > p {
|
||||
font-size: 16px !important;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.content blockquote {
|
||||
display: block;
|
||||
padding: 0 16px;
|
||||
border-left: 8px solid #dddfe4;
|
||||
background: #fff2c9;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.content pre {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
border-radius: 8px;
|
||||
box-shadow: 1px 1px 20px 3px #dddddd !important;
|
||||
}
|
||||
|
||||
.content code {
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
box-shadow: 1px 1px 1px whitesmoke;
|
||||
}
|
||||
|
||||
.content table {
|
||||
display: table;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-shadow: 2px 2px 20px 6px #dddddd !important;
|
||||
}
|
||||
|
||||
.content th {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
background-color: #cce6b6;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
@media (min-width: 600px) {
|
||||
.markdown-section pre > code {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.markdown-section pre > code {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
pre:after {
|
||||
content: "" !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
pre code {
|
||||
padding-left: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
pre {
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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",
|
||||
auto2top: true,
|
||||
coverpage: "coverpage.md",
|
||||
maxLevel: 4,
|
||||
subMaxLevel: 4,
|
||||
formatUpdated: "{MM}/{DD} {HH}:{mm}",
|
||||
search: {
|
||||
maxAge: 86400000,
|
||||
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>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||
|
||||
<!--代码高亮-->
|
||||
<!--@see https://github.com/PrismJS/prism/tree/gh-pages/components-->
|
||||
<script src="//unpkg.com/prismjs/components/prism-basic.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
|
||||
</body>
|
||||
<!--代码高亮-->
|
||||
<!--@see https://github.com/PrismJS/prism/tree/gh-pages/components-->
|
||||
<script src="//unpkg.com/prismjs/components/prism-basic.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue