diff --git a/package2/group/groupBuySingle.vue b/package2/group/groupBuySingle.vue index 4ea3319..4511aa2 100644 --- a/package2/group/groupBuySingle.vue +++ b/package2/group/groupBuySingle.vue @@ -126,7 +126,7 @@ + - 差{{item.targetMembers - item.currentMembers}}人拼成 + 差{{getMissingGroupMembers(item)}}人成团 @@ -164,7 +164,7 @@ 拼团价更香 - 约人一起下单 + 店内商品任选拼单 @@ -187,7 +187,7 @@ + - 差{{item.minGroupCount}}人拼成 + 差{{getMissingGroupMembers(item)}}人成团 @@ -424,11 +424,19 @@ 选{{spec.name}}(可选{{spec.canbuy}}个) - - - {{option}} + + + + {{option}} + + + + {{isSpecExpanded(sIndex) ? '收起' : '展开'}} + @@ -547,7 +555,7 @@ 差{{item.targetMembers - item.currentMembers}}人拼成 + class="missing-count">{{getMissingGroupMembers(item)}}人成团 @@ -820,6 +828,18 @@ 保存图片 + + + + 饭团提醒 + {{shopUnavailableDialog.title}} + {{shopUnavailableDialog.message}} + + 营业时间 {{shopUnavailableDialog.hours}} + + 返回首页 + + @@ -885,6 +905,7 @@ detailItem: {}, checkMoreBuyIndex: '', parsedSpecs: [], + specExpandedMap: [], moreBuyList: [], selectedGroupRule: {}, pageNum: 1, @@ -942,7 +963,12 @@ sharePosterImage: '', shareQrcodeUrl: '', posterCanvasWidth: 320, - posterCanvasHeight: 450 + posterCanvasHeight: 450, + shopUnavailableDialog: { + title: '', + message: '', + hours: '' + } } }, components: { @@ -964,12 +990,12 @@ shopSubtitle() { if (this.isStoreGroupOrder) { return this.isSocialArea - ? '到店核销,约上好友一起拼更划算' - : '到店核销,约上同学一起拼更划算' + ? '到店核销,任选商品即可参团' + : '到店核销,任选商品即可参团' } return this.isSocialArea - ? '约上好友一起拼,越快成团越快开吃' - : '约上室友同学一起拼,越快成团越快开吃' + ? '约上好友一起拼,任选商品即可参团' + : '约上室友同学一起拼,任选商品即可参团' }, shopNameSizeClass() { const nameLength = String(this.shopItem.shopName || '').length; @@ -1090,13 +1116,6 @@ if (this.type == 'shop') { if (parsedItem) { this.shopItem = parsedItem; - if (this.shopItem.products) { - this.shopRecommend = this.shopItem.products - for (let i = 0; i < this.shopRecommend.length; i++) { - this.shopRecommend[i].categoryId = '1' - this.shopRecommend[i].isChecked = false - } - } } } else { if (parsedItem) { @@ -1105,8 +1124,7 @@ } if (this.shopItem && this.shopItem.id) { if (!this.ensureShopInCurrentRegion(this.shopItem)) return; - this.getCategory(this.shopItem.id); - this.getProduct(''); + this.loadShopById(this.shopItem.id, this.shopItem); } else if (option.shopId) { this.loadShopById(option.shopId); } else if (this.groupId) { @@ -1280,6 +1298,85 @@ } } }, + prepareShopRecommend() { + this.shopRecommend = Array.isArray(this.shopItem.products) ? this.shopItem.products : []; + for (let i = 0; i < this.shopRecommend.length; i++) { + this.shopRecommend[i].categoryId = '1'; + this.shopRecommend[i].isChecked = false; + } + }, + resetShopContent() { + this.menuList = [{ + categoryName: '推荐', + id: 'tuijian', + checked: true + }]; + this.productItem = []; + this.moreBuyList = []; + }, + loadShopContent() { + this.resetShopContent(); + this.prepareShopRecommend(); + this.getCategory(this.shopItem.id); + this.getProduct(''); + }, + getShopStatus(item) { + const status = Number(item && item.status); + return isNaN(status) ? 1 : status; + }, + getTakeawayStatus(item) { + const status = Number(item && item.shopTakeaway && item.shopTakeaway.status); + return isNaN(status) ? 0 : status; + }, + isShopPaused(item) { + return this.getShopStatus(item) != 1 || this.getTakeawayStatus(item) != 0; + }, + isShopUnavailable(item) { + return this.isShopPaused(item) || !this.isShopWithinBusinessHours(item && item.shopTakeaway); + }, + getBusinessHoursText(item) { + const takeaway = item && item.shopTakeaway; + if (!takeaway) return ''; + const periods = this.parseBusinessHourPeriods(takeaway); + if (!periods.length) return ''; + return periods.map(p => p.begin + '-' + p.end).join('、'); + }, + getShopUnavailableInfo(item) { + const hours = this.getBusinessHoursText(item); + if (this.isShopPaused(item)) { + return { + title: '店铺暂停营业', + message: '商家当前已暂停接单,先去首页看看其他饭团吧。', + hours + }; + } + return { + title: '现在休息中', + message: hours ? '商家还没到营业时间,稍后再来拼团吧。' : '商家暂未配置可营业时段,先去首页看看其他饭团吧。', + hours + }; + }, + guardShopAvailability(shopItem) { + if (!this.isShopUnavailable(shopItem)) return true; + const info = this.getShopUnavailableInfo(shopItem); + this.shopUnavailableDialog = info; + this.clearShareRedirectCache(); + this.$nextTick(() => { + if (this.$refs.shopUnavailablePopup) { + this.$refs.shopUnavailablePopup.open(); + } else { + this.tui.toast(info.title); + this.backHome(); + } + }); + return false; + }, + confirmShopUnavailable() { + if (this.$refs.shopUnavailablePopup) { + this.$refs.shopUnavailablePopup.close(); + } + this.backHome(); + }, loadShopByGroupId() { if (!this.groupId) return; this.tui.request("/mall/order/selectMallOrderByGroupId/" + this.groupId, "GET", {}, false, true).then((res) => { @@ -1329,7 +1426,7 @@ groupDeliveryTimeIncludesTransfer: transferTime > 0 ? 1 : 0 }; }, - loadShopById(shopId) { + loadShopById(shopId, fallbackShop) { if (!shopId) return; let area = uni.getStorageSync('area'); let regionId = ''; @@ -1346,19 +1443,21 @@ }, false, true).then((shopRes) => { if (shopRes.code != 200 || !shopRes.result || !shopRes.result.shop) { this.tui.toast(shopRes.message || '商家信息获取失败'); + if (fallbackShop && this.guardShopAvailability(fallbackShop)) { + this.shopItem = fallbackShop; + this.loadShopContent(); + } return; } this.shopItem = this.normalizeShopDeliveryFields(shopRes.result); if (!this.ensureShopInCurrentRegion(this.shopItem)) return; - if (this.shopItem.products) { - this.shopRecommend = this.shopItem.products; - for (let i = 0; i < this.shopRecommend.length; i++) { - this.shopRecommend[i].categoryId = '1'; - this.shopRecommend[i].isChecked = false; - } + if (!this.guardShopAvailability(this.shopItem)) return; + this.loadShopContent(); + }).catch(() => { + if (fallbackShop && this.guardShopAvailability(fallbackShop)) { + this.shopItem = fallbackShop; + this.loadShopContent(); } - this.getCategory(this.shopItem.id); - this.getProduct(''); }); }, onBottomPopupChange(e) { @@ -1698,6 +1797,7 @@ } } catch (e) {} } + this.resetSpecExpandedMap(); this.isPintuan = true; if (this.groupId) { @@ -1843,6 +1943,7 @@ } } catch (e) {} } + this.resetSpecExpandedMap(); if (index == 'pintuan') { this.isPintuan = true; @@ -1928,6 +2029,18 @@ } } }, + resetSpecExpandedMap() { + this.specExpandedMap = this.parsedSpecs.map(() => false); + }, + shouldShowSpecExpand(spec) { + return spec && Array.isArray(spec.options) && spec.options.length > 4; + }, + isSpecExpanded(sIndex) { + return !!this.specExpandedMap[sIndex]; + }, + toggleSpecExpand(sIndex) { + this.$set(this.specExpandedMap, sIndex, !this.isSpecExpanded(sIndex)); + }, selectSpec(sIndex, option) { let spec = this.parsedSpecs[sIndex]; let idx = spec.selected.indexOf(option); @@ -2173,23 +2286,59 @@ }); } }, - //判断是否在营业时间内 - isWithinBusinessHours(begin, end) { - // 获取当前时间的时和分 + // 判断是否在营业时间内(支持多时段、跨夜) + isShopWithinBusinessHours(takeaway) { + if (!takeaway) return false; + const periods = this.parseBusinessHourPeriods(takeaway); + if (!periods.length) return false; const now = new Date(); const currentMinutes = now.getHours() * 60 + now.getMinutes(); - - // 解析开始和结束时间(格式 "HH:MM") + for (let i = 0; i < periods.length; i++) { + if (this.isWithinBusinessHours(periods[i].begin, periods[i].end, currentMinutes)) { + return true; + } + } + return false; + }, + parseBusinessHourPeriods(takeaway) { + let list = takeaway.businessHourList; + if ((!list || !list.length) && takeaway.businessHours) { + try { + list = typeof takeaway.businessHours === 'string' ? JSON.parse(takeaway.businessHours) : takeaway.businessHours; + } catch (e) { + list = []; + } + } + if (list && list.length) { + return list.filter(item => item && item.begin && item.end).map(item => ({ + begin: String(item.begin).substring(0, 5), + end: String(item.end).substring(0, 5) + })); + } + if (takeaway.businessHourBegin && takeaway.businessHourEnd) { + return [{ + begin: String(takeaway.businessHourBegin).substring(0, 5), + end: String(takeaway.businessHourEnd).substring(0, 5) + }]; + } + return []; + }, + isWithinBusinessHours(begin, end, currentMinutes) { + const nowMinutes = currentMinutes != null ? currentMinutes : (() => { + const now = new Date(); + return now.getHours() * 60 + now.getMinutes(); + })(); const parseTime = (timeStr) => { - const [hours, minutes] = timeStr.split(':').map(Number); - return hours * 60 + minutes; + const parts = String(timeStr || '00:00').split(':').map(Number); + return (parts[0] || 0) * 60 + (parts[1] || 0); }; - const startMinutes = parseTime(begin); const endMinutes = parseTime(end); - - // 判断是否在区间内(包含端点) - return currentMinutes >= startMinutes && currentMinutes <= endMinutes; + if (startMinutes === endMinutes) return true; + if (startMinutes < endMinutes) { + return nowMinutes >= startMinutes && nowMinutes <= endMinutes; + } + return nowMinutes >= startMinutes || nowMinutes <= endMinutes; }, adjustCart(cartId, delta) { let index = this.cartItems.findIndex(c => c.cartId === cartId); @@ -2329,6 +2478,17 @@ return !!(item && Array.isArray(item.productGroupBuyPrices) && item.productGroupBuyPrices.length > 0 && item.isMoreBuy != 1); }, + getMissingGroupMembers(item) { + if (!item) return 1; + if (item.minGroupCount !== undefined && item.minGroupCount !== null && item.minGroupCount !== '') { + const minGroupCount = Number(item.minGroupCount); + return Math.max(isNaN(minGroupCount) ? 1 : minGroupCount, 1); + } + const target = Number(item.targetMembers || 0); + const current = Number(item.currentMembers || 0); + const missing = target - current; + return Math.max(isNaN(missing) ? 1 : missing, 1); + }, buyingye() { uni.showToast({ title: '商品不在售卖时间!', @@ -2825,6 +2985,90 @@ position: relative; } + .shop-unavailable-popup { + width: 610rpx; + padding: 46rpx 38rpx 36rpx; + box-sizing: border-box; + border-radius: 42rpx; + background: + radial-gradient(circle at 12% 0%, rgba(223, 255, 150, 0.72), transparent 36%), + radial-gradient(circle at 92% 16%, rgba(166, 255, 234, 0.66), transparent 40%), + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(249, 255, 242, 0.98)); + box-shadow: 0 26rpx 70rpx rgba(6, 77, 58, 0.22); + border: 2rpx solid rgba(255, 255, 255, 0.9); + position: relative; + overflow: hidden; + text-align: center; + } + + .shop-unavailable-glow { + position: absolute; + right: -110rpx; + top: -120rpx; + width: 300rpx; + height: 300rpx; + border-radius: 50%; + background: rgba(255, 202, 116, 0.22); + } + + .shop-unavailable-badge { + position: relative; + display: inline-block; + height: 44rpx; + line-height: 44rpx; + padding: 0 20rpx; + border-radius: 44rpx 44rpx 44rpx 12rpx; + background: linear-gradient(90deg, #e3ff96, #a6ffea); + color: #08735d; + font-size: 22rpx; + font-weight: 900; + box-shadow: 0 10rpx 20rpx rgba(20, 115, 88, 0.12); + } + + .shop-unavailable-title { + position: relative; + margin-top: 24rpx; + font-size: 40rpx; + line-height: 52rpx; + font-weight: 900; + color: #073d33; + } + + .shop-unavailable-text { + position: relative; + margin-top: 16rpx; + font-size: 26rpx; + line-height: 40rpx; + color: rgba(0, 35, 28, 0.66); + font-weight: 700; + } + + .shop-unavailable-hours { + position: relative; + margin-top: 22rpx; + padding: 14rpx 20rpx; + border-radius: 24rpx; + background: rgba(255, 247, 225, 0.82); + color: #ff6f2c; + font-size: 23rpx; + line-height: 34rpx; + font-weight: 900; + word-break: break-all; + } + + .shop-unavailable-btn { + position: relative; + margin-top: 34rpx; + height: 78rpx; + line-height: 78rpx; + border-radius: 78rpx; + background: linear-gradient(90deg, #e3ff96, #a6ffea); + color: #073d33; + font-size: 30rpx; + font-weight: 900; + box-shadow: 0 16rpx 30rpx rgba(13, 114, 82, 0.18); + } + /* 顶部背景图随页面滚动(不固定) */ .title { background: url('https://jewel-shop.oss-cn-beijing.aliyuncs.com/8bc15960c2dc40268e295d6dd23aecce.png') no-repeat; @@ -3625,14 +3869,43 @@ font-weight: 700; } + .spec-option-row { + display: flex; + align-items: flex-start; + } + .spec22 { display: flex; + flex: 1; + min-width: 0; white-space: nowrap; overflow-x: scroll; } + .spec22-expanded { + flex-wrap: wrap; + white-space: normal; + overflow-x: visible; + row-gap: 20rpx; + } + + .spec-expand-btn { + flex: 0 0 112rpx; + height: 72rpx; + margin-left: 12rpx; + border-radius: 20rpx; + background: rgba(166, 255, 234, 0.35); + color: #20cda8; + display: flex; + align-items: center; + justify-content: center; + font-size: 24rpx; + font-weight: 700; + } + .spec222 { display: inline-block; + flex-shrink: 0; padding: 0 20rpx; background: rgba(247, 248, 248, 0.6); color: #777; @@ -3645,6 +3918,7 @@ .spec-check { display: inline-block; + flex-shrink: 0; padding: 0 20rpx; background: rgba(166, 255, 234, 1); height: 72rpx; diff --git a/package2/group/studentStoreList.vue b/package2/group/studentStoreList.vue index c034673..1cee421 100644 --- a/package2/group/studentStoreList.vue +++ b/package2/group/studentStoreList.vue @@ -679,7 +679,7 @@ }, getPreviewProducts(item) { const products = Array.isArray(item.products) ? item.products : [] - return products.filter(product => product.delFlag == 1).slice(0, 3) + return products.filter(product => product.isPush == 1 && product.delFlag == 1) }, getGroupPrice(product) { const prices = product.productGroupBuyPrices