Merge branch 'master' into xuchao
This commit is contained in:
+132
-23
@@ -1,5 +1,13 @@
|
||||
<template>
|
||||
<view class="page" v-if="store">
|
||||
<view>
|
||||
<view class="page" v-if="store">
|
||||
<!-- xuchao: 顶部导航(返回+页面名称) -->
|
||||
<view class="nav-bar">
|
||||
<view class="nav-back" @click="goBack">
|
||||
<u-icon name="arrow-left" color="#1a1818" size="40"></u-icon>
|
||||
</view>
|
||||
<text class="nav-title">{{ store.name }}</text>
|
||||
</view>
|
||||
<!-- 门店信息卡片(信息+地址合并容器) -->
|
||||
<view class="store-card">
|
||||
<view class="store-main">
|
||||
@@ -20,6 +28,31 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商户电话(取商铺客服电话字段,多个用,分隔,点击拨号) -->
|
||||
<view class="discount-section" v-if="servicePhoneList.length">
|
||||
<view class="section-title">
|
||||
<u-icon name="phone-fill" color="#1296DB" size="34"></u-icon>
|
||||
<text class="discount-title">商户电话</text>
|
||||
</view>
|
||||
<view class="discount-list">
|
||||
<text class="discount-item">
|
||||
<text v-for="(p, i) in servicePhoneList" :key="i" class="phone-link"
|
||||
@click="callPhone(p)">{{ i > 0 ? ',' : '' }}{{ p }}</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品信息(内容取商铺门票信息字段) -->
|
||||
<view class="discount-section" v-if="ticketInfoList.length">
|
||||
<view class="section-title">
|
||||
<image src="https://aliyunoss.hn12301.net/hhrs/hhrs_qysm.png" style="width: 30rpx;height: 30rpx;"></image>
|
||||
<text class="discount-title">商品信息</text>
|
||||
</view>
|
||||
<view class="discount-list">
|
||||
<text class="discount-item" v-for="(item, index) in ticketInfoList" :key="index">{{ item }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商户优惠 -->
|
||||
<view class="discount-section">
|
||||
<view class="section-title">
|
||||
@@ -30,11 +63,18 @@
|
||||
<text class="discount-item" v-for="(item, index) in discountList" :key="index">{{ item }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 返回按钮 -->
|
||||
<view class="back-btn" @click="goBack">
|
||||
<image class="back-icon" src="https://zhihuiyou.oss-cn-shenzhen.aliyuncs.com/hhrs/hhrs_back.png" mode="aspectFit"></image>
|
||||
<text class="back-text">返回上一页</text>
|
||||
</view>
|
||||
<!-- xuchao: 门店不存在或加载失败时的提示态,避免纯空白 -->
|
||||
<view class="page" v-else-if="loaded">
|
||||
<view class="nav-bar">
|
||||
<view class="nav-back" @click="goBack">
|
||||
<u-icon name="arrow-left" color="#1a1818" size="40"></u-icon>
|
||||
</view>
|
||||
<text class="nav-title">详情</text>
|
||||
</view>
|
||||
<view class="load-failed">
|
||||
<text class="load-failed-text">门店信息加载失败,该门店可能不存在或已下架</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -43,13 +83,41 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
store: null
|
||||
store: null,
|
||||
loaded: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
ticketInfoList() {
|
||||
if (!this.store || !this.store.ticketInfo) return []
|
||||
return this.store.ticketInfo.split('\n')
|
||||
},
|
||||
discountList() {
|
||||
if (!this.store || !this.store.merchantDiscount) return []
|
||||
return this.store.merchantDiscount.split('\n')
|
||||
},
|
||||
// xuchao: 客服电话列表:按常见分隔符切分;无分隔符连写的多个11位手机号也自动拆开
|
||||
servicePhoneList() {
|
||||
if (!this.store || !this.store.servicePhone) return []
|
||||
const parts = String(this.store.servicePhone).split(/[,,;;、\s\n]+/).filter(Boolean)
|
||||
const out = []
|
||||
parts.forEach(p => {
|
||||
if (p.length > 11 && /^1[3-9]\d{9}$/.test(p.slice(0, 11))) {
|
||||
let rest = p
|
||||
const segs = []
|
||||
while (rest.length >= 11 && /^1[3-9]\d{9}$/.test(rest.slice(0, 11))) {
|
||||
segs.push(rest.slice(0, 11))
|
||||
rest = rest.slice(11)
|
||||
}
|
||||
if (rest) segs[segs.length - 1] += rest
|
||||
if (segs.length > 1) {
|
||||
out.push(...segs)
|
||||
return
|
||||
}
|
||||
}
|
||||
out.push(p)
|
||||
})
|
||||
return out
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
@@ -58,6 +126,11 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// xuchao: 点击某个商户电话唤起拨号(多个号码时逐个可点)
|
||||
callPhone(phone) {
|
||||
if (!phone) return
|
||||
uni.makePhoneCall({ phoneNumber: String(phone) })
|
||||
},
|
||||
loadDetail(shopId) {
|
||||
const loc = uni.getStorageSync('lng') && uni.getStorageSync('lat')
|
||||
? { lng: uni.getStorageSync('lng'), lat: uni.getStorageSync('lat') }
|
||||
@@ -71,10 +144,19 @@ export default {
|
||||
if (res.errcode === 0 && res.data) {
|
||||
this.store = res.data
|
||||
}
|
||||
this.loaded = true
|
||||
}).catch(() => {
|
||||
this.loaded = true
|
||||
})
|
||||
},
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
// xuchao: 直接通过链接进入(无历史栈)时回到首页,避免返回无响应
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
uni.reLaunch({ url: '/pages/index/index' })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,9 +164,9 @@ export default {
|
||||
|
||||
<style>
|
||||
.page {
|
||||
height: 100vh;
|
||||
/* xuchao: 顶部导航条占用 56px,改为 min-height 让长内容正常滚动,避免底部被裁切 */
|
||||
min-height: 100vh;
|
||||
background-color: #f2f2f7;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 门店卡片(信息+地址合并容器) */
|
||||
@@ -207,24 +289,51 @@ export default {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 返回按钮 */
|
||||
.back-btn {
|
||||
position: fixed;
|
||||
left: 24px;
|
||||
bottom: 50px;
|
||||
/* xuchao: 可点击拨号的电话样式 */
|
||||
.phone-link {
|
||||
color: #0088ff;
|
||||
}
|
||||
|
||||
/* xuchao: 加载失败提示态 */
|
||||
.load-failed {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 80px 24px;
|
||||
}
|
||||
|
||||
.load-failed-text {
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
/* xuchao: 顶部返回导航条 */
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
height: 56px;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
.nav-back {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.back-text {
|
||||
font-size: 12px;
|
||||
color: #666666;
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
color: #1a1818;
|
||||
padding: 0 56px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
|
||||
+22
-6
@@ -16,7 +16,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 场馆列表 -->
|
||||
<scroll-view class="list-area" scroll-y @scrolltolower="loadMore" :lower-threshold="100">
|
||||
<view class="list-area">
|
||||
<view class="venue-card" v-for="item in list" :key="item.shopId" @click="goDetail(item)">
|
||||
<image class="card-img" :src="item.image" mode="aspectFill" />
|
||||
<view class="card-info">
|
||||
@@ -32,9 +32,9 @@
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="hasScrolled" class="nomore-area">
|
||||
<u-loadmore :status="loadStatus" :loading-text="'加载中...'" :loadmore-text="''" :nomore-text="'我也是有底线的'" />
|
||||
<u-loadmore :status="loadStatus" :load-text="{ loadmore: '', loading: '加载中...', nomore: '我也是有底线的' }" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -51,7 +51,8 @@ export default {
|
||||
lng: '',
|
||||
lat: '',
|
||||
loadStatus: 'loadmore',
|
||||
hasScrolled: false
|
||||
hasScrolled: false,
|
||||
reqSeq: 0
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
@@ -64,9 +65,14 @@ export default {
|
||||
}
|
||||
this.loadList()
|
||||
},
|
||||
// xuchao: 改用页面级触底加载(scroll-view 无固定高度时 scrolltolower 永不触发)
|
||||
onReachBottom() {
|
||||
this.loadMore()
|
||||
},
|
||||
methods: {
|
||||
loadList() {
|
||||
if (this.loading) return
|
||||
// xuchao: 请求序号 —— 新请求直接取代在途请求,过期响应整体丢弃(修复搜索竞态,故不再用 loading 提前 return)
|
||||
const seq = ++this.reqSeq
|
||||
this.loading = true
|
||||
this.loadStatus = 'loading'
|
||||
const params = {
|
||||
@@ -78,6 +84,7 @@ export default {
|
||||
if (this.lng) params.lng = this.lng
|
||||
if (this.lat) params.lat = this.lat
|
||||
this.$u.api.getStoreList(params).then(res => {
|
||||
if (seq !== this.reqSeq) return
|
||||
if (res.errcode === 0 && res.data) {
|
||||
const list = res.data.list || []
|
||||
if (this.pageNo === 1) {
|
||||
@@ -86,8 +93,11 @@ export default {
|
||||
this.list = this.list.concat(list)
|
||||
}
|
||||
this.total = res.data.total || 0
|
||||
// xuchao: 本页不足一页即已到尾部,钉住 total,防止 total 中途变大时空翻
|
||||
if (list.length < this.pageSize) this.total = this.list.length
|
||||
}
|
||||
}).finally(() => {
|
||||
if (seq !== this.reqSeq) return
|
||||
this.loading = false
|
||||
if (this.list.length === 0) {
|
||||
this.loadStatus = 'nomore'
|
||||
@@ -106,7 +116,13 @@ export default {
|
||||
}
|
||||
},
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
// xuchao: 直接通过链接进入(无历史栈)时回到首页
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
uni.reLaunch({ url: '/pages/index/index' })
|
||||
}
|
||||
},
|
||||
goDetail(item) {
|
||||
uni.navigateTo({ url: '/pages/venue/detail?id=' + item.shopId })
|
||||
|
||||
Reference in New Issue
Block a user