您当前的位置: 首页 >  后端

wespten

暂无认证

  • 0浏览

    0关注

    899博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

React前后端分离实战租房项目一

wespten 发布时间:2020-05-11 07:40:57 ,浏览量:0

React前后端分离实战租房项目一

好客租房-20天

ES6新特性以及ReactJS入门

day01-ES6新特性以及ReactJS入门&

(02.ES6新特性之了解ES6以及其发展历史&)

02.ES6新特性之了解ES6以及其发展历史&

let声明变量

(04.ES6新特性之字符串扩展&)

04.ES6新特性之字符串扩展&

判断字符串是否包含

解构表达式

参数默认值

箭头函数

对象属性简写

函数参数解构

map和reduce

三点扩展运算符

Promise

set和Map集合

class类语法

generator函数

 

for ...of循环

修饰器注解,

Babel

umi部署安装

模块化

(18.ReactJS入门之前端开发的演变&)

18.ReactJS入门之前端开发的演变&

(19.ReactJS入门之ReactJS简介&)

19.ReactJS入门之ReactJS简介&

(20.ReactJS入门之环境搭建以及编写HelloWorld程序&)

20.ReactJS入门之环境搭建以及编写HelloWorld程序&

创建项目工程

JSX语法

组件拆分

组件参数传递props.children

state组件状态

三点扩展运算符

组件生命周期函数

day02-Ant Design以及Ant Design Pro入门

(02.ReactJS入门之Model分层的概念&)

02.ReactJS入门之Model分层的概念&

(03.ReactJS入门之dva的使用&)

03.ReactJS入门之dva的使用&

DVA框架

ListData.js

import request from '../util/request';

export default {
    namespace: 'list',
    state: {
        data: [],
        maxNum: 1
    },
    reducers : { // 定义的一些函数
        addNewData : function (state, result) { // state:指的是更新之前的状态数据, result: 请求到的数据

            if(result.data){ //如果state中存在data数据,直接返回,在做初始化的操作
                return result.data;
            }

            let maxNum = state.maxNum + 1;
            let newArr = [...state.data, maxNum];


            return {
                data : newArr,
                maxNum : maxNum
            }
            //通过return 返回更新后的数据
        }
    },
    effects: { //新增effects配置,用于异步加载数据
        *initData(params, sagaEffects) { //定义异步方法
            const {call, put} = sagaEffects; //获取到call、put方法
            const url = "/ds/list"; // 定义请求的url
            let data = yield call(request, url); //执行请求
            yield put({ // 调用reducers中的方法
                type : "addNewData", //指定方法名
                data : data //传递ajax回来的数据
            });
        }
    }
}

List.js

import React from 'react';
import { connect } from 'dva';

const namespace = "list";

// 说明:第一个回调函数,作用:将page层和model层进行链接,返回modle中的数据
// 并且,将返回的数据,绑定到this.props

// 接收第二个函数,这个函数的作用:将定义的函数绑定到this.props中,调用model层中定义的函数
@connect((state) => {
    return {
        dataList : state[namespace].data,
        maxNum : state[namespace].maxNum
    }
}, (dispatch) => { // dispatch的作用:可以调用model层定义的函数
    return { // 将返回的函数,绑定到this.props中
        add : function () {
            dispatch({ //通过dispatch调用modle中定义的函数,通过type属性,指定函数命名,格式:namespace/函数名
                type : namespace + "/addNewData"
            });
        },
        init : () => {
            dispatch({ //通过dispatch调用modle中定义的函数,通过type属性,指定函数命名,格式:namespace/函数名
                type : namespace + "/initData"
            });
        }
    }
})
class  List extends React.Component{

    componentDidMount(){
        //初始化的操作
        this.props.init();
    }

    render(){
        return (
            
    { this.props.dataList.map((value,index)=>{ return
  • {value}
  • }) }
{ this.props.add(); }}>点我
); } } export default List;

(04.ReactJS入门之dva的使用(实现点击事件)&)

04.ReactJS入门之dva的使用(实现点击事件)&

(05.ReactJS入门之Model中请求数据&)

05.ReactJS入门之Model中请求数据&

request.js

// import fetch from 'dva/fetch';

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 async function request(url, options) {
    const response = await fetch(url, options);
    checkStatus(response);
    return await response.json();
}

(06.ReactJS入门之mock数据&)

06.ReactJS入门之mock数据&

MockListData.js mock数据

