1136 lines
29 KiB
Vue
1136 lines
29 KiB
Vue
<template>
|
||
<view class="group_detail_page">
|
||
<!-- 顶部紫色渐变背景与自定义导航栏 -->
|
||
<view class="top_nav_container" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="nav_bar">
|
||
<!-- 返回按钮 -->
|
||
<view class="nav_back_btn" @click="handleBack">
|
||
<up-image src="/static/common/left.png" width="16" height="16" bgColor="transparent" />
|
||
</view>
|
||
|
||
<!-- 导航标题与成功状态标识 -->
|
||
<view class="nav_title_wrap">
|
||
<view class="nav_status_icon" v-if="isSuccess || (isOngoing && isJoined)">
|
||
<up-image src="/pages/mine_package/static/order_status_2.png" width="38rpx" height="38rpx"
|
||
bgColor="transparent"></up-image>
|
||
</view>
|
||
<text class="nav_title_text">{{ navTitle }}</text>
|
||
</view>
|
||
|
||
<!-- 占位,保持标题居中 -->
|
||
<view class="nav_right_placeholder"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 页面内容主体 (带有负边距向上融入紫色背景) -->
|
||
<view class="page_body" v-if="teamDetail">
|
||
<!-- 1. 商品卡片 -->
|
||
<view class="product_card" @click="jumpProductDetail">
|
||
<!-- 商品图片 -->
|
||
<view class="product_img_wrap">
|
||
<image class="product_img" :src="teamDetail.mainGraph" mode="aspectFill" />
|
||
</view>
|
||
|
||
<!-- 商品右侧信息 -->
|
||
<view class="product_info_wrap">
|
||
<view class="product_name">{{ teamDetail.goodsName }}</view>
|
||
<view class="group_size_badge" v-if="teamDetail.requiredNum">
|
||
<text>{{ teamDetail.requiredNum }}人成团</text>
|
||
</view>
|
||
<view class="product_price_row">
|
||
<view class="group_price_box">
|
||
<text class="group_price_label">拼团价</text>
|
||
<text class="group_price_symbol">¥</text>
|
||
<text class="group_price_val">{{ teamDetail.groupPrice }}</text>
|
||
</view>
|
||
<view class="original_price_box" v-if="teamDetail.salePrice">
|
||
<text class="original_price">¥{{ teamDetail.salePrice }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 2. 拼团状态与操作卡片 -->
|
||
<view class="status_card">
|
||
<!-- 状态A:拼团中 (还差X人成团 + 倒计时) -->
|
||
<template v-if="isOngoing">
|
||
<view class="status_header_row">
|
||
<text class="status_title_text">还差 </text>
|
||
<text class="status_num_highlight">{{ teamDetail.remainingNum != null ? teamDetail.remainingNum
|
||
: 1 }}</text>
|
||
<text class="status_title_text"> 人成团</text>
|
||
</view>
|
||
<view class="countdown_row">
|
||
<text class="countdown_text">拼团剩余时间 {{ countdownText }}</text>
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 状态B:拼团成功 -->
|
||
<template v-else-if="isSuccess">
|
||
<view class="success_header_row">
|
||
<text class="success_title_text">已成功拼团</text>
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 状态C:拼团失败/超时/取消 -->
|
||
<template v-else>
|
||
<view class="success_header_row">
|
||
<text class="failed_title_text">{{ failedDescText }}</text>
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 成员头像坑位列表 (根据 requiredNum 控制坑位总数) -->
|
||
<view class="avatars_slot_row" :class="{ 'slots_compact': (teamDetail.requiredNum || 2) > 4 }">
|
||
<!-- 团长坑位 (第一位) -->
|
||
<view class="avatar_slot_item">
|
||
<image class="member_avatar leader_avatar" :src="leaderMember.avatar || defaultAvatar"
|
||
mode="aspectFill" />
|
||
<view class="leader_badge">
|
||
<text class="leader_badge_text">团长</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 其余坑位 (共 requiredNum - 1 个) -->
|
||
<view class="avatar_slot_item" v-for="(slot, sIdx) in otherSlots" :key="sIdx">
|
||
<!-- 已参团成员 -->
|
||
<image v-if="slot.joined" class="member_avatar" :src="slot.avatar || defaultAvatar"
|
||
mode="aspectFill" />
|
||
<!-- 空坑位 (待邀请),紫色浅底加号 -->
|
||
<view v-else class="empty_slot" @click="handleSlotClick">
|
||
<text class="plus_icon">+</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮区域 (不同角色在不同状态下显示不同按钮) -->
|
||
<view class="action_buttons_wrap" v-if="hasActionButtons">
|
||
<!-- 场景 1:拼团中且当前用户已参团 (邀请好友参团 + 没人拼单?单独购买) -->
|
||
<template v-if="isOngoing && isJoined">
|
||
<!-- #ifdef MP-WEIXIN -->
|
||
<button class="btn_primary btn_reset" @tap="handleInviteShare" hover-class="none">
|
||
邀请好友参团
|
||
</button>
|
||
<!-- #endif -->
|
||
<!-- #ifndef MP-WEIXIN -->
|
||
<view class="btn_primary" @click="handleInviteShare">
|
||
邀请好友参团
|
||
</view>
|
||
<!-- #endif -->
|
||
|
||
<view class="btn_secondary" @click="handleBuyAlone">
|
||
单独购买
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 场景 2:拼团中且当前用户未参团 (单按钮:参加这个团) -->
|
||
<template v-else-if="isOngoing && !isJoined">
|
||
<view class="btn_primary" @click="handleJoinGroup">
|
||
参加这个团
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 场景 3:已参团,处于拼团成功或拼团失败状态 (单按钮:查看订单) -->
|
||
<template v-else-if="isJoined && (isSuccess || isFailed)">
|
||
<view class="btn_primary" @click="handleViewOrder">
|
||
查看订单
|
||
</view>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 3. 拼团玩法说明卡片 -->
|
||
<view class="rules_card">
|
||
<view class="rules_card_title">拼团玩法</view>
|
||
|
||
<!-- 3 步骤流程 -->
|
||
<view class="rules_steps_row">
|
||
<view class="step_item">
|
||
<image class="step_icon" src="https://static.tbmall.xin/static/new/group_buying_1.png"
|
||
mode="aspectFit" />
|
||
<text class="step_label">开团/参加</text>
|
||
</view>
|
||
<view class="step_item">
|
||
<image class="step_icon" src="https://static.tbmall.xin/static/new/group_buying_2.png"
|
||
mode="aspectFit" />
|
||
<text class="step_label">邀请好友参团</text>
|
||
</view>
|
||
<view class="step_item">
|
||
<image class="step_icon" src="https://static.tbmall.xin/static/new/group_buying_3.png"
|
||
mode="aspectFit" />
|
||
<text class="step_label">成团发货</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 购买须知说明 -->
|
||
<view class="rules_notice">
|
||
购买须知:付款后等待成团,成团后 1-3 天发货。未成团且不支持自动成团时全额退款。
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 分享海报弹窗 -->
|
||
<SharePopup ref="share" v-if="shareOpen" :show="shareShow" @close="onShareClose" @wxShare="onWxShare"
|
||
@share="onShare" :isGroupBuy="true" :id="String(teamDetail?.goodsId || goodsId)"
|
||
:text="teamDetail?.goodsName ? teamDetail.goodsName : ''"
|
||
:tu="teamDetail?.mainGraph ? teamDetail.mainGraph : ''"
|
||
:price="teamDetail?.groupPrice ? String(teamDetail.groupPrice) : ''"
|
||
:groupPrice="teamDetail?.groupPrice ? String(teamDetail.groupPrice) : ''"
|
||
:requiredNum="teamDetail?.requiredNum || 2" :inviterName="inviterName" :inviterAvatar="inviterAvatar"
|
||
:sharePath="groupSharePath"></SharePopup>
|
||
|
||
<!-- 单独购买确认弹窗 -->
|
||
<up-modal :show="buyAloneModalShow" title="提示" content="单独购买将创建一笔新的普通订单,原拼团订单仍然保留。需要退出原团时,请在订单详情申请退款。"
|
||
:showCancelButton="true" cancelText="继续等团" cancelColor="#333333" confirmText="创建单买订单" confirmColor="#7F3BF5"
|
||
:closeOnClickOverlay="true" :borderRadius="16" @confirm="confirmBuyAlone" @cancel="cancelBuyAlone"
|
||
@close="cancelBuyAlone"></up-modal>
|
||
|
||
<qiaobao-assistant page-key="pages/active/group-detail/group-detail" title="拼团详情与邀请" />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { getTeamDetail } from "@/api/product.js";
|
||
import SharePopup from "@/pages/active/components/share-popup.vue";
|
||
import { SHARE_URL, MINI_PROGRAM_TYPE } from "@/utils/config.js";
|
||
import { getStorageFun, USER_DATA } from "@/utils/auth.js";
|
||
|
||
export default {
|
||
name: "group-detail",
|
||
components: {
|
||
SharePopup,
|
||
},
|
||
data() {
|
||
return {
|
||
statusBarHeight: 20,
|
||
teamId: "",
|
||
orderId: "",
|
||
goodsId: "",
|
||
teamDetail: null,
|
||
remainingSeconds: 0,
|
||
countdownText: "00:00:00",
|
||
countdownTimer: null,
|
||
defaultAvatar: "https://static.tbmall.xin/static/mine-purse/vcoin_1.png",
|
||
shareShow: false,
|
||
shareOpen: false,
|
||
buyAloneModalShow: false,
|
||
};
|
||
},
|
||
computed: {
|
||
// 是否拼团中
|
||
isOngoing() {
|
||
if (!this.teamDetail) return true;
|
||
return this.teamDetail.status === 0 || this.teamDetail.statusCode === "ONGOING";
|
||
},
|
||
// 是否拼团成功
|
||
isSuccess() {
|
||
if (!this.teamDetail) return false;
|
||
return this.teamDetail.status === 1 || this.teamDetail.statusCode === "SUCCESS";
|
||
},
|
||
// 是否拼团失败
|
||
isFailed() {
|
||
if (!this.teamDetail) return false;
|
||
return this.teamDetail.status === 2 || this.teamDetail.statusCode === "CANCELLED" || this.teamDetail.statusCode === "TIMEOUT";
|
||
},
|
||
// 当前用户是否已参团
|
||
isJoined() {
|
||
return Boolean(this.teamDetail?.joined);
|
||
},
|
||
// 是否有操作按钮需要显示 (未参团且处于成功/失败状态时不显示任何按钮)
|
||
hasActionButtons() {
|
||
if (this.isOngoing) return true;
|
||
if (this.isJoined && (this.isSuccess || this.isFailed)) return true;
|
||
return false;
|
||
},
|
||
// 导航栏标题
|
||
navTitle() {
|
||
if (this.isSuccess) {
|
||
return "拼团成功!";
|
||
}
|
||
if (this.isFailed) {
|
||
return "拼团失败!";
|
||
}
|
||
return "邀请好友参与拼团";
|
||
},
|
||
// 拼团失败状态下的文字说明
|
||
failedDescText() {
|
||
if (!this.teamDetail) return "拼团已结束";
|
||
const code = this.teamDetail.statusCode;
|
||
const text = this.teamDetail.statusText || "";
|
||
if (code === "CANCELLED" || text.includes("取消")) {
|
||
return this.isJoined ? "拼单已取消,款项将原路退回" : "拼单已取消";
|
||
}
|
||
if (code === "TIMEOUT" || text.includes("超时") || this.teamDetail.status === 2) {
|
||
return "未在规定时间内集齐人数";
|
||
}
|
||
return this.teamDetail.statusText || "拼团已结束";
|
||
},
|
||
// 团长成员信息
|
||
leaderMember() {
|
||
const members = this.teamDetail?.members || [];
|
||
return members.find((m) => m.leader) || members[0] || {};
|
||
},
|
||
// 其余坑位列表 (长度为 requiredNum - 1)
|
||
otherSlots() {
|
||
const requiredNum = Number(this.teamDetail?.requiredNum || 2);
|
||
const totalOther = Math.max(0, requiredNum - 1);
|
||
const members = this.teamDetail?.members || [];
|
||
const otherMembers = members.filter((m) => !m.leader);
|
||
|
||
const slots = [];
|
||
for (let i = 0; i < totalOther; i++) {
|
||
if (i < otherMembers.length) {
|
||
slots.push({
|
||
joined: true,
|
||
avatar: otherMembers[i].avatar,
|
||
nickname: otherMembers[i].nickname || `团员${i + 1}`,
|
||
});
|
||
} else {
|
||
slots.push({
|
||
joined: false,
|
||
});
|
||
}
|
||
}
|
||
return slots;
|
||
},
|
||
groupSharePath() {
|
||
const targetGoodsId = this.teamDetail?.goodsId || this.goodsId;
|
||
let path = `pages/other_package/productInfo/productInfo?id=${targetGoodsId}&activedType=groupBuy&activityId=1`;
|
||
if (this.teamId || this.teamDetail?.id) {
|
||
path += `&teamId=${this.teamId || this.teamDetail?.id}`;
|
||
}
|
||
return path;
|
||
},
|
||
inviterName() {
|
||
const userData = getStorageFun(USER_DATA) || {};
|
||
return (
|
||
this.teamDetail?.inviterName ||
|
||
this.leaderMember?.nickname ||
|
||
this.teamDetail?.leaderName ||
|
||
userData?.name ||
|
||
userData?.nickName ||
|
||
"Haonan Mu"
|
||
);
|
||
},
|
||
inviterAvatar() {
|
||
const userData = getStorageFun(USER_DATA) || {};
|
||
return (
|
||
this.teamDetail?.inviterAvatar ||
|
||
this.leaderMember?.avatar ||
|
||
this.teamDetail?.leaderAvatar ||
|
||
userData?.avatar ||
|
||
userData?.avatarUrl ||
|
||
"https://static.tbmall.xin/static/new/default_avatar.png"
|
||
);
|
||
},
|
||
},
|
||
onLoad(options) {
|
||
try {
|
||
const sys = uni.getSystemInfoSync();
|
||
if (sys && sys.statusBarHeight) {
|
||
this.statusBarHeight = sys.statusBarHeight;
|
||
}
|
||
} catch (e) {
|
||
console.error("获取系统信息失败:", e);
|
||
}
|
||
|
||
// #ifdef MP-WEIXIN
|
||
uni.showShareMenu({
|
||
withShareTicket: true,
|
||
menus: ["shareAppMessage", "shareTimeline"],
|
||
});
|
||
if (options && options.q) {
|
||
try {
|
||
const qrUrl = decodeURIComponent(options.q);
|
||
const queryIndex = qrUrl.indexOf("?");
|
||
if (queryIndex !== -1) {
|
||
const queryString = qrUrl.slice(queryIndex + 1);
|
||
const pairs = queryString.split("&");
|
||
pairs.forEach((pair) => {
|
||
if (!pair) return;
|
||
const [k, v] = pair.split("=");
|
||
if (k) {
|
||
options[decodeURIComponent(k)] = v ? decodeURIComponent(v) : "";
|
||
}
|
||
});
|
||
}
|
||
} catch (e) {
|
||
console.error("解析二维码参数 options.q 失败:", e);
|
||
}
|
||
}
|
||
// 如果从朋友圈等分享渠道直达此页面且携带商品与拼团参数,重定向至对应拼团商品详情
|
||
if (options?.activedType === "groupBuy" && options?.id) {
|
||
uni.redirectTo({
|
||
url: `/pages/other_package/productInfo/productInfo?id=${options.id}&activedType=${options.activedType}&activityId=${options.activityId || 1}`,
|
||
});
|
||
return;
|
||
}
|
||
// #endif
|
||
|
||
if (options?.teamId) {
|
||
this.teamId = options.teamId;
|
||
this.fetchTeamDetail();
|
||
}
|
||
},
|
||
onUnload() {
|
||
this.stopCountdown();
|
||
},
|
||
// 微信小程序原生分享给好友
|
||
onShareAppMessage() {
|
||
const targetGoodsId = this.teamDetail?.goodsId || this.goodsId;
|
||
const goodsName = this.teamDetail?.goodsName || "好物";
|
||
const remaining = this.teamDetail?.remainingNum != null ? this.teamDetail.remainingNum : 1;
|
||
let path = `/pages/other_package/productInfo/productInfo?id=${targetGoodsId}&activedType=groupBuy&activityId=1`;
|
||
if (this.teamId || this.teamDetail?.id) {
|
||
path += `&teamId=${this.teamId || this.teamDetail?.id}`;
|
||
}
|
||
return {
|
||
title: `【还差${remaining}人】快来和我一起拼团!${goodsName}`,
|
||
path: path,
|
||
imageUrl: this.teamDetail?.mainGraph,
|
||
};
|
||
},
|
||
// 微信小程序原生分享到朋友圈
|
||
onShareTimeline() {
|
||
const targetGoodsId = this.teamDetail?.goodsId || this.goodsId;
|
||
const remaining = this.teamDetail?.remainingNum != null ? this.teamDetail.remainingNum : 1;
|
||
return {
|
||
title: `【仅剩${remaining}个名额】¥${this.teamDetail?.groupPrice || ''} 拼团抢购!`,
|
||
query: `id=${targetGoodsId}&activedType=groupBuy&activityId=1`,
|
||
imageUrl: this.teamDetail?.mainGraph,
|
||
};
|
||
},
|
||
methods: {
|
||
// 请求拼团详情
|
||
async fetchTeamDetail() {
|
||
try {
|
||
const res = await getTeamDetail({ teamId: this.teamId, type: 5 });
|
||
if (res && res.bizcode === 100 && res.data) {
|
||
this.teamDetail = res.data;
|
||
if (res.data.goodsId) {
|
||
this.goodsId = res.data.goodsId;
|
||
}
|
||
if (res.data.myOrderId) {
|
||
this.orderId = res.data.myOrderId;
|
||
}
|
||
|
||
// 计算倒计时剩余秒数
|
||
if (res.data.remainingSeconds != null && res.data.remainingSeconds > 0) {
|
||
this.remainingSeconds = Number(res.data.remainingSeconds);
|
||
} else if (res.data.expireTime) {
|
||
const diff = Math.floor((Number(res.data.expireTime) - Date.now()) / 1000);
|
||
this.remainingSeconds = diff > 0 ? diff : 0;
|
||
} else {
|
||
this.remainingSeconds = 0;
|
||
}
|
||
|
||
if (this.isOngoing && this.remainingSeconds > 0) {
|
||
this.startCountdown();
|
||
} else {
|
||
this.countdownText = "00:00:00";
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.error("获取拼团详情失败:", e);
|
||
}
|
||
},
|
||
|
||
// 返回上一页
|
||
handleBack() {
|
||
const pages = getCurrentPages();
|
||
if (pages && pages.length > 1) {
|
||
uni.navigateBack();
|
||
} else {
|
||
uni.switchTab({
|
||
url: "/pages/home/home",
|
||
});
|
||
}
|
||
},
|
||
|
||
// 倒计时处理
|
||
startCountdown() {
|
||
this.stopCountdown();
|
||
this.updateCountdownText();
|
||
this.countdownTimer = setInterval(() => {
|
||
if (this.remainingSeconds > 0) {
|
||
this.remainingSeconds--;
|
||
this.updateCountdownText();
|
||
} else {
|
||
this.countdownText = "00:00:00";
|
||
this.stopCountdown();
|
||
// 倒计时结束后重新拉取拼团状态
|
||
this.fetchTeamDetail();
|
||
}
|
||
}, 1000);
|
||
},
|
||
stopCountdown() {
|
||
if (this.countdownTimer) {
|
||
clearInterval(this.countdownTimer);
|
||
this.countdownTimer = null;
|
||
}
|
||
},
|
||
updateCountdownText() {
|
||
const total = this.remainingSeconds;
|
||
const hh = String(Math.floor(total / 3600)).padStart(2, "0");
|
||
const mm = String(Math.floor((total % 3600) / 60)).padStart(2, "0");
|
||
const ss = String(total % 60).padStart(2, "0");
|
||
this.countdownText = `${hh}:${mm}:${ss}`;
|
||
},
|
||
|
||
// 点击空坑位:提示邀请
|
||
handleSlotClick() {
|
||
if (this.isJoined) {
|
||
this.handleInviteShare();
|
||
} else {
|
||
this.handleJoinGroup();
|
||
}
|
||
},
|
||
|
||
// 跳转商品详情
|
||
jumpProductDetail() {
|
||
const id = this.teamDetail?.goodsId || this.goodsId;
|
||
if (id) {
|
||
uni.navigateTo({
|
||
url: `/pages/other_package/productInfo/productInfo?id=${id}`,
|
||
});
|
||
}
|
||
},
|
||
|
||
// 邀请好友参团:打开分享弹窗
|
||
handleInviteShare() {
|
||
this.shareOpen = true;
|
||
this.shareShow = true;
|
||
},
|
||
|
||
// 关闭分享弹窗
|
||
onShareClose() {
|
||
this.shareShow = false;
|
||
setTimeout(() => {
|
||
this.shareOpen = false;
|
||
}, 300);
|
||
},
|
||
|
||
// 微信小程序分享回调
|
||
onWxShare(index) {
|
||
console.log("微信小程序分享", index);
|
||
if (index === 0) {
|
||
// 微信好友:通过 button open-type="share" 触发,延时关闭弹窗确保微信分享面板顺畅弹出
|
||
setTimeout(() => {
|
||
this.onShareClose();
|
||
}, 150);
|
||
} else if (index === 1) {
|
||
// 分享到朋友圈
|
||
// #ifdef MP-WEIXIN
|
||
uni.showShareMenu({
|
||
withShareTicket: true,
|
||
menus: ["shareTimeline"],
|
||
success: () => {
|
||
uni.showModal({
|
||
title: "提示",
|
||
content: "已为您开启朋友圈分享功能,请点击右上角 [...] 选择【分享到朋友圈】",
|
||
showCancel: false,
|
||
});
|
||
},
|
||
fail: () => {
|
||
uni.showModal({
|
||
title: "提示",
|
||
content: "请点击右上角 [...] 分享到朋友圈",
|
||
showCancel: false,
|
||
});
|
||
},
|
||
});
|
||
// #endif
|
||
this.onShareClose();
|
||
}
|
||
},
|
||
|
||
// App / H5 分享回调
|
||
onShare(index) {
|
||
const targetGoodsId = this.teamDetail?.goodsId || this.goodsId;
|
||
let targetPath = `/pages/other_package/productInfo/productInfo?id=${targetGoodsId}&activedType=groupBuy&activityId=1`;
|
||
if (this.teamId || this.teamDetail?.id) {
|
||
targetPath += `&teamId=${this.teamId || this.teamDetail?.id}`;
|
||
}
|
||
const targetUrl = `${SHARE_URL}/#${targetPath}`;
|
||
const goodsName = this.teamDetail?.goodsName || "";
|
||
const price = this.teamDetail?.groupPrice || "";
|
||
const remaining = this.teamDetail?.remainingNum != null ? this.teamDetail.remainingNum : 1;
|
||
const title = `【还差${remaining}人】快来和我一起拼团!${goodsName}`;
|
||
const summary = `【信任桥】邀请好友拼团!${goodsName} 拼团价 ¥${price}`;
|
||
|
||
if (index === 0) {
|
||
// 微信好友
|
||
// #ifdef APP-PLUS
|
||
uni.share({
|
||
provider: "weixin",
|
||
scene: "WXSceneSession",
|
||
type: 5,
|
||
imageUrl: this.teamDetail?.mainGraph,
|
||
title: title,
|
||
miniProgram: {
|
||
id: "gh_c31503d62920",
|
||
path: targetPath,
|
||
type: MINI_PROGRAM_TYPE,
|
||
webUrl: targetUrl,
|
||
},
|
||
success: () => {
|
||
this.onShareClose();
|
||
},
|
||
fail: (err) => {
|
||
console.error("App小程序分享失败,降级为普通网页分享:", err);
|
||
uni.share({
|
||
provider: "weixin",
|
||
scene: "WXSceneSession",
|
||
type: 0,
|
||
href: targetUrl,
|
||
title: title,
|
||
summary: summary,
|
||
imageUrl: this.teamDetail?.mainGraph,
|
||
complete: () => {
|
||
this.onShareClose();
|
||
},
|
||
});
|
||
},
|
||
});
|
||
// #endif
|
||
// #ifdef H5
|
||
uni.setClipboardData({
|
||
data: targetUrl,
|
||
success: () => {
|
||
uni.showToast({
|
||
title: "拼团链接已复制,请发送给微信好友",
|
||
icon: "none",
|
||
});
|
||
},
|
||
});
|
||
this.onShareClose();
|
||
// #endif
|
||
} else if (index === 1) {
|
||
// 微信朋友圈
|
||
// #ifdef APP-PLUS
|
||
uni.share({
|
||
provider: "weixin",
|
||
scene: "WXSceneTimeline",
|
||
type: 0,
|
||
href: targetUrl,
|
||
title: title,
|
||
summary: summary,
|
||
imageUrl: this.teamDetail?.mainGraph,
|
||
});
|
||
// #endif
|
||
// #ifdef H5
|
||
uni.setClipboardData({
|
||
data: targetUrl,
|
||
success: () => {
|
||
uni.showToast({
|
||
title: "拼团链接已复制,去分享到朋友圈吧",
|
||
icon: "none",
|
||
});
|
||
},
|
||
});
|
||
// #endif
|
||
this.onShareClose();
|
||
} else if (index === 2) {
|
||
let tmp = `【信任桥】消费共享数字化权益 ${SHARE_URL}/#/pages/other_package/productInfo/productInfo?id=${targetGoodsId}&activedType=groupBuy&activityId=1`;
|
||
// 复制链接
|
||
uni.setClipboardData({
|
||
data: tmp,
|
||
success: () => {
|
||
uni.showToast({
|
||
title: "拼团链接已复制,去发给好友吧",
|
||
icon: "none",
|
||
});
|
||
},
|
||
});
|
||
} else if (index === 3) {
|
||
// 保存图片
|
||
if (this.$refs.share && this.$refs.share.saveGroupCard) {
|
||
this.$refs.share.saveGroupCard();
|
||
}
|
||
} else {
|
||
this.onShareClose();
|
||
}
|
||
},
|
||
|
||
// 单独购买:弹出确认弹窗
|
||
handleBuyAlone() {
|
||
this.buyAloneModalShow = true;
|
||
},
|
||
|
||
// 确认创建单买订单
|
||
confirmBuyAlone() {
|
||
this.buyAloneModalShow = false;
|
||
const targetGoodsId = this.teamDetail?.goodsId || this.goodsId;
|
||
if (targetGoodsId) {
|
||
uni.navigateTo({
|
||
url: `/pages/other_package/productInfo/productInfo?id=${targetGoodsId}&activedType=groupBuy&activityId=1&fromBuyAlone=1`,
|
||
});
|
||
}
|
||
},
|
||
|
||
// 取消单买 (继续等团)
|
||
cancelBuyAlone() {
|
||
this.buyAloneModalShow = false;
|
||
},
|
||
|
||
// 参加这个团 (被邀请人点击)
|
||
handleJoinGroup() {
|
||
const id = this.teamDetail?.goodsId || this.goodsId;
|
||
if (id) {
|
||
uni.navigateTo({
|
||
url: `/pages/other_package/productInfo/productInfo?id=${id}&teamId=${this.teamId}&action=joinGroup`,
|
||
});
|
||
}
|
||
},
|
||
|
||
// 查看订单 (拼团成功后点击)
|
||
handleViewOrder() {
|
||
const targetOrderId = this.teamDetail?.myOrderId || this.orderId;
|
||
if (targetOrderId) {
|
||
uni.navigateTo({
|
||
url: `/pages/mine_package/mine_order_info/mine_order_info?orderId=${targetOrderId}`,
|
||
});
|
||
} else {
|
||
uni.navigateTo({
|
||
url: "/pages/mine_package/mine_order/mine_order?type=0",
|
||
});
|
||
}
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.group_detail_page {
|
||
min-height: 100vh;
|
||
background-color: #f6f7f9;
|
||
box-sizing: border-box;
|
||
padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
// ========== 顶部导航栏与紫色渐变背景 ==========
|
||
.top_nav_container {
|
||
background: linear-gradient(180deg, #742af5 0%, #8a3bf8 100%);
|
||
padding-bottom: 80rpx;
|
||
|
||
.nav_bar {
|
||
height: 88rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 28rpx;
|
||
|
||
.nav_back_btn {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border-radius: 16rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: background 0.2s;
|
||
|
||
&:active {
|
||
background: rgba(255, 255, 255, 0.35);
|
||
}
|
||
}
|
||
|
||
.nav_title_wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: 1;
|
||
height: 100%;
|
||
|
||
.nav_status_icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 12rpx;
|
||
flex-shrink: 0;
|
||
|
||
:deep(.u-image),
|
||
:deep(.u-transition) {
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
}
|
||
}
|
||
|
||
.nav_title_text {
|
||
color: #ffffff;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
letter-spacing: 1rpx;
|
||
line-height: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
|
||
.nav_right_placeholder {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========== 内容主体卡片区 (负边距上移) ==========
|
||
.page_body {
|
||
margin-top: -50rpx;
|
||
padding: 0 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
// ========== 1. 商品卡片 ==========
|
||
.product_card {
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 24rpx;
|
||
display: flex;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
|
||
|
||
.product_img_wrap {
|
||
width: 190rpx;
|
||
height: 190rpx;
|
||
border-radius: 16rpx;
|
||
position: relative;
|
||
overflow: hidden;
|
||
flex-shrink: 0;
|
||
background-color: #f7f7f7;
|
||
|
||
.product_img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
.product_info_wrap {
|
||
flex: 1;
|
||
min-width: 0;
|
||
margin-left: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
|
||
.product_name {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #1a1a1a;
|
||
line-height: 40rpx;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.group_size_badge {
|
||
align-self: flex-start;
|
||
background: #f2f3f5;
|
||
border-radius: 6rpx;
|
||
padding: 4rpx 14rpx;
|
||
font-size: 22rpx;
|
||
color: #666666;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.product_price_row {
|
||
display: flex;
|
||
align-items: baseline;
|
||
margin-top: 10rpx;
|
||
|
||
.group_price_box {
|
||
display: flex;
|
||
align-items: baseline;
|
||
color: #742af5;
|
||
|
||
.group_price_label {
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
margin-right: 6rpx;
|
||
}
|
||
|
||
.group_price_symbol {
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.group_price_val {
|
||
font-size: 38rpx;
|
||
font-weight: bold;
|
||
margin-left: 2rpx;
|
||
}
|
||
}
|
||
|
||
.original_price_box {
|
||
margin-left: 14rpx;
|
||
|
||
.original_price {
|
||
font-size: 24rpx;
|
||
color: #999999;
|
||
text-decoration: line-through;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========== 2. 拼团状态与操作卡片 ==========
|
||
.status_card {
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 40rpx 28rpx 36rpx;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
|
||
.status_header_row {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: center;
|
||
|
||
.status_title_text {
|
||
font-size: 34rpx;
|
||
font-weight: bold;
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
.status_num_highlight {
|
||
font-size: 40rpx;
|
||
font-weight: 800;
|
||
color: #742af5;
|
||
margin: 0 8rpx;
|
||
}
|
||
}
|
||
|
||
.countdown_row {
|
||
margin-top: 10rpx;
|
||
|
||
.countdown_text {
|
||
font-size: 24rpx;
|
||
color: #666666;
|
||
}
|
||
}
|
||
|
||
.success_header_row {
|
||
padding: 6rpx 0 10rpx;
|
||
|
||
.success_title_text {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #1a1a1a;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
|
||
.failed_title_text {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #e61d2b;
|
||
}
|
||
}
|
||
|
||
// 成员头像与坑位列表
|
||
.avatars_slot_row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
gap: 28rpx;
|
||
margin: 36rpx 0 44rpx;
|
||
width: 100%;
|
||
|
||
&.slots_compact {
|
||
gap: 18rpx;
|
||
}
|
||
|
||
.avatar_slot_item {
|
||
position: relative;
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.member_avatar {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 50%;
|
||
background-color: #eeeeee;
|
||
display: block;
|
||
}
|
||
|
||
.leader_badge {
|
||
position: absolute;
|
||
bottom: -8rpx;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: #7934f6;
|
||
border-radius: 16rpx;
|
||
padding: 0 14rpx;
|
||
height: 32rpx;
|
||
min-width: 68rpx;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 2;
|
||
white-space: nowrap;
|
||
|
||
.leader_badge_text {
|
||
color: #ffffff;
|
||
font-size: 20rpx;
|
||
font-weight: 500;
|
||
line-height: 1;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
// 空坑位加号
|
||
.empty_slot {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 50%;
|
||
background: #f0e8fe;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
transition: transform 0.15s ease;
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.plus_icon {
|
||
font-size: 42rpx;
|
||
color: #7934f6;
|
||
font-weight: 300;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 按钮区域
|
||
.action_buttons_wrap {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20rpx;
|
||
|
||
.btn_primary {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background: linear-gradient(90deg, #8a3bf8 0%, #742af5 100%);
|
||
color: #ffffff;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 8rpx 20rpx rgba(116, 42, 245, 0.25);
|
||
border: none;
|
||
outline: none;
|
||
margin: 0;
|
||
padding: 0;
|
||
line-height: 88rpx;
|
||
transition: opacity 0.2s ease, transform 0.1s ease;
|
||
|
||
&::after {
|
||
border: none;
|
||
}
|
||
|
||
&:active {
|
||
opacity: 0.9;
|
||
transform: scale(0.99);
|
||
}
|
||
}
|
||
|
||
// 清除 button 默认样式(用于微信小程序 button 元素)
|
||
.btn_reset {
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
background-color: transparent;
|
||
border-radius: 44rpx;
|
||
|
||
&::after {
|
||
border: none;
|
||
background: transparent;
|
||
}
|
||
}
|
||
|
||
.btn_secondary {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background: #f0e7fe;
|
||
color: #742af5;
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
border-radius: 44rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: opacity 0.2s ease;
|
||
|
||
&:active {
|
||
opacity: 0.85;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========== 3. 拼团玩法卡片 ==========
|
||
.rules_card {
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 28rpx;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
|
||
|
||
.rules_card_title {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #1a1a1a;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.rules_steps_row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-around;
|
||
padding: 10rpx 0;
|
||
|
||
.step_item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
width: 180rpx;
|
||
|
||
.step_icon {
|
||
width: 96rpx;
|
||
height: 96rpx;
|
||
}
|
||
|
||
.step_label {
|
||
font-size: 24rpx;
|
||
color: #333333;
|
||
margin-top: 14rpx;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
}
|
||
}
|
||
}
|
||
|
||
.rules_notice {
|
||
font-size: 22rpx;
|
||
color: #999999;
|
||
line-height: 36rpx;
|
||
margin-top: 20rpx;
|
||
padding-top: 16rpx;
|
||
border-top: 1rpx solid #f6f6f6;
|
||
}
|
||
}
|
||
</style>
|