Forráskód Böngészése

添加出租房源

liujq temp20230202 2 éve
szülő
commit
cd862afd61

+ 12 - 3
src/api/room.js

@@ -69,10 +69,19 @@ export default {
   apieshouseadd: params => { // 二手房 房源添加
     return request('/api/eshouse/add', params, 'loading')
   },
-  apieshousepricechange: params => { // 二手房 房源改价
-    return request('/api/eshouse/price/change', params, 'loading')
-  },
   apieshouseedit: params => { // 二手房 房源编辑
     return request('/api/eshouse/edit', params, 'loading')
   },
+  apirenthouselist: params => { // 二手房 出租 列表
+    return request('/api/rent/house/list', params, 'loading')
+  },
+  apirenthousedetail: params => { // 二手房 出租 详情
+    return request('/api/rent/house/detail', params, 'loading')
+  },
+  apirenthouseadd: params => { // 二手房 出租 添加
+    return request('/api/rent/house/add', params, 'loading')
+  },
+  apirenthouseedit: params => { // 二手房 出租 编辑
+    return request('/api/rent/house/edit', params, 'loading')
+  },
 }

+ 3 - 0
src/app.jsx

@@ -80,6 +80,7 @@ class App extends Component {
           'center/userEdit',
           'center/uploadRoom',
           'center/uploadRoom2',
+          'center/rentRoom',
           'comment/add',
           'comment/list',
           'comment/dtl',
@@ -133,6 +134,8 @@ class App extends Component {
         pages: [
           'estate',
           'list',
+          'rentlist',
+          'rentdtl',
           'dtl',
           'roomPrice',
           'roomPriceImg',

+ 8 - 1
src/pagesMore/center/index.jsx

@@ -208,7 +208,14 @@ class Index extends Component {
             </Navigator>
             <Navigator url="/pagesMore/center/uploadRoom2" className="entry-op">
               <Image src={icon4} className="entry-icon"></Image>
-              <View className="entry-text">上传房源2</View>
+              <View className="entry-text">上传房源</View>
+              <View className="entry-right">
+                <Image src={iconSign} className="sign"></Image>
+              </View>
+            </Navigator>
+            <Navigator url="/pagesMore/center/rentRoom" className="entry-op">
+              <Image src={icon4} className="entry-icon"></Image>
+              <View className="entry-text">添加租房</View>
               <View className="entry-right">
                 <Image src={iconSign} className="sign"></Image>
               </View>

+ 703 - 0
src/pagesMore/center/rentRoom.jsx

@@ -0,0 +1,703 @@
+import Taro, { Component } from '@tarojs/taro'
+import { View } from '@tarojs/components'
+import { AtTextarea }  from 'taro-ui'
+import LFormGroup from '@/c/lform/formGroup'
+const HLKEY = '654mca0l38b489d9'
+const CJ = require('crypto-js')
+import './rentRoom.scss'
+
+
+import { TaroCropper } from 'taro-cropper'
+
+class Index extends Component {
+
+  onShareAppMessage() {
+    return {
+      title: `自助上传房源`,
+    }
+  }
+  onShareTimeline () {
+    return {
+      title: `自助上传房源`,
+    }
+  }
+
+
+  constructor (props) {
+    super(props)
+    this.state = {
+      addr1: '',
+      addr2: '',
+      addr3: '',
+      hType1: '',
+      hType2: '',
+      hType3: '',
+      sRate1: '',
+      sRate2: '',
+      formObj: {
+        hide_status: '1',
+      },
+      imgArr: [],
+      cutImgTempUrl: '',
+      cutImgShow: false,
+    }
+  }
+  config = {
+    navigationBarTitleText: '出租',
+  }
+
+  componentWillMount () {
+    Taro.$AHU(this)
+  }
+
+  componentDidMount() {
+    const {id} = this.$router.params
+    if (id) {
+      Taro.api.room.apirenthousedetail({id}).then(res => {
+        let cObj = res || {}
+        // console.log(cObj)
+        const addr = cObj.house_no ? cObj.house_no.split('-') : []
+        const hType = cObj.house_type ? cObj.house_type.split('-') : []
+        const sRate = cObj.stairs_rate ? cObj.stairs_rate.split('-') : []
+        Taro.setNavigationBarTitle({
+          title: cObj.sale_user.sale_name + '-出租'
+        })
+        this.setState({
+          formObj: {
+            id: cObj.id,
+            hide_status: cObj.hide_status || '1',
+            estate_id: cObj.estate_id || '',
+            estate_name: cObj.estate_name || '',
+            title: cObj.title || '',
+            house_no: cObj.house_no || '',
+            delivery_at: cObj.delivery_at || '',
+            price: cObj.price || '',
+            area: cObj.area || '',
+            floor: cObj.floor || '',
+            storeys: cObj.storeys || '',
+            is_dec: cObj.is_dec || '',
+            is_elevator: cObj.is_elevator || '',
+            owner: cObj.owner || '',
+            owner_phone: cObj.owner_phone || '',
+            introduce: cObj.introduce || '',
+            remarked: cObj.remarked || '',
+            pri_image: cObj.pri_image || '',
+            house_img: cObj.house_img || '',
+            position: cObj.position || '',
+            // floor_price: cObj.floor_price || '',
+          },
+          imgArr: (cObj.images && cObj.images.length > 0) ? cObj.images.split(',') : [],
+          addr1: addr[0],
+          addr2: addr[1],
+          addr3: addr[2],
+          hType1: hType[0],
+          hType2: hType[1],
+          hType3: hType[2],
+          sRate1: sRate[0],
+          sRate2: sRate[1],
+        })
+      })
+    }
+  }
+
+
+
+  saveHandle () {
+    const { formObj, imgArr, addr1, addr2, addr3, hType1, hType2, hType3, sRate1, sRate2 } = this.state
+    let house_no = ''
+    if (addr1 && addr2 && addr3) {
+      house_no = `${addr1}-${addr2}-${addr3}`
+    } else {
+      Taro.$msg('请输入楼栋单号房间号')
+      return
+    }
+    let house_type = ''
+    if (hType1 && hType2 && hType3) {
+      house_type = `${hType1}-${hType2}-${hType3}`
+    }
+    let stairs_rate = ''
+    if (sRate1 && sRate2) {
+      stairs_rate = `${sRate1}-${sRate1}`
+    }
+    
+    // console.log(formObj.estate_id, formObj.title, formObj.pri_image)
+    let apiStr = 'apirenthouseadd'
+    let params = {
+      estate_id: formObj.estate_id,
+      title: formObj.title,
+      house_no,
+      delivery_at: formObj.delivery_at,
+      house_type,
+      stairs_rate,
+      price: formObj.price,
+      area: formObj.area,
+      floor: formObj.floor,
+      storeys: formObj.storeys,
+      is_dec: formObj.is_dec,
+      is_elevator: formObj.is_elevator,
+      owner: formObj.owner,
+      owner_phone: formObj.owner_phone,
+      introduce: formObj.introduce,
+      remarked: formObj.remarked,
+      hide_status: formObj.hide_status,
+      pri_image: formObj.pri_image,
+      house_img: formObj.house_img,
+      position: formObj.position,
+      // floor_price: formObj.floor_price,
+      images: imgArr.join(','),
+    }
+    if (formObj.id) {
+      apiStr = 'apirenthouseedit'
+      params.id = formObj.id
+    }
+    if (formObj.estate_id && formObj.title && formObj.pri_image) {
+      Taro.api.room[apiStr](params).then(res => {
+        Taro.$msgConfirm('操作成功', () => {
+          Taro.navigateBack({
+            delta: 1
+          })
+        }, () => {
+          Taro.navigateBack({
+            delta: 1
+          })
+        })
+      })
+    } else {
+      if (!formObj.estate_id) Taro.$msg('楼盘必填')
+      if (!formObj.title) Taro.$msg('标题必填')
+      if (!formObj.pri_image) Taro.$msg('封面图必填')
+    }
+  }
+
+  baseFormChange (key, val) {
+    let { formObj } = this.state
+    formObj[key] = val
+    this.setState({
+      formObj
+    })
+  }
+
+  dealImgHandle (key, moreStr) {
+    this.uploadComImg((val) => {
+      let { formObj } = this.state
+      formObj[key] = val
+      this.setState({
+        formObj
+      })
+    }, 1, moreStr)
+  }
+
+  addImg () {
+    this.uploadComImg((arr) => {
+      let { imgArr } = this.state
+      imgArr = [...imgArr, ...arr]
+      this.setState({
+        imgArr
+      })
+    }, 9)
+  }
+  uploadComImg (bc, count, moreStr) {
+    const that = this
+    Taro.chooseImage({
+      count: count ? count : 1, // 默认9
+      sizeType: ['compressed'],  // original
+      sourceType: ['album', 'camera'],
+      success: function (res) {
+        const tempFilePaths = res.tempFilePaths
+        if (tempFilePaths.length > 0) {
+          let imgBcArr = []
+          tempFilePaths.forEach((p, i) => {
+            that.diyUploadFile(p, moreStr).then(url => {
+              imgBcArr.push(url)
+              if (bc && imgBcArr.length === tempFilePaths.length) {
+                bc(imgBcArr)
+              }
+            })
+          })
+        }
+      }
+    })
+  }
+  diyUploadFile (filePath, moreStr) {
+    return new Promise((resolve, reject) => {
+      let token = Taro.getStorageSync('APP_token')
+      let url = `https://api.honglouplus.com/api/upload/cloudpir`
+      if (moreStr === 'noSign') url = `https://api.honglouplus.com/api/upload/cloud`
+      Taro.uploadFile({
+        url,
+        filePath,
+        name: 'upload',
+        formData: {
+          'token': token
+        },
+        success (res){
+          const msg = res.data || ''
+          const key = CJ.enc.Utf8.parse(HLKEY)
+          const bytes = CJ.AES.decrypt(msg, key, {
+            mode: CJ.mode.ECB,
+            padding: CJ.pad.Pkcs7
+          })
+          const originalText = bytes.toString(CJ.enc.Utf8)
+          const cData = JSON.parse(originalText)
+          const curImg =  cData.data.url || ''
+          resolve(curImg)
+        }
+      })
+    })
+  }
+  delImg (index) {
+    let { imgArr } = this.state
+    imgArr.splice(index, 1)
+    this.setState({
+      imgArr
+    })
+  }
+  previewImageHandle (current, arr) {
+    const { imgArr } = this.state
+    let nArr = imgArr.map(item => {
+      return item + '_plus'
+    })
+    Taro.previewImage({
+      current,
+      urls: nArr
+    })
+  }
+
+
+
+
+  renderAddr () {
+    const { addr1, addr2, addr3 } = this.state
+    return (
+      <View className="scoped-addr-box">
+        <Input type="number" value={addr1} onInput={this.changeAddrInput.bind(this, 'addr1')}  className="i" placeholder="__" />
+        <View className='t'>栋座</View>
+        <Input type="number" value={addr2} onInput={this.changeAddrInput.bind(this, 'addr2')}  className="i" placeholder="__" />
+        <View className='t'>单元</View>
+        <Input type="number" value={addr3} onInput={this.changeAddrInput.bind(this, 'addr3')}  className="i" placeholder="__" />
+        <View className='t'>室号</View>
+      </View>
+    )
+  }
+  renderHouseType () {
+    const { hType1, hType2, hType3 } = this.state
+    return (
+      <View className="scoped-addr-box">
+        <Input type="number" value={hType1} onInput={this.changeAddrInput.bind(this, 'hType1')}  className="i" placeholder="__" />
+        <View className='t'>室</View>
+        <Input type="number" value={hType2} onInput={this.changeAddrInput.bind(this, 'hType2')}  className="i" placeholder="__" />
+        <View className='t'>厅</View>
+        <Input type="number" value={hType3} onInput={this.changeAddrInput.bind(this, 'hType3')}  className="i" placeholder="__" />
+        <View className='t'>卫</View>
+      </View>
+    )
+  }
+  changeAddrInput (str, e) {
+    this.setState({
+      [str]: e.detail.value
+    })
+  }
+  
+
+  renderStairsRate () {
+    const { sRate1, sRate2 } = this.state
+    return (
+      <View className='scoped-floor-height-box'>
+        <Input type="number" value={sRate1} onInput={this.changeAddrInput.bind(this, 'sRate1')}  className="i" placeholder="__" />
+        <View className='t'>梯</View>
+        <Input type="number" value={sRate2} onInput={this.changeAddrInput.bind(this, 'sRate2')}  className="i" placeholder="__" />
+        <View className='t'>户</View>
+      </View>
+    )
+  }
+  renderFloorHeight () {
+    const { formObj } = this.state
+    return (
+      <View className='scoped-floor-height-box'>
+        <Input type="number" value={formObj.floor} onInput={this.changeFormObjInput.bind(this, 'floor')}  className="i" placeholder="所在楼层" />
+        <View className='t'>/</View>
+        <Input type="number" value={formObj.storeys} onInput={this.changeFormObjInput.bind(this, 'storeys')}  className="i" placeholder="总楼层" />
+        <View className='t'>层</View>
+      </View>
+    )
+  }
+  changeFormObjInput (str, e) {
+    let { formObj } = this.state
+    formObj[str] = e.detail.value
+    this.setState({
+      formObj
+    })
+  }
+
+
+
+
+
+
+
+
+
+
+
+  renderCutImg () {
+    const { cutImgTempUrl } = this.state
+    const { cutImgShow } = this.state
+    return (
+      <View className={cutImgShow ? 'scoped-ci-popup show' : 'scoped-ci-popup'}>
+        <TaroCropper
+          src={cutImgTempUrl}
+          cropperWidth={375}
+          cropperHeight={250}
+          fullScreen
+          onCut={this.cutHandle.bind(this)}
+        />
+      </View>
+    )
+  }
+  cutHandle (filePath) {
+    let { formObj } = this.state
+    let token = Taro.getStorageSync('APP_token')
+    const that = this
+    Taro.uploadFile({
+      url: `https://api.honglouplus.com/api/upload/cloudpir`,
+      filePath,
+      name: 'upload',
+      formData: {
+        'token': token
+      },
+      success (res){
+        const msg = res.data || ''
+        const key = CJ.enc.Utf8.parse(HLKEY)
+        const bytes = CJ.AES.decrypt(msg, key, {
+          mode: CJ.mode.ECB,
+          padding: CJ.pad.Pkcs7
+        })
+        const originalText = bytes.toString(CJ.enc.Utf8)
+        const cData = JSON.parse(originalText)
+        formObj.pri_image = cData.data.url || ''
+        that.setState({
+          cutImgShow: false,
+          formObj,
+        })
+      }
+    })
+  }
+  openCutImg () {
+    Taro.chooseImage({
+      count: 1,
+      sizeType: ['compressed'],
+      sourceType: ['album', 'camera'],
+    }).then(res => {
+      this.setState({
+        cutImgTempUrl: res.tempFilePaths[0],
+        cutImgShow: true,
+      })
+    })
+  }
+
+
+  render () {
+    const { formObj, imgArr } = this.state
+    const dictData = Taro.getStorageSync('dictData')
+    const roomDecMoreOptions = {arr: dictData.room_dec}
+    const yesnoMoreOptions = {arr: [...dictData.sys_yesno]}
+    const hideStatusoMoreOptions = {arr: [...dictData.hide_status]}
+    const roomPositionMoreOptions = {arr: [...dictData.room_position]}
+    const addIcon = require('@img/icon_upload_img.png')
+    const closeIcon = require('@img/icon_g_close.png')
+    const imgItems = imgArr.map((src, index) => {
+      return (
+        <View className="si-op" key={index}>
+          <Image src={src + '_plus'} className="img" onClick={this.previewImageHandle.bind(this, src + '_plus')} />
+          <Image src={closeIcon} className="i" onClick={this.delImg.bind(this, index)}/>
+        </View>
+      )
+    })
+    let moreEstateOptions = {
+      api: 'house.admestatelist',
+      opKey: 'estate_name',
+      opVal: 'id',
+      skey: 'estate_name',
+    }
+    
+    return (
+      <View className="l-box">
+        {/* {this.renderCutImg()} */}
+        {
+          formObj.estate_name
+          ?
+          <View className="l-floor-pos2">
+            <Navigator url={`/pagesHouse/indexDtl?id=${formObj.estate_id}`} className='scoped-estate-name'>{formObj.estate_name}{'>'}</Navigator>
+            <LFormGroup
+              val={formObj.estate_id}
+              valStr="estate_id"
+              keyStr="当前楼盘"
+            />
+          </View>
+          :
+          <LFormGroup
+            val={formObj.estate_id}
+            valStr="estate_id"
+            keyStr="选楼盘(必填)"
+            keyStr2="请选择"
+            typeStr="radio"
+            moreOptions={moreEstateOptions}
+            bc={this.baseFormChange.bind(this)}
+          />
+        }
+        {/* <View className="l-floor-pos2">
+          {
+            formObj.estate_name
+            ?
+            <View className='scoped-estate-name'>{formObj.estate_name}[{formObj.estate_id}]</View>
+            : ''
+          }
+          <LFormGroup
+            val={formObj.estate_id}
+            valStr="estate_id"
+            keyStr="选楼盘(必填)"
+            keyStr2="请选择"
+            typeStr="radio"
+            moreOptions={moreEstateOptions}
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View> */}
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.title}
+            valStr="title"
+            keyStr="标题(必填)"
+            keyStr2="请总结概括该房源特色"
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.house_no}
+            valStr="house_no"
+            keyStr="地址(必填)"
+          />
+          {this.renderAddr()}
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.house_type}
+            valStr="house_type"
+            keyStr="户型"
+          />
+          {this.renderHouseType()}
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.floor}
+            valStr="floor"
+            keyStr="楼层"
+          />
+          {this.renderFloorHeight()}
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.stairs_rate}
+            valStr="stairs_rate"
+            keyStr="梯户比"
+          />
+          {this.renderStairsRate()}
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.area}
+            valStr="area"
+            keyStr="房屋面积"
+            keyStr2="请输入"
+            typeStr="inputFont"
+            inputFont="㎡"
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.price}
+            valStr="price"
+            keyStr="出租价格"
+            keyStr2="请输入"
+            typeStr="inputFont"
+            inputFont="元"
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        {/* <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.floor_price}
+            valStr="floor_price"
+            keyStr="实际底价"
+            keyStr2="请输入"
+            typeStr="inputFont"
+            inputFont="元"
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View> */}
+        
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.owner}
+            valStr="owner"
+            keyStr="业主姓名"
+            keyStr2="请输入"
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.owner_phone}
+            valStr="owner_phone"
+            keyStr="业主电话"
+            keyStr2="请输入"
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.is_dec}
+            valStr="is_dec"
+            keyStr="装修情况"
+            keyStr2="请选择"
+            typeStr="select"
+            moreOptions={roomDecMoreOptions}
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.is_elevator}
+            valStr="is_elevator"
+            keyStr="有电梯"
+            keyStr2="请选择"
+            typeStr="select"
+            moreOptions={yesnoMoreOptions}
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.delivery_at}
+            valStr="delivery_at"
+            keyStr="交房时间"
+            keyStr2="请选择"
+            dateFields="month"
+            typeStr="date"
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.hide_status}
+            valStr="hide_status"
+            keyStr="显示隐藏"
+            keyStr2="请选择"
+            typeStr="select"
+            moreOptions={hideStatusoMoreOptions}
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className="l-floor-pos2">
+          <LFormGroup
+            val={formObj.position}
+            valStr="position"
+            keyStr="户型方位"
+            keyStr2="请选择"
+            typeStr="select"
+            moreOptions={roomPositionMoreOptions}
+            bc={this.baseFormChange.bind(this)}
+          />
+        </View>
+        <View className='scoped-has-right'>
+          <View className="scoped-box">
+            <View className="sb-title">封面主图片(必填)</View>
+            <View className="scoped-img">
+              {
+                formObj.pri_image
+                ?
+                <View className="si-op" onClick={this.dealImgHandle.bind(this, 'pri_image')}>
+                  <Image src={formObj.pri_image + '_plus'} className="img"/>
+                </View>
+                :
+                <View className="si-op" onClick={this.dealImgHandle.bind(this, 'pri_image')}>
+                  <Image src={addIcon} className="img"/>
+                </View>
+              }
+              {/* {
+                formObj.pri_image
+                ?
+                <View className="si-op" onClick={this.openCutImg.bind(this)}>
+                  <Image src={formObj.pri_image + '_plus'} className="img"/>
+                </View>
+                :
+                <View className="si-op" onClick={this.openCutImg.bind(this)}>
+                  <Image src={addIcon} className="img"/>
+                </View>
+              } */}
+            </View>
+          </View>
+          <View className="scoped-box shr-r">
+            <View className="sb-title">户型图</View>
+            <View className="scoped-img">
+              {
+                formObj.house_img
+                ?
+                <View className="si-op" onClick={this.dealImgHandle.bind(this, 'house_img', 'noSign')}>
+                  <Image src={formObj.house_img} className="img"/>
+                </View>
+                :
+                <View className="si-op" onClick={this.dealImgHandle.bind(this, 'house_img', 'noSign')}>
+                  <Image src={addIcon} className="img"/>
+                </View>
+              }
+            </View>
+          </View>
+        </View>
+        <View className="scoped-box">
+          <View className="sb-title">房源图片
+            <View className="s">(最多9张)</View>
+          </View>
+          <View className="scoped-img">
+            {imgItems}
+            {
+              imgArr.length < 9
+              &&
+              <View className="si-op" onClick={this.addImg.bind(this)}>
+                <Image src={addIcon} className="img"/>
+              </View>
+            }
+          </View>
+        </View>
+        <View className="scoped-box">
+          <View className="sb-title">更多对外描述</View>
+          <AtTextarea
+            value={formObj.introduce}
+            onChange={this.baseFormChange.bind(this, 'introduce')}
+            maxLength={300}
+            height={200}
+            placeholder='更多需要补充的描述,对外公开(300字以内)'
+          />
+        </View>
+        <View className="scoped-box">
+          <View className="sb-title">内部备注</View>
+          <AtTextarea
+            value={formObj.remarked}
+            onChange={this.baseFormChange.bind(this, 'remarked')}
+            maxLength={300}
+            height={200}
+            placeholder='仅编辑查看,房源内部备注信息(300字以内)'
+          />
+        </View>
+        <View className="l-floor-footer t2">
+          <View className="lff-flex">
+            <View className="lff-btn full" onClick={this.saveHandle.bind(this)}>提交</View>
+          </View>
+        </View>
+      </View>
+    )
+  }
+}
+
+export default Index

