1. 弹幕功能

2. 点赞
3. 导航引导
4. ai弹幕、审核
This commit is contained in:
李琦
2026-08-01 17:45:01 +08:00
parent 02202619c6
commit 37dc93b877
2 changed files with 75 additions and 24 deletions

View File

@@ -16,15 +16,19 @@ import { ref } from 'vue'
const hearts = ref([])
let uid = 0
/** 单次最多同时排队的爱心数,避免超高点赞拖垮渲染 */
const MAX_BURST = 80
const burst = (count = 3) => {
const n = Math.max(1, Math.min(3, count))
const n = Math.max(0, Math.min(MAX_BURST, Math.floor(Number(count) || 0)))
if (!n) return
for (let i = 0; i < n; i += 1) {
const id = ++uid
const left = 12 + Math.random() * 48
const drift = (Math.random() - 0.5) * 36
const duration = 1.2 + Math.random() * 0.6
const delay = i * 0.08
const scale = 0.85 + Math.random() * 0.45
const left = 10 + Math.random() * 200
const drift = (Math.random() - 0.5) * 90
const duration = 1.25 + Math.random() * 0.7
const delay = i * 0.045
const scale = 0.8 + Math.random() * 0.55
hearts.value.push({
id,
style: {
@@ -50,15 +54,15 @@ defineExpose({ burst })
position: fixed;
left: 0;
bottom: 0;
width: 120px;
height: 55vh;
width: min(46vw, 280px);
height: 58vh;
z-index: 45;
pointer-events: none;
overflow: hidden;
}
.like-burst-heart {
position: absolute;
bottom: 24px;
bottom: 28px;
color: #f472b6;
font-size: 22px;
line-height: 1;
@@ -78,7 +82,7 @@ defineExpose({ burst })
}
100% {
opacity: 0;
transform: translate3d(var(--drift, 0px), -42vh, 0) scale(var(--scale, 1));
transform: translate3d(var(--drift, 0px), -46vh, 0) scale(var(--scale, 1));
}
}
</style>

View File

@@ -85,19 +85,30 @@
</div>
<!-- 底部互动区点赞 / 填写 / 评论条 -->
<div class="action-dock">
<div
class="action-dock"
@touchstart.stop
@touchmove.stop
@touchend.stop
@mousedown.stop
@click.stop
>
<!-- 右下点赞邻域隐形遮罩吞掉穿透到页面的触摸避免误触预览/暂停 -->
<div class="like-side-shield" aria-hidden="true" />
<div class="action-dock-row">
<button
type="button"
class="action-pill like-fab"
:class="{ liked: likePulse, busy: likeBusy }"
:disabled="likeBusy"
title="点赞"
@click="handleLike"
>
<i class="fa-heart like-icon" :class="likePulse ? 'fa-solid' : 'fa-regular'"></i>
<span class="like-count">{{ likeCount }}</span>
</button>
<div class="like-hit-zone">
<button
type="button"
class="action-pill like-fab"
:class="{ liked: likePulse, busy: likeBusy }"
:disabled="likeBusy"
title="点赞"
@click="handleLike"
>
<i class="fa-heart like-icon" :class="likePulse ? 'fa-solid' : 'fa-regular'"></i>
<span class="like-count">{{ likeCount }}</span>
</button>
</div>
<button
type="button"
class="action-pill action-rsvp"
@@ -105,7 +116,6 @@
@click="showTrackList = false; isDrawerOpen = true"
>
<img src="https://api.iconify.design/lucide:clipboard-pen.svg?color=%23a88c6b" class="action-pill-icon" alt="" />
<!-- <span>填写</span>-->
</button>
</div>
<button
@@ -830,6 +840,11 @@ const completeIntro = () => {
scrollPageToTop()
showIntro.value = false
introOpening.value = false
if (pendingLikeBurst > 0) {
const n = pendingLikeBurst
pendingLikeBurst = 0
nextTick(() => likeBurstRef.value?.burst(n))
}
scheduleAutoScrollStart()
}
@@ -953,10 +968,17 @@ const handleSubmitBlessing = async () => {
}
}
let pendingLikeBurst = 0
const loadLikeStatus = async () => {
try {
const res = await getLikeStatus(getClientId())
likeCount.value = Number(res.data?.count) || 0
const count = Number(res.data?.count) || 0
likeCount.value = count
if (count <= 0) return
// 揭幕中则等结束后再播,避免帘幕后白播
if (showIntro.value) pendingLikeBurst = count
else nextTick(() => likeBurstRef.value?.burst(count))
} catch { /* ignore */ }
}
@@ -1104,13 +1126,36 @@ watch(
pointer-events: none;
}
.action-dock-row {
position: relative;
display: flex;
justify-content: flex-end;
align-items: center;
gap: 10px;
pointer-events: none;
z-index: 2;
}
.action-dock-row > * { pointer-events: auto; }
/* 右下点赞/填写周围扩大命中与遮罩,防止点到下方图片 */
.like-side-shield {
position: absolute;
right: 0;
bottom: 0;
width: min(52vw, 220px);
height: calc(132px + env(safe-area-inset-bottom, 0px));
pointer-events: auto;
z-index: 1;
background: transparent;
}
.like-hit-zone {
position: relative;
pointer-events: auto;
padding: 22px 26px 28px;
margin: -22px -26px -28px;
display: flex;
align-items: center;
justify-content: center;
z-index: 3;
}
.action-pill {
min-width: 52px;
min-height: 52px;
@@ -1155,6 +1200,8 @@ watch(
}
.like-fab.liked .like-count { color: #f472b6; font-weight: 600; }
.action-comment {
position: relative;
z-index: 2;
pointer-events: auto;
width: 100%;
min-height: 48px;