house.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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>
  118. </view>
  119. </template>
  120. <script>
  121. import {
  122. dayjs
  123. } from '../../uni_modules/iRainna-dayjs/js_sdk/dayjs.min';
  124. import {
  125. getHouseDetailById,
  126. insertVisitor,
  127. getVisitorByQuery,
  128. collection,
  129. disableCollection,
  130. getHouseEvaluateListByPage,
  131. insertEvaluate
  132. } from '@/request/api/house.js'
  133. export default {
  134. data() {
  135. return {
  136. detail: {
  137. area: 0
  138. },
  139. houseId: 15,
  140. responsibility: [],
  141. coordinates: [],
  142. latitude: 39.90923,
  143. longitude: 116.397428,
  144. mapContext: {},
  145. visitorList: [],
  146. startTime: '',
  147. commentData: {
  148. readNumer: 0,
  149. commentSize: 0,
  150. comment: []
  151. }
  152. }
  153. },
  154. onLoad(body) {
  155. if (body.houseId) this.houseId = body.houseId;
  156. this.startTime = new Date().getTime();
  157. },
  158. onReady() {
  159. this.mapContext = uni.createMapContext("map", this);
  160. this.init();
  161. },
  162. onUnload() {
  163. let endTime = new Date().getTime();
  164. let time = endTime - this.startTime;
  165. if (time > 10000) this.createVisitor();
  166. },
  167. methods: {
  168. init() {
  169. getHouseDetailById(this.houseId).then(res => {
  170. if (res.code === 200) {
  171. this.detail = res.data;
  172. if (this.detail.picture) this.responsibility = JSON.parse(this.detail.picture);
  173. if (this.detail.coordinates) {
  174. this.coordinates = this.detail.coordinates.split(',');
  175. this.latitude = this.coordinates[1];
  176. this.longitude = this.coordinates[0];
  177. this.addMarkers();
  178. }
  179. this.getVisitor();
  180. this.getHouseEvaluate();
  181. }
  182. })
  183. },
  184. getHouseEvaluate() {
  185. getHouseEvaluateListByPage({
  186. currPage: 1,
  187. pageSize: 100,
  188. projectItemTargetRoomId: this.houseId
  189. }).then(res => {
  190. if (res.code == 200) {
  191. this.commentData.commentSize = res.data.totalCount;
  192. this.commentData.comment = this.getTree(res.data.dataList.map(node => {
  193. return {
  194. "id": node.id, // 唯一主键
  195. "owner": true, // 是否是拥有者,为true则可以删除,管理员全部为true
  196. "hasLike": false, // 是否点赞
  197. "likeNum": 2, // 点赞数量
  198. "avatarUrl": node.userPortrait, // 评论者头像地址
  199. "nickName": node.userName, // 评论者昵称,昵称过长请在后端截断
  200. "content": node.content, // 评论内容
  201. "parentId": node.parentId, // 所属评论的唯一主键
  202. "createTime": node.date // 创建时间
  203. }
  204. }))
  205. }
  206. })
  207. },
  208. getTree(data) {
  209. let result = [];
  210. let map = {};
  211. data.forEach(item => {
  212. map[item.id] = item;
  213. });
  214. data.forEach(item => {
  215. let parent = map[item.parentId];
  216. if (parent) {
  217. (parent.children || (parent.children = [])).push(item);
  218. } else {
  219. result.push(item);
  220. }
  221. });
  222. return result;
  223. },
  224. addEvaluate(data) {
  225. insertEvaluate({
  226. userId: this.$store.getters.user.userId,
  227. projectItemTargetRoomId: this.houseId,
  228. content: data.content,
  229. parentId: data.pId || 0
  230. }).then(res => {
  231. if (res.code == 200) {
  232. this.$toast('评价成功');
  233. this.getHouseEvaluate();
  234. this.$refs.hbComment.addComplete();
  235. }
  236. })
  237. },
  238. del() {
  239. },
  240. like() {
  241. },
  242. tell() {
  243. uni.makePhoneCall({
  244. phoneNumber: '17601274604' //仅为示例
  245. });
  246. },
  247. roomCollection() {
  248. this.detail.roomCollection ? disableCollection(this.houseId).then(res => this.successCollection(res,
  249. '取消收藏')) : collection(this.houseId).then(res => this.successCollection(res, '收藏成功'));
  250. },
  251. successCollection(res, msg) {
  252. if (res.code === 200) {
  253. this.init();
  254. this.$toast(msg);
  255. }
  256. },
  257. addMarkers() {
  258. const positions = [{
  259. latitude: this.coordinates[1],
  260. longitude: this.coordinates[0],
  261. }]
  262. const markers = []
  263. positions.forEach((p, i) => {
  264. markers.push(
  265. Object.assign({}, {
  266. id: i + 1,
  267. width: 50,
  268. height: 50,
  269. joinCluster: true, // 指定了该参数才会参与聚合
  270. }, p)
  271. )
  272. })
  273. this.mapContext.addMarkers({
  274. markers,
  275. clear: false,
  276. complete(res) {}
  277. })
  278. },
  279. getVisitor() {
  280. getVisitorByQuery({
  281. currPage: 1,
  282. pageSize: 2,
  283. projectItemTargetRoomId: this.houseId
  284. }).then(res => {
  285. if (res.code === 200) {
  286. this.visitorList = res.data.dataList;
  287. }
  288. })
  289. },
  290. createVisitor() {
  291. insertVisitor({
  292. userId: this.$store.getters.user.userId,
  293. projectItemTargetRoomId: this.houseId
  294. })
  295. }
  296. },
  297. }
  298. </script>
  299. <style lang="scss">
  300. .house-detail {
  301. background: #fff;
  302. padding-bottom: 160rpx;
  303. .house-swiper {
  304. position: relative;
  305. .btn {
  306. position: absolute;
  307. top: 20rpx;
  308. right: 30rpx;
  309. }
  310. }
  311. .swiper {
  312. height: 400rpx;
  313. .image {
  314. width: 100%;
  315. height: 100%;
  316. }
  317. }
  318. .house-label {
  319. font-size: 24rpx;
  320. color: $uni-secondary-color;
  321. font-weight: 300;
  322. }
  323. .house-article {
  324. font-size: 28rpx;
  325. padding: 0 30rpx;
  326. }
  327. .house-title {
  328. padding: 40rpx 130rpx 30rpx 30rpx;
  329. position: relative;
  330. .house-name {
  331. font-size: 36rpx;
  332. font-weight: 500;
  333. }
  334. .project-label {
  335. font-size: 24rpx;
  336. color: $uni-secondary-color;
  337. font-weight: 300;
  338. position: absolute;
  339. bottom: 50rpx;
  340. right: 30rpx;
  341. }
  342. .tag {
  343. font-size: 24rpx;
  344. font-weight: 300;
  345. color: $uni-secondary-color;
  346. padding: 12rpx 0;
  347. }
  348. .pirce {
  349. color: $uni-primary;
  350. .number {
  351. font-weight: 600;
  352. font-size: 48rpx;
  353. }
  354. .label {
  355. font-size: 24rpx;
  356. }
  357. }
  358. .wx-icon {
  359. position: absolute;
  360. top: 0;
  361. right: 30rpx;
  362. transform: translateY(50%);
  363. }
  364. }
  365. .content-map {
  366. width: 100%;
  367. height: 360rpx;
  368. border-radius: 16rpx;
  369. overflow: hidden;
  370. display: flex;
  371. .map {
  372. flex: 1;
  373. height: 100%;
  374. border-radius: 16rpx;
  375. }
  376. }
  377. .house-content {
  378. padding: 0 30rpx;
  379. box-sizing: border-box;
  380. .content-title {
  381. font-size: 32rpx;
  382. font-weight: 500;
  383. margin: 30rpx 0;
  384. display: flex;
  385. align-items: center;
  386. justify-content: space-between;
  387. .more {
  388. color: $uni-secondary-color;
  389. font-weight: 300;
  390. font-size: 24rpx;
  391. }
  392. }
  393. .people-tell {
  394. margin: 40rpx 0;
  395. height: 140rpx;
  396. border-radius: 20rpx;
  397. box-shadow: 0px 1px 12px rgba(3, 3, 3, 0.08);
  398. display: flex;
  399. align-items: center;
  400. padding: 0 30rpx;
  401. .people-avatar {
  402. width: 90rpx;
  403. height: 90rpx;
  404. border-radius: 50%;
  405. margin-right: 30rpx;
  406. }
  407. .people-text {
  408. flex: 1;
  409. width: 0;
  410. overflow: hidden;
  411. }
  412. .people-name {
  413. font-size: 16px;
  414. font-weight: 500;
  415. margin-bottom: 8rpx;
  416. }
  417. .people-organization {
  418. font-weight: 300;
  419. font-size: 24rpx;
  420. color: $uni-secondary-color;
  421. }
  422. .people-icon {
  423. width: 60rpx;
  424. height: 60rpx;
  425. border-radius: 50%;
  426. background: $uni-primary;
  427. text-align: center;
  428. line-height: 60rpx;
  429. }
  430. }
  431. .visitor {
  432. .visitor-item {
  433. margin-bottom: 20rpx;
  434. display: flex;
  435. align-items: center;
  436. font-weight: 300;
  437. .visitor-avatar {
  438. width: 80rpx;
  439. height: 80rpx;
  440. border-radius: 80rpx;
  441. }
  442. .visitor-label {
  443. flex: 1;
  444. width: 0;
  445. overflow: hidden;
  446. white-space: nowrap;
  447. text-overflow: ellipsis;
  448. margin: 0 20rpx;
  449. }
  450. .visitor-time {
  451. font-size: 24rpx;
  452. color: $uni-secondary-color;
  453. }
  454. &:last-child {
  455. margin-bottom: 0;
  456. }
  457. }
  458. }
  459. .desc-text {
  460. font-weight: 300;
  461. }
  462. .information-list {
  463. display: flex;
  464. flex-wrap: wrap;
  465. .information-box {
  466. width: 50%;
  467. display: flex;
  468. margin-bottom: 30rpx;
  469. }
  470. .information-title {
  471. color: $uni-secondary-color;
  472. font-weight: 500;
  473. }
  474. .information-text {
  475. flex: 1;
  476. width: 0;
  477. overflow: hidden;
  478. white-space: nowrap;
  479. font-weight: 300;
  480. }
  481. }
  482. .content-device {
  483. display: flex;
  484. flex-wrap: wrap;
  485. .device-item {
  486. width: 50%;
  487. display: flex;
  488. align-items: center;
  489. margin-bottom: 20rpx;
  490. .device-label {
  491. flex: 1;
  492. width: 0;
  493. color: $uni-secondary-color;
  494. font-weight: 200;
  495. margin-left: 10rpx;
  496. }
  497. .device-icon {
  498. color: $uni-base-color;
  499. }
  500. }
  501. }
  502. }
  503. }
  504. </style>