+ 145 - 0
src/pagesMore/center/rentRoom.scss

@@ -0,0 +1,145 @@
+@import '@css/mixin.scss';
+.scoped-box {
+  padding: 20px 20px 0;
+  .sb-title {
+    font-size: 30px;
+    color: #333;
+    padding-bottom: 20px;
+    font-weight: bold;
+    padding-left: 10px;
+    .s {
+      display: inline-block;
+      font-size: 24px;
+      color: #999;
+      font-weight: normal;
+    }
+  }
+}
+.at-textarea {
+  border: 1PX solid #f2f2f2;
+}
+.at-textarea__textarea {
+  font-size: 28px;
+  color: #333;
+}
+
+.scoped-img {
+  .si-op {
+    display: inline-block;
+    vertical-align: middle;
+    width: 200px;
+    height: 200px;
+    margin-right: 30px;
+    margin-bottom: 30px;
+    position: relative;
+    border: 1PX solid #f2f2f2;
+    .img {
+      width: 200px;
+      height: 200px;
+    }
+    .i {
+      position: absolute;
+      top: -20px;
+      right: -20px;
+      width: 40px;
+      height: 40px;
+    }
+  }
+}
+
+
+
+
+
+
+
+.scoped-addr-box {
+  position: absolute;
+  right: 20px;
+  top: 0;
+  width: 70%;
+  z-index: 2;
+  background: #fff;
+  display: flex;
+  height: 90px;
+  // border-bottom: 1PX solid #f2f2f2;
+  .i {
+    flex: 3;
+    font-size: 28px;
+    line-height: 90px;
+    text-align: right;
+    height: 90px;
+    padding-right: 10px;
+  }
+  .t {
+    flex: 2;
+    font-size: 28px;
+    color: #999;
+    height: 90px;
+    line-height: 90px;
+  }
+}
+
+.scoped-floor-height-box {
+  position: absolute;
+  right: 20px;
+  top: 0;
+  width: 50%;
+  background: #fff;
+  display: flex;
+  height: 90px;
+  z-index: 2;
+  .i {
+    flex: 2;
+    font-size: 28px;
+    line-height: 90px;
+    height: 90px;
+    text-align: center;
+  }
+  .t {
+    flex: 1;
+    font-size: 28px;
+    color: #999;
+    line-height: 90px;
+    height: 90px;
+    text-align: center;
+  }
+}
+
+.scoped-estate-name {
+  position: absolute;
+  right: 20px;
+  top: 0;
+  width: 70%;
+  background: #fff;
+  height: 90px;
+  line-height: 90px;
+  text-align: right;
+  z-index: 9;
+}
+
+
+.scoped-has-right {
+  position: relative;
+  .shr-r {
+    position: absolute;
+    right: 20px;
+    top: 0;
+  }
+}
+
+.scoped-ci-popup {
+  position: fixed;
+  z-index: 99999;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  height: 0;
+  width: 100%;
+  overflow: hidden;
+  background: #000;
+  &.show {
+    height: 100%;
+  }
+}

