今天听雷鹏飞大佬讲了一个 material UI 记录一下 跟antd差不多
https://www.easy-mock.com/login 提供动态数据渲染 Easy mock
mockjs搭建的平台)
强大的插件Mock.js,可以非常方便的模拟后端的数据,也可以轻松的实现增删改查这些操作。

ps:操作时间码转换成统一格式
const columns=[
{title:'...',
dataIndex:'...',
render:Utils.formateDate
}]formateDate(time){if(!time)return '';let date= new Date(time);return date.getFullYear() + '-'+(data.getMouth()+1)+'-'+date.get.....;
}数据
{"code":0,//成功时返回
"msg":"",//错误时返回信息 等同于"message"
"result|10":[{  //|10指的是定义10条数据id:'0',userName:'Jack',...
},
...
],
page:1,
page_size:10,
}{"code":0,//成功时返回
"msg":"",//错误时返回信息 等同于"message"
"result":{  //|10指的是定义10条数据"list|5":[{"id|+1":1, //id值每次递增+1"userName":“@cname",//自动获取中文名"sex|1-2":1,//性别只有1、2
...}],
page:1,//第一页
page_size:10,//1页放10条
total:100//100页}
}

表格
pages/tabke
basic.js

src/config/menuConfig.js 定义路由地址 名字 等

