diff --git a/frontend/pages/support-activity/center.vue b/frontend/pages/support-activity/center.vue
index 088eec6..75f26db 100644
--- a/frontend/pages/support-activity/center.vue
+++ b/frontend/pages/support-activity/center.vue
@@ -8,7 +8,9 @@
:showTaskIcon="false"
:showStarActivityIcon="false"
/> -->
-
+
+ ←
+
@@ -224,6 +226,20 @@ const filteredActivities = computed(() => {
);
});
+const goBack = () => {
+ // 获取页面栈
+ const pages = getCurrentPages();
+ if (pages.length > 1) {
+ // 有上一页,执行返回
+ uni.navigateBack();
+ } else {
+ // 没有上一页,跳转到square页面
+ uni.reLaunch({
+ url: "/pages/square/square",
+ });
+ }
+};
+
function isEnded(item) {
return item.status === "expired" || item.status === "completed";
}
@@ -395,6 +411,24 @@ onShow(() => {
}
}
+.nav-back {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ /* background: rgba(255,255,255,0.5);
+ border-radius: 50%; */
+ position: fixed;
+ top: 88rpx;
+ left: 32rpx;
+ z-index: 4;
+}
+
+.nav-back-icon {
+ font-size: 48rpx;
+ font-weight: bold;
+ color: #fff;
+}
+
.status-bar {
width: 100%;
background: transparent;
diff --git a/frontend/pages/support-activity/components/ActionBar.vue b/frontend/pages/support-activity/components/ActionBar.vue
index 25ff3a4..74a002f 100644
--- a/frontend/pages/support-activity/components/ActionBar.vue
+++ b/frontend/pages/support-activity/components/ActionBar.vue
@@ -502,8 +502,8 @@ async function contributeItem(item, isRetry = false, silent = false, qty = 1) {
await updateLocalBalanceFromResult(result.remainingBalance);
}
- // 通知父组件更新进度(使用返回的当前进度)
- emit("contribute", item.type, result.currentProgress);
+ // 通知父组件更新水晶余额(使用返回的剩余余额)
+ emit("contribute", item.type, result.remainingBalance);
// 如果是重试成功或静默模式,不单独弹 toast
if (!isRetry && !silent) {
diff --git a/frontend/pages/support-activity/components/ContributionList.vue b/frontend/pages/support-activity/components/ContributionList.vue
index efd4b2b..32778f2 100644
--- a/frontend/pages/support-activity/components/ContributionList.vue
+++ b/frontend/pages/support-activity/components/ContributionList.vue
@@ -1,8 +1,7 @@
-
+
+
+
-
- {{ record.nickname }}
+
+
+ {{ record.nickname }}
+ 送{{ record.item_name }}
+
-
-
- x
- {{ record.combo_count > 1 ? record.combo_count : record.quantity }}
+
+
+
+
+
+ X
+ {{
+ record.combo_count > 1 ? record.combo_count : record.quantity
+ }}
+
@@ -25,37 +44,83 @@
\ No newline at end of file
+
diff --git a/frontend/pages/support-activity/components/MessageBoard.vue b/frontend/pages/support-activity/components/MessageBoard.vue
new file mode 100644
index 0000000..f041e73
--- /dev/null
+++ b/frontend/pages/support-activity/components/MessageBoard.vue
@@ -0,0 +1,108 @@
+
+
+
+
+ {{ msg.user }}:
+ {{ msg.content }}
+
+
+ 暂无留言,快来抢沙发吧~
+
+
+
+
+
+
+
+
diff --git a/frontend/pages/support-activity/components/MessageInput.vue b/frontend/pages/support-activity/components/MessageInput.vue
new file mode 100644
index 0000000..475765b
--- /dev/null
+++ b/frontend/pages/support-activity/components/MessageInput.vue
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+ {{ displayText }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/pages/support-activity/components/TopRanking.vue b/frontend/pages/support-activity/components/TopRanking.vue
new file mode 100644
index 0000000..d4ae32f
--- /dev/null
+++ b/frontend/pages/support-activity/components/TopRanking.vue
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 当前排名
+ {{ myInfo.rank }}
+
+
+
+ 距离上一名贡献值
+ {{ myInfo.gapToPrev }}
+
+
+
+
+
+
+
+
+
diff --git a/frontend/pages/support-activity/composables/useContributionPolling.js b/frontend/pages/support-activity/composables/useContributionPolling.js
index c2a0094..f0a9895 100644
--- a/frontend/pages/support-activity/composables/useContributionPolling.js
+++ b/frontend/pages/support-activity/composables/useContributionPolling.js
@@ -5,12 +5,15 @@ import { getActivityContributionsLatestApi } from '@/utils/api.js'
* 贡献轮询逻辑 composable
* @param {Ref} activityId - 活动ID
* @param {boolean} isPageActive - 页面是否可见
+ * @param {Object} [options] - 配置项
+ * @param {boolean} [options.enableTTL=false] - 是否开启"每条记录 5 秒后自动消失"的开关(默认关闭,记录一直保留直到被新数据挤掉)
+ * @param {number} [options.ttlMs=5000] - 自动消失的延时(毫秒),仅在 enableTTL=true 时生效
* @returns {Object} records, visible, loading, error, start, stop, reset
*/
-export function useContributionPolling(activityId, isPageActive) {
+export function useContributionPolling(activityId, isPageActive, options = {}) {
+ const { enableTTL = false, ttlMs = 5000 } = options
const MAX_RECORDS = 5
const POLL_INTERVAL = 1000 // 每秒拉取
- const RECORD_TTL = 5000 // 每条记录 5 秒后消失
const records = ref([])
const visible = ref(true)
@@ -25,6 +28,9 @@ export function useContributionPolling(activityId, isPageActive) {
// 重置记录计时器
function resetRecordTimer(record) {
+ // TTL 功能未开启时:不做任何定时器与淡出处理,记录会一直保留
+ if (!enableTTL) return
+
// 清除已有定时器
if (recordTimers.has(record.id)) {
clearTimeout(recordTimers.get(record.id))
@@ -49,7 +55,7 @@ export function useContributionPolling(activityId, isPageActive) {
} else {
recordTimers.delete(record.id)
}
- }, RECORD_TTL)
+ }, ttlMs)
recordTimers.set(record.id, timer)
}
@@ -58,7 +64,7 @@ export function useContributionPolling(activityId, isPageActive) {
if (!activityId.value) return
try {
- const res = await getActivityContributionsLatestApi(activityId.value, latestTimestamp, latestId, 1)
+ const res = await getActivityContributionsLatestApi(activityId.value, latestTimestamp, latestId, 3)
// 处理 code 不为 200 的情况(静默忽略)
if (res.code !== 0) return
@@ -66,22 +72,22 @@ export function useContributionPolling(activityId, isPageActive) {
const newRecords = res.data?.records || []
if (newRecords.length === 0) return
- const newRecord = newRecords[0]
-
- // 检测到新记录(时间戳更新,或时间戳相同但 ID 更新)
- const isNew = newRecord.created_at > latestTimestamp ||
- (newRecord.created_at === latestTimestamp && newRecord.id > latestId)
+ // API 返回的 records 按 created_at DESC, id DESC 排序。
+ // 只需比对第一条;后面的记录时间戳/ID 必然不更小。
+ const firstRecord = newRecords[0]
+ const isNew = firstRecord.created_at > latestTimestamp ||
+ (firstRecord.created_at === latestTimestamp && firstRecord.id > latestId)
if (isNew) {
// 重置所有现有记录的计时器(新数据到来,刷新列表)
records.value.forEach(resetRecordTimer)
- // 新记录插入到列表头部
- records.value = [newRecord, ...records.value].slice(0, MAX_RECORDS)
- // 为新记录启动消失计时器
- resetRecordTimer(newRecord)
- // 更新时间戳和 ID
- latestTimestamp = newRecord.created_at
- latestId = newRecord.id
+ // 一次性插入本轮拉取到的全部新记录(API 已按"新→旧"排序,新的在前)
+ records.value = [...newRecords, ...records.value].slice(0, MAX_RECORDS)
+ // 为每条新记录启动消失计时器
+ newRecords.forEach(resetRecordTimer)
+ // 更新游标到最新一条
+ latestTimestamp = firstRecord.created_at
+ latestId = firstRecord.id
}
} catch (e) {
// 网络错误等,静默忽略,继续等待下一次轮询
diff --git a/frontend/pages/support-activity/index.vue b/frontend/pages/support-activity/index.vue
index b667c77..9b16f46 100644
--- a/frontend/pages/support-activity/index.vue
+++ b/frontend/pages/support-activity/index.vue
@@ -6,10 +6,51 @@
backIconColor="#e6e6e6"
:showGuideIcon="false" :showTaskIcon="false" :showStarActivityIcon="false"
/> -->
-
+
+ ←
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ exhibitionRevenue }}
+
+
+
+
+
+
+
+
+
+ 排行榜
+
+
-
+
-
-
+ /> -->
+
-
+
-
+
+
+
+
+
+
+
-
+
-
-
+
+
加载中...
-
+
{{ Math.round(loadingProgress) }}%
-
+
@@ -120,180 +178,294 @@
\ No newline at end of file
+
+/* 留言板触发按钮(与 action-bar-trigger 对称,位于左侧) */
+.message-trigger {
+ width: 80rpx;
+ height: 80rpx;
+ border-radius: 80rpx;
+ position: fixed;
+ bottom: 32rpx;
+ left: 32rpx;
+ z-index: 100;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background: rgba(217, 217, 217, 0.4);
+ box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.25);
+}
+
+.message-trigger .trigger-icon-text {
+ font-size: 44rpx;
+}
+
+/* 留言板弹出框样式 */
+.message-board-popup {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 998;
+}
+
+.message-board-mask {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+}
+
+.message-board-content {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ max-height: 80vh;
+ background-image: url("@/static/rank/activity-support-icon/beijingkuang.png");
+ background-size: 105% 130%;
+ background-position: center;
+ border-radius: 40rpx 40rpx 0 0;
+ padding: 32rpx 32rpx 40rpx;
+ display: flex;
+ flex-direction: column;
+ gap: 24rpx;
+ animation: slideUp 0.3s ease-out;
+}
+
+.message-board-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-bottom: 16rpx;
+ border-bottom: 1rpx solid rgba(255, 255, 255, 0.3);
+}
+
+.message-board-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
+}
+
+.message-board-close {
+ width: 56rpx;
+ height: 56rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ font-size: 48rpx;
+ font-weight: bold;
+ background: rgba(255, 255, 255, 0.15);
+ border-radius: 50%;
+}
+
+/*
+ * 留言输入框浮层:对齐底部确认赠送按钮
+ * 与 ActionBar 的 .quantity-control 处于同一水平线
+ */
+.message-input-floating-bottom {
+ width: 100%;
+ padding-top: 16rpx;
+ border-top: 1rpx solid rgba(255, 255, 255, 0.3);
+}
+
+/* 右上角 TOP3 + 我的排名 悬浮组件 */
+.top-ranking-wrapper {
+ position: fixed;
+ top: 96rpx;
+ right: 24rpx;
+ z-index: 50;
+ max-width: 320rpx;
+}
+
+.rank-ph {
+ position: fixed;
+ top: 288rpx;
+ right: 24rpx;
+ z-index: 50;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.ph-image {
+ width: 96rpx;
+ height: 96rpx;
+}
+
+.ph-text {
+ color: #fff;
+ text-shadow: -1px 1px 4px rgba(82, 8, 8, 0.45);
+ font-family: "Abhaya Libre ExtraBold";
+ font-size: 22rpx;
+ font-style: normal;
+ font-weight: 600;
+ line-height: normal;
+}
+
diff --git a/frontend/static/rank/activity-support-icon/message-row/avatar.png b/frontend/static/rank/activity-support-icon/message-row/avatar.png
new file mode 100644
index 0000000..f3a425d
Binary files /dev/null and b/frontend/static/rank/activity-support-icon/message-row/avatar.png differ
diff --git a/frontend/static/rank/activity-support-icon/message-row/emoji.png b/frontend/static/rank/activity-support-icon/message-row/emoji.png
new file mode 100644
index 0000000..b545b94
Binary files /dev/null and b/frontend/static/rank/activity-support-icon/message-row/emoji.png differ
diff --git a/frontend/static/rank/activity-support-icon/message-row/send.png b/frontend/static/rank/activity-support-icon/message-row/send.png
new file mode 100644
index 0000000..ffb9ed6
Binary files /dev/null and b/frontend/static/rank/activity-support-icon/message-row/send.png differ
diff --git a/frontend/static/rank/phtb.png b/frontend/static/rank/phtb.png
new file mode 100644
index 0000000..1769751
Binary files /dev/null and b/frontend/static/rank/phtb.png differ
diff --git a/frontend/static/rank/sjbj.png b/frontend/static/rank/sjbj.png
new file mode 100644
index 0000000..847760d
Binary files /dev/null and b/frontend/static/rank/sjbj.png differ