+ 427 - 0
src/pagesRoom/rentdtl.jsx

@@ -0,0 +1,427 @@
+import Taro, { Component } from '@tarojs/taro'
+import { View, Swiper, SwiperItem } from '@tarojs/components'
+import { AtCurtain } from 'taro-ui'
+import { arrToObj } from '@utils'
+import Rooms from './components/dtl/rooms'
+import './rentdtl.scss'
+
+class Index extends Component {
+  onShareAppMessage() {
+    const { curId, curObj } = this.state
+    return {
+      title: `${curObj.title}`,
+      path: `/pagesRoom/rentdtl?id=${curId}`,
+    }
+  }
+  onShareTimeline () {
+    const { curId, curObj } = this.state
+    return {
+      title: `${curObj.title}`,
+      path: `/pagesRoom/rentdtl?id=${curId}`,
+    }
+  }
+
+  constructor (props) {
+    super(props)
+    const {id: curId} = this.$router.params
+    this.state = {
+      curId,
+      curObj: {},
+      curImgIndex: 0,
+      curShareCardImg: require('./img/dtl/bg_room_dtl.png')
+    }
+  }
+
+  config = {
+    navigationBarTitleText: '出租房源详情',
+  }
+
+  componentWillMount () {
+    Taro.$AHU(this)
+    this.getDtl()
+    // this.popupOpen()
+  }
+  
+  getDtl = () => {
+    const { curId } = this.state
+    Taro.api.room.apirenthousedetail({id: curId}).then(res => {
+      Taro.setNavigationBarTitle({
+        title: res.title || '出租房源详情'
+      })
+      this.drawAndShareImage(res.mini_coder)
+      this.setState({
+        curObj: res || {}
+      }, () =>{
+        if (this.subRooms) this.subRooms.getData(res.old_house_list || [])
+      })
+    })
+  }
+
+  componentDidShow () { }
+
+  componentDidHide () { }
+
+  renderHeader () {
+    const { curImgIndex, curObj } = this.state
+    let moreImg = []
+    let images = curObj.images ? curObj.images.split(',') : []
+    images.forEach(url => {
+      moreImg.push({img_url: `${url}`})
+    })
+    const imgArr = [{img_url: `${curObj.pri_image}`}, ...moreImg, {img_url: curObj.house_img}]
+    return (
+      <View className="dtl-header">
+        <Swiper
+          circular
+          current={curImgIndex}
+          onChange={this.headerImgChange.bind(this)}
+          className='dh-swiper'>
+            {
+              imgArr.map((item, index) => {
+                return (
+                  <SwiperItem key={index}>
+                    <View className='dh-item'>
+                      <Image src={item.img_url ? item.img_url + '_white' : ''} className="img" onClick={this.previewImage2Handle.bind(this, item.img_url, imgArr)} />
+                    </View>
+                  </SwiperItem>
+                )
+              })
+            }
+        </Swiper>
+        <View className="dh-count">
+          <View className="bg"></View>
+          <View className="num">{curImgIndex + 1}/{imgArr.length}</View>
+        </View>
+      </View>
+    )
+  }
+  headerImgChange (e) {
+    this.setState({
+      curImgIndex: e.detail.current || 0
+    })
+  }
+  previewImage2Handle (cur, arr) {
+    const current = `${cur}_plus`
+    const urls = arr.map(item => {
+      return `${item.img_url}_plus`
+    })
+    Taro.previewImage({
+      current,
+      urls
+    })
+  }
+
+
+  renderQrcode () {
+    const qrcodeImg = 'http://icon.honglounews.com/miniqrcode.jpg'
+    return (
+      <Image src={qrcodeImg} className="scoped-qrcode"  onClick={this.previewQrcodeImageHandle.bind(this, qrcodeImg, [qrcodeImg])} />
+    )
+  }
+  previewQrcodeImageHandle (current, urls) {
+    Taro.previewImage({
+      current,
+      urls
+    })
+  }
+
+
+  editHandle () {
+    const { curId } = this.state
+    const appUserInfo = Taro.getStorageSync('APP_userInfo')
+    if (appUserInfo.is_sale == 1) {
+      Taro.navigateTo({
+        url: `/pagesMore/center/rentRoom?id=${curId}`
+      })
+    }
+  }
+  
+  renderMain () {
+    const dictData = Taro.getStorageSync('dictData')
+    const atObj = arrToObj(dictData.area_type)
+    const hryObj = arrToObj(dictData.house_room_year)
+    const roomDecObj = arrToObj(dictData.room_dec)
+    const yesnoObj = arrToObj(dictData.sys_yesno)
+    const { curObj } = this.state
+    const tagArr = curObj.custom_tag ? curObj.custom_tag.split(',') : []
+    const moreImg = require('./img/dtl/bg_estate.png')
+    const FH = Number(curObj.floor) || 1
+    const H = Number(curObj.storeys) || 1
+    let FHstr = '未知'
+    if (FH > H * 0.6666) {
+      FHstr = '中高层'
+    } else if (FH > H * 0.33333) {
+      FHstr = '中楼层'
+    } else {
+      FHstr = '中低层'
+    }
+    if (FH === 1) FHstr = '一楼'
+    if (FH === H) FHstr = '顶楼'
+
+    let houseTypeStr = '未知'
+    if (curObj.house_type) {
+      let arr = curObj.house_type.split('-')
+      houseTypeStr = `${arr[0]}室${arr[1]}厅${arr[2]}卫`
+    }
+    return (
+      <View className="scoped-main">
+        {this.renderQrcode()}
+        <View className="sm-tags">
+          {
+            tagArr.map((tag, tI) => {
+              return (
+                <View className="s" key={tI}>{tag}</View>
+              )
+            })
+          }
+        </View>
+        <View className="sm-title" onClick={this.editHandle.bind(this)}>{curObj.title}</View>
+        <View className="sm-op">
+          <View className="op">
+            <View className="k">价格:</View>
+            <View className="v">{curObj.price}元/月</View>
+          </View>
+          <View className="op">
+            <View className="k">面积:</View>
+            <View className="v">{curObj.area}㎡</View>
+          </View>
+          <View className="op" onClick={this.houseImgHandle.bind(this)}>
+            <View className="k">户型:</View>
+            <View className="v">{houseTypeStr}
+              <View className="s">查看户型</View>
+            </View>
+          </View>
+          <View className="op">
+            <View className="k">预约:</View>
+            <View className="v">朝向梯户比?<View onClick={this.countHandle.bind(this, 'chat')} className="s">【免费咨询】</View></View>
+          </View>
+          <View className="op">
+            <View className="k">楼盘:</View>
+            <View className="v">{curObj.estate_name}<View onClick={this.dtlLink.bind(this)}  className="s">查看该楼盘</View></View>
+          </View>
+          <View className="op">
+            <View className="k">楼层:</View>
+            <View className="v">{FHstr}/{curObj.storeys}层</View>
+          </View>
+          <View className="op">
+            <View className="k">装修状态:</View>
+            <View className="v">{roomDecObj[curObj.is_dec]}</View>
+          </View>
+          <View className="op">
+            <View className="k">交房时间:</View>
+            <View className="v">{curObj.delivery_at}</View>
+          </View>
+          <View className="op">
+            <View className="k">是否电梯:</View>
+            <View className="v">{yesnoObj[curObj.is_elevator]}</View>
+          </View>
+          <Navigator url={`/pagesHouse/indexDtlAround?id=${curObj.estate_id}&name=${curObj.estate_name}`} className="op">
+            <View className="k">区域:</View>
+            <View className="v">{atObj[curObj.area_type]}<View className="s">查看周边配套</View></View>
+          </Navigator>
+          <View className="op">
+            <View className="k">录入时间:</View>
+            <View className="v">{curObj.create_at ? curObj.create_at.substring(0, 10) : ''}</View>
+          </View>
+          {
+            curObj.introduce
+            &&
+            <View className="op full">
+              <View className="k">房源简介:</View>
+              <View className="v">{curObj.introduce}</View>
+            </View>
+          }
+        </View>
+        <Image className="sm-more" src={moreImg} onClick={this.dtlLink.bind(this)} />
+      </View>
+    )
+  }
+  dtlLink () {
+    const { curObj } = this.state
+    Taro.navigateTo({
+      url: `/pagesHouse/indexDtl?id=${curObj.estate_id}`
+    })
+  }
+
+  renderImg () {
+    const { curObj } = this.state
+    return (
+      <View className="dtl-options">
+        <View className="do-title">
+          <View className="t">户型图</View>
+        </View>
+        <View className="do-content" onClick={this.houseImgHandle.bind(this)}>
+          <View className="scoped-img">
+            <Image src={curObj.house_img} className="img"/>
+            <View className="tips">
+              <View className="bg"></View>
+              <View className="t">查看大图</View>
+            </View>
+          </View>
+        </View>
+      </View>
+    )
+  }
+  houseImgHandle () {
+    const { curObj } = this.state
+    const current = `${curObj.house_img}`
+    const urls = [`${curObj.house_img}`]
+    Taro.previewImage({
+      current,
+      urls
+    })
+  }
+
+
+  renderOther () {
+    const { curObj } = this.state
+    return (
+      <View className="dtl-options">
+        <View className="do-title">
+          <View className="t">同小区房源</View>
+          <Navigator url={'/pagesRoom/list?estate_id=' + curObj.estate_id + '&estate_name=' + curObj.estate_name} className="r">查看更多{' >'}</Navigator>
+        </View>
+        <Rooms onRef={this.refRooms} />
+      </View>
+    )
+  }
+  refRooms = (ref) => {
+    this.subRooms = ref
+  }
+
+
+  netLink (saleObj) {
+    const { curObj } = this.state
+    Taro.navigateTo({
+      url: `/pagesQa/msg/chat?to_user_id=${saleObj.user_id}&qTitle=${curObj.title}&qId=${curObj.id}`
+    })
+  }
+  callHandle (saleObj) {
+    Taro.makePhoneCall({
+      phoneNumber: saleObj.sale_phone
+    })
+  }
+  afterCount (type) {
+    const { curObj } = this.state
+    if (type === 'chat') {
+      this.netLink(curObj.sale_user)
+    }
+    if (type === 'call') {
+      this.callHandle(curObj.sale_user)
+    }
+  }
+  countHandle (type) {
+    const { curObj } = this.state
+    Taro.api.room.apiusercontactclick({
+      target_id: curObj.id,
+      sale_id: curObj.sale_id,
+      click_type: type === 'call' ? '2' : '1' // 1在线聊 2打电话
+    }).then(() => {
+      this.afterCount(type)
+    }).catch(() => {
+      this.afterCount(type)
+    })
+  }
+
+  renderSale () {
+    const { curObj } = this.state
+    const saleObj = curObj.sale_user || {}
+    const tagStr = saleObj.custom_tag ? saleObj.custom_tag.substring(0, 8) : ''
+    return (
+      <View className="scoped-sale">
+        <View className="ss-img">
+          <Image src={saleObj.sale_avatar} className="img"/>
+        </View>
+        <View className="ss-info">
+          <View className="p1">{saleObj.sale_name}</View>
+          <View className="p2">{tagStr}</View>
+        </View>
+        <View className="ss-r">
+          <View className="b" onClick={this.countHandle.bind(this, 'chat')}>在线问</View>
+          <View className="b t2" onClick={this.countHandle.bind(this, 'call')}>打电话</View>
+        </View>
+      </View>
+    )
+  }
+
+
+  renderPopup () {
+    const { isPopupShow, curShareCardImg  } = this.state
+    return (
+      <AtCurtain
+        isOpened={isPopupShow}
+        onClose={this.popupClose.bind(this)}
+      >
+        <Image
+          className="scoped-share-card-img"
+          src={curShareCardImg}
+        />
+      </AtCurtain>
+    )
+  }
+  popupClose () {
+    this.setState({
+      isPopupShow: false
+    })
+  }
+  popupOpen () {
+    this.setState({
+      isPopupShow: true
+    })
+  }
+
+
+  drawAndShareImage (qrcodeSrc) {
+    const { curObj } = this.state
+    const that = this
+    const canvas = Taro.createOffscreenCanvas({type: '2d', width: 600, height: 1067})
+    const ctx = canvas.getContext('2d')
+    ctx.rect(0 , 0 , canvas.width , canvas.height)
+    ctx.fillStyle = "#fff"
+    ctx.fill()
+    const img1 = canvas.createImage()
+    img1.src = require('./img/dtl/bg_room_dtl.png')
+    img1.crossOrigin = 'Anonymous'
+    img1.onload = () => {
+      ctx.drawImage(img1, 0, 0, 600, 1067)
+      const img2 = canvas.createImage()
+      img2.src = qrcodeSrc
+      img2.crossOrigin = 'Anonymous'
+      img2.onload = () => {
+        ctx.drawImage(img2, 320, 950, 100, 100)
+        that.drawText(ctx, 'red', "哈哈哈哈,测试文字", 100, 500)
+        let base64 = ctx.canvas.toDataURL("image/png")
+        that.setState({
+          curShareCardImg: base64
+        })
+      }
+    }
+  }
+  drawText = (ctx, color, text, x, y, font = 50) => {
+    ctx.font="50px Arial";
+    ctx.fillStyle = color;
+    ctx.textAlign = 'left';
+    ctx.fillText(text, x, y);
+    // ctx.stroke();
+    // ctx.closePath();
+   }
+
+
+
+
+  render () {
+    const { curObj } = this.state
+    return (
+      <View className="l-box has-footer">
+        {this.renderHeader()}
+        {this.renderMain()}
+        {this.renderImg()}
+        {(curObj.old_house_list && curObj.old_house_list.length > 0) && this.renderOther()}
+        {this.renderSale()}
+        {this.renderPopup()}
+      </View>
+    )
+  }
+}
+
+export default Index

