house.vue 14 KB

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