home.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <template>
  2. <view class="container">
  3. <!-- 搜索框区域 -->
  4. <uv-row custom-style="margin: 10px 0px" gutter="10">
  5. <picker @change="bindPickerChange" range-key="name" :value="placeIndex" :range="placeList">
  6. <view class="address">
  7. <view class="address_text">{{ placeList[placeIndex].name }}</view>
  8. <img src="../../static/index/bottom.png" />
  9. </view>
  10. </picker>
  11. <view class="search">
  12. <view class="add">
  13. <image class="img" src="../../static/index/search.png" mode="aspectFit"></image>
  14. </view>
  15. <input class="inp" type="text" v-model="keywords" placeholder="请输入关键字搜索" />
  16. <view class="btnSearch" @click="searchHandler">搜索</view>
  17. </view>
  18. </uv-row>
  19. <!-- 名宿列表区域 -->
  20. <view class="body" v-if="hotelList.length">
  21. <!-- 每一个名宿区域 -->
  22. <view class="item" v-for="item in hotelList" :key="item.id" @click="goPageDetail(item)">
  23. <image class="item-img" :src="item.coverImg" mode="scaleToFill"></image>
  24. <view class="descrition">
  25. <text class="title">{{ item.hotel_name }}</text>
  26. <text class="type">{{ item.hTypeName }}</text>
  27. <text class="distance" v-if="showdDistance">距您直线{{ item.distance }}公里</text>
  28. <view class="detail">
  29. <img class="img" src="../../static/index/hotel.png" />
  30. <view class="price">
  31. <text class="txt1">¥{{ item.min_price }}</text>
  32. <text class="txt2">起</text>
  33. </view>
  34. </view>
  35. </view>
  36. </view>
  37. </view>
  38. <!-- 没有数据时展示的页面 -->
  39. <view class="noData" v-else>
  40. <img src="../../static/images/noData.png" />
  41. 暂无数据
  42. </view>
  43. </view>
  44. </template>
  45. <script>
  46. export default {
  47. data() {
  48. return {
  49. // 是否显示距离差
  50. showdDistance: false,
  51. // 搜索框绑定数据
  52. keywords: '',
  53. // 民宿列表数组
  54. hotelList: [],
  55. // 地区数组
  56. placeList: [
  57. {
  58. name: '靖安县'
  59. }
  60. ],
  61. // 当前选择地区索引
  62. placeIndex: 0,
  63. // 当前页
  64. page: 1,
  65. // 每页多少条
  66. rows: 6,
  67. // 总条数
  68. total: null,
  69. // 用户定位经度
  70. myLng: 0,
  71. // 用户定位纬度
  72. myLat: 0
  73. }
  74. },
  75. onLoad() {
  76. this.getLocation()
  77. this.getTownList()
  78. },
  79. // 页面下拉回调
  80. onPullDownRefresh() {
  81. setTimeout(() => {
  82. this.hotelList = []
  83. this.page = 1
  84. this.getLocation()
  85. uni.stopPullDownRefresh()
  86. }, 2000)
  87. },
  88. // 页面下拉到底部回调
  89. onReachBottom() {
  90. if (this.hotelList.length < this.total) {
  91. this.page++
  92. this.getHotelList()
  93. } else {
  94. uni.showToast({
  95. title: '没有更多数据了',
  96. icon: 'none'
  97. })
  98. }
  99. },
  100. methods: {
  101. // 获取乡镇集合
  102. async getTownList() {
  103. const res = await this.$myRequest({
  104. url: '/mhotel/hotelqueryList.action',
  105. method: 'get',
  106. data: {
  107. code: 10
  108. }
  109. })
  110. // console.log(res)
  111. if (res.code === 200) {
  112. this.placeList = [...this.placeList, ...res.data]
  113. }
  114. },
  115. // 获取用户当前位置
  116. getLocation() {
  117. uni.getSetting({
  118. success: (res) => {
  119. if (!res.authSetting['scope.userLocation']) {
  120. uni.authorize({
  121. scope: 'scope.userLocation',
  122. success: (res) => {
  123. // 授权成功
  124. uni.getLocation({
  125. type: 'gcj02',
  126. success: (res) => {
  127. this.myLat = res.latitude
  128. this.myLng = res.longitude
  129. this.showdDistance = true
  130. this.getHotelList()
  131. }
  132. })
  133. },
  134. fail: () => {
  135. uni.showModal({
  136. content: '获取定位权限失败将会影响使用部分功能,是否去设置打开?',
  137. confirmText: '确认',
  138. cancelText: '取消',
  139. success: (res) => {
  140. if (res.confirm) {
  141. uni.openSetting({
  142. success: (res) => {
  143. console.log(res)
  144. this.getLocation()
  145. }
  146. })
  147. } else {
  148. this.showdDistance = false
  149. this.getHotelList()
  150. uni.showToast({
  151. title: '获取定位权限失败',
  152. icon: 'none'
  153. })
  154. }
  155. }
  156. })
  157. }
  158. })
  159. } else {
  160. uni.getLocation({
  161. type: 'gcj02',
  162. success: (res) => {
  163. this.myLat = res.latitude
  164. this.myLng = res.longitude
  165. this.showdDistance = true
  166. this.getHotelList()
  167. }
  168. })
  169. }
  170. }
  171. })
  172. },
  173. // 获取民宿列表
  174. async getHotelList() {
  175. const res = await this.$myRequest({
  176. url: '/mhotel/ahphomePage.action',
  177. data: {
  178. queryValue: this.keywords,
  179. page: this.page,
  180. rows: this.rows,
  181. hotel_township: this.placeList[this.placeIndex].id || ''
  182. }
  183. })
  184. // console.log(res)
  185. if (res.code === 200) {
  186. this.hotelList = [...this.hotelList, ...res.data.pageList]
  187. this.total = res.data.total
  188. // 如果定位成功则获取和民宿之间的距离
  189. if (this.showdDistance && this.hotelList.length) {
  190. this.hotelList.forEach((ele) => {
  191. let lat = ele.hpositionWens.split(',')[0]
  192. let lng = ele.hpositionWens.split(',')[1]
  193. ele.distance = this.calculateDistance(lat, lng)
  194. })
  195. }
  196. }
  197. },
  198. // 计算两个点之间的距离
  199. calculateDistance(lat, lng) {
  200. let centerLat = lat
  201. let centerLng = lng
  202. let red1 = (this.myLat * Math.PI) / 180.0
  203. let red2 = (centerLat * Math.PI) / 180.0
  204. let a = red1 - red2
  205. let b = (this.myLng * Math.PI) / 180.0 - (centerLng * Math.PI) / 180.0
  206. let R = 6378137
  207. let distance = R * 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(red1) * Math.cos(red2) * Math.pow(Math.sin(b / 2), 2)))
  208. let res = (distance / 1000).toFixed(2) * 1
  209. return res
  210. },
  211. // 搜索按钮点击回调
  212. searchHandler() {
  213. this.hotelList = []
  214. this.page = 1
  215. this.getHotelList()
  216. },
  217. // 点击每一个名宿卡片回调
  218. goPageDetail(item) {
  219. uni.navigateTo({
  220. url: `/pages/detail/detail?id=${item.id}&distance=${item.distance}`
  221. })
  222. },
  223. // 选择地区时的回调
  224. bindPickerChange(e) {
  225. this.placeIndex = e.detail.value
  226. this.hotelList = []
  227. this.page = 1
  228. this.getHotelList()
  229. }
  230. }
  231. }
  232. </script>
  233. <style lang="scss" scoped>
  234. .container {
  235. display: flex;
  236. flex-direction: column;
  237. width: 750rpx;
  238. min-height: 100vh;
  239. padding: 0 30rpx;
  240. box-sizing: border-box;
  241. background-color: #f7f7f7;
  242. .address {
  243. display: flex;
  244. width: 152rpx;
  245. font-size: 28rpx;
  246. .address_text {
  247. width: 104rpx;
  248. text-align: center;
  249. overflow: hidden;
  250. white-space: nowrap;
  251. text-overflow: ellipsis;
  252. }
  253. img {
  254. width: 48rpx;
  255. height: 48rpx;
  256. }
  257. }
  258. .search {
  259. display: flex;
  260. justify-content: space-between;
  261. align-items: center;
  262. width: 538rpx;
  263. height: 80rpx;
  264. opacity: 1;
  265. border-radius: 70px;
  266. background-color: #fff;
  267. .add {
  268. display: flex;
  269. justify-content: center;
  270. align-items: center;
  271. margin-left: 10rpx;
  272. width: 60rpx;
  273. font-size: 50rpx;
  274. height: 60rpx;
  275. line-height: 60rpx;
  276. color: rgba(30, 125, 251, 1);
  277. .img {
  278. width: 30rpx;
  279. height: 30rpx;
  280. }
  281. }
  282. .inp {
  283. height: 60rpx;
  284. line-height: 60rpx;
  285. flex-grow: 1;
  286. font-size: 28rpx;
  287. }
  288. .btnSearch {
  289. width: 100rpx;
  290. text-align: center;
  291. margin-right: 10rpx;
  292. height: 60rpx;
  293. line-height: 60rpx;
  294. opacity: 1;
  295. font-size: 28rpx;
  296. font-weight: 400;
  297. height: 2rem;
  298. color: #096562;
  299. }
  300. }
  301. .body {
  302. display: flex;
  303. justify-content: space-between;
  304. flex-wrap: wrap;
  305. .item {
  306. width: 335rpx;
  307. box-sizing: border-box;
  308. margin-bottom: 20rpx;
  309. .item-img {
  310. width: 100%;
  311. height: 223rpx;
  312. border-radius: 18rpx 18rpx 0 0;
  313. box-sizing: border-box;
  314. }
  315. .descrition {
  316. display: flex;
  317. flex-direction: column;
  318. width: 100%;
  319. border-radius: 0 0 18rpx 18rpx;
  320. box-sizing: border-box;
  321. background: rgba(255, 255, 255, 1);
  322. margin-top: -10rpx;
  323. .title {
  324. font-size: 28rpx;
  325. font-weight: 600;
  326. padding: 20rpx 20rpx 10rpx;
  327. color: rgba(0, 0, 0, 1);
  328. overflow: hidden;
  329. white-space: nowrap;
  330. text-overflow: ellipsis;
  331. }
  332. .type {
  333. padding: 5rpx 20rpx;
  334. height: 40rpx;
  335. font-size: 24rpx;
  336. color: #a6a6a6;
  337. }
  338. .distance {
  339. padding: 10rpx 20rpx;
  340. font-size: 24rpx;
  341. color: #a6a6a6;
  342. }
  343. .detail {
  344. display: flex;
  345. flex-direction: row;
  346. justify-content: space-between;
  347. align-items: center;
  348. padding: 0 20rpx 20rpx 20rpx;
  349. color: rgba(0, 0, 0, 1);
  350. .img {
  351. width: 40rpx;
  352. height: 40rpx;
  353. }
  354. .price {
  355. .txt1 {
  356. font-size: 36rpx;
  357. font-weight: 600;
  358. color: rgba(255, 87, 51, 1);
  359. }
  360. .txt2 {
  361. font-size: 24rpx;
  362. font-weight: 400;
  363. color: #a6a6a6;
  364. }
  365. }
  366. .score {
  367. font-size: 24rpx;
  368. font-weight: 400;
  369. padding-top: 10rpx;
  370. color: rgba(166, 166, 166, 1);
  371. }
  372. }
  373. }
  374. }
  375. }
  376. .noData {
  377. display: flex;
  378. flex-direction: column;
  379. justify-content: center;
  380. align-items: center;
  381. img {
  382. margin-top: 150rpx;
  383. width: 600rpx;
  384. height: 600rpx;
  385. }
  386. }
  387. }
  388. </style>