+ 344 - 0
src/pagesRoom/rentdtl.scss

@@ -0,0 +1,344 @@
+@import '@css/mixin.scss';
+@import '@css/list-box.scss';
+page {
+  height: 100%;
+  background: #f2f2f2;
+  font-size: 28px;
+}
+.dtl-header {
+  position: relative;
+  swiper {
+    height: 500px;
+  }
+  .dh-item {
+    width: 100%;
+    background: #fff;
+    .img {
+      width: 100%;
+      height: 500px;
+    }
+  }
+  .dh-count {
+    position: absolute;
+    right: 20px;
+    bottom: 20px;
+    width: 90px;
+    height: 40px;
+    border-radius: 20px;
+    overflow: hidden;
+    .bg {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      background: #000;
+      opacity: .6;
+      z-index: 1;
+    }
+    .num {
+      position: absolute;
+      color: #fff;
+      z-index: 2;
+      font-size: 26px;
+      left: 50%;
+      transform: translateX(-50%)
+    }
+  }
+}
+
+
+.dtl-options {
+  background: #fff;
+  margin-bottom: 20px;
+  &:last-child {
+    margin-bottom: 0;
+  }
+  .do-title {
+    padding: 20px 20px 10px;
+    position: relative;
+    .t {
+      display: inline-block;
+      vertical-align: top;
+      font-size: 30px;
+      height: 30px;
+      line-height: 30px;
+      overflow: hidden;
+      border-left: 4PX solid $mainColor;
+      padding-left: 10px;
+      font-weight: bold;
+    }
+    .s {
+      display: inline-block;
+      vertical-align: top;
+      color: #999;
+      font-size: 28px;
+      text-decoration: underline;
+      padding-left: 20px;
+    }
+    .r {
+      position: absolute;
+      top: 20px;
+      right: 20px;
+      font-size: 28px;
+      color: #999;
+    }
+    .r2 {
+      display: inline-block;
+      vertical-align: top;
+      margin-left: 10px;
+      font-size: 24px;
+      font-weight: bold;
+      color: $dangerColor;
+    }
+  }
+  .do-content {
+    padding: 0 20px 20px;
+  }
+  .do-p {
+    display: flex;
+    padding: 10px;
+    &:nth-child(2n) {
+      background: #f2f2f2;
+    }
+    .k {
+      width: 20%;
+      color: #777;
+    }
+    .v {
+      width: 80%;
+      text-align: left;
+      color: #555;
+    }
+    .v-item {
+      .n {
+        display: inline-block;
+        color: $mainColor;
+      }
+    }
+  }
+}
+
+.scoped-main {
+  background: #fff;
+  margin-bottom: 20px;
+  padding: 20px 30px;
+  position: relative;
+  .sm-tags {
+    .s {
+      display: inline-block;
+      vertical-align: middle;
+      font-size: 20px;
+      color: #369af7;
+      background: #dff0ff;
+      border-radius: 6px;
+      margin-right: 20px;
+      margin-bottom: 10px;
+      padding: 4px 6px;
+    }
+  }
+  .sm-title {
+    font-size: 40px;
+    font-weight: bold;
+    margin-bottom: 20px;
+  }
+  .sm-focus {
+    border: 2PX solid #c5e3ff;
+    border-radius: 20px;
+    padding: 20px;
+    display: flex;
+    margin-bottom: 20px;
+    .op {
+      border-right: 1PX solid #c5e3ff;
+      text-align: center;
+      &:nth-child(1) {
+        width: 180px;
+      }
+      &:nth-child(2) {
+        width: 280px;
+      }
+      &:last-child {
+        border-right: 0;
+        width: 180px;
+      }
+      .v {
+        color: $mainColor;
+        font-size: 36px;
+        font-weight: bold;
+      }
+      .k {
+        font-size: 24px;
+        color: #9499ac;
+      }
+    }
+  }
+  .sm-op {
+    display: flex;
+    flex-wrap: wrap;
+    padding-top: 10px;
+    margin-bottom: 20px;
+    .op {
+      width: 100%;
+      display: flex;
+      margin-bottom: 10px;
+      &.full {
+        width: 500px;
+      }
+      .k {
+        width: 160px;
+        color: #9499ac;
+        font-size: 28px;
+        text-align: right;
+      }
+      .v {
+        flex: 1;
+        color: #313131;
+        font-size: 28px;
+        &.c2 {
+          font-weight: bold;
+          color: #e94141;
+          font-size: 32px;
+        }
+        .s {
+          display: inline-block;
+          text-decoration: underline;
+          color: $mainColor;
+          font-weight: bold;
+        }
+        &.t2 {
+          text-decoration: underline;
+          color: $mainColor;
+          font-weight: bold;
+        }
+      }
+    }
+  }
+  .sm-more {
+    display: block;
+    width: 690px;
+    height: 100px;
+    border-radius: 10px;
+    margin: 0 auto;
+  }
+}
+
+
+.scoped-img {
+  display: block;
+  margin: 0 auto;
+  width: 700px;
+  height: 200px;
+  text-align: center;
+  position: relative;
+  overflow: hidden;
+  border: 1PX dashed #f2f2f2;
+  .img {
+    width: 700px;
+    height: 700px;
+  }
+  .tips {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    height: 60px;
+    width: 100%;
+    .bg {
+      position: absolute;
+      width: 100%;
+      height: 60px;
+      left: 0;
+      bottom: 0;
+      background: #000;
+      opacity: .2;
+      z-index: 1;
+    }
+    .t {
+      position: absolute;
+      width: 100%;
+      height: 60px;
+      line-height: 60px;
+      left: 0;
+      bottom: 0;
+      color: #fff;
+      z-index: 1;
+      font-size: 28px;
+    }
+  }
+}
+
+.scoped-qrcode {
+  position: absolute;
+  bottom: 140px;
+  right: 30px;
+  width: 160px;
+  height: 160px;
+  border: 4PX solid #f8f8f8;
+  border-radius: 10px;
+}
+
+.scoped-sale {
+  position: fixed;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 140px;
+  background: #fff;
+  display: flex;
+  box-sizing: border-box;
+  padding: 20px;
+  z-index: 99;
+  border: 1PX solid #f2f2f2;
+  .ss-img {
+    width: 90px;
+    height: 90px;
+    border-radius: 50%;
+    overflow: hidden;
+    margin-right: 20px;
+    .img {
+      width: 90px;
+      height: 90px;
+      border-radius: 50%;
+      overflow: hidden;
+    }
+  }
+  .ss-info {
+    flex: 1;
+    .p1 {
+      color: #313131;
+      font-weight: bold;
+      font-size: 30px;
+      padding-bottom: 6px;
+      padding-left: 10px;
+    }
+    .p2 {
+      display: inline-block;
+      padding: 6px 10px;
+      color: #8b94b1;
+      background: #eceff5;
+      font-size: 24px;
+      border-radius: 10px;
+    }
+  }
+  .ss-r {
+    width: 350px;
+    display: flex;
+    padding-top: 10px;
+    justify-content: space-between;
+    .b {
+      width: 170px;
+      height: 80px;
+      line-height: 80px;
+      text-align: center;
+      background: #3bc48b;
+      color: #fff;
+      border-radius: 10px;
+      &.t2 {
+        background: #3072f6;
+      }
+    }
+  }
+}
+
+
+.scoped-share-card-img, canvas {
+  width: 600px;
+  height: 1067px;
+}