menuConfig.js
export default [{title:'首页',key:'/admin/home'},{    title:'UI',key:'admin/ui',children:[{title:'按钮',key:'url',},//一个大括号里是一个人的信息...]},...
]basic.js
...
state={//state里数据用来渲染Htmldom结构的 执行setState会重新渲染domdataSource2:[]//dataSource2如果不存入state render不执行
}
params={//只改变页码不需要改变dom结构page:1 //接口调用需要 而不是页面需要
}
componentDidMount(){const dataSource =[//数据源{id:'0',userName:'Jack'sex:'1',...}]data.map((item,index)=>{item.key = index;}) //datasource在表格中应有独一无二的keythis.setState({dataSource//相当于dataSource:dataSource})this.request();
}request=() =>{ //动态获取mock数据let baseUrl = 'url';axios.get(baseUrl +'/table/list').then((res)=>{//.then...就是一个promise的结构if(res.status =='200'&&res.data.code==0){this.setState({dataSource2:res.data.result,selectedRowKeys:[],selectedRows:null})}})
}
onRowClick =(record,index) =>{let selectKey = [index];//多选会用到这个数组this.setState({selectedRowKeys:selectKey,//选中索引selectedItem:record//选择某一行})
}
//多选执行删除动作
handleDelete =()=>{let row = this.state.selectedRows;let ids= [];rows.map((item)=>{ids.push(item.id)})Modal.confirm({title:'...',content:`...${ids.join(',')`,//用,连接起来ids里面的值onOk:()=>{message.success('...');this.request();//刷新一下}})}
render () {const columns =[//定义表头{title:'id',//列名dataIndex:'id'//数据项中所对应的key},{title:'用户名',//列名dataIndex:'userName'},{title:'性别',//列名dataIndex:'sex',render(sex){return sex==1 ? '男':'女'}},{title:'状态',dataIndex:'state',render(abc){//或者statelet config ={//太多了的话也可以专门定义一个字典文件.js'1':'咸鱼',....}return config[abc];//或者state}还有一种写法:render(abc){//或者statereturn {'1':'咸鱼','2':'风华浪子',...}[abc];//或者state}}...]const { selectedRowKeys } =this.state;//等于const selectedRowKeys =this.state.selectedRowKeys ;const rowSelection = {type:'radio',//复选为checkboxselectedRowKeys//存选中某一项的key//也可以加onchange:意为选中下一个框时发生了改变启动事件}const rowSelection = {type:'checkbox',//复选为checkboxselectedRowKeys,//存选中某一项的keyonChange:(selectedRowKeys,selectedRows)=>{//rows指行let ids =[];selectedRows.map((item)=>{ids.push(item.id)})this.setState({selectedRowKeys,selectedIds:ids//存下对应的id})}}return(<div><Card title="基础表格"><Table bordered //边框columns={columns}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource}pagination={false}//不分页/></Card><Card title="动态数据渲染表格" style={{margin:'10px 0' }}><Table bordered //边框columns={columns}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource2}pagination={false}//不分页/></Card><Card title="Mock-单选" style={{margin:'10px 0' }}><div><Button onClick={}this.handleDelete}>删除</Button></div><Table onRow={(record,index) => {return {onClick: () => {this.onRowClick(record,index);}     // 点击行即可选中};bordered //边框rowSelection={rowSelection}//设置为单选columns={columns}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource2}pagination={false}//不分页/></Card><Card title="Mock-分页" style={{margin:'10px 0' }}><Table bordered //边框columns={columns}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource2}pagination={this.state.pagination}//把接口里数据存下来/></Card></div>)}
src/axios/index.js
...
//请求插件的封装
static ajax(options) { //resolve成功时返回 reject失败时返回let loading;if(options.data && options.data.isShowLoading !== false){//不是false就showloading = document.getElementById('ajaxLoading'); //loading代码在全局html文件里 //直接用这种方式获取loading.style.display = 'block';}let baseApi= 'url';return new Promise((resolve,reject)=>{axios({url:options.url,method:'get',baseURL:baseApi, //地址通用前缀timeout:5000,//超过五秒即超时会报错params:(options.data && options.data.params)||'' //获取参数}).then((response)=>{if(options.data && options.data.isShowLoading !== false){//不是false就showloading = document.getElementById('ajaxLoading'); //loading代码在全局html文件里 //直接用这种方式获取loading.style.display = 'none';//关闭掉}if(response.status == '200'){//HTTP状态请求码let res= response.data;if(res.code == '0') {//业务代码成功定义为0resolve(res);//把res.data抛出去 我们可以接收到}else{Modal.info({ //错误信息title:"提示",content:res.msg})}}else {reject(response.data);}//把它打印出来并报错})});}封装了之后我们可以修改上述的request 即
request =() =>{let _this =this;//怕作用域出问题 提前提取thisaxios.ajax({url:'/table/list',data:{params:{ page:this.params.page},//第一页的isShowLoading:false//不需要show loading}}).then((res)=>{if(res.code == 0){res.result.list.map((item,index)=>{item.key= index;})this.setState({dataSource2:res.result.list,selectedRowKeys:[],selectedRows:null,pagination:Utils.pagination(res,(current)=>{_this.params.page = current;//把current存入this.params.page里this.request();})})}})
}
然后要做一个在请求完成之前的loading效果
public/index.html
....
<div id="root"></div>//插入以下代码
<div class="ajax-loading" id="ajaxLoading" style="display:none;"><div class="overlay"></div><div class="loading"><img src="url" alt=" "><span>加载中</span></div>
</div>还有性别等里面显示的是数字 我们希望显示文字 修改一下columns
那如果想在打开的网页中修改表格数据呢?----
分页功能
utils.js
export default{...,//关于分页的封装//当点击下一页时触发回调函数 pagination(data,callback){let page = {//current当前页数 onchange为页码改变的回调,参数是改变后的页码及每页条数onChange:(current)=>{callback(current);},current:data.result.page,pageSize:data.result.page_size,total:dada.result.total,showTotal:()=>{//用于显示数据总量和当前数据顺序return `共${data.result.total}条`},showQuickJumper:true//showQuickJumper是否可以快速跳转至某页}return page;//或者 整个return {...}即可},getOptionList(data){if(!data){return [];}let option = [];data.map((item)=>{options.push(<Option value={item.id} key={item.id}>{item.name}</Option>)})return options;//不要忘记返回}
}

高级表格:分别是表头固定和左侧固定
pages/table/highTable.js

handleChange =(pagination, filters, sorter)=>{this.setState({sortOrder:sorter.order})
}
handleDelete =(item) =>{let id =item.id;Modal.confirm({title:'确认',content:'确认删除?',onOk:()=>{message.success('删除成功');this.request();}})
}
render () {const columns =[//定义表头{title:'id',//列名key:'id',width:80,//这一列宽度为80dataIndex:'id'//数据项中所对应的key},{title:'用户名',//列名dataIndex:'userName'},{title:'性别',//列名dataIndex:'sex',render(sex){return sex==1 ? '男':'女'}},{title:'状态',dataIndex:'state',render(abc){//或者statelet config ={//太多了的话也可以专门定义一个字典文件.js'1':'咸鱼',....}return config[abc];//或者state}}...]const columns2 =[//定义表头{title:'id',//列名key:'id',width:80,//这一列宽度为80fixed:'left', //该列左侧固定不动dataIndex:'id'//数据项中所对应的key},{title:'用户名',//列名dataIndex:'userName'},{title:'性别',//列名dataIndex:'sex',render(sex){return sex==1 ? '男':'女'}},{title:'状态',dataIndex:'state',render(abc){//或者statelet config ={//太多了的话也可以专门定义一个字典文件.js'1':'咸鱼',....}return config[abc];//或者state}}...]const columns3 =[//定义表头{title:'id',//列名key:'id',width:80,//这一列宽度为80dataIndex:'id'//数据项中所对应的key},{title:'用户名',//列名dataIndex:'userName'},{title:'年龄',//列名key:'age',dataIndex:'age',width:80,sorter:(a,b)=>{return a.age -b.age; //小于0则a<b 即为升序},sortOrder:this.state.sortOrder},{title:'性别',//列名dataIndex:'sex',render(sex){return sex==1 ? '男':'女'}},{title:'状态',dataIndex:'state',render(abc){//或者statelet config ={//太多了的话也可以专门定义一个字典文件.js'1':'咸鱼',....}return config[abc];//或者state}}...]const columns4 =[//定义表头{title:'id',//列名列宽度为80dataIndex:'id'//数据项中所对应的key},{title:'用户名',//列名dataIndex:'userName'},{title:'年龄',//列名dataIndex:'age',width:80,},{title:'性别',//列名dataIndex:'sex',render(sex){return sex==1 ? '男':'女'}},{title:'状态',dataIndex:'state',render(abc){let config ={//badge 徽标'1':<Badge status="success" text="1"/>,//status :error default processing warning....}return config[abc];//或者state}},{title:'操作',render:(text,item)=>{//item指一行  改为箭头函数使this指向react里面return <Button size="small" onClick ={(item)=>{this.handleDelete(item)} }>删除</Button> }}...]return(){<div><Card title="头部固定"><Table bordered //边框columns={columns}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource}pagination={false}//不分页scroll={{y:240}}//在y轴滚动 :后为高度px //注意表头和表格要对齐 /></Card><Card title="左侧固定" style={{margin:'10px 0' }}><Table bordered //边框columns={columns2}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource2}pagination={false}//不分页scroll={{x:2650}}//在x轴滚动 :后为高度px  注意把每一列的宽度相加再多一点的值放到这//注意表头和表格要对齐 /></Card><Card title="表格排序" style={{margin:'10px 0' }}><Table bordered //边框columns={columns3}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource2}pagination={false}//不分页onChange={this.handleChange} //排序 分页都可用scroll={{x:2650}}//在x轴滚动 :后为高度px  注意把每一列的宽度相加再多一点的值放到这//注意表头和表格要对齐 /></Card><Card title="操作按钮" style={{margin:'10px 0' }}><Table bordered //边框columns={columns4}//如果放在render外需要用this.state.columns引用dataSource={this.state.dataSource2}pagination={false}//不分页scroll={{x:2650}}//在x轴滚动 :后为高度px  注意把每一列的宽度相加再多一点的值放到这//注意表头和表格要对齐 /></Card></div>}

城市开通

state ={ list:[],isShowOpenCity:false
}
page = {page:1
}componentDidMount(){this.requestList();
}
requestList ={ //获取接口中的list let _this= this;axios.ajax({url:'...',data:{params:{page:this.params.page}}}).then((res)=>{this.setState({list:res.result.item_list.map((item,index)=>{//为了加上独一的key值 不然报错item.key = index;return item;//返回一个全新的对象 不return还是之前那个老版的}),pagination:Utils.pagination(res,()=>{_this.params.page =current;_this.requestList();})})})
}
handleOpenCity =() =>{this.setState({isShowOpenCity:true})
}handleSubmit =()=>{let cityInfo =this.cityForm.props.form.getFieldsValue();axios.ajax({url:'url',data:{params:cityInfo}}).then((res)=>{if(res.code =='0'){message.success('开通成功');this.setState({isShowOpenCity:false})this.requestList();//更新列表}})
}
render(){const columns = [表格其中的一列 一格中数据不能渲染复杂的对象、数组等,只能渲染普通的如数字文字等,所以要修改数据源{title:'...',dataIndex:'...', //dataIndex传过来的值是一个数组render(arr){return arr.map((item)=>{return item.user_name;//得到全新的数组 数组中只有username}).join(',';//以逗号分开并连接成一个全新的字符串}},...]return(<div><Card><FilterForm /></Card><Card><Button type="primary" onClick={this.handleOpenCity} />          </Card><div className="content-wrap"><Table columns={columns}dataSource={this.state.list}pagination={this.state.pagination}/></div><Modaltitle="开通城市"visible={this.state.isShowOpenCity}onCancle={()=>{this.setState({isShowOpenCity:false})}}onOk={this.handleSubmit}><OpenCityForm wrappedComponentRef={(inst)=>{this.cityForm = inst;}}/>//wrappedComponentRef相当于ref 把表单对象存到本地 便于获取里面的值//再次引用时直接this.cityForm.props.from.getFieldValue();)
}
//注意是在一个文件里
class OpenCityForm extends React.Component{render(){const formItemLayout ={labelCol:{span:5},wrapperCol:{span:10}}const { getFieldDecorator } =this.props.form;//辅助性的帮助双向数据绑定return(<Form layout="horizontal" {...formItemLayout}><FormItem label="选择城市">{getFieldDecorator('city_id',{initialValue:'1'})(<Select><Option value="1">全部</Option><Option value="2">北京市</Option><Option value="3">天津市</Option></Select>)}</FormItem>...</Form>)}
}
OpenCityForm = Form.create({})(openCityForm);

订单管理
pages/order/index.js

const FormItem=Form.Item;
const Option = Select.Option;
state={}
params ={ page:1}
componentDidMount(){this.requestList()
}
requestList =()=>{axios.ajax({url:'/order/list',data:{params:{page:this.params}}}).then((res)=>{(//写法1let list = res.result.item_list.map((item,index) => {item.key = index;return item;});)if(res.code ==0)this.setState({list:res.result.item_list.map((item,index)=>{//为了加上独一的key值 不然报错item.key = index;return item;//返回一个全新的对象 不return还是之前那个老版的}),pagination:Utils.pagination(res,()=>{_this.params.page =current;_this.requestList();})})})
}handleFinishOrder =() =>
{let item = this.state.selectedItem;if(!item){Modal.info({title:'信息',content:'请选择一条订单结束'})return;}axios.ajax({url:'/order/ebike_info',data:{params:{orderId:item.id}}}).then((res)=>{if(res.code ==0){.this.setState({orderInfo:res.result,orderConfirmVisible:true}),pagination:Utils.pagination(res,()=>{_this.params.page =current;_this.requestList();})})})}}openOrderDetail =()=>{let item = this.state.selectedItem;if(!item){//没选择一个行时Modal.info({title:'信息',content:'请选择一条订单结束'})return;}//新建页加载window.open(`/#/common/order/detail/${item.id}`,'_blank')//window.location.href = `/#/common/order/detail/${item.id}`同一页加载
}handleFinishOrder =() =>{}render(){const columns=[//表头{title:'订单编号',dataIndex:'order_sn'//要严格 遵守接口的返回名},{title:'车辆编号',dataIndex:'bike_sn'//要严格 遵守接口的返回名},{title:'用户名',dataIndex:'user_name'//要严格 遵守接口的返回名},{title:'手机号',dataIndex:'mobile'//要严格 遵守接口的返回名},{title:'里程',dataIndex:'distance'//要严格 遵守接口的返回名},。。。]return(<div><Card><FilterForm /></Card><Card><Button onClick={this.openOrderDetail>订单详情</Button><Button>结束订单</Button></Card><div className="content-wrap"><Tableborderedcolumns={columns}dataSource={this.state.list}pagination={this.state.pagination}//注意区分:datasource里面是数据 columns里面是标题以及它的索引和key值/></div></div>)
}<FilterForm />:
render(){const {getFieldDecorator}=this.props.form;return(<Form layout="inline"><FormItem label="城市">{getFieldDecorator('city_id')(<Selectstyle={{width:100}}placeholder="全部"><Option value=""> 全部</Option><Option value="1"> 北京市</Option>。。。</Select>))
}
</FormItem>
<Form layout="inline"><FormItem label="订单时间">{getFieldDecorator('start_time')(<DatePicker showTimen format="YYYY-MM-DD HH:mm:ss" />)}  {getFieldDecorator('end_time')(<DatePicker style={{marginLeft:10}} showTimen format="YYYY-MM-DD HH:mm:ss" />)}
</FormItem>

通用页面的结构设计

router.js
import ....
export default class ....{render(){return(<HashRouter><App><Route path="/login" component={Login} /><Route path="/admin" render={()=><Admin>//都属于admin下面的子页面<Switch><Route path="/admin/ui/buttons" component={Buttons} />//子路由的嵌套<Route  component={NoMatch} />//没匹配的都会跳转到404</Switch></Admin>} />//进入admin即可进入主页面</App></HashRouter>);}
}//通用的js文件承载大体不动的部分 比如页头页脚 。。只改变里面的内容部分
admin.js
import React from 'react'
import { Row } from 'antd';
import './style/common.less'
import Header from './components/Header'
import Footer from './components/Footer'
import NavLeft from './components/Navleft'
export default class Admin extends React.Component {render(){return (<Row className="container"><Col span="3" className="nav-left"><NavLeft /></Col><Col span="21" className="main"><Header /><Row className="content">{this.props.children}//动态实现 嵌套子组件</Row>//body区域<Footer /></Col></Row>)}
}

我们再建一个common.js作为类似一个admin.js 作为详情页面

common.js
<Row className="simple-page">//二级页面头部不一样 另取一个classname
<Header menuType="second" />//menuType //传了一个second值
</Row>
...在header/index.js
render(){const menuType =this.props.menuType;render(...{//menutype有值返回空 无值返回页头menuType?'':<div className="header"><Row className="header-top"> //行{menuType?<Col span="6"><img src="/assets/logo-ant.svg" alt="" /><span>IMooc 通用管理系统 </span></Col>:' '}<Col span={menuTyoe?18:24}><span>欢迎,{this.state.userName}</span><a href="#">退出</a></Col></Row><Row className="breadcrumb"><Col span="4" className="breadcrumb-title">首页</Col><Col span="20" className="weather"><span className="date">{this.state.sysTime}</span><span className="weather-img"><img src={this.state.dayPictureUrl} alt="" /></span><span className="weather-detail">{this.state.weather}</span></Col></Row></div>})}定义路由
<Route path="/common" render{() =><Common> <Route path="/common/order/detail/:orderId" component={OrderDetail}/>//:后加动态路由 变量为orderId</Common>
} />const info =this.state.orderInfo ||{};
//若为空则是一个{}

.clearfix//清除浮动
首先来看一下伪元素 ::after
https://www.cnblogs.com/starof/p/4459991.html
里面有清除浮动实例
https://www.cnblogs.com/937522zy/p/6650708.html
我们提取一个典型出来

.cf:before,
.cf:after {content: " ";//清空内容clear:both;//清除两边浮动display:block;visibility:hidden;//使元素不可见 不然会占位
}
//可在元素头/尾部自动清除浮动

地图功能实现
打开map.baidu.com
然后点击最下面的百度地图开放平台
开发文档 - javascript API
使用前应先申请ak密钥 申请成为开发者 登陆
创建应用
在public/index.html
在title下面把<script …><… />引入进来即可

BMap挂载在window下 window....来引用然后在detail.js里初始化地图 在render上面
通过this.renderMap(res.result);来调用它renderMap =(result)=>{this.map = new window.BMap.Map('要初始化的百度地图的div的id');this.map.centerAndZoom('北京',11);//BMap.Map.centerAndZoom()方法要求设置中心点坐标和地图级别。this.addMapControl();this.drawBikeRoute(result.position_list);this.drawServiceArea(result.area);
}
//添加地图控件
addMapControl =() =>{let map = this.map;map.addControl(new  window.BMap.ScaleControl({ anchor:  window.BMAP_ANCHOR_TOP_RIGHT}));//比例尺 右上角map.addControl(new  window.BMap.NavigationControl({ anchor:  window.BMAP_ANCHOR_TOP_RIGHT}));//比例尺 右上角
}
//绘制用户行驶路线 positionList坐标点
drawBikeRoute =(positionList)=>{let map =this.map;let startPoint ='';//起始点let endPoint = '';if(positionList.length>0){let first =positionList[0];let last =positionList[positionList.length-1];startPoint = new window.BMap.Point(first.lon,first.lat);//lon经度 lat纬度let startIcon = new window.BMap.Icon('/assets/start_point.png',new window.BMap.Size(36,42),{//icon需要的空间大小imageSize:new window.BMap.Size(36,42), //图像大小anchor:new window.BMap.Size(36,42)//anchor图标的定位点相对于图标左上角的偏移值})//图标宽高let startMarker =new window.BMap.Marker(startPoint,{icon:startIcon});//将坐标点和图标对应起来 点在文档里面叫做markerthis.map.addOverlay(startMarker);//添加点endPoint = new window.BMap.Point(last.lon,last.lat);//lon经度 lat纬度let endIcon = new window.BMap.Icon('/assets/start_point.png',new window.BMap.Size(36,42),{//icon需要的空间大小imageSize:new window.BMap.Size(36,42), //图像大小anchor:new window.BMap.Size(36,42)//anchor图标的定位点相对于图标左上角的偏移值})let endMarker =new window.BMap.Marker(endPoint,{icon:endIcon});//将坐标点和图标对应起来 点在文档里面叫做markerthis.map.addOverlay(endMarker);//添加点//连接路线图let trackPoint =[];//跟踪点for(let i=0;i<positionList.length;i++){let point =positionList[i];trackPoint.push(new window.BMap.Point(point.lon,point.lat));}let polyline =new window.BMap.Polyline(trackPoint,{//折现属性 详情见http://lbsyun.baidu.com/cms/jsapi/reference/jsapi_reference.html#a3b11strokeColor:'#FFFFFF',strokeWeight:3,strokeOpacity:1})this.map.addOverlay(polyline);this.map.centerAndZoom(endPoint,11);}}
drawServiceArea =(positionList) =>{//绘制服务区let trackPoint =[];//跟踪点for(let i=0;i<positionList.length;i++){let point =positionList[i];trackPoint.push(new window.BMap.Point(point.lon,point.lat));}let polygon = new Window.BMap.Polygon(trackPoint,{strokeColor:'#FFFFFF',strokeWeight:3,strokeOpacity:1,fillColor:'#ff8605',fillOpacity:0.4})this.map.addOverlay(polygon);
}render(){const info =this.state.orderInfo || {};return(<div><Card><div id="orderDetailMap" className="order-map">要初始化的百度地图的div</div> )
}

项目工程化

  • 项目架构设计
  • 目录结构定义
  • 制定项目开发规范 (实例如https://www.cnblogs.com/luxiaoxiao/p/6432788.html) eslint
  • 模块化 组件化
  • 前后端接口规范
  • 性能优化 自动化部署(压缩 合并 打包

对表单等基本组件进行封装
src/components/BaseForm 文件夹

  • index.js
应用:
在order/index.js下测试
封装了之后就可以把之后的Filterform删掉了
formList = [{type:'SELECT',label:'城市',field:'city',placeholder:'全部',initialValue:'1',width:100,list:[{id:'0',name:'全部'},{id:'1',name:'北京'},{id:'2',name:'天津'},{id:'3',name:'上海'}]},{type:'时间查询',},{type:'SELECT',field:'order_status',label:'订单状态',placeholder:'全部',initialValue:'1',width:100,list:[{id:'0',name:'全部'},{id:'1',name:'进行中'},{id:'2',name:'结束行程'},]},]handleFilter = (params)=>{this.params = params;this.requestList();
}
return(<div><Card><BaseForm formList = { this.formList } filterSubmit={this.handleFilter} /> //formlist为了把该表单数据传给封装好的basicform </div>
)
BaseForm /index.jsconst FormItem =Form.Item;
const Option = Select.Option;class FilterForm extends React.Component
{handleFilterSubmit =() =>{let fieldsValue =this.props.form.getFieldValue();this.props.filterSubmit(fieldsValue); //调用那边本部的方法 这个不是固定的}reset =()=>{this.props.form.resetFields();}initFormList =()=>{const { getFieldDecorator } =this.props.form;//antd里有getFieldDecorator参数的设置const formList = this.props.formList;//然后我们需要把数据解析出来const formItemList = [];if(formList &&formList.length>0){formList.forEach((item,i) =>{let label = item.label;let field = item.field;let initValue = item.initialValue || '';let placeholder = item.placeholder;let width =item.width;if(item.type == '时间查询'){const begin_time=<FormItem label={label} key={field} >{getFieldDecorator('begin_time',{initialValue:initialValue,})(<DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>)}</FormItem>;formItemList.push(begin_time);const end_time=<FormItem label={label} key={field} >{getFieldDecorator('begin_time',)(<DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>)}</FormItem>;formItemList.push(end_time);}if(item.type =='SELECT'){const SELECT = <FormItem label="~" colon={false}  key={field} >//colon 不显示label后的:{getFieldDecorator('end_time')(<Select style={{ width:width  }}placeholder={placeholder}>{Utils.getOptionList(item.list)}//遍历option 在utils里进行封装</Select>)}</FormItem>;formItemList.push(SELECT)} else if (item.type == 'INPUT'}{const INPUT = <FormItem label={label} key={field} >{getFieldDecorator([field],{initialValue:initialValue,})(<Input type="text" placeholder={placeholder} />)}</FormItem>;formItemList.push(INPUT)}else if (item.type == 'CHECKBOX'}{const SELECT = <FormItem label={label} key={field} >{getFieldDecorator([field],{valuePropName:'checked',//这个属性必须要加上initialValue:initialValue,//checkbox初始值必须为true/false})(<Checkbox> {label}<Checkbox />)}</FormItem>;formItemList.push(CHECKBOX)}})}return formItemList;}render(){return(<Form layout="inline">{this.initFormList()}</Form><FormItem><Button onClick={this.handleFilterSubmit}>查询</Button><Button onClick={this.reset}>重置</Button></FormItem>)}
}
export default Form.create({})(FilterForm);

公共机制封装
打开src/axios/index.js
定义一个专门表单查询的

 static requestList(_this,url,params,isMock){//还可以检测是否是mock数据 根据情况变化var data= {params:params//isMock}this.ajax({url:url,data:data,//可以省略为url,data}).then((data)=>{if(data&&data.result){let list = data.result.item_list.map((item,index) => {item.key = index;return item;});_this.setState({list,pagination:Utils.pagination(data,(current) =>{_this.params.page = current;_this.requestList(); //注意 此this非彼this 我们需要修改order index里的requestList 修改如后所示}})}})}order index.js 修改如下 (为了传递this
requestList= ()=>{let _this=this;axios.requestList(this,'/order/list',this.params);
}

表格封装

<Tablebordered //边框columns={columns} //表头dataSource={this.state.list} //数据源 与表头形成一一映射 渲染出表格pagination={this.state.pagination}//分页rowSelection={rowSelection}//控制单选复选onRow={(record,index) =>{return{onClick:()=>{this.onRowClick(record,index);}};}}//跟单选复选配合 点中某一行实现某一行被选中components/ETable/index.js
import Utils from './../../utils/utils'export default class ETable extends React.Component{onRowClick = (record,index)=>{let rowSeletion =this.props.rowSelection;if(rowSelection =='checkbox'){//多选框需要的是idlet selectedRowKeys=this.props.selectedRowKeys;let selectedIds = this.props.selectedIds;let selectedItem =this.props.selectedItem;if(selectedIds){//已有那么要判断是否有重复的const i=selectedIds.indexOF(record.id);if(i==-1){//新的放入 旧的取消勾选selectedIds.push(record.id);selectedRowKeys.push(index);selectedItem.push(record);}else{selectedIds.splice(i,1);//注意 slice不会改变原先数组 只会返回新数组 splice改变原先数组selectedRowKeys.splice(i,1);selectedItem.splice(i,1);}}else{selectedIds=[record.id];selectedRowKeys=[index];selectedItem =[record];this.props.updateSelectedItem(selectedRowKeys,selectedItem,selectedIds)}}else{let selectedRowKeys = [index];let selectedItem =record;//单选不需要[record]数组this.props.updateSelectedItem(selectedRowKeys,selectedItem)}}tableInit =()=>{let selectedRowKeys = this.props.selectedRowKeys;let row_selection =this.props.rowSelection;const rowSelection ={type:'radio',selectedRowKeys,//选中哪一行onChange:this.onSelectChange//跟上个属性配合使用}if(row_selection === false ||row_selection===null){row_selection = false;}else if(row_selection=='checkbox'){row_selection.type = 'checkbox';}else { row_selection ='radio' }this.props return <Tablebordered //边框{...this.props} //把这个源组件的属性传到这里来 即 order index.js的columns datasource paginationrowSelection={row_Selection?rowSelection:null}//控制单选复选onRow={(record,index) =>{//record是一整行数据 index是索引值return{onClick:()=>{if(!row_selection)return;                this.onRowClick(record,index);}};}}/>}render(){return(<div>{this.tableInit()}</div>);}
}应用到order/index.js
import ETable from './../../Components/ETable'
把return上面的const selectedRowKeys rowSelection onRowClick都删掉
<div className="content-wrap"><ETableselectedItem ={this.state.selectedItem} //接口统一要id时可以删除selecteditemselectedIds={this.state.selectedIds}updateSelectedItem ={Utils.updateSelectedItem.bind(this)}//把当前页面的作用域传进去  columns={columns}dataSource={this.state.list} //数据源 与表头形成一一映射 渲染出表格pagination={this.state.pagination}//分页selectedRowKeys={this.state.selectedRowKeys}rowSelection={false}/>
</div>Utils.js
updateSelectedItem(selectedRowKeys,selectedItem,selectedIds){//选中的行的key 选中的那一行
//判断单选复选if(selectedIds){this.setState({selectedRowKeys,selectedItem,selectedIds})}else{this.setState({selectedRowKeys,selectedItem})}}

封装了之后可以用一个方法做各种功能

onClick={()=>this.handle('create')}
onClick={()=>this.handle('edit')}
onClick={()=>this.handle('detail')}
onClick={()=>this.handle('delete')}
函数里区别参数即可注意
返回数组时<Radio value={1}>变量形式 而非"1" 字符串形式
返回字符串时才能用"1"要想通过
<Modal footer={this.state.type=='detail'?null:''}>//不可行
解决方案:
<Modal {...footer}>let footer={};
if(this.state.type=='detail'){footer={footer:null}
}

车辆地图

renderMap =(res) =>{let list =res.result.route_list;this.map =new window.BMap.Map('container');//在div是这个名的里面渲染地图let gps1=list[0].split(',');//起点let gps2=list[list.length-1].split(',');//起点let startPoint =new window.BMap.Point(gsp1[0],gsp1[1]);//一个数组里面 左边经度 右边纬度let endPoint =new window.BMap.Point(gsp2[0],gsp2[1]);this.map.centerAndZoom(endPoint,11);//以什么点居中let startPointIcon = new window.BMap.Icoon('url.png',new window.BMap.Size(36,42),{//指定属性imageSize:new window.BMap.Size(36,42)})let endPointIcon = new window.BMap.Icoon('url.png',new window.BMap.Size(36,42),{imageSize:new window.BMap.Size(36,42),anchor:new window.BMap.Size(18,42)})let bikeMarkerStart =new window.BMap.Marker(startPoint,{icon:startPointIcon})
}this.map.addOverlay(bikeMarkerStart);//把点添加到上面同理结束点//绘制车辆行驶路线
let routeList =[];
list.forEach((item)=>{let p=item.split(',');routeList.push(new window.BMap.Point(p[0],p[1]))
})
let polyLine =new window.BMap.Polyline(routeList,{//用折线把routelist里面的点连接起来strokeColor:'#ef4136',strokeWeight:2,strokeOpacity:1
})
this.map.addOverlay(polyLine);
}
//绘制服务区
let servicePointList =[];
let serviceList =res.result.service_list;
serviceList.forEach((item)=>{servicePointList.push(new window.BMap.Point(item.lon,item.lat))
})
let polyServiceLine =new window.BMap.Polyline(servicePointList,{//用折线把routelist里面的点连接起来strokeColor:'#ef4136',strokeWeight:3,strokeOpacity:1
})
this.map.addOverlay(polyServiceLine);//添加图中自行车图标
let bikeList =res.result.bike_list;
let bikeIcon =new window.BMap.Icon('....jpg',new window.BMap.Size(36,42),{...同理})
bikeList.forEach((item)=>{let p=item.split(',');let point = new window.BMap.Point(p[0],p[1]);let bikeMarker =new window.BMap.Marker(point,{icon:bikeIcon})this.map.addOverlay(bikeMarker);
})

图表
ECharts
可以选择把主题下载下来
(主题的源码由AMD-异步模块定义(AMD是RequireJS的)和commonJS
还可以定制主题
–save 可以使该组件保存到package.jsoon里 install即安装了

node版本过高怎么办
降级即可 npm官网搜索n 安装n这个插件


$ n 版本号 即可安装这个版本lts:指的是长期稳定支持的版本echarts是一核心类 做图表肯定要安装的
echarts-for-react 导入之后是组件化的(ES6单页面开发) 不需要像百度地图一样new 一个对象 (多页面的形式) 不需要导入所有的图标 即import echarts from 'echarts'
按需加载:
import echarts from 'echars/lib/echarts'主题导入://注意先把下载好的主题文件放入定义好的src/echarts/包里
import echartTheme from './../echartTheme'导入柱形图://如何看在哪个包里呢  搜npm里echars 或github
import  'echars/lib/chart/bar'
import 'echars/lib/component/tooltip' //图表上的信息框
import 'echars/lib/component/title'
import 'echars/lib/component/legend'
import 'echars/lib/component/markPoint'import ReactEcharts from 'echarts-for-react'componentWillMount(){//注册主题echarts.registerTheme('自定义主题名',echartTheme);//导入的这个主题
}getOption(){let option ={title:{text:'用户骑行订单'},tooltip:{trigger:'axis'},xAxis:{//x轴数据data:['周一','周二',....] //可以直接从服务端提取数据即可},yAxis:{type:'value' //把数据自动计算 列出来即可},series:[//定义数据量 数据源   展示{name:'订单量',type:'bar',data:[1000,2000,1500,...],}]}return option;
}getOption2(){let option ={title:{text:'用户骑行订单'},legend:{data:['OFO','摩拜‘,’小蓝'] //渲染出来一个关于同一x轴不同分类 点击一方可进行不展示操作},tooltip:{trigger:'axis'},xAxis:{//x轴数据data:['周一','周二',....] //可以直接从服务端提取数据即可},yAxis:{type:'value' //把数据自动计算 列出来即可},series:[//定义数据量 展示{name:'OFO',type:'bar',data:[1000,2000,3500,...],},{name:'摩拜',type:'bar',data:[2000,3000,4500,...],},{name:'小蓝',type:'bar',data:[5000,5200,5500,...],}]}return option;
}<Card title="柱形图1"> <ReactEcharts optioon={this.getOption() }  theme="自定义主题名” /> //跟上面保持一致 先注册再使用</Card><Card title="柱形图2"> <ReactEcharts optioon={this.getOption2() }  theme="自定义主题名” /> //跟上面保持一致 先注册再使用</Card>饼图
getOption= () => {let option ={title:{text:'用户骑行订单',x:'center'},tooltip:{trigger:'item',//指数据项formatter:'{a}<br />{b}:{c}({d}%)'//格式化:系列名 回车 数据名 value 比例%},legend:{right:10,top:20,botton:20,orient:'vertical',//垂直方向居中data:['OFO','摩拜‘,’小蓝'] //渲染出来一个关于同一x轴不同分类 点击一方可进行不展示操作},series:[//定义数据量 展示{name:'订单量',//系列名type:'pie',radius:['50%,‘30%’],//有这一项就是环形图半径 分别控制内外环 没有就是大饼图center:['50%','60%'],//整个图往左往下移动data:[{value:1000,name:'周一'//数据名},{...},{...}],}]}return option;
}还有一种根据数据量定义半径大小的饼图(南丁格尔图
首先要对数据进行排序
getOption= () => {let option ={title:{text:'用户骑行订单',x:'center'},tooltip:{trigger:'item',//指数据项formatter:'{a}<br />{b}:{c}({d}%)'//格式化:系列名 回车 数据名 value 比例%},legend:{right:10,top:20,botton:20,orient:'vertical',//垂直方向居中data:['OFO','摩拜‘,’小蓝'] //渲染出来一个关于同一x轴不同分类 点击一方可进行不展示操作},series:[//定义数据量 展示{name:'订单量',//系列名type:'pie',data:[{value:1000,name:'周一'//数据名},{...},{...}].sort((a,b)=>{return a.value -b.value;}),roseType:'radius'//显示风格为南丁格尔图//还可以加动画animationType:'scale',//鼠标移上去松开会变大变小animationEasing:'elasticOut',animationDelay:function (idx){return Math.random() *200;}}]}return option;
}折线
import  'echars/lib/chart/line'
getOption= () => {let option ={title:{text:'用户骑行订单',},tooltip:{trigger:'axis'//指数据项},xAxis:{type:'category',//默认值boundaryGap:false,//控制面积x轴上开始的起点是0 还是第一个数据点data:['周一',....]},yAxis:{type:'value'},series:[//定义数据量 展示{type:'line',data:[1500,2500,1000,...],areaStyle:{}//填充面积}]}return option;
}import  'echars/lib/chart/line'
getOption= () => {let option ={title:{text:'用户骑行订单',},tooltip:{trigger:'axis'//指数据项},legend:{data:['ofo订单量','mobike订单量']},xAxis:{data:['周一',....]},yAxis:{type:'value'},series:[//定义数据量 展示{name:'ofo订单量',//系列名type:'line',data:[1500,2500,1000,...]}},{name:'mobike订单量',//系列名type:'line',data:[1000,2000,1500,...]}}]}return option;
}富文本功能 满足文字各种样子的需求
npm官网里有react-draft-wysiwyg插件
还需要一个转化成HTML内容的插件  draftjs-to-html
都需要终端进行安装
import {Editor } from 'react-draft-wysiwyg';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import draftToHtml from 'draftjs-to-html';state={showRichText:false //默认不显示
editorState:''
}onEditorChange=(contentState)=>{this.setState({contentState//内容状态});
}onEditorStateChange =( editorState) =>{this.setState({editorState,//编辑器状态});
}handleClearContent =()=>{this.setState({editorState:' ' ,});
}handleGetText =() =>{this.setState({showRichText:true});
}render(){const { editorState } =this.state;return(<div><Card><Button type="primary" onClick={this.handleClearContent}>清空内容</Button ><Button  type="primary" onClick={this.handleGetText}>获取html文本</Button></Card><Card><EditoreditorState={editorState} //接收到状态值onContentStateChange={this.onEditorChange}onEditorStateChange={this.onEditorStateChange} //状态值变化之后/></Card></div><Modaltitle="。。。" visible={this.state.showRichText}onCancel={ ()=>{this.setState({showRichText:false})  }footer={null}}>{draftjs(this.state.contentState)}//转化成对应的html文本</Modal>)
}

项目实战二:共享单车后台2相关推荐

  1. Taro多端开发实现原理与项目实战(二)

    Taro多端开发实现原理与项目实战(二) 多端电商平台项目概述及开发准备 学习了前面的基础知识和进阶后是否跃跃欲试?我们准备了一个电商平台的项目来和大家一起实践使用 Taro 开发电商平台. 项目概述 ...

  2. flutter 项目实战二 网络请求

    本项目借用 逛丢 网站的部分数据,仅作为 flutter 开发学习之用. 逛丢官方网址:https://guangdiu.com/ flutter windows开发环境设置 flutter 项目实战 ...

  3. c语言期中项目实战二—简易扫雷,思路分析加代码详细注释

    c语言期中项目实战二-简易扫雷,思路分析+代码详细注释 游戏介绍 项目步骤 模块化编程 设置菜单 设置棋盘 打印棋盘 布置雷 排查雷 总结及总代码和详细注释 游戏介绍 扫雷这个经典游戏,直到现在仍有很 ...

  4. Python业务分析实战|共享单车数据挖掘

    本文详细介绍了共享单车数据挖掘,包括数据分析和模型开发.它包含以下步骤: 共享单车数据挖掘 数据集简介 关于共享单车数据集 自行车共享系统是传统自行车租赁的新一代,从注册会员.租赁到归还的整个过程都是 ...

  5. 机器学习项目一:共享单车

    共享单车项目 import numpy as np import pandas as pd from sklearn.decomposition import PCA,TruncatedSVD fro ...

  6. Vue项目实战之电商后台管理系统(一) 用户登录模块

    目录 一.项目概述 二.项目初始化 2.1 前端项目初始化步骤 2.2 后台项目的环境安装配置 三.用户登录/登出功能实现 3.1 登录功能概述 3.1.1 登录状态保持 3.1.2 登录逻辑: 3. ...

  7. 前端开发Vue项目实战:电商后台管理系统(二)-- 登录退出功能 --主页界面

    目录 1. 登录/退出功能 1.1 登录概述 1.2 token 原理分析 1.3 登录功能实现 1.3.1 Git 创建分支 1.3.2 渲染Login组件并实现路由重定向 1.3.3 设置背景颜色 ...

  8. Vue项目实战之电商后台管理系统(二) 主页模块

    前言 目录 前言 一.主页布局 1.1 整体布局 1.2 头部区域布局 1.3 左侧菜单布局 1.3.1 静态布局 1.3.2 通过axios请求拦截器来进行权限验证 1.3.3 通过axios获取左 ...

  9. 微信小程序项目实战+JAVA SSM框架后台管理系统

    毕业设计做的是一个阅读微信小程序+后台管理系统 ,最后被评为优秀毕业设计,在此将项目源码及设计思路进行分享(文末含源码下载地址). 效果图如下: 一.系统开发环境 (1)Windows10操作系统 ( ...

最新文章

  1. 计算机试题高考作文阅卷组对考生,2017年广东高考评卷收尾
  2. linux squid日志滚动,linux squid 日志
  3. 低成本、高性能创客开发板——PYB Nano
  4. 国防科大提出基于可变形三维卷积(D3Dnet)的视频超分辨,代码已开源
  5. python 格式化工具_推荐一个小而美的 Python 格式化工具
  6. 用牛顿法求方程的根的c语言编程,用牛顿迭代法和二分法求方程的根【C语言】...
  7. sql server计算日期到当前日期天数_Excel必学的7个计算日期间隔差的技巧
  8. 量化指标公式源码_量化庄建仓(副图指标源码)下载 通达信源码
  9. 手机图案密码(3*3点阵)开锁次数 C++
  10. 机器视觉之镜头景深概念与计算
  11. stata输出相关系数表到word
  12. BZOJ 2339 【HNOI2011】 卡农
  13. 计算机一级表格技巧,计算机一级考试MS Office应试技巧指导
  14. Zabbix实现企业微信报警
  15. Android下监听返回键、home键、任务键
  16. 在阿里云从0开始部署vue+springboot项目
  17. PS2017使用快速选择工具的时候因内存不足提示“要求96和8之间的整数,已插入最接近的数值”问题解决方案
  18. 如何用继电器实现逻辑门(与或非门)- 编码隐匿在计算机软硬件背后的语言读后感
  19. 考考你的眼力 又一张神奇的图片
  20. 向程序发送命令时出现错误

热门文章

  1. 浅谈数据结构以及其特点
  2. 常见数据结构及特点介绍
  3. AI把你打造成时尚界宠儿 1
  4. 23考研预报名详细步骤、流程及常见问题解答
  5. 基于图像的虚拟换装:Towards Photo-Realistic Virtual Try-On by Adaptively Generating-Preserving Image Content
  6. 1年时间业务量疯长40倍,谈人人车的平台架构演进之路
  7. Oracle建库建表
  8. 微信小程序网络请求配置问题及本地网络请求测试解决方案
  9. 饥荒mod制作教程--物品(食物)该篇主讲贴图--01
  10. 拼多多根据关键词获取商品列表接口调用展示