export default {
    'get /ds/list': function (req, res) { //模拟请求返回数据
        res.json({
            data: [1, 2, 3, 4, 5],
            maxNum: 5
        });
    },
    'get /ds/user/list': function (req, res) {
        res.json([{
            key: '1',
            name: '张三1',
            age: 32,
            address: '上海市',
            tags: ['程序员', '帅气'],
        }, {
            key: '2',
            name: '李四2',
            age: 42,
            address: '北京市',
            tags: ['屌丝'],
        }, {
            key: '3',
            name: '王五3',
            age: 32,
            address: '杭州市',
            tags: ['高富帅', '富二代'],
        }]);
    }
}

(07.Ant Design入门之介绍&)

07.Ant Design入门之介绍&

(08.Ant Design入门之开始使用&)

08.Ant Design入门之开始使用&

MyTabs.js  tab组件

import React from 'react';
import { Tabs } from 'antd'; // 第一步,导入需要使用的组件

const TabPane = Tabs.TabPane;

function callback(key) {
    console.log(key);
}

class MyTabs extends React.Component{

    render(){
        return (
            
                hello antd wo de 第一个 tabs
                Content of Tab Pane 2
                Content of Tab Pane 3
            
        )
    }

}

export default MyTabs;

(09.Ant Design入门之布局&)

09.Ant Design入门之布局&

布局layout

src\layouts\index.js

导航栏 菜单链接

import React from 'react';
import { Layout, Menu, Icon } from 'antd';
import Link from 'umi/link';

const { Header, Footer, Sider, Content } = Layout;
const SubMenu = Menu.SubMenu;

class BasicLayout extends React.Component{

    constructor(props){
        super(props);
        this.state = {
            collapsed: false,
        }
    }

    render(){
        return (
            
                {minHeight: '100vh', color: 'white'}}
                    { height: '32px', background: 'rgba(255,255,255,.2)', margin: '16px'}}/
                    
                        
                            新增用户
                            新增列表
                        
                    
                
                
                    { background: '#fff', textAlign: 'center', padding: 0 }}Header
                    { margin: '24px 16px 0' }}
                        { padding: 24, background: '#fff', minHeight: 360 }}
                            {this.props.children}
                        
{ textAlign: 'center' }}后台系统 ©2018 Created by 黑马程序员 ) } } export default BasicLayout;

 

umi路由配置

props.children

(10.Ant Design入门之美化布局和引入导航条&)

10.Ant Design入门之美化布局和引入导航条&

(11.Ant Design入门之导航菜单添加链接&)

11.Ant Design入门之导航菜单添加链接&

src\pages\user\UserList.js

import React from 'react';
import { connect } from 'dva';

import {Table, Divider, Tag, Pagination } from 'antd';

const {Column} = Table;

const namespace = 'userList';

@connect((state)=>{
    return {
        data : state[namespace].list
    }
}, (dispatch) => {
    return {
        initData : () => {
            dispatch({
                type: namespace + "/initData"
            });
        }
    }
})
class UserList extends React.Component {

    componentDidMount(){
        this.props.initData();
    }

    render() {
        return (
            
{position:"bottom",total:500,pageSize:10, defaultCurrent:3}} ( {tags.map(tag => {tag})} )} /> ( 编辑 删除 )} />
); } } export default UserList;

src\pages\user\UserAdd.js

import React from 'react'

class UserAdd extends React.Component{

    render(){
        return (
            
新增用户
); } } export default UserAdd;

 

 

(12.Ant Design入门之表格的基本使用&)

12.Ant Design入门之表格的基本使用&

(13.Ant Design入门之表格的数据分离&)

13.Ant Design入门之表格的数据分离&

 

 

day03-项目介绍以及开发后台系统

(07.后台系统开发之form表单组件以及表单提交的讲解&)

07.后台系统开发之form表单组件以及表单提交的讲解&

form方法

表单校验

AddResource.js getFieldDecorator双向数据绑定,提交表单,class内部this,提交表单多选项,input组件设置

import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { formatMessage, FormattedMessage } from 'umi/locale';
import {
    Form,
    Input,
    DatePicker,
    Select,
    Button,
    Card,
    InputNumber,
    Radio,
    Icon,
    Tooltip,
    Checkbox,
    AutoComplete
} from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import PicturesWall from '../Utils/PicturesWall';

const FormItem = Form.Item;
const { Option } = Select;
const { RangePicker } = DatePicker;
const { TextArea } = Input;
const Search = Input.Search;
const InputGroup = Input.Group;
const CheckboxGroup = Checkbox.Group;

