(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 {
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 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(startPageNumtotalPageNum)
{
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(prePageNumtotalPageNum)
{
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 日志配置文件
%d %p (%file:%line\)- %m%n
UTF8
basedata_log/basedata.log
basedata_log/basedata.log.%d.%i
64 MB
%d %p (%file:%line\)- %m%n
UTF-8
控制层 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 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(){});
}
@RequestMapping("/users/query")
public PageUtil 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 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 deleteUsers(@PathVariable("ids") String ids) {
int deleteRows = -1;
if(ids != null){
if(ids.contains(",")){
String[] arrayIds = ids.split(",");
List 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 usersFuzzyQuery(Puser puser);
PageUtil usersFuzzyQuery(Puser puser, Integer current);
void addUsers(Puser puser);
Integer updateUser(Puser puser);
Integer deleteUser(Integer id);
Integer getTotalRecords(Puser puser);
Integer deleteBatchUsers(List 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 implements PuserService {
@Resource
private PuserMapper puserMapper;
@Override
public PageUtil usersFuzzyQuery(Puser puser, Integer currentPageNum) {
int totalRecords=getTotalRecords(puser);
PageUtil pu= new PageUtil(currentPageNum, totalRecords);
List 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 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 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 {
// 模糊查询
List 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
SELECT * FROM p_user where 1=1
AND name like CONCAT('%',#{user.name},'%')
AND address like CONCAT('%',#{user.address},'%')
ORDER BY name
limit 10 OFFSET #{current}
(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 ;
};
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 (
{/* 用户筛选搜索框 */}
{/* 用户信息展示列表 */}
{/* 添加用户 & 修改用户弹出的浮层 */}
);
}
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 (
);
}
}
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 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; istate.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 (
欢迎加入深圳高速工程顾问有限公司
)
}
}
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) => {text},
}, {
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) => (
{onEditItem(record)}} >编辑
onDeleteItem(record.id)}>
删除
),
}];
// 定义分页对象
{/*const pagination = {
total,
current,
pageSize: 10,
onChange: ()=>{},
};*/}
//多选框
const rowCheckSelection = {
type: 'checkbox',
selectedRowKeys,
onChange:onSelectedRowKeys
}
return (
record.id}
pagination={pagination}
onChange={onPageChange}
rowSelection={rowCheckSelection}
/>
{/* */}
);
}
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 (
{getFieldDecorator('name', {
initialValue: item.name,
rules: [
{ required: true, message: '姓名必须填写!' }
],
})(
)}
{getFieldDecorator('age', {
initialValue: item.age,
rules: [
{ validator: checkNumber },{ required: true, message: '年龄必须填写!' }
],
})(
)}
{getFieldDecorator('sex', {
initialValue: item.sex,
rules: [
{ required: true, message: '性别必须填写!' },
],
})(
男
女
)}
{getFieldDecorator('address', {
initialValue: item.address,
rules: [
{ required: true, message: '住址必须填写!' },
],
})(
)}
);
};
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 (
{getFieldDecorator('field', {
initialValue: field || 'name',
})(
姓名
住址
)}
{getFieldDecorator('keyword', {
initialValue: keyword || '',
})(
)}
{ marginRight: '10px' }} type="primary" htmlType="submit"搜索
Add
Delete
);
};
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;
}