|
|
|
@ -18,42 +18,42 @@ |
|
|
|
<view class="search-trend" @tap.stop="goSearch">搜索</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="title-tab" style="margin-top: 12rpx;"> |
|
|
|
<view class="campus-banner" @tap="goPendingGroup"> |
|
|
|
<view class="banner-glow"></view> |
|
|
|
<view class="steam steam-one"></view> |
|
|
|
<view class="steam steam-two"></view> |
|
|
|
<view class="steam steam-three"></view> |
|
|
|
<!-- <view class="food-float float-one">🍜</view> |
|
|
|
</view> |
|
|
|
<view class="title-fixed-holder"></view> |
|
|
|
<view class="title-tab" style="margin-top: 12rpx;"> |
|
|
|
<view class="campus-banner" @tap="goPendingGroup"> |
|
|
|
<view class="banner-glow"></view> |
|
|
|
<view class="steam steam-one"></view> |
|
|
|
<view class="steam steam-two"></view> |
|
|
|
<view class="steam steam-three"></view> |
|
|
|
<!-- <view class="food-float float-one">🍜</view> |
|
|
|
<view class="food-float float-two">🥤</view> |
|
|
|
<view class="food-float float-three">🍢</view> |
|
|
|
<view class="food-float float-four">🥟</view> --> |
|
|
|
<view class="banner-copy"> |
|
|
|
<view class="banner-sticker">大家正在拼</view> |
|
|
|
<view class="banner-title">快来加入成团</view> |
|
|
|
<!-- <view class="banner-desc">楼下热乎的那口,凑个饭搭子就出发。</view> --> |
|
|
|
<view class="banner-bubbles"> |
|
|
|
<swiper class="banner-live-swiper" vertical circular autoplay :interval="2600" :duration="1500"> |
|
|
|
<swiper-item v-for="(item,index) in liveFeeds" :key="index"> |
|
|
|
<view class="banner-live-bubble"> |
|
|
|
<view class="live-avatar">{{item.avatar}}</view> |
|
|
|
<view class="live-copy"> |
|
|
|
<view class="live-main">{{item.name}} · {{item.dorm}}</view> |
|
|
|
<view class="live-sub">{{item.food}}</view> |
|
|
|
</view> |
|
|
|
<view class="banner-copy"> |
|
|
|
<view class="banner-sticker">大家正在拼</view> |
|
|
|
<view class="banner-title">快来加入成团</view> |
|
|
|
<!-- <view class="banner-desc">楼下热乎的那口,凑个饭搭子就出发。</view> --> |
|
|
|
<view class="banner-bubbles"> |
|
|
|
<swiper class="banner-live-swiper" vertical circular autoplay :interval="2600" :duration="1500"> |
|
|
|
<swiper-item v-for="(item,index) in liveFeeds" :key="index"> |
|
|
|
<view class="banner-live-bubble"> |
|
|
|
<view class="live-avatar">{{item.avatar}}</view> |
|
|
|
<view class="live-copy"> |
|
|
|
<view class="live-main">{{item.name}} · {{item.dorm}}</view> |
|
|
|
<view class="live-sub">{{item.food}}</view> |
|
|
|
</view> |
|
|
|
</swiper-item> |
|
|
|
</swiper> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="banner-food-card"> |
|
|
|
<img src="/static/images/img/loading.gif" alt="" /> |
|
|
|
<!-- <view class="food-card-tag">刚刚有人拼成功</view> --> |
|
|
|
</view> |
|
|
|
</swiper-item> |
|
|
|
</swiper> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="banner-food-card"> |
|
|
|
<img src="/static/images/img/loading.gif" alt="" /> |
|
|
|
<!-- <view class="food-card-tag">刚刚有人拼成功</view> --> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="title-fixed-holder"></view> |
|
|
|
<view class="interest-card" :class="{'interest-card-expanded': categoryExpanded}"> |
|
|
|
<view class="section-head"> |
|
|
|
<text>校园美食兴趣入口</text> |
|
|
|
@ -106,7 +106,7 @@ |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="shop-list"> |
|
|
|
<view class="shop-member" :class="{'shop-member-disabled': item.status != 1}" v-for="(item,index) in shopList" :key="index" @tap="goDetail('shop',item)"> |
|
|
|
<view class="shop-member" :class="{'shop-member-disabled': item.status != 1}" v-for="(item,index) in shopList" :key="item._renderKey" @tap="goDetail('shop',item)"> |
|
|
|
<view class="shop-disabled-mask" @tap.stop="buyingye" v-if="item.status != 1"> |
|
|
|
</view> |
|
|
|
<view class="shop-card-bg"></view> |
|
|
|
@ -162,7 +162,7 @@ |
|
|
|
</view> |
|
|
|
<view class="shop-bottom" v-if="item._visibleProducts && item._visibleProducts.length > 0"> |
|
|
|
<view class="menu-member" |
|
|
|
v-for="(item1,index1) in item._visibleProducts" :key="index1" @tap="goDetail('shop',item)"> |
|
|
|
v-for="(item1,index1) in item._visibleProducts" :key="item1._renderKey" @tap="goDetail('shop',item)"> |
|
|
|
<view class="menu-img"> |
|
|
|
<img :src="item1.productPicture" lazy-load alt=""> |
|
|
|
<view class="menu-img-gloss"></view> |
|
|
|
@ -171,12 +171,12 @@ |
|
|
|
<view class="shop-menu-name"> |
|
|
|
{{item1.productName}} |
|
|
|
</view> |
|
|
|
<view class="shop-menu-price"> |
|
|
|
¥{{item1.attributeListPrice | sliceMsg}} |
|
|
|
<view class="shop-menu-price" :class="{'shop-menu-price-solo': !item1._hasGroupBuyPrice}"> |
|
|
|
¥{{item1._displayPrice}} |
|
|
|
</view> |
|
|
|
<view class="shop-menu-purchase"> |
|
|
|
<view class="shop-menu-purchase" v-if="item1._hasGroupBuyPrice"> |
|
|
|
<text class="group-badge">拼</text> |
|
|
|
<text class="group-price">¥{{item1.productGroupBuyPrices | slicePrice}}</text> |
|
|
|
<text class="group-price">¥{{item1._displayGroupPrice}}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
@ -202,6 +202,10 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
const GROUP_META_CACHE_TTL = 5 * 60 * 1000 |
|
|
|
const GROUP_EAT_TYPE_CACHE_KEY = 'group_buy_eat_type_cache_v1' |
|
|
|
const GROUP_SHOP_AREA_CACHE_PREFIX = 'group_buy_shop_area_cache_v1_' |
|
|
|
|
|
|
|
export default { |
|
|
|
data() { |
|
|
|
return { |
|
|
|
@ -375,9 +379,6 @@ |
|
|
|
}, |
|
|
|
onLoad() { |
|
|
|
this.getShopList(); |
|
|
|
this.getEatType(); |
|
|
|
this.getShopArea(); |
|
|
|
this.getOnlineWorkerCountByCanteenArea(); |
|
|
|
}, |
|
|
|
onShow() { |
|
|
|
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect() |
|
|
|
@ -429,44 +430,80 @@ |
|
|
|
toggleCategory() { |
|
|
|
this.categoryExpanded = !this.categoryExpanded |
|
|
|
}, |
|
|
|
isFreshCache(cache) { |
|
|
|
return !!(cache && cache.time && Date.now() - cache.time < GROUP_META_CACHE_TTL) |
|
|
|
}, |
|
|
|
scheduleGroupMetaLoad() { |
|
|
|
clearTimeout(this._groupMetaTimer) |
|
|
|
this._groupMetaTimer = setTimeout(() => { |
|
|
|
this.getEatType() |
|
|
|
this.getShopArea() |
|
|
|
}, 300) |
|
|
|
}, |
|
|
|
getEatType() { |
|
|
|
const cache = uni.getStorageSync(GROUP_EAT_TYPE_CACHE_KEY) |
|
|
|
if (this.isFreshCache(cache)) { |
|
|
|
this.applyEatTypeList(cache.list || []) |
|
|
|
return |
|
|
|
} |
|
|
|
let that = this |
|
|
|
that.tui.request("/dictData/getByCondition", "GET", { |
|
|
|
sort: 'sortOrder', |
|
|
|
order: 'asc', |
|
|
|
dictId: '1712359407444168704' |
|
|
|
}, false, true).then((res) => { |
|
|
|
}, false, true, true).then((res) => { |
|
|
|
if (res.code == 200) { |
|
|
|
for (let i = 0; i < res.result.content.length; i++) { |
|
|
|
for (let m = 0; m < this.menuBtn.length; m++) { |
|
|
|
if (this.menuBtn[m].name == res.result.content[i].title) { |
|
|
|
this.menuBtn[m].value = res.result.content[i].value |
|
|
|
} |
|
|
|
} |
|
|
|
for (let m = 0; m < this.menuBtn1.length; m++) { |
|
|
|
if (this.menuBtn1[m].name == res.result.content[i].title) { |
|
|
|
this.menuBtn1[m].value = res.result.content[i].value |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
const list = res.result.content || [] |
|
|
|
this.applyEatTypeList(list) |
|
|
|
uni.setStorageSync(GROUP_EAT_TYPE_CACHE_KEY, { |
|
|
|
time: Date.now(), |
|
|
|
list |
|
|
|
}) |
|
|
|
} else { |
|
|
|
that.tui.toast(res.message) |
|
|
|
return |
|
|
|
} |
|
|
|
}).catch((res) => {}) |
|
|
|
}, |
|
|
|
applyEatTypeList(list) { |
|
|
|
for (let i = 0; i < list.length; i++) { |
|
|
|
for (let m = 0; m < this.menuBtn.length; m++) { |
|
|
|
if (this.menuBtn[m].name == list[i].title) { |
|
|
|
this.menuBtn[m].value = list[i].value |
|
|
|
} |
|
|
|
} |
|
|
|
for (let m = 0; m < this.menuBtn1.length; m++) { |
|
|
|
if (this.menuBtn1[m].name == list[i].title) { |
|
|
|
this.menuBtn1[m].value = list[i].value |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
getShopArea() { |
|
|
|
const regionId = JSON.parse(uni.getStorageSync('area')).id |
|
|
|
const cacheKey = GROUP_SHOP_AREA_CACHE_PREFIX + regionId |
|
|
|
const cache = uni.getStorageSync(cacheKey) |
|
|
|
if (this.isFreshCache(cache)) { |
|
|
|
this.shopArea = cache.list || [] |
|
|
|
return |
|
|
|
} |
|
|
|
let that = this |
|
|
|
that.tui.request("/app/shopArea/getByParentId/" + JSON.parse(uni.getStorageSync('area')).id, "GET", {}, |
|
|
|
false, true).then((res) => { |
|
|
|
that.tui.request("/app/shopArea/getByParentId/" + regionId, "GET", {}, |
|
|
|
false, true, true).then((res) => { |
|
|
|
if (res.code == 200) { |
|
|
|
const shopArea = [] |
|
|
|
if (res.result != null) { |
|
|
|
for (let m = 0; m < res.result.length; m++) { |
|
|
|
if (res.result[m].isCanteen == 1) { |
|
|
|
that.shopArea.push(res.result[m]) |
|
|
|
shopArea.push(res.result[m]) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
that.shopArea = shopArea |
|
|
|
uni.setStorageSync(cacheKey, { |
|
|
|
time: Date.now(), |
|
|
|
list: shopArea |
|
|
|
}) |
|
|
|
} else { |
|
|
|
that.tui.toast(res.message) |
|
|
|
return |
|
|
|
@ -477,7 +514,7 @@ |
|
|
|
let that = this |
|
|
|
that.tui.request("/worker/getOnlineWorkerByArea", "GET", { |
|
|
|
parentId: JSON.parse(uni.getStorageSync('area')).id |
|
|
|
}, false, true).then((res) => { |
|
|
|
}, false, true, true).then((res) => { |
|
|
|
if (res.code == 200) { |
|
|
|
const list = Array.isArray(res.result) ? res.result : [] |
|
|
|
that.onlineWorkerAreaList = list |
|
|
|
@ -517,6 +554,10 @@ |
|
|
|
that.totalPages = res.result.totalPages |
|
|
|
that.judgeBusinessStatus() |
|
|
|
that.isArea = false |
|
|
|
if (that.searchForm.pageNumber == 1) { |
|
|
|
that.scheduleGroupMetaLoad() |
|
|
|
that.scheduleOnlineWorkerCountLoad() |
|
|
|
} |
|
|
|
} else { |
|
|
|
that.tui.toast(res.message); |
|
|
|
return |
|
|
|
@ -524,10 +565,17 @@ |
|
|
|
uni.hideLoading() |
|
|
|
}).catch((res) => {}) |
|
|
|
}, |
|
|
|
scheduleOnlineWorkerCountLoad() { |
|
|
|
clearTimeout(this._onlineWorkerCountTimer) |
|
|
|
this._onlineWorkerCountTimer = setTimeout(() => { |
|
|
|
this.getOnlineWorkerCountByCanteenArea() |
|
|
|
}, 300) |
|
|
|
}, |
|
|
|
prepareShopList(list, offset) { |
|
|
|
return (list || []).map((item, i) => { |
|
|
|
const index = (offset || 0) + i |
|
|
|
const products = Array.isArray(item.products) ? item.products : [] |
|
|
|
item._renderKey = item.id || ('shop-' + index) |
|
|
|
const cookingTimeValue = item.shopTakeaway && item.shopTakeaway.cookingTime ? Number(item.shopTakeaway.cookingTime) : 0 |
|
|
|
const cookingTime = isNaN(cookingTimeValue) ? 0 : cookingTimeValue |
|
|
|
const selfDeliveryTime = Number(item.shopDeliveryDuration) |
|
|
|
@ -549,10 +597,48 @@ |
|
|
|
this.groupAvatars[(index + 1) % this.groupAvatars.length], |
|
|
|
this.groupAvatars[(index + 2) % this.groupAvatars.length] |
|
|
|
] |
|
|
|
item._visibleProducts = products.filter(product => product.isPush == 1 && product.delFlag == 1) |
|
|
|
item._visibleProducts = products.filter(product => product.isPush == 1 && product.delFlag == 1).map((product, productIndex) => { |
|
|
|
product._renderKey = product.id || product.productId || ('product-' + index + '-' + productIndex) |
|
|
|
product._displayPrice = this.getProductDisplayPrice(product.attributeListPrice) |
|
|
|
product._displayGroupPrice = this.getProductGroupDisplayPrice(product.productGroupBuyPrices) |
|
|
|
product._hasGroupBuyPrice = this.hasProductGroupBuyPrice(product) |
|
|
|
return product |
|
|
|
}) |
|
|
|
return item |
|
|
|
}) |
|
|
|
}, |
|
|
|
getProductDisplayPrice(value) { |
|
|
|
let price = '' |
|
|
|
if (typeof(value) == 'string') { |
|
|
|
try { |
|
|
|
const priceMap = JSON.parse(value) |
|
|
|
for (let key in priceMap) { |
|
|
|
price = priceMap[key].specPrice |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
price = '' |
|
|
|
} |
|
|
|
} |
|
|
|
return price |
|
|
|
}, |
|
|
|
hasProductGroupBuyPrice(product) { |
|
|
|
if (!product || product.isMoreBuy == 1) return false |
|
|
|
return this.getProductGroupDisplayPrice(product.productGroupBuyPrices) !== '' |
|
|
|
}, |
|
|
|
getProductGroupDisplayPrice(value) { |
|
|
|
let price = '' |
|
|
|
if (value != null && value.length > 0) { |
|
|
|
const firstPrice = parseFloat(value[0].groupPrice) |
|
|
|
price = isNaN(firstPrice) ? '' : firstPrice |
|
|
|
for (let i = 0; i < value.length; i++) { |
|
|
|
const groupPrice = parseFloat(value[i].groupPrice) |
|
|
|
if (!isNaN(groupPrice) && (price === '' || groupPrice < price)) { |
|
|
|
price = groupPrice |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return price |
|
|
|
}, |
|
|
|
formatSelfDeliveryTag(item) { |
|
|
|
const fee = parseFloat(item.orderBkge || 0) |
|
|
|
const feeText = fee > 0 ? `¥${fee.toFixed(1)}` : '免配送费' |
|
|
|
@ -716,7 +802,7 @@ |
|
|
|
} |
|
|
|
|
|
|
|
.title-fixed-holder { |
|
|
|
height: 466rpx; |
|
|
|
height: 210rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.title-fixed::before { |
|
|
|
@ -869,11 +955,16 @@ |
|
|
|
|
|
|
|
.banner-title { |
|
|
|
margin-top: 18rpx; |
|
|
|
font-size: 48rpx; |
|
|
|
line-height: 56rpx; |
|
|
|
display: inline-block; |
|
|
|
font-size: 50rpx; |
|
|
|
line-height: 60rpx; |
|
|
|
font-weight: 900; |
|
|
|
color: #083f34; |
|
|
|
letter-spacing: 1rpx; |
|
|
|
color: #075240; |
|
|
|
letter-spacing: 2rpx; |
|
|
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif; |
|
|
|
text-shadow: |
|
|
|
0 4rpx 0 rgba(255, 255, 255, 0.76), |
|
|
|
0 10rpx 18rpx rgba(5, 120, 91, 0.2); |
|
|
|
} |
|
|
|
|
|
|
|
.banner-desc { |
|
|
|
@ -1591,6 +1682,13 @@ |
|
|
|
text-decoration: line-through; |
|
|
|
} |
|
|
|
|
|
|
|
.shop-menu-price-solo { |
|
|
|
color: #ff1f1f; |
|
|
|
font-size: 24rpx; |
|
|
|
font-weight: 900; |
|
|
|
text-decoration: none; |
|
|
|
} |
|
|
|
|
|
|
|
.shop-menu-purchase { |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
|