const estateMap = new Map([
  ['中远两湾城','1001|上海市,上海市,普陀区,远景路97弄'],
  ['上海康城','1002|上海市,上海市,闵行区,莘松路958弄'],
  ['保利西子湾','1003|上海市,上海市,松江区,广富林路1188弄'],
  ['万科城市花园','1004|上海市,上海市,闵行区,七莘路3333弄2区-15区'],
  ['上海阳城','1005|上海市,上海市,闵行区,罗锦路888弄']
]);


@connect(({ loading }) => ({
    submitting: loading.effects['form/submitRegularForm'],
}))
@Form.create()
class AddResource extends PureComponent {
    handleSubmit = e => {
        const { dispatch, form } = this.props;
        e.preventDefault();
      console.log(this.state.fileList);
        form.validateFieldsAndScroll((err, values) => {
            if (!err) {

              if(values.facilities){
                values.facilities = values.facilities.join(",");
              }
              if(values.floor_1 && values.floor_2){
                values.floor = values.floor_1 + "/" + values.floor_2;

              }

              values.houseType = values.houseType_1 + "室" + values.houseType_2 + "厅"
                                 + values.houseType_3 + "卫" + values.houseType_4 + "厨"
                                 + values.houseType_2 + "阳台";
              delete values.floor_1;
              delete values.floor_2;
              delete values.houseType_1;
              delete values.houseType_2;
              delete values.houseType_3;
              delete values.houseType_4;
              delete values.houseType_5;



              dispatch({
                    type: 'form/submitRegularForm',
                    payload: values,
                });
            }
        });
    };

    handleSearch = (value)=>{
      let arr = new Array();
      if(value.length > 0 ){
        estateMap.forEach((v, k) => {
          if(k.startsWith(value)){
            arr.push(k);
          }
        });
      }
      this.setState({
        estateDataSource: arr
      });
    } ;

  handleFileList = (obj)=>{
    console.log(obj, "图片列表");
  }


  constructor(props){
      super(props);
      this.state = {
        estateDataSource : [],
        estateAddress : '',
        estateId : ''
      }
    }

