wangfukang 3 weeks ago
parent
commit
cdd4f96d18
  1. 360
      package2/group/groupBuySingle.vue
  2. 2
      package2/group/studentStoreList.vue

360
package2/group/groupBuySingle.vue

@ -126,7 +126,7 @@
<view class="weipincheng">+</view>
</view>
<view class="pintuan-right-cha">
差<text class="missing-count">{{item.targetMembers - item.currentMembers}}人</text>拼成
差<text class="missing-count">{{getMissingGroupMembers(item)}}人</text>成团
</view>
</view>
</view>
@ -164,7 +164,7 @@
</view>
<view class="goods-vibe" v-if="isProductGroupBuyAvailable(item)">
<text class="goods-vibe-tag">拼团价更香</text>
<text class="goods-vibe-copy">约人一起下单</text>
<text class="goods-vibe-copy">店内商品任选拼单</text>
</view>
<view class="goods-content-center">
<view class="goods-deal1">
@ -187,7 +187,7 @@
<view class="weipincheng">+</view>
</view>
<view class="pintuan-right-cha" @tap.stop="openOrderWait(item)">
差<text style="color: red;">{{item.minGroupCount}}人</text>拼成
差<text style="color: red;">{{getMissingGroupMembers(item)}}人</text>成团
</view>
</view>
</view>
@ -424,11 +424,19 @@
<view class="spec11">
选{{spec.name}}(可选{{spec.canbuy}}个)
</view>
<view class="spec22">
<view :class="spec.selected.indexOf(option) !== -1 ? 'spec-check' : 'spec222'"
v-for="(option, oIndex) in spec.options" :key="oIndex"
@tap="selectSpec(sIndex, option)">
{{option}}
<view class="spec-option-row">
<view class="spec22" :class="{'spec22-expanded': isSpecExpanded(sIndex)}">
<view :class="spec.selected.indexOf(option) !== -1 ? 'spec-check' : 'spec222'"
v-for="(option, oIndex) in spec.options" :key="oIndex"
@tap="selectSpec(sIndex, option)">
{{option}}
</view>
</view>
<view class="spec-expand-btn" v-if="shouldShowSpecExpand(spec)"
@tap.stop="toggleSpecExpand(sIndex)">
<text>{{isSpecExpanded(sIndex) ? '收起' : '展开'}}</text>
<uni-icons :type="isSpecExpanded(sIndex) ? 'top' : 'bottom'" size="12"
color="#20cda8"></uni-icons>
</view>
</view>
</view>
@ -547,7 +555,7 @@
</view>
<view style="line-height: 40rpx;padding-left: 10rpx;">
差<text
class="missing-count">{{item.targetMembers - item.currentMembers}}人</text>拼成
class="missing-count">{{getMissingGroupMembers(item)}}人</text>成团
</view>
</view>
</view>
@ -820,6 +828,18 @@
<view class="share-save-btn" @tap="saveSharePoster">保存图片</view>
</view>
</uni-popup>
<uni-popup ref="shopUnavailablePopup" background-color="transparent" :mask-click="false">
<view class="shop-unavailable-popup" @tap.stop>
<view class="shop-unavailable-glow"></view>
<view class="shop-unavailable-badge">饭团提醒</view>
<view class="shop-unavailable-title">{{shopUnavailableDialog.title}}</view>
<view class="shop-unavailable-text">{{shopUnavailableDialog.message}}</view>
<view class="shop-unavailable-hours" v-if="shopUnavailableDialog.hours">
营业时间 {{shopUnavailableDialog.hours}}
</view>
<view class="shop-unavailable-btn" @tap="confirmShopUnavailable">返回首页</view>
</view>
</uni-popup>
<common-loading />
<canvas canvas-id="shopShareCanvas" id="shopShareCanvas" class="share-canvas"
:style="{width: posterCanvasWidth + 'px', height: posterCanvasHeight + 'px'}"></canvas>
@ -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;

2
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

Loading…
Cancel
Save