You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

526 lines
11 KiB

10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
  1. <template>
  2. <view class="home">
  3. <!-- <view class="home-top"> -->
  4. <!-- <view class="search">
  5. <view @click="showSelectArea" class="left-area">
  6. <image src="@/static/home/address-icon.png"></image>
  7. <view class="area">{{ area }}</view>
  8. <image src="../../static/home/arrow-icon.png" mode="aspectFit"></image>
  9. <view class="parting-line">|</view>
  10. </view>
  11. <view class="center-area">
  12. <image src="@/static/home/search-icon.png"></image>
  13. <van-field @click="searchAddress" v-model="queryParams.title" center placeholder="请选择地区" />
  14. </view>
  15. <view class="right-area">
  16. <view @click="searchAddress" class="search-button">
  17. 搜索
  18. </view>
  19. </view>
  20. </view> -->
  21. <!-- </view> -->
  22. <view class="banner b-relative">
  23. <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
  24. <van-swipe-item v-for="item in bannerList" :key="item.id">
  25. <image class="banner-image" :src="item.image" mode="widthFix"></image>
  26. </van-swipe-item>
  27. </van-swipe>
  28. </view>
  29. <view class="home-content">
  30. <!-- <view class="banner b-relative">
  31. <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
  32. <van-swipe-item v-for="item in bannerList" :key="item.id">
  33. <image class="banner-image" :src="item.image" mode="widthFix"></image>
  34. </van-swipe-item>
  35. </van-swipe>
  36. </view> -->
  37. <view class="search">
  38. <view @click="showSelectArea" class="left-area">
  39. <image src="@/static/home/address-icon.png"></image>
  40. <view class="area">{{ selectArea.name }}</view>
  41. <image src="../../static/home/arrow-icon.png" mode="aspectFit"></image>
  42. <view class="parting-line">|</view>
  43. </view>
  44. <view class="center-area">
  45. <image src="@/static/home/search-icon.png"></image>
  46. <van-field @click="searchAddress" v-model="queryParams.title" center placeholder="请选择地区" />
  47. </view>
  48. <view class="right-area">
  49. <view @click="searchAddress" class="search-button">
  50. 搜索
  51. </view>
  52. </view>
  53. </view>
  54. <view v-if="projectList.length > 0" class="server-list">
  55. <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" ref="list"
  56. @load="onLoad">
  57. <view v-for="item in projectList" class="server-item" @click="toServiceDetail(item.id)">
  58. <view class="img-box">
  59. <image :src="item.image" mode="aspectFill"></image>
  60. </view>
  61. <view class="server-info">
  62. <view class="server-title">{{ item.title }}</view>
  63. <view class="time-coupon">
  64. <image src="@/static/home/time-icon.png"></image>
  65. <view class="time">{{ item.times }}分钟</view>
  66. <!-- <view class="coupon">{{ item.subTitle }}</view> -->
  67. </view>
  68. <view class="price">
  69. <view class="current-price">
  70. <text class="unit"></text>{{ item.price }}
  71. </view>
  72. <view class="original-price">
  73. <text class="unit"></text>{{ item.oldPrice }}
  74. </view>
  75. </view>
  76. <view class="sales-volume">
  77. <image src="@/static/icons/icon1.png"></image>
  78. <view class="desc">已售出{{ item.payNum }}+</view>
  79. </view>
  80. </view>
  81. <view class="selective-technician">
  82. <view @click.stop="selectTechnician(item.id)" class="btn">
  83. 选择技师
  84. </view>
  85. </view>
  86. </view>
  87. </van-list>
  88. </view>
  89. <van-empty v-else image="/static/empty/data.png" image-size="400rpx" description="暂无项目" />
  90. </view>
  91. <selectArea :show="showAeraPro" @close="closeAreaPro" @select="selectArea"></selectArea>
  92. </view>
  93. </template>
  94. <script>
  95. import selectArea from '../../components/selectArea.vue';
  96. import Position from '@/utils/position.js'
  97. export default {
  98. components: {
  99. selectArea
  100. },
  101. data() {
  102. return {
  103. bannerList: [],
  104. projectList: [],
  105. queryParams: {
  106. pageNo: 1,
  107. pageSize: 10,
  108. title: ''
  109. },
  110. loading: false,
  111. finished: false,
  112. technicianList: [],
  113. showAeraPro: false,
  114. area: ''
  115. }
  116. },
  117. onShow() {
  118. this.getBanner()
  119. this.getProject()
  120. this.getLocation()
  121. },
  122. methods: {
  123. //list列表滑动到底部自动新增数据列表
  124. onLoad() {
  125. this.queryParams.pageSize += 10;
  126. this.getProject()
  127. },
  128. //获取banner
  129. getBanner() {
  130. this.$api('getBanner', {}, res => {
  131. this.bannerList = res.result;
  132. })
  133. },
  134. //获取项目列表
  135. getProject() {
  136. this.$api('getProjectList', this.queryParams, res => {
  137. if (res.code == 200) {
  138. this.projectList = res.result.records;
  139. } else {
  140. this.finished = true
  141. }
  142. if (this.queryParams.pageSize > res.result.total) {
  143. this.finished = true
  144. }
  145. this.loading = false
  146. })
  147. },
  148. //获取项目详情
  149. selectTechnician(id) {
  150. uni.navigateTo({
  151. url: `/pages/technician/selectTechnician?serviceId=${id}`
  152. })
  153. // this.$api('getProjectDetail', {
  154. // id
  155. // }, res => {
  156. // if (res.code == 200) {
  157. // uni.navigateTo({
  158. // url: `/pages/technician/selectTechnician?serviceId=${id}`
  159. // })
  160. // sessionStorage.setItem('technicianList', JSON.stringify(res.result.tenPageList))
  161. // }
  162. // })
  163. },
  164. //跳转技师详情
  165. toServiceDetail(id) {
  166. uni.navigateTo({
  167. url: '/pages/technician/subscribeService?id=' + id
  168. })
  169. },
  170. //显示选择地区
  171. showSelectArea() {
  172. this.showAeraPro = true;
  173. },
  174. //关闭选择地区
  175. closeAreaPro() {
  176. this.showAeraPro = false;
  177. },
  178. //选择了地区信息
  179. selectArea(area) {
  180. // this.area = area;
  181. this.showAeraPro = false;
  182. },
  183. //搜索地址
  184. searchAddress() {
  185. if(uni.getStorageSync('open_address') == 0){
  186. return
  187. }
  188. // Position.getLocation(res => {
  189. Position.selectAddress(success => {
  190. let address = this.extractProvinceAndCity(success)
  191. this.queryParams.title = address.city
  192. })
  193. // })
  194. },
  195. //提取用户选择的地址信息(省市县信息)
  196. extractProvinceAndCity(res) { //提取用户选择的地址信息(省市)
  197. if (!res.address && res.name) { //用户直接选择城市的逻辑
  198. return {
  199. province: '',
  200. city: res.name
  201. };
  202. }
  203. if (res.address) { //用户选择了详细地址,要从详细地址中提取出省市县信息
  204. // 使用正则表达式匹配省市县
  205. const regex = /(?<province>[\u4e00-\u9fa5]+?省)(?<city>[\u4e00-\u9fa5]+?(?:市|自治州|盟|地区))/;
  206. const match = res.address.match(regex);
  207. if (match) { // 如果匹配成功,则返回省和市的信息
  208. return {
  209. province: match.groups.province,
  210. city: match.groups.city
  211. };
  212. }
  213. }
  214. return { //用户没选择地址就点了确定按钮
  215. province: '',
  216. city: ''
  217. }
  218. },
  219. //获取用户详细地址(省市县)
  220. getLocation() {
  221. if(uni.getStorageSync('open_address') == 0){
  222. return
  223. }
  224. Position.getLocationDetail().then(res => {
  225. if(!this.selectArea.name && this.configList.open_address == 0){
  226. this.$store.commit('setArea', {
  227. name : res.addressDetail.district
  228. })
  229. }
  230. })
  231. },
  232. }
  233. }
  234. </script>
  235. <style lang="scss" scoped>
  236. .home {
  237. width: 750rpx;
  238. background: #F5F5F5;
  239. margin: 0 auto;
  240. .home-top {
  241. height: 400rpx;
  242. // height: 350rpx;
  243. background: linear-gradient(38deg, #4899A6, #60BDA2);
  244. padding-top: 60rpx;
  245. }
  246. .search {
  247. height: 82rpx;
  248. width: 710rpx;
  249. background: #FFFFFF;
  250. margin: 20rpx auto;
  251. border-radius: 41rpx;
  252. box-sizing: border-box;
  253. padding: 0 15rpx;
  254. display: flex;
  255. align-items: center;
  256. justify-content: space-between;
  257. .left-area,
  258. .center-area {
  259. display: flex;
  260. align-items: center;
  261. }
  262. .left-area {
  263. max-width: 160rpx;
  264. image {
  265. flex-shrink: 0;
  266. width: 26rpx;
  267. height: 26rpx;
  268. }
  269. .area {
  270. font-size: 24rpx;
  271. display: -webkit-box;
  272. -webkit-line-clamp: 2;
  273. /* 限制显示两行 */
  274. -webkit-box-orient: vertical;
  275. overflow: hidden;
  276. text-overflow: ellipsis;
  277. color: #292929;
  278. }
  279. .parting-line {
  280. flex-shrink: 0;
  281. font-size: 26rpx;
  282. color: #ccc;
  283. margin: 0rpx 5rpx;
  284. }
  285. }
  286. .center-area {
  287. display: flex;
  288. flex-wrap: nowrap;
  289. align-items: center;
  290. width: calc(100% - 290rpx);
  291. image {
  292. width: 26rpx;
  293. height: 26rpx;
  294. }
  295. .van-field {
  296. background-color: transparent;
  297. box-sizing: border-box;
  298. height: 82rpx;
  299. line-height: 82rpx;
  300. width: calc(100% - 30rpx);
  301. padding: 0rpx 10rpx 0rpx 0rpx;
  302. input {
  303. height: 82rpx;
  304. font-size: 60rpx;
  305. }
  306. }
  307. }
  308. .right-area {
  309. .search-button {
  310. background: #60BDA2;
  311. height: 60rpx;
  312. width: 130rpx;
  313. font-size: 26rpx;
  314. border-radius: 35rpx;
  315. color: white;
  316. display: flex;
  317. align-items: center;
  318. justify-content: center;
  319. }
  320. }
  321. }
  322. .banner {
  323. box-sizing: border-box;
  324. .my-swipe {
  325. width: 100%;
  326. margin: 0px auto;
  327. // border-radius: 20rpx;
  328. // height: 334rpx;
  329. overflow: hidden;
  330. .van-swipe-item {
  331. width: 100%;
  332. .banner-image {
  333. width: 100%;
  334. image {
  335. width: 100%;
  336. }
  337. }
  338. }
  339. }
  340. }
  341. .home-content {
  342. width: calc(100% - 40rpx);
  343. margin: 20rpx 20rpx 0rpx 20rpx;
  344. // margin: -440rpx 20rpx 0rpx 20rpx;
  345. // margin: -240rpx 20rpx 0rpx 20rpx;
  346. .server-list {
  347. padding-bottom: 80rpx;
  348. .server-item {
  349. display: flex;
  350. flex-wrap: wrap;
  351. justify-content: space-between;
  352. background: white;
  353. border-radius: 15rpx;
  354. box-sizing: border-box;
  355. padding: 15rpx;
  356. margin: 20rpx 0rpx;
  357. .img-box {
  358. width: 150rpx;
  359. height: 150rpx;
  360. border-radius: 10rpx;
  361. overflow: hidden;
  362. image {
  363. width: 100%;
  364. height: 100%;
  365. }
  366. }
  367. .server-info {
  368. display: flex;
  369. flex-direction: column;
  370. justify-content: space-around;
  371. width: calc(100% - 330rpx);
  372. box-sizing: border-box;
  373. padding: 0 10rpx;
  374. .server-title {}
  375. .time-coupon,
  376. .price {
  377. display: flex;
  378. flex-wrap: wrap;
  379. align-items: center;
  380. }
  381. .time-coupon {
  382. font-size: 26rpx;
  383. image {
  384. width: 22rpx;
  385. height: 22rpx;
  386. }
  387. .time {
  388. color: #B8B8B8;
  389. margin-left: 6rpx;
  390. }
  391. .coupon {
  392. display: flex;
  393. justify-content: center;
  394. align-items: center;
  395. background: #F29E45;
  396. color: white;
  397. width: 140rpx;
  398. height: 45rpx;
  399. border-radius: 10rpx;
  400. margin-left: 10rpx;
  401. }
  402. }
  403. .price {
  404. display: flex;
  405. align-items: center;
  406. color: #B8B8B8;
  407. .current-price {
  408. font-size: 30rpx;
  409. font-weight: 600;
  410. color: #D34430;
  411. margin-right: 5rpx;
  412. }
  413. .unit {
  414. font-size: 20rpx;
  415. }
  416. }
  417. .sales-volume {
  418. display: flex;
  419. align-items: center;
  420. color: #B8B8B8;
  421. font-size: 26rpx;
  422. image {
  423. width: 23rpx;
  424. height: 23rpx;
  425. }
  426. }
  427. }
  428. .selective-technician {
  429. display: flex;
  430. flex-wrap: wrap;
  431. align-items: center;
  432. width: 170rpx;
  433. .btn {
  434. display: flex;
  435. align-items: center;
  436. justify-content: center;
  437. height: 60rpx;
  438. width: 170rpx;
  439. border-radius: 40rpx;
  440. color: white;
  441. background: linear-gradient(170deg, #53CEAC, #5AC796);
  442. }
  443. }
  444. }
  445. }
  446. }
  447. }
  448. </style>