    render() {
        const { submitting } = this.props;
        const {
            form: { getFieldDecorator, getFieldValue },
        } = this.props;

        const formItemLayout = {
            labelCol: {
                xs: { span: 24 },
                sm: { span: 7 },
            },
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 12 },
                md: { span: 10 },
            },
        };

        const submitFormLayout = {
            wrapperCol: {
                xs: { span: 24, offset: 0 },
                sm: { span: 10, offset: 7 },
            },
        };



        return (
            
                { marginTop: 8 }}
                    
                        
                            { width: '100%' }}
                              dataSource={this.state.estateDataSource}
                              placeholder="搜索楼盘"
                              onSelect={(value, option)={
                                let v = estateMap.get(value);
                                this.setState({
                                  estateAddress: v.substring(v.indexOf('|')+1),
                                  estateId : v.substring(0,v.indexOf('|'))
                                });
                              }}
                              onSearch={this.handleSearch}
                              filterOption={(inputValue, option) => option.props.children.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1}
                            />
                        
                        
                          { color: 'rgba(0,0,0,.25)' }} /}
                             value={this.state.estateAddress} defaultValue={this.state.estateAddress} readOnly/
                        
                        
                            
                                {getFieldDecorator('buildingNum',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }}  addonAfter="栋" /)}
                                {getFieldDecorator('buildingUnit',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }}  addonAfter="单元" /)}
                                {getFieldDecorator('buildingFloorNum',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }}  addonAfter="门牌号" /)}
                            
                        
                        
                            
                              {getFieldDecorator('rent',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '50%' }} addonAfter="元/月" /)}
                            
                        
                        
                          {getFieldDecorator('paymentMethod',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '50%' }}
                              付一押一
                              付三押一
                              付六押一
                              年付押一
                              其它
                            
                          )}
                        
                        
                          {getFieldDecorator('rentMethod',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '50%' }}
                              整租
                              合租
                            
                          )}
                        
                        
                            
                              {getFieldDecorator('houseType_1',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%' }} addonAfter="室" /)}
                              {getFieldDecorator('houseType_2',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%', marginLeft: '5px' }} addonAfter="厅" /)}
                              {getFieldDecorator('houseType_3',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%', marginLeft: '5px' }} addonAfter="卫" /)}
                              {getFieldDecorator('houseType_4',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%', marginLeft: '5px' }} addonAfter="厨" /)}
                              {getFieldDecorator('houseType_5',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '23%', marginLeft: '5px' }} addonAfter="阳台" /)}
                            

                        
                        
                            
                              {getFieldDecorator('coveredArea',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '40%' }} addonAfter="平米" /)}
                            
                        
                        
                            
                              {getFieldDecorator('useArea',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '40%' }} addonAfter="平米" /)}
                            
                        
                        
                            
                              {getFieldDecorator('floor_1',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }} addonBefore="第" addonAfter="层" /)}
                              {getFieldDecorator('floor_2',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%', marginLeft: '10px' }} addonBefore="总" addonAfter="层" /)}
                            
                        
                        
                          {getFieldDecorator('orientation',{initialValue:'南',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '20%' }}
                              南
                              北
                              东
                              西
                            
                          )}
                        
                        
                          {getFieldDecorator('decoration',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '20%' }}
                              精装
                              简装
                              毛坯
                            
                          )}
                        
                        
                          {getFieldDecorator('facilities',{initialValue:['1','2','3'],rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            
                          )}
                        
                    
                    
                        
                          {getFieldDecorator('desc')
                          (
                            { minRows: 4, maxRows: 10 }} /
                          )}
                            请勿填写联系方式或与房源无关信息以及图片、链接或名牌、优秀、顶级、全网首发、零距离、回报率等词汇。
                        

                        
                            
                        
                    
                    
                        
                            
                              {getFieldDecorator('contact',{rules:[{ required: true, message:"此项为必填项" }]})
                              (
                                
                              )}
                            
                        
                        
                            
                              {getFieldDecorator('mobile',{rules:[{ required: true,max:11, message:"此项为必填项" }]})
                              (
                                
                              )}
                            
                        
                        
                          {getFieldDecorator('time',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '20%' }}
                              上午
                              中午
                              下午
                              晚上
                              全天
                            
                          )}

                        
                        
                          
                          {getFieldDecorator('propertyCost',{rules:[{ required: true,max:11, message:"此项为必填项" }]})
                          (
                              { width: '30%' }} addonAfter="元/平" /
                          )}
                          

                        

                        { marginTop: 32 }}
                            
                                
                            
                            { marginLeft: 8 }}
                                
                            
                        
                    
                
            
        );
    }
}

export default AddResource;

(08.后台系统开发之新增房源的自动完成功能的讲解&)

08.后台系统开发之新增房源的自动完成功能的讲解&

AutoComplete级联自动完成表单内容填写

 

day04-服务的具体实现以及MybatisPlus的入门

(10.新增房源服务实现之搭建工程&)

10.新增房源服务实现之搭建工程&

 

(11.新增房源服务实现之AutoGenerator使用以及创建pojo对象&)

11.新增房源服务实现之AutoGenerator使用以及创建pojo对象&

BasePojo.java lombok @Data

package cn.itcast.haoke.dubbo.server.pojo;

import lombok.Data;

import java.util.Date;

@Data
public abstract class BasePojo implements java.io.Serializable {

    private Date created;
    private Date updated;

}

HouseResources.java Accessors链式实体编程

package cn.itcast.haoke.dubbo.server.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.time.LocalDateTime;

/**
 * 

* 房源表 *

* * @author itcast */ @Data @Accessors(chain = true) @TableName("tb_house_resources") public class HouseResources extends BasePojo { private static final long serialVersionUID = 779152022777511825L; @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 房源标题 */ private String title; /** * 楼盘id */ private Long estateId; /** * 楼号(栋) */ private String buildingNum; /** * 单元号 */ private String buildingUnit; /** * 门牌号 */ private String buildingFloorNum; /** * 租金 */ private Integer rent; /** * 租赁方式,1-整租,2-合租 */ private Integer rentMethod; /** * 支付方式,1-付一押一,2-付三押一,3-付六押一,4-年付押一,5-其它 */ private Integer paymentMethod; /** * 户型,如:2室1厅1卫 */ private String houseType; /** * 建筑面积 */ private String coveredArea; /** * 使用面积 */ private String useArea; /** * 楼层,如:8/26 */ private String floor; /** * 朝向:东、南、西、北 */ private String orientation; /** * 装修,1-精装,2-简装,3-毛坯 */ private Integer decoration; /** * 配套设施, 如:1,2,3 */ private String facilities; /** * 图片,最多5张 */ private String pic; /** * 描述 */ private String houseDesc; /** * 联系人 */ private String contact; /** * 手机号 */ private String mobile; /** * 看房时间,1-上午,2-中午,3-下午,4-晚上,5-全天 */ private Integer time; /** * 物业费 */ private String propertyCost; }

