diff --git a/App.vue b/App.vue
index 8c2b732..d22b78e 100644
--- a/App.vue
+++ b/App.vue
@@ -2,6 +2,7 @@
export default {
onLaunch: function() {
console.log('App Launch')
+ try { uni.setStorageSync('app_session_id', String(Date.now())) } catch (_) {}
},
onShow: function() {
console.log('App Show')
diff --git a/api/appUser.js b/api/appUser.js
index bf2c5d4..93ebb4c 100644
--- a/api/appUser.js
+++ b/api/appUser.js
@@ -57,4 +57,12 @@ export function getActivityIssues(activity_id) {
export function getActivityIssueRewards(activity_id, issue_id) {
return authRequest({ url: `/api/app/activities/${activity_id}/issues/${issue_id}/rewards`, method: 'GET' })
-}
\ No newline at end of file
+}
+
+export function drawActivityIssue(activity_id, issue_id) {
+ return authRequest({ url: `/api/app/activities/${activity_id}/issues/${issue_id}/draw`, method: 'POST' })
+}
+
+export function getActivityWinRecords(activity_id, page = 1, page_size = 20) {
+ return authRequest({ url: `/api/app/activities/${activity_id}/wins`, method: 'GET', data: { page, page_size } })
+}
diff --git a/components/ElCard.vue b/components/ElCard.vue
new file mode 100644
index 0000000..3ff944f
--- /dev/null
+++ b/components/ElCard.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/FlipGrid.vue b/components/FlipGrid.vue
new file mode 100644
index 0000000..816bd8e
--- /dev/null
+++ b/components/FlipGrid.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ cell.title || '' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/activity/duiduipeng/index.vue b/pages/activity/duiduipeng/index.vue
index 8ef9e2c..e44d131 100644
--- a/pages/activity/duiduipeng/index.vue
+++ b/pages/activity/duiduipeng/index.vue
@@ -5,46 +5,83 @@
-
-
-
-
-
+
+
期数
-
- {{ it.title || ('第' + (it.no || it.index || it.issue_no || '-') + '期') }}
- {{ it.status_text }}
-
-
-
-
- {{ rw.title }}
- {{ [rw.rarity, rw.odds].filter(Boolean).join(' · ') }}
+
+
+ {{ it.title || ('第' + (it.no || it.index || it.issue_no || '-') + '期') }}
+
+
+
+
+ 本机奖池
+ 中奖记录
+
+
+
+
+
+
+
+
+
+
+ 概率 {{ rw.percent }}%
-
+
暂无奖励配置
+
+
+
+
+
+
+
+
+
+ 占比 {{ it.percent }}%
+
+
+
+ 暂无中奖记录
+
暂无期数
+
+
+
\ No newline at end of file
+
diff --git a/pages/activity/wuxianshang/index.vue b/pages/activity/wuxianshang/index.vue
index 94b27e1..954b074 100644
--- a/pages/activity/wuxianshang/index.vue
+++ b/pages/activity/wuxianshang/index.vue
@@ -5,46 +5,57 @@
-
-
-
+
+
+
+
-
- 期数
-
-
- {{ it.title || ('第' + (it.no || it.index || it.issue_no || '-') + '期') }}
- {{ it.status_text }}
-
-
-
-
- {{ rw.title }}
- {{ [rw.rarity, rw.odds].filter(Boolean).join(' · ') }}
-
-
-
- 暂无奖励配置
-
+
+
+
+ {{ currentIssueTitle }}
+
- 暂无期数
+
+
+
+
+
+
+
+
diff --git a/pages/activity/yifanshang/index.vue b/pages/activity/yifanshang/index.vue
index 4ae43ca..8da00cd 100644
--- a/pages/activity/yifanshang/index.vue
+++ b/pages/activity/yifanshang/index.vue
@@ -5,45 +5,58 @@
-
-
-
+
+
+
+
-
- 期数
-
-
- {{ it.title || ('第' + (it.no || it.index || it.issue_no || '-') + '期') }}
- {{ it.status_text }}
-
-
-
-
- {{ rw.title }}
- {{ [rw.rarity, rw.odds].filter(Boolean).join(' · ') }}
-
-
-
- 暂无奖励配置
-
+
+
+
+ {{ currentIssueTitle }}
+
- 暂无期数
+
+
+
+
+
+
+
+
\ No newline at end of file
+
diff --git a/pages/agreement/purchase.vue b/pages/agreement/purchase.vue
index 3cbf33a..d563371 100644
--- a/pages/agreement/purchase.vue
+++ b/pages/agreement/purchase.vue
@@ -2,8 +2,8 @@
购买协议
生效日期:2025年11月18日
- 运营方:【公司全称】
- 本《购买协议》适用于您在【您的小程序名称】(以下简称“本平台”)购买盲盒商品的行为。当您点击“立即购买”并完成支付时,即视为您已阅读、理解并同意本协议全部内容。
+ 运营方:柯大鸭潮玩
+ 本《购买协议》适用于您在【柯大鸭潮玩】(以下简称“本平台”)购买盲盒商品的行为。当您点击“立即购买”并完成支付时,即视为您已阅读、理解并同意本协议全部内容。
一、商品说明
盲盒特性:本平台所售盲盒为系列化商品,包装外观一致,内部款式随机,具体款式无法提前指定或预知。
@@ -22,7 +22,7 @@
四、售后服务
- 质量问题(如商品破损、漏发、错发、非盲盒系列商品):请在签收后2到4小时内联系客服并提供凭证(如开箱视频、照片);经核实后,平台将为您补发、换货或退款。
+ 质量问题(如商品破损、漏发、错发、非盲盒系列商品):请在签收后2小时内联系客服并提供凭证(如开箱视频、照片);经核实后,平台将为您补发、换货或退款。
非质量问题(如抽中重复款式、不喜欢款式、未抽中隐藏款等):不支持无理由退换货。
拆封后商品:出于卫生与二次销售考虑,已拆封盲盒恕不退换(质量问题除外)。
@@ -45,10 +45,9 @@
八、协议效力
本购买协议为《用户协议》的补充,两者冲突时,以本协议中关于交易的条款为准。未尽事宜,依照《消费者权益保护法》《电子商务法》等法律法规执行。
九、联系我们
- 售后专线:service@yourdomain.com
- 工作时间:工作日 9:00–18:00
- 运营主体:【公司全称】
- 统一社会信用代码:【XXXXXXXXXXXXXX】
+ 售后专线:请联系企业客服,客服将在工作时间内为您服务。
+ 工作时间:工作日 13:00–04:00
+ 运营主体:【柯大鸭潮玩】
理性消费提醒:盲盒是一种娱乐消费形式,请根据自身经济能力合理购买,切勿沉迷或过度投入。
diff --git a/pages/agreement/user.vue b/pages/agreement/user.vue
index 849b27c..442090b 100644
--- a/pages/agreement/user.vue
+++ b/pages/agreement/user.vue
@@ -2,8 +2,8 @@
用户协议
生效日期:2025年11月18日
- 运营方:【公司全称】
- 欢迎您使用【您的小程序名称】(以下简称“本平台”)提供的服务。请您在注册、登录或使用本平台前,认真阅读并充分理解本《用户协议》(以下简称“本协议”)。一旦您完成注册、登录或以任何方式使用本平台服务,即视为您已完全接受本协议全部条款。如您不同意,请勿使用本平台。
+ 运营方:【柯大鸭潮玩】
+ 欢迎您使用【柯大鸭潮玩】(以下简称“本平台”)提供的服务。请您在注册、登录或使用本平台前,认真阅读并充分理解本《用户协议》(以下简称“本协议”)。一旦您完成注册、登录或以任何方式使用本平台服务,即视为您已完全接受本协议全部条款。如您不同意,请勿使用本平台。
一、协议范围
本协议规范您作为用户在本平台注册、浏览、互动、参与活动等行为,是您与本平台之间的基本权利义务约定。
二、用户资格
@@ -44,10 +44,9 @@
九、法律适用与争议解决
本协议适用中华人民共和国法律。因本协议引起的争议,双方应协商解决;协商不成的,提交本平台运营方所在地有管辖权的人民法院诉讼解决。
十、联系我们
- 客服邮箱:service@yourdomain.com
- 客服电话:400-XXX-XXXX(工作日 9:00–18:00)
- 运营主体:【公司全称】
- 地址:【公司注册地址】
+ 客服邮箱:请通过企业客服联系我们,客服将在工作时间内为您服务。
+ 工作时间:(工作日 13:00–04:00)
+ 运营主体:【柯大鸭潮玩】
温馨提示:盲盒具有随机性和娱乐性,请理性参与,避免沉迷。未成年人禁止参与购买。
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 0f825a6..bca5b27 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -21,15 +21,21 @@
活动
-
-
-
-
- {{ a.title || '活动敬请期待' }}
+
+
+ {{ g.name }}
+
+
+
+
+
+ {{ a.title || '活动敬请期待' }}
+
+ {{ a.title }}
+ {{ a.subtitle }}
- {{ a.title }}
- {{ a.subtitle }}
+ 该分组暂无活动
暂无活动
@@ -43,7 +49,8 @@ export default {
return {
notices: [],
banners: [],
- activities: []
+ activities: [],
+ selectedGroupName: ''
}
},
computed: {
@@ -61,6 +68,22 @@ export default {
{ id: 'ph-2', title: '敬请期待', image: '' },
{ id: 'ph-3', title: '更多活动请关注', image: '' }
]
+ },
+ activityGroups() {
+ const list = Array.isArray(this.activities) ? this.activities : []
+ const map = new Map()
+ list.forEach(a => {
+ const key = (a.category_name || '').trim() || '其他'
+ if (!map.has(key)) map.set(key, [])
+ map.get(key).push(a)
+ })
+ return Array.from(map.entries()).map(([name, items]) => ({ name, items }))
+ },
+ activeGroupItems() {
+ const groups = this.activityGroups
+ const name = this.selectedGroupName || (groups[0] && groups[0].name) || ''
+ const g = groups.find(x => x.name === name)
+ return g ? g.items : []
}
},
onShow() {
@@ -82,6 +105,16 @@ export default {
this.loadHomeData()
},
methods: {
+ onSelectGroup(name) {
+ this.selectedGroupName = String(name || '')
+ },
+ updateSelectedGroup() {
+ const groups = this.activityGroups
+ if (!groups.length) { this.selectedGroupName = ''; return }
+ if (!groups.find(g => g.name === this.selectedGroupName)) {
+ this.selectedGroupName = groups[0].name
+ }
+ },
toArray(x) { return Array.isArray(x) ? x : [] },
unwrap(list) {
if (Array.isArray(list)) return list
@@ -126,7 +159,7 @@ export default {
console.log('normalizeActivities input', list, 'unwrapped', arr)
const mapped = arr.map((i, idx) => ({
id: i.id ?? String(idx),
- image: this.cleanUrl(i.banner ?? i.coverUrl ?? i.cover_url ?? i.image ?? i.img ?? i.pic ?? ''),
+ image: this.cleanUrl(i.image ?? i.banner ?? i.coverUrl ?? i.cover_url ?? i.img ?? i.pic ?? ''),
title: i.title ?? i.name ?? '',
subtitle: this.buildActivitySubtitle(i),
link: this.cleanUrl(i.linkUrl ?? i.link_url ?? i.link ?? i.url ?? ''),
@@ -168,9 +201,11 @@ export default {
if (acRes.status === 'fulfilled') {
console.log('activities ok', acRes.value)
this.activities = this.normalizeActivities(acRes.value)
+ this.updateSelectedGroup()
} else {
console.error('activities error', acRes.reason)
this.activities = []
+ this.updateSelectedGroup()
}
console.log('home normalized', { notices: this.notices, banners: this.banners, activities: this.activities })
},
@@ -216,6 +251,9 @@ export default {
.banner-fallback-text { color: #666; font-size: 28rpx }
.activity-section { background: #ffffff; border-radius: 12rpx; padding: 24rpx }
.section-title { font-size: 30rpx; font-weight: 600; margin-bottom: 16rpx }
+.tabs { white-space: nowrap; display: flex; gap: 12rpx; margin-bottom: 16rpx }
+.tab { display: inline-flex; align-items: center; height: 56rpx; padding: 0 20rpx; border-radius: 999rpx; background: #f5f7fa; color: #555; font-size: 26rpx }
+.tab.active { background: #007AFF; color: #fff }
.activity-grid { display: flex; flex-wrap: wrap; margin: -12rpx }
.activity-item { width: 50%; padding: 12rpx }
.activity-thumb { width: 100%; height: 200rpx; border-radius: 8rpx }
diff --git a/pages/shop/index.vue b/pages/shop/index.vue
index 1d5477b..2e26794 100644
--- a/pages/shop/index.vue
+++ b/pages/shop/index.vue
@@ -1,5 +1,18 @@
+
+
+ 提示
+ 由于价格浮动,当前暂不支持自行兑换商品,兑换请联系客服核对价格。
+
+
+
+ 不再显示
+
+
+
+
+
商品
@@ -53,6 +66,9 @@ const minPrice = ref('')
const maxPrice = ref('')
const displayCount = computed(() => (columns.value[0].length + columns.value[1].length))
const loadedMap = ref({})
+const showNotice = ref(false)
+const hideForever = ref(false)
+const skipReloadOnce = ref(false)
function getKey(p) { return String((p && p.id) ?? '') + '|' + String((p && p.image) ?? '') }
function unwrap(list) {
if (Array.isArray(list)) return list
@@ -146,6 +162,8 @@ function onProductTap(p) {
const imgs = (Array.isArray(products.value) ? products.value : []).map(x => x.image).filter(Boolean)
const current = p && p.image
if (current) {
+ skipReloadOnce.value = true
+ try { uni.setStorageSync('shop_skip_reload_once', '1') } catch (_) {}
uni.previewImage({ urls: imgs.length ? imgs : [current], current })
return
}
@@ -249,14 +267,50 @@ onShow(async () => {
})
return
}
+ try {
+ const sess = String(uni.getStorageSync('app_session_id') || '')
+ const hiddenSess = String(uni.getStorageSync('shop_notice_hidden_session_id') || '')
+ const hiddenThisSession = !!(sess && hiddenSess && hiddenSess === sess)
+ showNotice.value = !hiddenThisSession
+ hideForever.value = hiddenThisSession
+ } catch (_) { showNotice.value = true; hideForever.value = false }
+ try {
+ const skip = !!uni.getStorageSync('shop_skip_reload_once')
+ if (skipReloadOnce.value || skip) {
+ skipReloadOnce.value = false
+ uni.setStorageSync('shop_skip_reload_once', '')
+ return
+ }
+ } catch (_) {}
loading.value = true
await loadProducts()
loading.value = false
})
+
+function toggleHideForever() { hideForever.value = !hideForever.value }
+function onDismissNotice() {
+ if (hideForever.value) {
+ try {
+ const sess = String(uni.getStorageSync('app_session_id') || '')
+ if (sess) uni.setStorageSync('shop_notice_hidden_session_id', sess)
+ } catch (_) {}
+ }
+ showNotice.value = false
+}