house.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. <template>
  2. <view class="house-detail">
  3. <view class="house-swiper">
  4. <swiper class="swiper" circular :indicator-dots="true">
  5. <swiper-item v-for="item in responsibility" :key="item.id">
  6. <image class="image" :src="item.url" mode="aspectFill">
  7. </image>
  8. </swiper-item>
  9. </swiper>
  10. <uni-icons class="btn" @click="roomCollection" :type="detail.roomCollection ? 'heart-filled' : 'heart'"
  11. color="#ff4d4f" size="28">
  12. </uni-icons>
  13. </view>
  14. <view class="house-title">
  15. <view class="house-name">{{detail.name}}</view>
  16. <view class="tag">
  17. <text style="margin-right: 6rpx;">{{detail.area}}m²</text>
  18. <text v-for="(tag,index) in detail.tagList" :key="index"> | {{tag.name}}</text>
  19. </view>
  20. <view class="pirce">
  21. <text class="number">{{detail.price}}</text>
  22. <text class="label">/月</text>
  23. </view>
  24. <view class="project-label">距离您{{detail.distance || '-'}}km</view>
  25. <button type="default" class="wx-icon" open-type="share">
  26. <uni-icons type="weixin" open-type="share" size="38" color="#43b156">
  27. </uni-icons>
  28. </button>
  29. </view>
  30. <view class="house-label house-article">{{detail.comment}}</view>
  31. <view class="house-content">
  32. <view class="content-title">基本信息</view>
  33. <view class="information-list">
  34. <view class="information-box">
  35. <text class="information-title">所属楼宇:</text>
  36. <text class="information-text">{{detail.projectItemName}}</text>
  37. </view>
  38. <view class="information-box">
  39. <text class="information-title">所属楼层:</text>
  40. <text class="information-text">{{detail.projectItemTargetName}}</text>
  41. </view>
  42. <view class="information-box">
  43. <text class="information-title">房源类型:</text>
  44. <text class="information-text">{{$field.findTypeName('houseType',detail.roomTypeId)}}</text>
  45. </view>
  46. <view class="information-box">
  47. <text class="information-title">房间号码:</text>
  48. <text class="information-text">{{detail.roomNumber}}</text>
  49. </view>
  50. <view class="information-box">
  51. <text class="information-title">房源面积:</text>
  52. <text class="information-text">{{detail.area}}</text>
  53. </view>
  54. <view class="information-box">
  55. <text class="information-title">付款方式:</text>
  56. <text class="information-text">{{$field.findTypeName('payWay',detail.payWay)}}</text>
  57. </view>
  58. <view class="information-box" style="margin-bottom: 0;">
  59. <text class="information-title">产权证书:</text>
  60. <text class="information-text">{{detail.propertyCertificateNumber}}</text>
  61. </view>
  62. <view class="information-box" style="margin-bottom: 0;">
  63. <text class="information-title">是否装修:</text>
  64. <text class="information-text">{{detail.decoration === 1 ? '已装修':'未装修'}}</text>
  65. </view>
  66. </view>
  67. <view class="content-title">房源简介</view>
  68. <view class="desc-text" v-html="detail.introduce"></view>
  69. <view class="people-tell">
  70. <image class="people-avatar" :src="detail.chargePersonPortrait" mode="aspectFill"
  71. @click="$navigateTo('/pages/person/person?userId='+detail.chargePersonId)"></image>
  72. <view class="people-text" @click="$navigateTo('/pages/person/person?userId='+detail.chargePersonId)">
  73. <view class="people-name">{{detail.chargePersonName}}</view>
  74. <view class="people-organization">
  75. 组织名称
  76. </view>
  77. </view>
  78. <view class="people-icon" @click="tell">
  79. <uni-icons type="phone-filled" color="#fff"></uni-icons>
  80. </view>
  81. </view>
  82. <view class="content-title">地理位置</view>
  83. <view class="content-map">
  84. <map id="map" class="map" :show-location="true" :latitude="latitude" :longitude="longitude"></map>
  85. </view>
  86. <view class="content-title">配套设施</view>
  87. <view class="content-device">
  88. <view class="device-item"
  89. v-for="item in $field.findTypeNameByList('supportingFacilities',detail.supportingFacilities)"
  90. :key="item.id">
  91. <uni-icons class="device-icon" custom-prefix="iconfont" :type="item.icon" size="18"></uni-icons>
  92. <text class="device-label">{{item.name}}</text>
  93. </view>
  94. </view>
  95. <view class="content-title">
  96. <text>访客记录</text>
  97. <text class="more" @click="$navigateTo('/pages/visitor/visitor?houseId=' + houseId)">查看更多>></text>
  98. </view>
  99. <view class="visitor">
  100. <view class="visitor-item" v-for="(item,index) in visitorList" :key="index">
  101. <image class="visitor-avatar" :src="item.userPortrait" mode="aspectFill">
  102. </image>
  103. <text class="visitor-label">{{item.userName}}访问了房源</text>
  104. <uni-dateformat class="visitor-time" :date="item.date" :threshold="[60000,3600000 * 24 * 365]">
  105. </uni-dateformat>
  106. </view>
  107. </view>
  108. <view class="content-title">
  109. <text>房源评价</text>
  110. </view>
  111. <view class="evaluate">
  112. <hb-comment ref="hbComment" @add="addEvaluate" @del="del" @like="like" :deleteTip="'确认删除?'"
  113. :cmData="commentData" v-if="commentData">
  114. </hb-comment>
  115. </view>
  116. </view>
  117. <view class="hui-button-box">
  118. <view class="hui-button hui-button-light"
  119. @click="$navigateTo('/pages/reservation/reservation?houseId=' + houseId)">
  120. <uni-icons class="hui-button-icon" type="calendar" color="#08979c" size="22"></uni-icons> 预约看房
  121. </view>
  122. <view class="hui-button"
  123. @click="$navigateTo('/pages/chat/chat?userId='+detail.chargePersonId+'&userName='+detail.chargePersonName)">
  124. <uni-icons class="hui-button-icon" type="chat" color="#fff" size="22"></uni-icons>
  125. 在线联系
  126. </view>
  127. </view>
  128. </view>
  129. </template>
  130. <script>
  131. import {
  132. dayjs
  133. } from '../../uni_modules/iRainna-dayjs/js_sdk/dayjs.min';
  134. import {
  135. getHouseDetailById,
  136. insertVisitor,
  137. getVisitorByQuery,
  138. collection,
  139. disableCollection,
  140. getHouseEvaluateListByPage,
  141. insertEvaluate
  142. } from '@/request/api/house.js'
  143. export default {
  144. data() {
  145. return {
  146. detail: {
  147. area: 0
  148. },
  149. houseId: 15,
  150. responsibility: [],
  151. coordinates: [],
  152. latitude: 39.90923,
  153. longitude: 116.397428,
  154. mapContext: {},
  155. visitorList: [],
  156. startTime: '',
  157. commentData: {
  158. readNumer: 0,
  159. commentSize: 0,
  160. comment: []
  161. },
  162. shareButton: false,
  163. coordinates: ''
  164. }
  165. },
  166. onLoad(body) {
  167. if (body.houseId) this.houseId = body.houseId;
  168. this.coordinates = this.$store.getters.coordinates;
  169. this.startTime = new Date().getTime();
  170. },
  171. onReady() {
  172. this.mapContext = uni.createMapContext("map", this);
  173. this.init();
  174. },
  175. onUnload() {
  176. let endTime = new Date().getTime();
  177. let time = endTime - this.startTime;
  178. if (time > 10000) this.createVisitor();
  179. },
  180. onShareAppMessage(res) {
  181. return {
  182. title: this.detail.name || '',
  183. }
  184. },
  185. methods: {
  186. init() {
  187. getHouseDetailById(this.houseId + '?coordinates=' + this.coordinates).then(res => {
  188. if (res.code === 200) {
  189. this.detail = res.data;
  190. if (this.detail.picture) this.responsibility = JSON.parse(this.detail.picture);
  191. if (this.detail.coordinates) {
  192. this.coordinates = this.detail.coordinates.split(',');
  193. this.latitude = this.coordinates[1];
  194. this.longitude = this.coordinates[0];
  195. this.addMarkers();
  196. }
  197. this.getVisitor();
  198. this.getHouseEvaluate();
  199. }
  200. })
  201. },
  202. getHouseEvaluate() {
  203. getHouseEvaluateListByPage({
  204. currPage: 1,
  205. pageSize: 100,
  206. projectItemTargetRoomId: this.houseId
  207. }).then(res => {
  208. if (res.code == 200) {
  209. this.commentData.commentSize = res.data.totalCount;
  210. this.commentData.comment = this.getTree(res.data.dataList.map(node => {
  211. return {
  212. "id": node.id, // 唯一主键
  213. "owner": true, // 是否是拥有者,为true则可以删除,管理员全部为true
  214. "hasLike": false, // 是否点赞
  215. "likeNum": 2, // 点赞数量
  216. "avatarUrl": node.userPortrait, // 评论者头像地址
  217. "nickName": node.userName, // 评论者昵称,昵称过长请在后端截断
  218. "content": node.content, // 评论内容
  219. "parentId": node.parentId, // 所属评论的唯一主键
  220. "createTime": node.date // 创建时间
  221. }
  222. }))
  223. }
  224. })
  225. },
  226. getTree(data) {
  227. let result = [];
  228. let map = {};
  229. data.forEach(item => {
  230. map[item.id] = item;
  231. });
  232. data.forEach(item => {
  233. let parent = map[item.parentId];
  234. if (parent) {
  235. (parent.children || (parent.children = [])).push(item);
  236. } else {
  237. result.push(item);
  238. }
  239. });
  240. return result;
  241. },
  242. addEvaluate(data) {
  243. insertEvaluate({
  244. userId: this.$store.getters.user.userId,
  245. projectItemTargetRoomId: this.houseId,
  246. content: data.content,
  247. parentId: data.pId || 0
  248. }).then(res => {
  249. if (res.code == 200) {
  250. this.$toast('评价成功');
  251. this.getHouseEvaluate();
  252. this.$refs.hbComment.addComplete();
  253. }
  254. })
  255. },
  256. del() {
  257. },
  258. like() {
  259. },
  260. tell() {
  261. uni.makePhoneCall({
  262. phoneNumber: '17601274604' //仅为示例
  263. });
  264. },
  265. roomCollection() {
  266. this.detail.roomCollection ? disableCollection(this.houseId).then(res => this.successCollection(res,
  267. '取消收藏')) : collection(this.houseId).then(res => this.successCollection(res, '收藏成功'));
  268. },
  269. successCollection(res, msg) {
  270. if (res.code === 200) {
  271. this.init();
  272. this.$toast(msg);
  273. }
  274. },
  275. addMarkers() {
  276. const positions = [{
  277. latitude: this.coordinates[1],
  278. longitude: this.coordinates[0],
  279. }]
  280. const markers = []
  281. positions.forEach((p, i) => {
  282. markers.push(
  283. Object.assign({}, {
  284. id: i + 1,
  285. width: 50,
  286. height: 50,
  287. joinCluster: true, // 指定了该参数才会参与聚合
  288. }, p)
  289. )
  290. })
  291. this.mapContext.addMarkers({
  292. markers,
  293. clear: false,
  294. complete(res) {}
  295. })
  296. },
  297. getVisitor() {
  298. getVisitorByQuery({
  299. currPage: 1,
  300. pageSize: 2,
  301. projectItemTargetRoomId: this.houseId
  302. }).then(res => {
  303. if (res.code === 200) {
  304. this.visitorList = res.data.dataList;
  305. }
  306. })
  307. },
  308. createVisitor() {
  309. insertVisitor({
  310. userId: this.$store.getters.user.userId,
  311. projectItemTargetRoomId: this.houseId
  312. })
  313. },
  314. share() {
  315. //根据id获取
  316. uni.createSelectorQuery().select('#shareButton').node().exec(res => {
  317. //res[0].node未获取到的指定的dom元素对象
  318. console.log("res", res[0].node)
  319. })
  320. }
  321. },
  322. }
  323. </script>
  324. <style lang="scss">
  325. .house-detail {
  326. background: #fff;
  327. padding-bottom: 160rpx;
  328. .house-swiper {
  329. position: relative;
  330. .btn {
  331. position: absolute;
  332. top: 20rpx;
  333. right: 30rpx;
  334. }
  335. }
  336. .swiper {
  337. height: 400rpx;
  338. .image {
  339. width: 100%;
  340. height: 100%;
  341. }
  342. }
  343. .house-label {
  344. font-size: 24rpx;
  345. color: $uni-secondary-color;
  346. font-weight: 300;
  347. }
  348. .house-article {
  349. font-size: 28rpx;
  350. padding: 0 30rpx;
  351. }
  352. .house-title {
  353. padding: 40rpx 130rpx 30rpx 30rpx;
  354. position: relative;
  355. .house-name {
  356. font-size: 36rpx;
  357. font-weight: 500;
  358. }
  359. .project-label {
  360. font-size: 24rpx;
  361. color: $uni-secondary-color;
  362. font-weight: 300;
  363. position: absolute;
  364. bottom: 50rpx;
  365. right: 30rpx;
  366. }
  367. .tag {
  368. font-size: 24rpx;
  369. font-weight: 300;
  370. color: $uni-secondary-color;
  371. padding: 12rpx 0;
  372. }
  373. .pirce {
  374. color: $uni-primary;
  375. .number {
  376. font-weight: 600;
  377. font-size: 48rpx;
  378. }
  379. .label {
  380. font-size: 24rpx;
  381. }
  382. }
  383. .wx-icon {
  384. position: absolute;
  385. top: 0;
  386. right: 30rpx;
  387. transform: translateY(50%);
  388. line-height: 1;
  389. background: transparent;
  390. &::after {
  391. display: none;
  392. }
  393. }
  394. }
  395. .content-map {
  396. width: 100%;
  397. height: 360rpx;
  398. border-radius: 16rpx;
  399. overflow: hidden;
  400. display: flex;
  401. .map {
  402. flex: 1;
  403. height: 100%;
  404. border-radius: 16rpx;
  405. }
  406. }
  407. .house-content {
  408. padding: 0 30rpx;
  409. box-sizing: border-box;
  410. .content-title {
  411. font-size: 32rpx;
  412. font-weight: 500;
  413. margin: 30rpx 0;
  414. display: flex;
  415. align-items: center;
  416. justify-content: space-between;
  417. .more {
  418. color: $uni-secondary-color;
  419. font-weight: 300;
  420. font-size: 24rpx;
  421. }
  422. }
  423. .people-tell {
  424. margin: 40rpx 0;
  425. height: 140rpx;
  426. border-radius: 20rpx;
  427. box-shadow: 0px 1px 12px rgba(3, 3, 3, 0.08);
  428. display: flex;
  429. align-items: center;
  430. padding: 0 30rpx;
  431. .people-avatar {
  432. width: 90rpx;
  433. height: 90rpx;
  434. border-radius: 50%;
  435. margin-right: 30rpx;
  436. }
  437. .people-text {
  438. flex: 1;
  439. width: 0;
  440. overflow: hidden;
  441. }
  442. .people-name {
  443. font-size: 16px;
  444. font-weight: 500;
  445. margin-bottom: 8rpx;
  446. }
  447. .people-organization {
  448. font-weight: 300;
  449. font-size: 24rpx;
  450. color: $uni-secondary-color;
  451. }
  452. .people-icon {
  453. width: 60rpx;
  454. height: 60rpx;
  455. border-radius: 50%;
  456. background: $uni-primary;
  457. text-align: center;
  458. line-height: 60rpx;
  459. }
  460. }
  461. .visitor {
  462. .visitor-item {
  463. margin-bottom: 20rpx;
  464. display: flex;
  465. align-items: center;
  466. font-weight: 300;
  467. .visitor-avatar {
  468. width: 80rpx;
  469. height: 80rpx;
  470. border-radius: 80rpx;
  471. }
  472. .visitor-label {
  473. flex: 1;
  474. width: 0;
  475. overflow: hidden;
  476. white-space: nowrap;
  477. text-overflow: ellipsis;
  478. margin: 0 20rpx;
  479. }
  480. .visitor-time {
  481. font-size: 24rpx;
  482. color: $uni-secondary-color;
  483. }
  484. &:last-child {
  485. margin-bottom: 0;
  486. }
  487. }
  488. }
  489. .desc-text {
  490. font-weight: 300;
  491. }
  492. .information-list {
  493. display: flex;
  494. flex-wrap: wrap;
  495. .information-box {
  496. width: 50%;
  497. display: flex;
  498. margin-bottom: 30rpx;
  499. }
  500. .information-title {
  501. color: $uni-secondary-color;
  502. font-weight: 500;
  503. }
  504. .information-text {
  505. flex: 1;
  506. width: 0;
  507. overflow: hidden;
  508. white-space: nowrap;
  509. font-weight: 300;
  510. }
  511. }
  512. .content-device {
  513. display: flex;
  514. flex-wrap: wrap;
  515. .device-item {
  516. width: 50%;
  517. display: flex;
  518. align-items: center;
  519. margin-bottom: 20rpx;
  520. .device-label {
  521. flex: 1;
  522. width: 0;
  523. color: $uni-secondary-color;
  524. font-weight: 200;
  525. margin-left: 10rpx;
  526. }
  527. .device-icon {
  528. color: $uni-base-color;
  529. }
  530. }
  531. }
  532. }
  533. }
  534. </style>