ApiHouseResourcesService.java

package cn.itcast.haoke.dubbo.server.api;

import cn.itcast.haoke.dubbo.server.pojo.HouseResources;

public interface ApiHouseResourcesService {

    /**
     * 新增房源
     *
     * @param houseResources
     *
     * @return -1:输入的参数不符合要求,0:数据插入数据库失败,1:成功
     */
    int saveHouseResources(HouseResources houseResources);
}

(12.新增房源服务实现之新增房源服务的具体实现&)

12.新增房源服务实现之新增房源服务的具体实现&

 

(13.新增房源服务实现之新增房源RESTful接口的开发&)

13.新增房源服务实现之新增房源RESTful接口的开发

HouseResourcesService.java

package cn.itcast.haoke.dubbo.api.service;

import cn.itcast.haoke.dubbo.server.api.ApiHouseResourcesService;
import cn.itcast.haoke.dubbo.server.pojo.HouseResources;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

@Service
public class HouseResourcesService {

    @Reference(version = "1.0.0")
    private ApiHouseResourcesService apiHouseResourcesService;

    public boolean save(HouseResources houseResources) {
        int result =
                this.apiHouseResourcesService.saveHouseResources(houseResources);
        return result == 1;
    }
}

HouseResourcesController.java ResponseEntity @ResponseBody

package cn.itcast.haoke.dubbo.api.controller;

import cn.itcast.haoke.dubbo.api.service.HouseResourcesService;
import cn.itcast.haoke.dubbo.server.pojo.HouseResources;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("house/resources")
public class HouseResourcesController {

    @Autowired
    private HouseResourcesService houseResourcesService;

    /**
     * 新增房源
     *
     * @param houseResources json数据
     * @return
     */
    @PostMapping
    @ResponseBody
    public ResponseEntity save(@RequestBody HouseResources houseResources) {
        try {
            boolean bool = this.houseResourcesService.save(houseResources);
            if (bool) {
                return ResponseEntity.status(HttpStatus.CREATED).build();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }

    /**
     * test
     *
     * @return
     */
    @GetMapping
    @ResponseBody
    public ResponseEntity get() {
        return ResponseEntity.ok("ok");
    }
}

\models\form.js

import { routerRedux } from 'dva/router';
import { message } from 'antd';
import { addHouseResource } from '@/services/haoke';

export default {
  namespace: 'house',

  state: {

  },

  effects: {
    *submitHouseForm({ payload }, { call }) {
      yield call(addHouseResource, payload);
      message.success('提交成功');
    }
  },

  reducers: {
    saveStepFormData(state, { payload }) {
      return {
        ...state
      };
    },
  },
};

haoke.js

import request from '@/utils/request';

export async function addHouseResource(params) {
  return request('/haoke/house/resources', {
    method: 'POST',
    body: params
  });
}

request.js request封装状态码

import fetch from 'dva/fetch';
import { notification } from 'antd';
import router from 'umi/router';
import hash from 'hash.js';
import { isAntdPro } from './utils';

const codeMessage = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队(异步任务)。',
  204: '删除数据成功。',
  400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限(令牌、用户名、密码错误)。',
  403: '用户得到授权,但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除,且不会再得到的。',
  422: '当创建一个对象时,发生一个验证错误。',
  500: '服务器发生错误,请检查服务器。',
  502: '网关错误。',
  503: '服务不可用,服务器暂时过载或维护。',
  504: '网关超时。',
};

const checkStatus = response => {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }
  const errortext = codeMessage[response.status] || response.statusText;
  notification.error({
    message: `请求错误 ${response.status}: ${response.url}`,
    description: errortext,
  });
  const error = new Error(errortext);
  error.name = response.status;
  error.response = response;
  throw error;
};