+ 636 - 0
src/pagesRoom/rentlist.jsx

@@ -0,0 +1,636 @@
+import Taro, { Component } from '@tarojs/taro'
+import { View, Image, Text, Navigator } from '@tarojs/components'
+
+import { AtSearchBar } from 'taro-ui'
+import ListMore from '@/c/pageDataList/listMore'
+import MultiSelect from '@/c/lform/MultiSelect'
+import './rentlist.scss'
+import { arrToObj } from '@utils'
+
+class Index extends Component {
+
+  onShareAppMessage() {
+    return {
+      title: '来看看南昌这些出租信息',
+    }
+  }
+  onShareTimeline () {
+    return {
+      title: '洪楼Plus,专注南昌本地房地产市场,让买房,更省心!',
+    }
+  }
+
+  constructor (props) {
+    super(props)
+    const { estate_id } = this.$router.params
+    let estateIdCur = []
+    if (estate_id) estateIdCur = [estate_id]
+    this.state = {
+      searchKey: '',
+      page_size: 10,
+      page: 1,
+      isListEnd: false,
+      isListLoading: false,
+      isListEmpty: false,
+      dataList: [],
+      curNav: 1,
+      isDShow: false,
+      curObj: {},
+      searchIndex: -1,
+      searchText1: '',
+      searchText5: '',
+      searchText3: '',
+      searchText4: '',
+      searchText5: '',
+      curPos: 'area_type',
+      curAreaType: [],
+      curProductTypeName: [],
+      curHouseTypeRange: [],
+      houseAreaCur: [],
+      productTypeCur: [],
+      isEstateShow: false,
+      estateIdCur,
+    }
+  }
+
+  config = {
+    navigationBarTitleText: '房屋出租',
+  }
+
+  componentWillMount () {
+    Taro.$AHU(this)
+    const { estate_id } = this.$router.params
+    if (estate_id) {
+      this.getDataList()
+    }
+  }
+
+  componentDidShow () { }
+
+  componentDidHide () { }
+
+  renderSearch () {
+    const { searchKey } = this.state
+    return (
+      <AtSearchBar
+        value={searchKey}
+        fixed={true}
+        placeholder="请输入房源关键字"
+        onChange={this.onSeachChange.bind(this)}
+        onActionClick={this.onSelectActionClick.bind(this)}
+        onClear={this.onClearHandle.bind(this)}
+      />
+    )
+  }
+  onSeachChange (value) {
+    this.setState({
+      searchKey: value
+    })
+  }
+  onClearHandle () {
+    this.setState({
+      searchKey: '',
+      page: 1
+    }, () => {
+      this.getDataList()
+    })
+  }
+  onSelectActionClick () {
+    this.setState({
+      page: 1,
+    }, () => {
+      this.getDataList()
+    })
+  }
+
+  searchIndex1Render () {
+    const { curPos, curAreaType } = this.state
+    const dictData = Taro.getStorageSync('dictData')
+    const areaTypeViews = dictData.area_type.map(item =>{
+      let curClassName = "op"
+      curAreaType.forEach(curVal =>{
+        if (curVal === item.val) {
+          curClassName = "op cur"
+        }
+      })
+      return (
+        <View className={curClassName} key={item.val} onClick={this.areaTypeHandle.bind(this, item)}>{item.key}</View>
+      )
+    })
+    let areaTypeAllClassName = curAreaType.length === 0 ? 'op cur' : 'op'
+    return (
+      <View className="stc-wrap">
+        {/* <View className="stc-item">
+          <View className={curPos === 'area_type' ? 'stc-op cur' : 'stc-op'}  onClick={this.posHandle.bind(this, 'area_type')}>区域</View>
+        </View> */}
+        {
+          curPos === 'area_type'
+          &&
+          <View className="stc-pane">
+            <View className={areaTypeAllClassName} onClick={this.areaTypeHandle.bind(this, 'all')}>不限</View>
+            {areaTypeViews}
+          </View>
+        }
+      </View>
+    )
+  }
+  posHandle (str) {
+    this.setState({
+      curPos: str,
+      curAreaType: [],
+    })
+  }
+  areaTypeHandle (curOp) {
+    if (curOp === 'all') {
+      this.setState({
+        curAreaType: []
+      })
+    } else {
+      let { curAreaType } = this.state
+      let ed = false
+      let curI = 0
+      curAreaType.forEach((item, index) => {
+        if (curOp.val === item) {
+          ed = true
+          curI = index
+        }
+      })
+      if (ed) {
+        curAreaType.splice(curI, 1)
+      } else {
+        curAreaType.push(curOp.val)
+      }
+      this.setState({
+        curAreaType
+      })
+    }
+  }
+
+
+
+  searchIndex3Render () {
+    const { curHouseTypeRange } = this.state
+    const dictData = Taro.getStorageSync('dictData')
+    const edIcon = require('@img/images/icon_g_ed.png')
+    const rangeViews = dictData.house_type.map(item =>{
+      let curClassName = "stc-op"
+      curHouseTypeRange.forEach(curVal =>{
+        if (curVal === item.val) {
+          curClassName = "stc-op cur"
+        }
+      })
+      return (
+        <View className={curClassName} key={item.val} onClick={this.houseTypeRangeHandle.bind(this, item)}>{item.key}
+          <Image className="img" src={edIcon} />
+        </View>
+      )
+    })
+    let allClassName = curHouseTypeRange.length === 0 ? 'stc-op cur' : 'stc-op'
+    return (
+      <View className="stc-wrap">
+        <View className="stc-item">
+          <View className={allClassName} onClick={this.houseTypeRangeHandle.bind(this, 'all')}>不限</View>
+          {rangeViews}
+        </View>
+      </View>
+    )
+  }
+  houseTypeRangeHandle (curOp) {
+    if (curOp === 'all') {
+      this.setState({
+        curHouseTypeRange: []
+      })
+    } else {
+      let { curHouseTypeRange } = this.state
+      let ed = false
+      let curI = 0
+      curHouseTypeRange.forEach((item, index) => {
+        if (curOp.val === item) {
+          ed = true
+          curI = index
+        }
+      })
+      if (ed) {
+        curHouseTypeRange.splice(curI, 1)
+      } else {
+        curHouseTypeRange.push(curOp.val)
+      }
+      this.setState({
+        curHouseTypeRange
+      })
+    }
+  }
+
+
+  searchIndex4Render () {
+    const dictData = Taro.getStorageSync('dictData')
+    // 房屋面积
+    const { houseAreaCur } = this.state
+    const house_area = dictData.house_area || []
+    const houseAreaViews = house_area.map(item =>{
+      let curClassName = "mp-op"
+      houseAreaCur.forEach(curVal =>{
+        if (curVal === item.val) {
+          curClassName = "mp-op cur"
+        }
+      })
+      return (
+        <View className={curClassName} key={item.val} onClick={this.comSelectHandle.bind(this, item, 'houseAreaCur')}>{item.key}</View>
+      )
+    })
+    const houseAreaAllClassName = houseAreaCur.length === 0 ? 'mp-op cur' : 'mp-op'
+    // 产品类型
+    const { productTypeCur } = this.state
+    const product_type = dictData.product_type || []
+    const productTypeViews = product_type.map(item =>{
+      let curClassName = "mp-op"
+      productTypeCur.forEach(curVal =>{
+        if (curVal === item.val) {
+          curClassName = "mp-op cur"
+        }
+      })
+      return (
+        <View className={curClassName} key={item.val} onClick={this.comSelectHandle.bind(this, item, 'productTypeCur')}>{item.key}</View>
+      )
+    })
+    const productTypeAllClassName = productTypeCur.length === 0 ? 'mp-op cur' : 'mp-op'
+    return (
+      <View className="more-pane">
+        <View className="mp-item">
+          <View className="mp-title">房源面积</View>
+          <View className="mp-content">
+            <View className={houseAreaAllClassName} onClick={this.comSelectHandle.bind(this, 'all', 'houseAreaCur')}>不限</View>
+            {houseAreaViews}
+          </View>
+        </View>
+        <View className="mp-item">
+          <View className="mp-title">产品类型</View>
+          <View className="mp-content">
+            <View className={productTypeAllClassName} onClick={this.comSelectHandle.bind(this, 'all', 'productTypeCur')}>不限</View>
+            {productTypeViews}
+          </View>
+        </View>
+      </View>
+    )
+  }
+  comSelectHandle (curOp, str) {
+    if (curOp === 'all') {
+      this.setState({
+        [str]: []
+      })
+    } else {
+      const state = this.state
+      let curStr = state[str]
+      let ed = false
+      let curI = 0
+      curStr.forEach((item, index) => {
+        if (curOp.val === item) {
+          ed = true
+          curI = index
+        }
+      })
+      if (ed) {
+        curStr.splice(curI, 1)
+      } else {
+        curStr.push(curOp.val)
+      }
+      this.setState({
+        [str]: curStr
+      })
+    }
+  }
+
+
+  renderTop () {
+    const { searchIndex, searchText1, searchText5, searchText3, searchText4 } = this.state
+    const { estate_name } = this.$router.params
+    return (
+      <View className="l-search-top t2">
+        <View className="st-nav">
+          {
+            estate_name
+            ?
+            <View className="stn-op col-3 cur">
+              <View className="stn-label t2">{estate_name}</View>
+            </View>
+            :
+            <View className={(searchIndex === 5 || searchText5) ? 'stn-op col-4 cur' : 'stn-op col-4'} onClick={this.searchNavHandle.bind(this, 5)}>
+              <View className="stn-label">{searchText5 || '楼盘'}</View>
+              <View className="stn-sign"></View>
+            </View>
+          }
+          <View className={(searchIndex === 1 || searchText1) ? 'stn-op col-4 cur' : 'stn-op col-4'} onClick={this.searchNavHandle.bind(this, 1)}>
+            <View className="stn-label">{searchText1 || '区域'}</View>
+            <View className="stn-sign"></View>
+          </View>
+          <View className={(searchIndex === 3 || searchText3) ? 'stn-op col-4 cur' : 'stn-op col-4'} onClick={this.searchNavHandle.bind(this, 3)}>
+            <View className="stn-label">{searchText3 || '户型'}</View>
+            <View className="stn-sign"></View>
+          </View>
+          <View className={(searchIndex === 4 || searchText4) ? 'stn-op col-4 cur' : 'stn-op col-4'} onClick={this.searchNavHandle.bind(this, 4)}>
+            <View className="stn-label">{searchText4 || '更多'}</View>
+            <View className="stn-sign"></View>
+          </View>
+        </View>
+        <View className={searchIndex > 0 ? searchIndex === 4 ? 'st-content show more' : 'st-content show' : 'st-content'}>
+          {
+            searchIndex === 1
+            &&
+            this.searchIndex1Render()
+          }
+          {
+            searchIndex === 3
+            &&
+            this.searchIndex3Render()
+          }
+          {
+            searchIndex === 4
+            &&
+            this.searchIndex4Render()
+          }
+          <View className="l-floor-footer t2">
+            <View className="lff-flex">
+              <View className="lff-btn t3" onClick={this.resetHandle.bind(this)} >重置</View>
+              <View className="lff-btn" onClick={this.saveHandle.bind(this)}>搜索</View>
+            </View>
+          </View>
+        </View>
+      </View>
+    )
+  }
+  searchNavHandle (index) {
+    if (index === 5) {
+      this.openMSPopup()
+      return
+    }
+    let { searchIndex } = this.state
+    searchIndex = index === searchIndex ? -1 : index
+    this.setState({
+      searchIndex
+    })
+  }
+  resetHandle () {
+    const { searchIndex } = this.state
+    if (searchIndex === 1) {
+      this.setState({
+        searchText1: '',
+        curPos: 'area_type',
+      })
+    }
+    if (searchIndex === 3) {
+      this.setState({
+        searchText3: '',
+        curHouseTypeRange: [],
+      })
+    }
+    if (searchIndex === 4) {
+      this.setState({
+        searchText4: '',
+        houseAreaCur: [],
+        productTypeCur: [],
+      })
+    }
+  }
+  saveHandle () {
+    const dictData = Taro.getStorageSync('dictData')
+    const {
+      searchIndex,
+      curAreaType,
+      curHouseTypeRange,
+      houseAreaCur,
+      productTypeCur,
+    } = this.state
+    if (searchIndex === 1) {
+      let tagArr = []
+      curAreaType.forEach(v => {
+        tagArr.push(arrToObj(dictData.area_type)[v])
+      })
+      if (tagArr) {
+        this.setState({
+          searchText1: tagArr.join(',')
+        })
+      }
+    }
+    if (searchIndex === 3) {
+      let tagArr = []
+      curHouseTypeRange.forEach(v => {
+        tagArr.push(arrToObj(dictData.house_type)[v])
+      })
+      if (tagArr) {
+        this.setState({
+          searchText3: tagArr.join(',')
+        })
+      }
+    }
+    if (searchIndex === 4) {
+      let tagArr = []
+      houseAreaCur.forEach(v => {
+        tagArr.push(arrToObj(dictData.house_area)[v])
+      })
+      productTypeCur.forEach(v => {
+        tagArr.push(arrToObj(dictData.product_type)[v])
+      })
+      if (tagArr) {
+        this.setState({
+          searchText4: tagArr.join(',')
+        })
+      }
+    }
+    this.setState({
+      page: 1,
+      searchIndex: -1,
+    }, () => {
+      this.getDataList()
+    })
+  }
+
+
+
+
+
+  openMSPopup (e) {
+    this.setState({
+      isEstateShow: true,
+      searchIndex: -1,
+    })
+  }
+  dealMSPopup (curVal, curCheckedArr) {
+    this.closeMSPopup()
+    if (curVal && curCheckedArr) {
+      const nameArr = curCheckedArr.map(item =>{
+        return item.estate_name
+      })
+      this.setState({
+        estateIdCur: curVal,
+        searchText5: nameArr.join(','),
+        page: 1,
+      }, () => {
+        this.getDataList()
+      })
+    } else {
+      this.setState({
+        estateIdCur: [],
+        searchText5: '',
+      })
+    }
+  }
+  closeMSPopup () {
+    this.setState({
+      isEstateShow: false,
+    })
+  }
+
+
+
+
+
+
+
+  getDataList () {
+    let { page_size, page, dataList, isListEmpty } = this.state
+    const { searchKey } = this.state
+    const {
+      curAreaType,
+      curHouseTypeRange,
+      houseAreaCur,
+      productTypeCur,
+      estateIdCur,
+    } = this.state
+    let apiStr = 'apirenthouselist'
+    let params = {
+      page,
+      page_size,
+      title: searchKey,
+      area_type: curAreaType.join(','),
+      house_type: curHouseTypeRange.join(','),
+      house_area: houseAreaCur.join(','),
+      product_type: productTypeCur.join(','),
+      estate_id: estateIdCur.join(','),
+    }
+    Taro.api.room[apiStr](params).then(res => {
+      const curData = res.list || []
+      let isListEnd = false
+      if (curData.length > 0) {
+        if (page === 1) {
+          dataList = curData
+        } else {
+          dataList = dataList.concat(curData)
+        }
+        if (curData.length === page_size && res.total !== curData.length) {
+          isListEnd = false
+        } else {
+          isListEnd = true
+        }
+      }
+      if (curData.length === 0 && page === 1) {
+        isListEmpty = true
+        dataList = []
+      } else {
+        isListEmpty = false
+      }
+      this.setState({
+        dataList,
+        isListEnd,
+        isListEmpty,
+        isListLoading: false
+      })
+    })
+  }
+  onScrollToLower (e) {
+    let { isListEnd, isListLoading, page } = this.state
+    if (!isListEnd && !isListLoading) {
+      page++
+      this.setState({
+        page,
+        isListLoading: true
+      }, () => {
+        this.getDataList()
+      })
+    }
+  }
+
+  renderList () {
+    const { dataList, isListEnd, isListLoading, isListEmpty } = this.state
+    const itemsList = dataList.map((item, index) => {
+      let FHstr = '未知楼层'
+      if (item.floor) {
+        const FH = Number(item.floor) || 1
+        const H = Number(item.storeys) || 1
+        if (FH > H * 0.6666) {
+          FHstr = '中高层'
+        } else if (FH > H * 0.33333) {
+          FHstr = '中楼层'
+        } else {
+          FHstr = '中低层'
+        }
+        if (FH === 1) FHstr = '一楼'
+        if (FH === H) FHstr = '顶楼'
+      }
+      const cTagStr = item.custom_tag || ''
+      const tagViews = cTagStr.split(',').map((tag, tagIndex) => {
+        return (
+          <View className="s" key={tagIndex}>{tag}</View>
+        )
+      })
+      return (
+        <View className="lhl-item col-1" key={index} onClick={this.linkHandle.bind(this, item)}>
+          <View className="lhl-img">
+            <Image src={item.pri_image + '_xs'} className="img" />
+          </View>
+          <View className="lhl-info">
+            <View className="lhl-p1">{item.title}</View>
+            <View className="lhl-p2">{item.price}元</View>
+            <View className="lhl-p3">{FHstr}-{item.estate_name}</View>
+            <View className="lhl-sign">
+              {tagViews}
+            </View>
+          </View>
+        </View>
+      )
+    })
+    return (
+      <ScrollView
+        className='l-scroll-view'
+        scrollY
+        scrollWithAnimation
+        scrollTop="0"
+        lowerThreshold="30"
+        onScrollToLower={this.onScrollToLower.bind(this)}
+      >
+        <View className="l-house-list">
+          {itemsList}
+        </View>
+        <ListMore isListEnd={isListEnd} isListLoading={isListLoading} isListEmpty={isListEmpty} />
+      </ScrollView>
+    )
+  }
+
+
+  linkHandle (item) {
+    Taro.navigateTo({
+      url: `/pagesRoom/rentdtl?id=${item.id}`
+    })
+  }
+
+  render () {
+    const { estateIdCur, isEstateShow } = this.state
+    const { estate_id } = this.$router.params
+    const estateMoreOptions = {skey: 'estate_name', api: `room.apiestatehouselist`, opKey: 'estate_name', opVal: 'estate_id'}
+    return (
+      <View className="l-box">
+        {this.renderSearch()}
+        {this.renderTop()}
+        {this.renderList()}
+        {
+          estate_id
+          ?
+          ''
+          :
+          <MultiSelect val={estateIdCur} moreOptions={estateMoreOptions} isShow={isEstateShow} initUpdate="no" bc={this.dealMSPopup.bind(this)} close={this.closeMSPopup.bind(this)}/>
+        }
+      </View>
+    )
+  }
+}
+
+export default Index

+ 24 - 0
src/pagesRoom/rentlist.scss

@@ -0,0 +1,24 @@
+@import '@css/mixin.scss';
+@import '@css/house-list.scss';
+@import '@css/search-top.scss';
+.l-box {
+  padding-top: calc(84px + 90px);
+}
+.l-scroll-view {
+  height: calc(100vh - 84px - 90px);
+  box-sizing: border-box;
+}
+.scoped-fixed {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  z-index: 99;
+  background-color: #fff;
+}
+
+
+.lhl-info {
+  width: 300px;
+}
+