feat(M03-C): 完成地图选店与距离排序
This commit is contained in:
@@ -1,46 +1,55 @@
|
||||
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
||||
const { request } = require('../../utils/api.js')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
motto: '自助棋牌室',
|
||||
userInfo: {
|
||||
avatarUrl: defaultAvatarUrl,
|
||||
nickName: '',
|
||||
},
|
||||
hasUserInfo: false,
|
||||
canIUseGetUserProfile: wx.canIUse('getUserProfile'),
|
||||
canIUseNicknameComp: wx.canIUse('input.type.nickname'),
|
||||
city: '',
|
||||
locating: false,
|
||||
loading: false,
|
||||
errorMessage: '',
|
||||
stores: [],
|
||||
},
|
||||
bindViewTap() {
|
||||
wx.navigateTo({
|
||||
url: '../logs/logs'
|
||||
|
||||
onCityInput(event) {
|
||||
this.setData({ city: event.detail.value })
|
||||
},
|
||||
|
||||
async searchByCity() {
|
||||
const city = this.data.city.trim()
|
||||
if (!city) {
|
||||
this.setData({ errorMessage: '请输入城市名称' })
|
||||
return
|
||||
}
|
||||
await this.loadStores({ city })
|
||||
},
|
||||
|
||||
locateNearby() {
|
||||
this.setData({ locating: true, errorMessage: '' })
|
||||
wx.getLocation({
|
||||
type: 'gcj02',
|
||||
success: async ({ latitude, longitude }) => {
|
||||
await this.loadStores({ latitude, longitude })
|
||||
},
|
||||
fail: () => {
|
||||
this.setData({ errorMessage: '定位未授权,请输入城市手工选店' })
|
||||
},
|
||||
complete: () => {
|
||||
this.setData({ locating: false })
|
||||
},
|
||||
})
|
||||
},
|
||||
onChooseAvatar(e) {
|
||||
const { avatarUrl } = e.detail
|
||||
const { nickName } = this.data.userInfo
|
||||
this.setData({
|
||||
'userInfo.avatarUrl': avatarUrl,
|
||||
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
||||
})
|
||||
},
|
||||
onInputChange(e) {
|
||||
const nickName = e.detail.value
|
||||
const { avatarUrl } = this.data.userInfo
|
||||
this.setData({
|
||||
'userInfo.nickName': nickName,
|
||||
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
||||
})
|
||||
},
|
||||
getUserProfile() {
|
||||
wx.getUserProfile({
|
||||
desc: '用于展示用户头像和昵称',
|
||||
success: (res) => {
|
||||
this.setData({
|
||||
userInfo: res.userInfo,
|
||||
hasUserInfo: true
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
async loadStores(filters) {
|
||||
this.setData({ loading: true, errorMessage: '' })
|
||||
try {
|
||||
const query = Object.entries(filters)
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
||||
.join('&')
|
||||
const response = await request(`/stores?${query}`)
|
||||
this.setData({ stores: response.data || [] })
|
||||
} catch (error) {
|
||||
this.setData({ errorMessage: error.message || '门店加载失败' })
|
||||
} finally {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
<scroll-view class="scrollarea" scroll-y type="list">
|
||||
<view class="container">
|
||||
<view class="userinfo">
|
||||
<block wx:if="{{canIUseNicknameComp && !hasUserInfo}}">
|
||||
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
|
||||
<image class="avatar" src="{{userInfo.avatarUrl}}"></image>
|
||||
</button>
|
||||
<view class="nickname-wrapper">
|
||||
<text class="nickname-label">昵称</text>
|
||||
<input type="nickname" class="nickname-input" placeholder="请输入昵称" bind:change="onInputChange" />
|
||||
</view>
|
||||
</block>
|
||||
<block wx:elif="{{!hasUserInfo}}">
|
||||
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile">获取头像昵称</button>
|
||||
<view wx:else>请升级微信后重试</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
|
||||
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
|
||||
</block>
|
||||
<view class="title">选择门店</view>
|
||||
<button loading="{{locating}}" bindtap="locateNearby">定位附近门店</button>
|
||||
<view class="city-search">
|
||||
<input value="{{city}}" placeholder="拒绝定位时输入城市" bindinput="onCityInput" />
|
||||
<button size="mini" loading="{{loading}}" bindtap="searchByCity">查询</button>
|
||||
</view>
|
||||
<view class="usermotto">
|
||||
<text class="user-motto">{{motto}}</text>
|
||||
<view wx:if="{{errorMessage}}" class="error">{{errorMessage}}</view>
|
||||
<view wx:if="{{!loading && stores.length === 0}}" class="empty">暂无门店</view>
|
||||
<view wx:for="{{stores}}" wx:key="id" class="store-card">
|
||||
<view class="store-name">{{item.name}}</view>
|
||||
<view>{{item.city}}{{item.district}} {{item.address}}</view>
|
||||
<view wx:if="{{item.distanceMeters !== null}}">距离 {{item.distanceMeters}} 米</view>
|
||||
<view class="{{item.openNow ? 'open' : 'closed'}}">
|
||||
{{item.openNow ? '营业中' : '休息中'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
@@ -1,62 +1,57 @@
|
||||
/**index.wxss**/
|
||||
page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.scrollarea {
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
height: 100vh;
|
||||
background: #f5f6f8;
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
.container {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 24rpx;
|
||||
font-size: 40rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.city-search {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
align-items: center;
|
||||
color: #aaa;
|
||||
width: 80%;
|
||||
margin: 24rpx 0;
|
||||
}
|
||||
|
||||
.userinfo-avatar {
|
||||
overflow: hidden;
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
margin: 20rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.usermotto {
|
||||
margin-top: 200px;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
padding: 0;
|
||||
width: 56px !important;
|
||||
border-radius: 8px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: block;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.nickname-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
border-top: .5px solid rgba(0, 0, 0, 0.1);
|
||||
border-bottom: .5px solid rgba(0, 0, 0, 0.1);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.nickname-label {
|
||||
width: 105px;
|
||||
}
|
||||
|
||||
.nickname-input {
|
||||
.city-search input {
|
||||
flex: 1;
|
||||
padding: 18rpx 24rpx;
|
||||
border: 1rpx solid #d7dbe0;
|
||||
border-radius: 12rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.store-card {
|
||||
margin-top: 20rpx;
|
||||
padding: 28rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.store-name {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.open {
|
||||
color: #17823b;
|
||||
}
|
||||
|
||||
.closed,
|
||||
.error {
|
||||
color: #c73535;
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 80rpx 0;
|
||||
color: #888888;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user