const cachedSave = (response, hashcode) => {
  /**
   * Clone a response data and store it in sessionStorage
   * Does not support data other than json, Cache only json
   */
  const contentType = response.headers.get('Content-Type');
  if (contentType && contentType.match(/application\/json/i)) {
    // All data is saved as text
    response
      .clone()
      .text()
      .then(content => {
        sessionStorage.setItem(hashcode, content);
        sessionStorage.setItem(`${hashcode}:timestamp`, Date.now());
      });
  }
  return response;
};

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [option] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default function request(
  url,
  option,
) {
  const options = {
    expirys: isAntdPro(),
    ...option,
  };
  /**
   * Produce fingerprints based on url and parameters
   * Maybe url has the same parameters
   */
  const fingerprint = url + (options.body ? JSON.stringify(options.body) : '');
  const hashcode = hash
    .sha256()
    .update(fingerprint)
    .digest('hex');

  const defaultOptions = {
    credentials: 'include',
  };
  const newOptions = { ...defaultOptions, ...options };
  if (
    newOptions.method === 'POST' ||
    newOptions.method === 'PUT' ||
    newOptions.method === 'DELETE'
  ) {
    if (!(newOptions.body instanceof FormData)) {
      newOptions.headers = {
        Accept: 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        ...newOptions.headers,
      };
      newOptions.body = JSON.stringify(newOptions.body);
    } else {
      // newOptions.body is FormData
      newOptions.headers = {
        Accept: 'application/json',
        ...newOptions.headers,
      };
    }
  }

  const expirys = options.expirys && 60;
  // options.expirys !== false, return the cache,
  if (options.expirys !== false) {
    const cached = sessionStorage.getItem(hashcode);
    const whenCached = sessionStorage.getItem(`${hashcode}:timestamp`);
    if (cached !== null && whenCached !== null) {
      const age = (Date.now() - whenCached) / 1000;
      if (age < expirys) {
        const response = new Response(new Blob([cached]));
        return response.json();
      }
      sessionStorage.removeItem(hashcode);
      sessionStorage.removeItem(`${hashcode}:timestamp`);
    }
  }
  return fetch(url, newOptions)
    .then(checkStatus)
    .then(response => cachedSave(response, hashcode))
    .then(response => {
      // DELETE and 204 do not return data by default
      // using .json will report an error.
      if (newOptions.method === 'DELETE' || response.status === 204) {
        return response.text();
      }
      return response.json();
    })
    .catch(e => {
      const status = e.name;
      if (status === 401) {
        // @HACK
        /* eslint-disable no-underscore-dangle */
        window.g_app._store.dispatch({
          type: 'login/logout',
        });
        return;
      }
      // environment should not be used
      if (status === 403) {
        router.push('/exception/403');
        return;
      }
      if (status = 500) {
        router.push('/exception/500');
        return;
      }
      if (status >= 404 && status < 422) {
        router.push('/exception/404');
      }
    });
}

AddResource.js

import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { formatMessage, FormattedMessage } from 'umi/locale';
import {
    Form,
    Input,
    DatePicker,
    Select,
    Button,
    Card,
    InputNumber,
    Radio,
    Icon,
    Tooltip,
    Checkbox,
    AutoComplete
} from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import PicturesWall from '../Utils/PicturesWall';

const FormItem = Form.Item;
const { Option } = Select;
const { RangePicker } = DatePicker;
const { TextArea } = Input;
const Search = Input.Search;
const InputGroup = Input.Group;
const CheckboxGroup = Checkbox.Group;

const estateMap = new Map([
  ['中远两湾城','1001|上海市,上海市,普陀区,远景路97弄'],
  ['上海康城','1002|上海市,上海市,闵行区,莘松路958弄'],
  ['保利西子湾','1003|上海市,上海市,松江区,广富林路1188弄'],
  ['万科城市花园','1004|上海市,上海市,闵行区,七莘路3333弄2区-15区'],
  ['上海阳城','1005|上海市,上海市,闵行区,罗锦路888弄']
]);


@connect(({ loading }) => ({
    submitting: loading.effects['form/submitRegularForm'],
}))
@Form.create()
class AddResource extends PureComponent {
    handleSubmit = e => {
        const { dispatch, form } = this.props;
        e.preventDefault();
      console.log(this.state.fileList);
        form.validateFieldsAndScroll((err, values) => {
            if (!err) {
              if(values.facilities){
                values.facilities = values.facilities.join(",");
              }
              if(values.floor_1 && values.floor_2){
                values.floor = values.floor_1 + "/" + values.floor_2;

              }

              values.houseType = values.houseType_1 + "室" + values.houseType_2 + "厅"
                + values.houseType_3 + "卫" + values.houseType_4 + "厨"
                + values.houseType_2 + "阳台";
              delete values.floor_1;
              delete values.floor_2;
              delete values.houseType_1;
              delete values.houseType_2;
              delete values.houseType_3;
              delete values.houseType_4;
              delete values.houseType_5;

              // 楼盘id
              values.estateId =  this.state.estateId;

              dispatch({
                    type: 'house/submitHouseForm',
                    payload: values,
                });
            }
        });
    };

