house.vue 15 KB

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