Dva员工增删改查Demo实现

(Dva员工增删改查Demo实现&)

Dva员工增删改查Demo实现&

(demo-service&)

demo-service&

启动文件

package com.huawei;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@SpringBootApplication
@RestController
@MapperScan("com.huawei.**.mapper")
public class ServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

    @RequestMapping("/index")
    String index(){
    	return "Hello Basedata";
    }
}

application.yml

##数据源地址
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:postgresql://127.0.0.1:5432/postgres
    username: postgres
    password: 123456
    driverClassName: org.postgresql.Driver
    initialSize: 1
    maxActive: 20
    maxWait: 60000
  application:
    name: demo-service

##启用Mybatis
orm:
  mybatis:
    only: true

#mybatis
mybatis-plus:
  mapper-locations: classpath:/mapper/*.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.huawei.model
  global-config:
    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
    id-type: 2
    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
    field-strategy: 2
    #驼峰下划线转换
    db-column-underline: true
    #刷新mapper 调试神器
    refresh-mapper: true
    #数据库大写下划线转换
    #capital-mode: true
    #序列接口实现类配置
    #key-generator: com.baomidou.springboot.xxx
    #逻辑删除配置
    #logic-delete-value: 0
    #logic-not-delete-value: 1
    #自定义填充策略接口实现
    #meta-object-handler: com.baomidou.springboot.xxx
    #自定义SQL注入器
    #sql-injector: com.baomidou.springboot.xxx
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false

## 服务器端口,自行设置
server:
  port: 1111

## 服务注册中心地址
eureka:
  instance:
      status-page-url-path: /swagger-ui.html

## 日志
logging:
  config: classpath:logback.xml
  level:
    root: debug

platform:
  url: http://10.0.7.128:8080
##swagger配置
swagger:
  ##是否开启swagger文档
  enable: true
  ##网关
  host: 10.0.7.128:8080
  ##接口包(多个用,隔开)
  basePackage: com.huawei.controller
  ##文档标题
  title: 示例
  ##文档描述
  description: 变更管理的功能
  ##文档版本
  version: 1.0

springMVC配置文件

WebConfiguration
package com.huawei.common.util;

import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {

    @Bean
    public RemoteIpFilter remoteIpFilter(){
        return new RemoteIpFilter();
    }

    @Bean
    public CorsFilter corsFilter(){
        // SpringMvc 提供了 CorsFilter 过滤器

        // 初始化cors配置对象
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 允许跨域的域名,如果要携带cookie,不要写*,*:代表所有域名都可以跨域访问
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);  // 设置允许携带cookie
        corsConfiguration.addAllowedMethod("*"); // 代表所有的请求方法:GET POST PUT DELETE...
        corsConfiguration.addAllowedHeader("*"); // 允许携带任何头信息

        //初始化cors配置源对象
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);

        // 返回corsFilter实例,参数:cors配置源对象
        return new CorsFilter(corsConfigurationSource);
    }

    @Bean
    public FilterRegistrationBean testFilterRegistration(){
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*");
        registration.addInitParameter("paramName","paramValue");
        registration.setName("MyFilter");
        registration.setOrder(1);
        return registration;
    }

    public class MyFilter implements Filter{
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {

        }

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

            HttpServletResponse res = (HttpServletResponse) servletResponse;
            HttpServletRequest req = (HttpServletRequest) servletRequest;
            String origin = req.getHeader("Origin");
            if (!org.springframework.util.StringUtils.isEmpty(origin)) {
                //带cookie的时候,origin必须是全匹配,不能使用*
                res.addHeader("Access-Control-Allow-Origin", origin);
            }
            res.addHeader("Access-Control-Allow-Methods", "*");
            String headers = req.getHeader("Access-Control-Request-Headers");
            // 支持所有自定义头
            if (!org.springframework.util.StringUtils.isEmpty(headers)) {
                res.addHeader("Access-Control-Allow-Headers", headers);
            }
            res.addHeader("Access-Control-Max-Age", "3600");
            // enable cookie
            res.addHeader("Access-Control-Allow-Credentials", "true");
            filterChain.doFilter(req, res);
        }

        @Override
        public void destroy() {
            Map map = new HashMap();
        }
    }

}

分页工具类 PageUtil

package com.huawei.common.util;

import java.util.List;

public class PageUtil<T> {
    private int currentPageNum; //当前要看哪一页

    private int pageSize=10;//每页显示的条数

    private int totalSize;//总记录条数

    private int startIndex;//查询开始记录的索引 limit ? ?

    private int totalPageNum;//总页数

    private int prePageNum;//上一页

    private int nextPageNum;//下一页

    private List<T>  records;//当前页的记录集


    //用于显示页面上的导航的页号  用户可自定义

    private int startPageNum;

    private int endPageNum;

    private String url;


    //使用构造方法,传递必要的两个参数.第一个是页码,第二个总记录条数
    public PageUtil(int currentPageNum,int totalrecords)
    {
        this.currentPageNum=currentPageNum;
        this.totalSize=totalrecords;
        //计算开始记录索引
        startIndex=(currentPageNum-1)*pageSize;
        //计算总页数
        totalPageNum=totalSize%pageSize==0?totalSize/pageSize:totalSize/pageSize+1;
        //计算开始和结束页号  这个根据自身可设计
        if(totalPageNum>9)
        {
            startPageNum=currentPageNum-4;
            endPageNum=currentPageNum+4;

            if(startPageNum<1)
            {
                startPageNum=1;
                endPageNum=startPageNum+8;
            }
            if(endPageNum>totalPageNum)
            {
                endPageNum=totalPageNum;
                startPageNum=endPageNum-8;
            }

        }
        else
        {
            startPageNum=1;
            endPageNum=totalPageNum;

        }


    }


    public int getStartPageNum() {
        return startPageNum;
    }


    public void setStartPageNum(int startPageNum) {
        this.startPageNum = startPageNum;
    }


    public int getEndPageNum() {
        return endPageNum;
    }


    public void setEndPageNum(int endPageNum) {
        this.endPageNum = endPageNum;
    }


    public int getPrePageNum() {
        prePageNum=currentPageNum-1;

        if(prePageNum<=0)
        {
            prePageNum=1;
        }
        return prePageNum;
    }

    public int getNextPageNum() {

        nextPageNum=currentPageNum+1;

        if(nextPageNum>totalPageNum)
        {
            nextPageNum=totalPageNum;
        }
        return nextPageNum;
    }

    public int getCurrentPageNum() {
        return currentPageNum;
    }

    public void setCurrentPageNum(int currentPageNum) {
        this.currentPageNum = currentPageNum;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getTotalSize() {
        return totalSize;
    }

    public void setTotalSize(int totalSize) {
        this.totalSize = totalSize;
    }

    public int getStartIndex() {
        return startIndex;
    }

    public void setStartIndex(int startIndex) {
        this.startIndex = startIndex;
    }

    public int getTotalPageNum() {
        return totalPageNum;
    }

    public void setTotalPageNum(int totalPageNum) {
        this.totalPageNum = totalPageNum;
    }

    public List  getRecords() {
        return records;
    }

    public void setRecords(List records) {
        this.records = records;
    }

    public void setPrePageNum(int prePageNum) {
        this.prePageNum = prePageNum;
    }

    public void setNextPageNum(int nextPageNum) {
        this.nextPageNum = nextPageNum;
    }


    public String getUrl() {
        return url;
    }


    public void setUrl(String url) {
        this.url = url;
    }
}


项目结构

logback.xml 日志配置文件

<configuration>
    <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,,,, -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %p (%file:%line\)- %m%n</pattern>
            <charset>UTF8</charset>
        </encoder>
    </appender>
    <appender name="basedatalog"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>basedata_log/basedata.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>basedata_log/basedata.log.%d.%i</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>64 MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>
                %d %p (%file:%line\)- %m%n
            </pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>
    <logger name="com.szewec" level="DEBUG">
        <appender-ref ref="basedatalog"/>
    </logger>
</configuration>

控制层 Controller

package com.huawei.controller;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huawei.common.util.PageUtil;
import com.huawei.model.vo.PageBean;
import com.huawei.model.vo.Puser;
import com.huawei.service.PuserService;
import io.swagger.annotations.Api;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RestController
@EnableSwagger2
@Api("swaggerDemoController相关的api")
@RequestMapping("/api")
public class PuserController {

    @Resource
    private PuserService puserService;

    @RequestMapping("/users/test")
    public PageBean<Puser> getParamsTest(HttpServletRequest request) throws IOException {
        String field = request.getParameter("field");
        String keyword = request.getParameter("keyword");
        ObjectMapper mapper = new ObjectMapper();
        String s = "{\"total\":3,\"current\":1,\"list\":[{\"id\":1,\"name\":\"张三\",\"age\":23,\"sex\":\"女\",\"address\":\"成都\"},{\"id\":2,\"name\":\"李四\",\"age\":24,\"sex\":\"男\",\"address\":\"杭州\"},{\"id\":3,\"name\":\"王五\",\"age\":25,\"sex\":\"男\",\"address\":\"上海\"}]}";
        if(StringUtils.isNotBlank(field)){
             s = "{\"total\":3,\"current\":1,\"list\":[{\"id\":1,\"name\":\"张三111111\",\"age\":23,\"sex\":\"女\",\"address\":\"成都\"},{\"id\":2,\"name\":\"李四\",\"age\":24,\"sex\":\"男\",\"address\":\"杭州\"},{\"id\":3,\"name\":\"王五\",\"age\":25,\"sex\":\"男\",\"address\":\"上海\"}]}";
        }
        return mapper.readValue(s,new TypeReference<PageBean<Puser>>(){});
    }

    @RequestMapping("/users/query")
    public PageUtil<Puser> usersFuzzyQuery(HttpServletRequest request) {
        Puser puser = new Puser();
        String field = request.getParameter("field");
        String keyword = request.getParameter("keyword");
        String current = request.getParameter("current");
        if(StringUtils.isBlank(current)){
            current="1";
        }
        if(StringUtils.isNotBlank(field)&&StringUtils.isNotBlank(keyword)){
            if("name".equals(field)){
                puser.setName(keyword);
            }
            if("address".equals(field)){
                puser.setAddress(keyword);
            }
        }
        return puserService.usersFuzzyQuery(puser,Integer.valueOf(current));
    }

    @RequestMapping("/users/create")
    public PageUtil<Puser> createUser(@RequestBody Puser puser) {
        int fid = (int)((Math.random()*9+1)*100000);
        puser.setId(fid);
        puserService.addUsers(puser);
        return puserService.usersFuzzyQuery(new Puser(),1);
    }

    @RequestMapping("/users/update")
    public Integer updateUser(@RequestBody Puser puser) {
        System.out.println(puser);
        return puserService.updateUser(puser);
    }

    @RequestMapping("/users/delete/{ids}")
    public PageUtil<Puser> deleteUsers(@PathVariable("ids") String ids) {
       int deleteRows = -1;
        if(ids != null){
            if(ids.contains(",")){
                String[] arrayIds = ids.split(",");
                List<Integer> idList = new ArrayList<>();
                for(String id:arrayIds){
                    idList.add(Integer.valueOf(id));
                }
                deleteRows =  puserService.deleteBatchUsers(idList);
            }else{
                deleteRows = puserService.deleteUser(Integer.valueOf(ids));
            }
        }
        return puserService.usersFuzzyQuery(new Puser(),1);
    }
}

服务层Service

package com.huawei.service;

import com.huawei.common.util.PageUtil;
import com.huawei.model.vo.Puser;
import java.util.List;


public interface PuserService {
    //List<Puser> usersFuzzyQuery(Puser puser);
    PageUtil<Puser> usersFuzzyQuery(Puser puser, Integer current);
    void addUsers(Puser puser);
    Integer updateUser(Puser puser);
    Integer deleteUser(Integer id);
    Integer getTotalRecords(Puser puser);
    Integer deleteBatchUsers(List<Integer> idList);
}

服务实现层

package com.huawei.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.huawei.common.util.PageUtil;
import com.huawei.mapper.PuserMapper;
import com.huawei.model.vo.Puser;
import com.huawei.service.PuserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class PuserServiceImpl extends ServiceImpl<PuserMapper, Puser> implements PuserService {

    @Resource
    private PuserMapper puserMapper;

    @Override
    public PageUtil<Puser> usersFuzzyQuery(Puser puser, Integer currentPageNum) {
        int totalRecords=getTotalRecords(puser);
        PageUtil<Puser> pu= new PageUtil<>(currentPageNum, totalRecords);
        List<Puser> users= puserMapper.usersFuzzyQuery(puser,pu.getStartIndex());
        pu.setRecords(users);
        return pu;
    }

    @Override
    public void addUsers(Puser puser) {
        boolean result = this.insert(puser);
    }

    @Override
    public Integer updateUser(Puser puser) {
        return puserMapper.updateById(puser);
    }

    @Override
    public Integer deleteUser(Integer id) {
        return puserMapper.deleteById(id);
    }

    @Override
    public Integer getTotalRecords(Puser puser) {
        EntityWrapper<Puser> wrapper = new EntityWrapper<>();
        if(StringUtils.isNotBlank(puser.getName())){
            wrapper.like("name", puser.getName());
        }
        if(StringUtils.isNotBlank(puser.getAddress())){
            wrapper.like("address", puser.getAddress());
        }
        return puserMapper.selectCount(wrapper);
    }

    @Override
    public Integer deleteBatchUsers(List<Integer> idList) {
        return puserMapper.deleteBatchIds(idList);
    }
}

接口层Mapper

package com.huawei.mapper;

import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.huawei.model.vo.Puser;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface PuserMapper extends BaseMapper<Puser> {
    // 模糊查询
    List<Puser> usersFuzzyQuery(@Param("user") Puser puser,@Param("current") Integer current);
    void addUsers(Puser puser);
}

实体类

package com.huawei.model.vo;

import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;

import java.io.Serializable;

@TableName("p_user")
public class Puser implements Serializable {
    @TableId("fid")
    private Integer fid;
    private String name;
    private String sex;
    private Integer age;
    private String address;

    public Puser() {
    }

    public Puser(Integer fid, String name, String sex, Integer age, String address) {
        this.fid = fid;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public Integer getId() {
        return fid;
    }

    public String getSex() {
        return sex;
    }

    public Integer getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }

    public void setId(Integer fid) {
        this.fid = fid;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

PuserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huawei.mapper.PuserMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.huawei.model.vo.Puser">
        <id column="fid" property="fid" />
        <result column="name" property="name" />
        <result column="age" property="age" />
        <result column="sex" property="sex" />
        <result column="address" property="address" />
    </resultMap>

    <select id="usersFuzzyQuery" parameterType="map" resultMap="BaseResultMap">
        SELECT * FROM p_user where 1=1
        <if test='user.name!=null and user.name!=" "'>
            AND name like CONCAT('%',#{user.name},'%')
        </if>
        <if test='user.address!=null and user.address!=" "'>
            AND address like CONCAT('%',#{user.address},'%')
        </if>
        ORDER BY name
        <if test='current!=null'>
            limit 10 OFFSET #{current}
        </if>
    </select>

</mapper>

(demo-web&)

demo-web&

.roadhogrc配置文件

{
  "entry": "src/index.js",
  "theme": {
		"@icon-url": "'~antd-iconfont/iconfont'"
  },
  "proxy": {
    "/api": {
      "target": "http://localhost:1111/",
      "changeOrigin": true,
      "pathRewrite": { "^/api" : "" }
    }
  },
  "env": {
    "development": {
      "extraBabelPlugins": [
        "dva-hmr",
         ["module-resolver", {
            "alias": {
                "@": "./src"
            }
          }],
        "transform-runtime",
        ["import", {
            "libraryName": "antd",
            "libraryDirectory": "lib",
            "style": true
        }]
      ]
    },
    "production": {
      "extraBabelPlugins": [
        "transform-runtime",
		"dva-hmr",
		 ["module-resolver", {
			"alias": {
				"@": "./src"
			}
		  }],
         ["import", {
            "libraryName": "antd",
            "libraryDirectory": "lib",
            "style": true
        }]
      ]
    }
  }
}

package.json

{
  "private": true,
  "scripts": {
    "start": "set BROWSER=none&&set PORT=2222&&roadhog server",
    "build": "roadhog build"
  },
  "engines": {
    "install-node": "6.9.2"
  },
  "dependencies": {
    "antd": "^2.12.3",
    "antd-iconfont": "^2.10.0",
    "axios": "^0.16.2",
    "babel-plugin-import": "^1.3.1",
    "babel-runtime": "^6.9.2",
    "dva": "^1.2.1",
    "dva-loading": "^0.2.1",
    "jquery": "^3.2.1",
    "prop-types": "^15.5.10",
    "qs": "^6.5.0",
    "react": "^15.4.0",
    "react-dom": "^15.4.0",
    "underscore": "^1.8.3"
  },
  "devDependencies": {
    "babel-eslint": "^7.1.1",
    "babel-plugin-dva-hmr": "^0.3.2",
    "babel-plugin-transform-runtime": "^6.9.0",
    "babel-plugin-module-resolver": "^2.7.1",
    "eslint": "^3.12.2",
    "eslint-config-airbnb": "^13.0.0",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-jsx-a11y": "^2.2.3",
    "eslint-plugin-react": "^6.8.0",
    "expect": "^1.20.2",
    "husky": "^0.12.0",
    "redbox-react": "^1.3.2",
    "roadhog": "^0.5.2"
  },
  "proxy": {
    "/api": {
      "target": "http://localhost:1111/",
      "changeOrigin":true
    }
  }
}

router.js 路由文件

import React from 'react';
import PropTypes from 'prop-types';
import { Router } from 'dva/router';

const registerModel = (app, model) => {
  if (!(app._models.filter(m => m.namespace === model.namespace).length === 1)) {
    app.model(model);
  }
};

const RouterConfig = ({ history, app }) => {
  /**
   * 添加路由,path是请求路基,name是名称说明
   * */
  const routes = [
    {
      path: '/',
      name: 'welcome',
      getComponent(nextState, cb) {
        require.ensure([], (require) => {
          cb(null, require('./routes/indexPage/IndexPage'));
        });
      },
    },
    {
      path: '/users',
      name: 'users',
      getComponent(nextState, cb) {
        require.ensure([], (require) => {
          registerModel(app, require('./models/users'));
          cb(null, require('./routes/users/Users'));
        });
      },
    },
  ];
  return <Router history={history} routes={routes} />;
};