    handleSearch = (value)=>{
    let arr = new Array();
    if(value.length > 0 ){
      estateMap.forEach((v, k) => {
        if(k.startsWith(value)){
          arr.push(k);
        }
      });
    }
    this.setState({
      estateDataSource: arr
    });
  } ;

  handleFileList = (obj)=>{
    console.log(obj, "图片列表");
  }


  constructor(props){
      super(props);
      this.state = {
        estateDataSource : [],
        estateAddress : '',
        estateId : ''
      }
    }

    render() {
        const { submitting } = this.props;
        const {
            form: { getFieldDecorator, getFieldValue },
        } = this.props;

        const formItemLayout = {
            labelCol: {
                xs: { span: 24 },
                sm: { span: 7 },
            },
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 12 },
                md: { span: 10 },
            },
        };

        const submitFormLayout = {
            wrapperCol: {
                xs: { span: 24, offset: 0 },
                sm: { span: 10, offset: 7 },
            },
        };



        return (
            
                { marginTop: 8 }}
                    
                        
                            { width: '100%' }}
                              dataSource={this.state.estateDataSource}
                              placeholder="搜索楼盘"
                              onSelect={(value, option)={
                                let v = estateMap.get(value);
                                this.setState({
                                  estateAddress: v.substring(v.indexOf('|')+1),
                                  estateId : v.substring(0,v.indexOf('|'))
                                });
                              }}
                              onSearch={this.handleSearch}
                              filterOption={(inputValue, option) => option.props.children.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1}
                            />
                        
                        
                          { color: 'rgba(0,0,0,.25)' }} /}
                             value={this.state.estateAddress} defaultValue={this.state.estateAddress} readOnly/
                        
                        
                          {getFieldDecorator('title',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '100%' }}  /)}
                        
                        
                            
                                {getFieldDecorator('buildingNum',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }}  addonAfter="栋" /)}
                                {getFieldDecorator('buildingUnit',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }}  addonAfter="单元" /)}
                                {getFieldDecorator('buildingFloorNum',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }}  addonAfter="门牌号" /)}
                            
                        
                        
                            
                              {getFieldDecorator('rent',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '50%' }} addonAfter="元/月" /)}
                            
                        
                        
                          {getFieldDecorator('paymentMethod',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '50%' }}
                              付一押一
                              付三押一
                              付六押一
                              年付押一
                              其它
                            
                          )}
                        
                        
                          {getFieldDecorator('rentMethod',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '50%' }}
                              整租
                              合租
                            
                          )}
                        
                        
                            
                              {getFieldDecorator('houseType_1',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%' }} addonAfter="室" /)}
                              {getFieldDecorator('houseType_2',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%', marginLeft: '5px' }} addonAfter="厅" /)}
                              {getFieldDecorator('houseType_3',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%', marginLeft: '5px' }} addonAfter="卫" /)}
                              {getFieldDecorator('houseType_4',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '18%', marginLeft: '5px' }} addonAfter="厨" /)}
                              {getFieldDecorator('houseType_5',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '23%', marginLeft: '5px' }} addonAfter="阳台" /)}
                            

                        
                        
                            
                              {getFieldDecorator('coveredArea',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '40%' }} addonAfter="平米" /)}
                            
                        
                        
                            
                              {getFieldDecorator('useArea',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '40%' }} addonAfter="平米" /)}
                            
                        
                        
                            
                              {getFieldDecorator('floor_1',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%' }} addonBefore="第" addonAfter="层" /)}
                              {getFieldDecorator('floor_2',{rules:[{ required: true, message:"此项为必填项" }]})({ width: '30%', marginLeft: '10px' }} addonBefore="总" addonAfter="层" /)}
                            
                        
                        
                          {getFieldDecorator('orientation',{initialValue:'南',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '20%' }}
                              南
                              北
                              东
                              西
                            
                          )}
                        
                        
                          {getFieldDecorator('decoration',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '20%' }}
                              精装
                              简装
                              毛坯
                            
                          )}
                        
                        
                          {getFieldDecorator('facilities',{initialValue:['1','2','3'],rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            
                          )}
                        
                    
                    
                        
                          {getFieldDecorator('houseDesc')
                          (
                            { minRows: 4, maxRows: 10 }} /
                          )}
                            请勿填写联系方式或与房源无关信息以及图片、链接或名牌、优秀、顶级、全网首发、零距离、回报率等词汇。
                        

                        
                            
                        
                    
                    
                        
                            
                              {getFieldDecorator('contact',{rules:[{ required: true, message:"此项为必填项" }]})
                              (
                                
                              )}
                            
                        
                        
                            
                              {getFieldDecorator('mobile',{rules:[{ required: true,max:11, message:"此项为必填项" }]})
                              (
                                
                              )}
                            
                        
                        
                          {getFieldDecorator('time',{initialValue:'1',rules:[{ required: true, message:"此项为必填项" }]})
                          (
                            { width: '20%' }}
                              上午
                              中午
                              下午
                              晚上
                              全天
                            
                          )}

                        
                        
                          
                          {getFieldDecorator('propertyCost',{rules:[{ required: true,max:11, message:"此项为必填项" }]})
                          (
                              { width: '30%' }} addonAfter="元/平" /
                          )}
                          

                        

                        { marginTop: 32 }}
                            
                                
                            
                            { marginLeft: 8 }}
                                
                            
                        
                    
                
            
        );
    }
}

export default AddResource;

config.js 跨域代理设置

// https://umijs.org/config/
import os from 'os';
import pageRoutes from './router.config';
import webpackPlugin from './plugin.config';
import defaultSettings from '../src/defaultSettings';

export default {
  // add for transfer to umi
  plugins: [
    [
      'umi-plugin-react',
      {
        antd: true,
        dva: {
          hmr: true,
        },
        targets: {
          ie: 11,
        },
        locale: {
          enable: true, // default false
          default: 'zh-CN', // default zh-CN
          baseNavigator: true, // default true, when it is true, will use `navigator.language` overwrite default
        },
        dynamicImport: {
          loadingComponent: './components/PageLoading/index',
        },
        ...(!process.env.TEST && os.platform() === 'darwin'
          ? {
              dll: {
                include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'],
                exclude: ['@babel/runtime'],
              },
              hardSource: true,
            }
          : {}),
      },
    ],
    [
      'umi-plugin-ga',
      {
        code: 'UA-72788897-6',
        judge: () => process.env.APP_TYPE === 'site',
      },
    ],
  ],
  targets: {
    ie: 11,
  },
  define: {
    APP_TYPE: process.env.APP_TYPE || '',
  },
  // 路由配置
  routes: pageRoutes,
  // Theme for antd
  // https://ant.design/docs/react/customize-theme-cn
  theme: {
    'primary-color': defaultSettings.primaryColor,
  },
  externals: {
    '@antv/data-set': 'DataSet',
  },
  proxy: {
    '/haoke/': {
      target: 'http://127.0.0.1:18080',
      changeOrigin: true,
      pathRewrite: { '^/haoke/': '' }
    }
  },
  ignoreMomentLocale: true,
  lessLoaderOptions: {
    javascriptEnabled: true,
  },
  disableRedirectHoist: true,
  cssLoaderOptions: {
    modules: true,
    getLocalIdent: (context, localIdentName, localName) => {
      if (
        context.resourcePath.includes('node_modules') ||
        context.resourcePath.includes('ant.design.pro.less') ||
        context.resourcePath.includes('global.less')
      ) {
        return localName;
      }
      const match = context.resourcePath.match(/src(.*)/);
      if (match && match[1]) {
        const antdProPath = match[1].replace('.less', '');
        const arr = antdProPath
          .split('/')
          .map(a => a.replace(/([A-Z])/g, '-$1'))
          .map(a => a.toLowerCase());
        return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-');
      }
      return localName;
    },
  },
  manifest: {
    name: 'ant-design-pro',
    background_color: '#FFF',
    description: 'An out-of-box UI solution for enterprise applications as a React boilerplate.',
    display: 'standalone',
    start_url: '/index.html',
    icons: [
      {
        src: '/favicon.png',
        sizes: '48x48',
        type: 'image/png',
      },
    ],
  },

  chainWebpack: webpackPlugin,
  cssnano: {
    mergeRules: false,
  },
};

(14.前后端整合开发之新增房源&)

14.前后端整合开发之新增房源&

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

关注
打赏
1665965058
查看更多评论

最近更新

热门博客

立即登录/注册

微信扫码登录

0.0414s