RouterConfig.propTypes = {
  history: PropTypes.object,
  app: PropTypes.object,
};

export default RouterConfig;

index.js 入口文件

import dva from 'dva';
import { browserHistory } from 'dva/router';
import createLoading from 'dva-loading';
// 1. Initialize
const app = dva({
 history:browserHistory
});

// 2. Plugins
app.use(createLoading());

// 3. Model
//app.model(require('./models/users/users'));

// 4. Router
app.router(require('./router'));

// 5. Start
app.start('#root');

index.less


html, body, :global(#root) {
  height: 100%;
  padding:0;
  margin:0;
}

项目结构

src/utils/request.js

import fetch from 'dva/fetch';

function parseJSON(response) {
  return response.json();
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  const error = new Error(response.statusText);
  error.response = response;
  throw error;
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default function request(url, options) {
  const defaultOptions = {
    mode: 'cors',
  };
  const mergeOptions = {
    ...options,
    ...defaultOptions
  };
  return fetch(url, mergeOptions)
    .then(checkStatus)
    .then(parseJSON)
    .then((data) => ({ data }))
    .catch((err) => ({ err }));
}

src/utils/commonConstant.js

export const url = "http://127.0.0.1:1111/api";

src/services/users.js

import request from '../utils/request';
import qs from 'qs';
import {url} from '../utils/commonConstant';

export async function query(params) {
  if(JSON.stringify(params) == "{}"){
    return request(`${url}/users/query`);
  }
  return request(`${url}/users/query?${qs.stringify(params)}`);
}

export async function create(params) {
  return request(`${url}/users/create`, {
    method: 'post',
    headers: {
      'Content-Type': 'application/json; charset=utf-8'
    },
    body: JSON.stringify(params),
  });
}

export async function remove(params) {
  return request(`${url}/users/delete/${params.id}`, {
    method: 'delete',
    body: qs.stringify(params),
  });
}

export async function update(params) {
  return request(`${url}/users/update`, {
    method: 'put',
    headers: {
      'Content-Type': 'application/json; charset=utf-8'
    },
    body: JSON.stringify(params),
  });
}

src/routes/users/Users.jsx

import UserList from '../../components/users/UserList';
import UserSearch from '../../components/users/UserSearch';
import UserModal from '../../components/users/UserModal';
import PropTypes from 'prop-types'
import styles from './Users.less';
import { connect } from 'dva';
import React, { useEffect } from 'react'
import { routerRedux } from 'dva/router';
import { notification ,Modal, message} from 'antd';

function Users({ location, dispatch,users }) {
  const {
    loading, list, total, current,field, keyword,
    currentItem, modalVisible, modalType,pagination,
    selectedRowKeys,selectedRows
    } = users;

  const userSearchProps = {
    field,
    keyword,
    onAdd() {
      dispatch({
        type: 'users/showModal',
        payload: {
          modalType: 'create',
          currentItem : {}
        },
      });
    },
    onDelete() {
        const ids = selectedRowKeys.join(',');
        if(selectedRowKeys.length===0){
          notification['warning']({
            message:'提示!',
            description:'请选择要删除的数据。'
        });
        }else{
          Modal.confirm({
            title:'删除提示',
            content: `您确定要删除这些数据吗?`,
            onOk:()=>{
              dispatch({
                type: 'users/delete',
                payload: ids,
              });
                message.success('删除成功'); 
              dispatch(routerRedux.push({
                  pathname: '/users'
              }))
            },
        })
        }
    },
    onSearch(fieldsValue) {
      dispatch({
        type: 'users/query',
        payload: fieldsValue,
      });
    },
  };

  const userListProps={
		dataSource: list,
		total,
		loading,
    current,
    pagination,
    selectedRowKeys,
    selectedRows,
    onPageChange(page) {
      dispatch(routerRedux.push({
        pathname: '/users',
        query: { field, keyword, current:page.current },
      }));
    },
    onDeleteItem(id) {
      dispatch({
        type: 'users/delete',
        payload: id,
      });
    },
    onEditItem(item) {
      dispatch({
        type: 'users/showModal',
        payload: {
          modalType: 'update',
          currentItem: item,
        },
      });
    },
    onSelectedRowKeys(selectedRowKeys,selectedRows){
      dispatch({
        type: 'users/selectRows',
        payload: {
          selectedRowKeys,
          selectedRows,
        },
      });
    }
  };
  
  const userModalProps = {
    item: modalType === 'create' ? {} : currentItem,
    type: modalType,
    visible: modalVisible,
    onOk(data) {
      dispatch({
        type: `users/${modalType}`,
        payload: data,
      });
    },
    onCancel() {
      dispatch({
        type: 'users/hideModal',
      });
    },
    afterClose(){
      dispatch(routerRedux.push({
        pathname: '/users',
        query: { field, keyword, current:current},
     }));
    }
  };

  //useEffect(() => { getUsers },[])
  return (
    <div className={styles.normal}>
      {/* 用户筛选搜索框 */}
      <UserSearch {...userSearchProps} />
      {/* 用户信息展示列表 */}
      <UserList {...userListProps} />
      {/* 添加用户 & 修改用户弹出的浮层 */}
      <UserModal {...userModalProps} />
    </div>
  );
}

Users.propTypes = {
  users: PropTypes.object,
  location: PropTypes.object,
  dispatch: PropTypes.func,
};

const mapStateToProps = ({users})=>{
  return {users};
}

//const mapDispatchToProps = (dispatch)=>{
//  return {
//    getUsers : ()=>{
//      dispatch({
//      type : "users/querySuccess",
//      payload : {}
//      });
//      return {
//        type : "users/querySuccess",
//        payload : {}
//      }
//    }
//  }
//}

export default connect(mapStateToProps)(Users);

src/routes/users/Users.less

.normal {
    width: 1200px;
    margin: 20px auto;
  }
  

src/routes/indexPage/IndexPage.js

import React from 'react';
import { connect } from 'dva';
import styles from './index.less'
import Welcome from '../../components/welcome/Welcome'


class IndexPage extends React.Component {
  constructor(props) {
    super(props);
  }
  render(){

    return (
      <div className={styles.main}>
        <Welcome />
      </div>
    );
  }
}

function mapStateToProps({  }) {
  return {  };
}
export default connect(mapStateToProps)(IndexPage);
//export default Database;

src/routes/indexPage/Index.less

.main{
    width:100%;
    height:100%;
}

src/models/users.js

import { create, remove, update, query } from '../services/users';
import { parse } from 'qs';
import Utils from '../utils/utils'

export default {
    namespace: 'users',
    state: {
      list: [],
      total: null, 
      field: '', // 搜索框字段
      keyword: '', // 搜索框输入的关键字
      loading: false, // 控制加载状态
      current: 1, // 当前分页信息
      currentItem: {}, // 当前操作的用户对象
      modalVisible: false, // 弹出窗的显示状态
      modalType: 'create', // 弹出窗的类型(添加用户,编辑用户)
      pagination:{},        //分页
      selectedRowKeys:[],  //选择行的id
      selectedRows:null,   //选择的行
    },
      effects: {
        *query({ payload }, { call, put }) {
            yield put({ type: 'showLoading' });
            yield put({ type: 'updateQueryKey', payload});
            const { data } = yield call(query, parse(payload));
            if (data) {
              yield put({
                type: 'querySuccess',
                payload: {
                  list: data.records,
                  total: data.totalSize,
                  current: data.currentPageNum,
                  pagination:Utils.pagination(data)
                },
              });
            }
          },
          *create({ payload }, { call, put }) {
            yield put({ type: 'hideModal' });
            yield put({ type: 'showLoading' });
            const { data } = yield call(create, payload);
            if (data) {
              yield put({
                type: 'createSuccess',
                payload: {
                  field: '',
                  keyword: '',
                },
              });
            }
          },
          *'delete'({ payload }, { call, put }) {
            yield put({ type: 'showLoading' });
            const { data } = yield call(remove, { id: payload });
            if (data) {
              yield put({
                type: 'deleteSuccess',
                payload: {
                  list: data.records,
                  total: data.totalSize,
                  current: data.currentPageNum,
                  pagination:Utils.pagination(data),
                  field: '',
                  keyword: '',
                },
              });
            }
          },
          *update({ payload }, { select, call, put }) {
            yield put({ type: 'hideModal' });
            yield put({ type: 'showLoading' });
            const id = yield select(({ users }) => users.currentItem.id);
            const newUser = { ...payload, id };
            const { data } = yield call(update, newUser);
            if (data ) {
              yield put({
                type: 'updateSuccess',
                payload: newUser,
              });
            }
          },
      },
      subscriptions: {
        setup({ dispatch, history }) {
          history.listen(location => {
            if (location.pathname === '/users') {
              dispatch({
                type: 'query',
                payload: location.query
              });
            }
          });
        },
      },
      reducers: {
          showLoading(state) {// 控制加载状态的 reducer
            return { ...state, loading: true };
          }, 
          showModal(state, action) {// 控制 Modal 显示状态的 reducer
            return { ...state, ...action.payload, modalVisible: true };
          },
          hideModal(state) {
            return { ...state, modalVisible: false };
          },
          querySuccess(state, action){
              return {...state, ...action.payload, loading: false};              
          },
          createSuccess(state, action) {
            return { ...state, ...action.payload, loading: false };
          },
          deleteSuccess(state, action) {
            {/*let id = action.payload+"";
            const idArray = id.split(",");
            const newList = state.list.filter(user => !idArray.includes(`${user.id}`));
            const totalSize = state.total-idArray.length;
            const data = {currentPageNum:state.current,pageSize:10,totalSize:totalSize}
            return { ...state, list: newList, loading: false, pagination:Utils.pagination(data)};
             */}
             return { ...state, ...action.payload, loading: false };
          },
          updateSuccess(state, action) {
            const updateUser = action.payload;
            const newList = state.list.map(user => {
              if (user.id === updateUser.id) {
                return { ...user, ...updateUser };
              }
              return user;
            });
            return { ...state, list: newList, loading: false,currentItem: {} };
          },
          updateQueryKey(state, action) {
            return { ...state, ...action.payload };
          },
          selectRows(state, action) {
            return { ...state, ...action.payload };
          }
      }
  }

src/models/global.js

import {getMenuTreeList, getOrgList} from '@/services/global';
import { getCookie, setCookie, clearCookie } from '@/utils';
import { routerRedux } from 'dva/router';
import * as CONFIG from '@/config/commonConfig';
export default {
    namespace: 'global',
    state: {
        token:'',
        userInfo:{},
        isCollapseSider: false,
        menuList: [],
        activeSubmenu: [],
        activeChildrenMenu:[],
        orgList:[],
        iframeActiveRoute:{},
        iframeRouteList:[]
    },
    subscriptions: {
        //路由监听
        //eslint-disable-line
        getGlobalData(e) {
            const {dispatch ,history} =e;
            // var _token = !!localStorage && localStorage.token || '';
            // var _userInfo = !!localStorage && !!localStorage.userInfo && JSON.parse(localStorage.userInfo) || {};
            dispatch({type:'getToken', params:{token:window.__TOKEN___}});
            dispatch({type:'getUserInfo', params:{userInfo:window.__USERINFO__}});
            // window.__TOKEN___ && dispatch({type:'getMenuTreeList', params:{expandAll:'true'}});
            // window.__USERINFO__ && dispatch({type:'getOrgList', params:{}});
            //侧边菜单默认使用cookie保存的值
            dispatch({type:'toggleSider', params:{isCollapseSider:!!Number(getCookie('isCollapseSider'))}});
        },
        //全局路由权限控制
        limitRouterController({dispatch, history}){
            return history.listen(({pathname}) => {
            	console.log(CONFIG)
                CONFIG.LIMIT_ROUTES.map(item=>{
                    if(pathname.indexOf(item) >=0){
                        dispatch({type:'limitRouterController'});
                    }
                });
            });
        },
        //登录之后,无法走登录和注册页面
        signRouterController({dispatch, history}){
            return history.listen(({pathname}) => {
                CONFIG.AFTER_SIGNIN_LIMIT_ROUTES.map(item=>{
                    if(pathname.indexOf(item) >=0){
                        dispatch({type:'signRouterController'});
                    }
                });
            });
        },
        //如果路由不在menuList内,就重置二级和三级菜单的激活状态
        onRouteChange({dispatch, history}){
            return history.listen(({pathname})=>{
                let menuList = window.app._store.getState().global.menuList;
                let b = true;
                let recursive = list=>list.map(item=>{
                    if(item.route == pathname){
                        b = false;
                    }
                    if(item.children && !!item.children.length){
                        recursive(item.children);
                    }
                });
                recursive(menuList);
                b && dispatch({type:'resetActiveSubmenu'});
            });
        }
    },
    effects: {
        //组织列表
        * getOrgList({params}, {call, put}){
            let data = yield call(getOrgList, params);
            yield put({type: 'setOrgList', payload:{orgList:data.result}});
        },
        //侧边栏收展
        * toggleSider({params}, {call,put}) { // eslint-disable-line
            clearCookie('isCollapseSider');
            setCookie('isCollapseSider', Number(params.isCollapseSider), 1000);
            yield put({type: 'setCollapseState',payload: {isCollapseSider: params.isCollapseSider}});
        },
        //获取属性菜单
        * getMenuTreeList({params}, {call,put, select}) { // eslint-disable-line
            var data = yield call(getMenuTreeList, params);

            //递归树形结构,给每个节点添加isActive, label, value, key属性, 并优先使用cookie的记录激活相应菜单
            var defaultActiveSubMenuIndex = 0;
            var recursive = loopData=>{
                for(var i=0; i<loopData.length; i++){
                    loopData[i].isActive = false;
                    loopData[i].label = loopData[i].name;
                    loopData[i].value = loopData[i].id;
                    loopData[i].key = loopData[i].id;
                    //使用cookie设置默认头部菜单
                    if(!!getCookie('menuActiveItemRoute') && (loopData[i].route == getCookie('menuActiveItemRoute'))){
                        defaultActiveSubMenuIndex = i;
                        loopData[i].isActive = true;
                    }
                    if(loopData[i].children){
                        recursive(loopData[i].children);
                    }
                }
                return loopData;
            }
            data.result = recursive(data.result);
            yield put({type: 'setMenuList',payload: {menuList: data.result}});
            let _activeSubmenu = !!data.result.length && !!data.result.slice(defaultActiveSubMenuIndex, (defaultActiveSubMenuIndex+1)).length && data.result.slice(defaultActiveSubMenuIndex, (defaultActiveSubMenuIndex+1))[0].children || [];
            let _activeChildrenMenu = [];
            //根据路由匹配激活二级菜单的激活状态,并获取相应三级菜单列表
            const currentPathname = yield select(state=> state.routing.locationBeforeTransitions.pathname);
            _activeSubmenu = _activeSubmenu.map(item=>{
                item.isActive = false;
                if(currentPathname.indexOf(item.route) >= 0){
                    item.isActive = true;
                    _activeChildrenMenu = item.children;
                }
                return item;
            });
            yield put({type: 'setActiveSubmenu', payload: {activeSubmenu: _activeSubmenu}});
            yield put({type: 'setActiveChildrenMenu', payload:{activeChildrenMenu:_activeChildrenMenu}});
            //如果激活的二级菜单数组为空,则关闭侧边栏
            !_activeSubmenu.length == 0 ? (yield put({type: 'setCollapseState',payload: {isCollapseSider: false}})) : (yield put({type: 'setCollapseState',payload: {isCollapseSider: true}}));
        },
        //获取展开的二级菜单
        * getActiveSubmenu({ params}, {call, put, select}) { // eslint-disable-line
            //点击头部一级菜单后,需要切换当前状态,并设置相应的二级菜单列表
            let menuList = yield select(state=>state.global.menuList);
            menuList.map(item=>{
                item.isActive = false;
            });
            let newItem = params.item;
            //保存一级菜单索引
            clearCookie('menuActiveItemRoute');
            setCookie('menuActiveItemRoute', newItem.route, 1000);
            newItem.isActive = !newItem.isActive;
            menuList.splice(menuList.indexOf(params.item), 1, newItem)

            //根据路由匹配设置展开的二级级菜单的激活状态,并获取相应三级菜单列表
            const currentPathname = yield select(state=>state.routing.locationBeforeTransitions.pathname);
            let _activeSubmenu = [];
            let _activeChildrenMenu = [];
            _activeSubmenu = params.activeSubmenu.map(item=>{
                item.isActive = false;
                if(currentPathname.indexOf(item.route) >= 0){
                    item.isActive = true;
                    _activeChildrenMenu = item.children;
                }
                return item;
            });

            yield put({type: 'setActiveSubmenu', payload: {activeSubmenu: _activeSubmenu, menuList:menuList} });
            yield put({type: 'setActiveChildrenMenu', payload:{activeChildrenMenu:_activeChildrenMenu}})
            //如果激活的子节点数组为空,关闭侧边栏
            !params.activeSubmenu.length == 0 ? (yield put({type: 'setCollapseState',payload: {isCollapseSider: false}})) : (yield put({type: 'setCollapseState',payload: {isCollapseSider: true}}));
        },
        //获取展开的三级菜单
        * getActiveChildrenMenu({ params }, {call, put, select}) { // eslint-disable-line
            let activeSubmenu = yield select(state=>state.global.activeSubmenu);
            let _activeChildrenMenu = [];
            let newActiveSubmenuItem = params.activeSubmenuItem;
            activeSubmenu.map(item=>{
                item.isActive = false;
                item.route == params.activeSubmenuKey && !!item.children.length &&  (_activeChildrenMenu = item.children);
                return item;
            });

            newActiveSubmenuItem.isActive = true;
            activeSubmenu.splice(activeSubmenu.indexOf(params.activeSubmenuItem), 1, newActiveSubmenuItem);
            yield put({type: 'setActiveSubmenu', payload: {activeSubmenu: activeSubmenu}});
            yield put({type:'setActiveChildrenMenu', payload:{activeChildrenMenu:_activeChildrenMenu}})
        },
        //获取激活的路由视图
        * getActiveRoute({ params }, { call, put, select }){
            let { iframeActiveRoute, iframeRouteList } = yield select(state=>state.global);
            let _iframeActiveRoute = params.iframeActiveRoute;
            if(_iframeActiveRoute == iframeActiveRoute ) return;
            for(var i=0; i<iframeRouteList.length; i++){
                if(iframeRouteList[i].route == _iframeActiveRoute.route){
                    return yield put({type:'setActiveIframeRoute', payload:{iframeActiveRoute:_iframeActiveRoute}});
                }
            }
            iframeRouteList.push(params.iframeActiveRoute);
            yield put({type:'setActiveIframeRoute', payload:{iframeActiveRoute:_iframeActiveRoute, iframeRouteList}})

        },
        //获取token
        * getToken({ params}, {call, put}) { // eslint-disable-line
            yield put({type: 'setToken', payload: {token: params.token}});
            // localStorage && (localStorage.token = params.token);
        },
        //获取用户信息
        * getUserInfo({params}, {call, put}){
            // localStorage && (localStorage.userInfo = JSON.stringify(params.userInfo));
            yield put({type:'setUserInfo', payload:{userInfo:params.userInfo}});
        },
        //用户请求无权限
        * getUngrantInfo({ params }, {call, put, select}){
            // localStorage.token && delete localStorage.token;
            // localStorage.userInfo && delete localStorage.userInfo;
            // yield put({type:'setToken', payload:{token:''}});
            // yield put({type:'setUserInfo', payload:{userInfo:{}}});
            // yield put(routerRedux.push('/signin'));
        },
        //全局路由控制
        * limitRouterController({ params }, {call, put, select}){
            // let _token = (yield select(state=>state.global.token)) || localStorage.token || '';
            let _token = (yield select(state=>state.global.token));
            !_token && (yield put(routerRedux.push('/ungrant')));
        },
        //登录后路由控制
        * signRouterController({ params }, {call, put, select}){
            // let _token = (yield select(state=>state.global.token)) || localStorage.token || '';
            let _token = (yield select(state=>state.global.token));
            !!_token && (yield put(routerRedux.push('/')));
        },
        //如果不是菜单里面的路由,主要针对个人中心,重置二级三级菜单
        * resetActiveSubmenu({ param }, {call, put, select}){
            let _activeSubmenu = yield select(state=>state.global.activeSubmenu);
            _activeSubmenu.map(item=>{
                return item.isActive = false;
            });
            yield put({type:'setActiveSubmenu', payload:{activeSubmenu:_activeSubmenu}});
            yield put({type:'setActiveChildrenMenu', payload:{activeChildrenMenu:[]}});
        },
        // 操作bim
        * handleBim({ params }, {call, put, select}){
          let {type, data} = params;
          let _message = {
            isHandleBim:true,
            type,
            data
          }
          window.parent.postMessage(JSON.stringify(_message), '*');
        }
    },

    reducers: {
        setOrgList(state, action){
            return{
                ...state,
                ...action.payload
            }
        },
        setCollapseState(state, action) {
            return {
                ...state,
                ...action.payload
            };
        },
        setActiveSubmenu(state, action) {
            return {
                ...state,
                ...action.payload
            };
        },
        setActiveChildrenMenu(state, action) {
            return {
                ...state,
                ...action.payload
            };
        },
        setMenuList(state, action){
            return{
                ...state,
                ...action.payload
            }
        },
        setActiveIframeRoute(state, action){
            return{
                ...state,
                ...action.payload
            }
        },
        setToken(state, action){
            return{
                ...state,
                ...action.payload
            }
        },
        setUserInfo(state, action){
            return{
                ...state,
                ...action.payload
            }
        }
    }

};

src/config/commonConfig.js

const API = 'http://localhost:1111';
const config = {
    name: '三维BIM协同管理平台',
    prefix: 'bim',
    footerText: '三维BIM协同管理平台 © 2017 create by szewec',
    PAGE_SIZE: 5,
};
export default config;

src/components/welcome/Welcome.js

import React from 'react';
import { Form, Modal, Button, Row, Col, Input, Select, Table, Icon, Tooltip, Pagination } from 'antd';
import logo from '../../assets/logo_sgs1.png'
import styles from './index.less'
/**
 * demo首页
 */
class Welcome extends React.Component{
  constructor(){
    super();

  }

  render(){

    return (
      <div className={styles.main}>
        <div className={styles.main_box}>
          <img src={logo}/>
          <p>欢迎加入深圳高速工程顾问有限公司</p>
        </div>
      </div>
    )
  }
}
export default Welcome;

src/components/welcome/inedx.less

.main{
    width:100%;
    height:100%;
    display: flex;
    justify-content: center;
    align-items: center;
    .main_box{
        display:flex;
        flex-direction:column;
        align-items: center;
        justify-content: center;
        img{
            display: inline-block;
            width:150px;
            height:150px;
        }
        p{
            margin-top:15px;
            font-size: 30px;
            font-style: italic;
            font-family: monospace;
            font-weight: 900;
        }
    }
}

src/components/users/UserList.jsx

// ./src/components/Users/UserList.jsx
import React, { Component, PropTypes } from 'react';
// 采用antd的UI组件
import { Table, message, Popconfirm, Pagination } from 'antd';
import styles from './UserList.less';

// 采用 stateless 的写法
const UserList = ({
    total,
    current,
    loading,
    dataSource,
    onPageChange,
    onDeleteItem,
    onEditItem,
    pagination,
    onSelectedRowKeys,
    selectedRowKeys,
}) => {
  const columns = [{
    title: '姓名',
    dataIndex: 'name',
    key: 'name',
    render: (text) => <a href="#">{text}</a>,
  }, {
    title: '年龄',
    dataIndex: 'age',
    key: 'age', 
  }, {
    title: '性别',
    dataIndex: 'sex',
    key: 'sex', 
    render(sex){
      return sex ==1 ?'男':'女'
    },
  }, {
    title: '住址',
    dataIndex: 'address',
    key: 'address',
  }, {
    title: '操作',
    key: 'operation',
    render: (text, record) => (
      <p>
        <a onClick={()=>{onEditItem(record)}} >编辑</a>
        &nbsp;
        <Popconfirm title="确定要删除吗?" onConfirm={() => onDeleteItem(record.id)}>
          <a>删除</a>
        </Popconfirm>
      </p>
    ),
  }];

	// 定义分页对象
  {/*const pagination = {
    total,
    current,
    pageSize: 10,
    onChange: ()=>{},
  };*/}
  //多选框
  const rowCheckSelection = {
    type: 'checkbox',
    selectedRowKeys,
    onChange:onSelectedRowKeys
  }
  return (
    <div className={styles.standardTable}>
      <Table
        bordered
        columns={columns}
        dataSource={dataSource}
        loading={loading}
        rowKey={record => record.id}
        pagination={pagination}
        onChange={onPageChange}
        rowSelection={rowCheckSelection}
      />
      {/*<Pagination
        className="ant-table-pagination"
        total={total}
        current={current}
        pageSize={10}
        onChange={onPageChange}
      /> */}
    </div>
  );
}
export default UserList;

src/components/users/UserList.less

.column-left{
    text-align: left;
  }
.column-right{
    text-align: right;
 }
 .columnCell{
    display: table-cell;
    vertical-align: middle;
 }

.standardTable {

   :global {
   
   .ant-table-thead > tr > th > {
   
   text-align: center;
   
   }
   
   .ant-table-tbody > tr > td {
   
   text-align: center;
   
   }
}
}

src/components/users/UserModal.jsx

import React, { PropTypes } from 'react';
import { Form, Input, Modal, Icon, InputNumber,Radio } from 'antd';
const FormItem = Form.Item;
const RadioGroup = Radio.Group;

const formItemLayout = {
  labelCol: {
    span: 6,
  },
  wrapperCol: {
    span: 6,
  }
};
const formItemAddressLayout = {
  labelCol: {
    span: 6,
  },
  wrapperCol: {
    span: 14,
  }
};

const UserModal = ({
  visible,
  item = item || {},
  onOk,
  onCancel,
  afterClose,
  form: {
    getFieldDecorator,
    validateFields,
    getFieldsValue,
    },
  }) => {
  function handleOk() {
    validateFields((errors) => {
      if (errors) {
        return;
      }
      const data = { ...getFieldsValue(), id: item.id };
      onOk(data);
    });
  }

  function checkNumber(rule, value, callback) {
    if (!value) {
      callback(new Error('年龄必须填写!'));
    }
    if (!/^[\d]{1,2}$/.test(value)) {
      callback(new Error('请输入合法年龄!'));
    } else {
      callback();
    }
  }

  const modalOpts = {
    visible,
    onOk: handleOk,
    onCancel,
    afterClose
  };

  return (

    <Modal {...modalOpts} title={item.id ? '修改用户' : '添加用户'}>
      <Form horizontal>
        <FormItem
          label="姓名:"
          hasFeedback
          {...formItemLayout}
        >
          {getFieldDecorator('name', {
            initialValue: item.name,
            rules: [
              { required: true, message: '姓名必须填写!' }
            ],
          })(
            <Input type="text" prefix={<Icon type="user"/>} placeholder="请输入用户名" />
          )}
        </FormItem>
        <FormItem
          label="年龄:"
          hasFeedback
          {...formItemLayout}
        >
          {getFieldDecorator('age', {
            initialValue: item.age,
            rules: [
              { validator: checkNumber },{ required: true, message: '年龄必须填写!' }
            ],
          })(
            <InputNumber />
          )}
        </FormItem>
        <FormItem
          label="性别:"
          hasFeedback
          {...formItemLayout}
        >
          {getFieldDecorator('sex', {
            initialValue: item.sex,
            rules: [
            { required: true, message: '性别必须填写!' },
            ],
          })(
            <RadioGroup>
                <Radio value="1">男</Radio>
                <Radio value="2">女</Radio>
            </RadioGroup>
          )}
        </FormItem>
        <FormItem
          label="住址:"
          hasFeedback
          {...formItemAddressLayout}
        >
          {getFieldDecorator('address', {
            initialValue: item.address,
            rules: [
              { required: true, message: '住址必须填写!' },
            ],
          })(
            <Input type="address" />
          )}
        </FormItem>
      </Form>
    </Modal>
  );
};

UserModal.propTypes = {
  visible: PropTypes.any,
  form: PropTypes.object,
  item: PropTypes.object,
  onOk: PropTypes.func,
  onCancel: PropTypes.func,
};

export default Form.create({
  mapPropsToFields(props) {
    if (props.type==='create') {
      return {
        name: {},
        age: {},
        sex: {},
        address: {}
      }
    }
    return {
      name: {...props.item.name},
      age: {...props.item.age},
      sex: {...props.item.sex},
      address: {...props.item.address}
    }
  }
})(UserModal);


src/components/users/UserSearch.jsx

import React, { PropTypes } from 'react';
import { Form, Input, Button, Select} from 'antd';
import styles from './UserSearch.less';

const UserSearch = ({
  field, keyword,
  onSearch,
  onAdd,
  onDelete,
  form: {
    getFieldDecorator,
    validateFields,
    getFieldsValue,
    },
  }) => {
  function handleSubmit(e) {
    e.preventDefault();
    validateFields((errors) => {
      if (!!errors) {
        return;
      }
      onSearch(getFieldsValue());
    });
  }

  return (
    <div className={styles.normal}>
      <div className={styles.search}>
        <Form inline onSubmit={handleSubmit}>
          <Form.Item>
            {getFieldDecorator('field', {
              initialValue: field || 'name',
            })(
              <Select>
                <Select.Option value="name">姓名 &nbsp; </Select.Option>
                <Select.Option value="address">住址 &nbsp; </Select.Option>
              </Select>
            )}
          </Form.Item>
          <Form.Item
            hasFeedback
          >
            {getFieldDecorator('keyword', {
              initialValue: keyword || '',
            })(
              <Input type="text" />
            )}
          </Form.Item>
          <Button style={{ marginRight: '10px' }} type="primary" htmlType="submit">搜索</Button>
        </Form>
      </div>
      <div className={styles.create}>
        <Button type="ghost" onClick={onAdd}>Add</Button>
        <Button type="ghost" onClick={onDelete}>Delete</Button>
      </div>
    </div>
  );
};

UserSearch.propTypes = {
  form: PropTypes.object.isRequired,
  onSearch: PropTypes.func,
  onAdd: PropTypes.func,
  field: PropTypes.string,
  keyword: PropTypes.string,
};

export default Form.create()(UserSearch);

src/components/users/UserSearch.less


.normal {
  display: flex;
  margin-bottom: 20px;
}

.search {
  flex: 1;
}


 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页