You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2290 lines
62 KiB
2290 lines
62 KiB
<template>
|
|
<view class="ie-page" :class="{ 'low-performance': lowPowerMode }">
|
|
<view class="aurora aurora-a"></view>
|
|
<view class="aurora aurora-b"></view>
|
|
<view class="aurora aurora-c"></view>
|
|
<view class="top-safe" :style="{ height: menuButtonInfo.top + 'px' }"></view>
|
|
|
|
<view class="float-bar">
|
|
<view class="home-back" @tap="backHome">
|
|
<text class="home-back-icon">‹</text>
|
|
<text>返回首页</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="hero">
|
|
<view class="hero-top">
|
|
<view class="hero-eyebrow">{{ timeLabel }} · {{ greeting }}</view>
|
|
<view class="perf-toggle" :class="{ active: lowPowerMode }" @tap="toggleLowPowerMode">
|
|
{{ lowPowerMode ? '⚡ 流畅' : '✨ 氛围' }}
|
|
</view>
|
|
</view>
|
|
<view class="hero-statement">
|
|
此刻有 <text class="hero-num">{{ displayAwakeCount }}</text> 个灵魂正在这片星系漂流
|
|
</view>
|
|
<!-- <view class="hero-statement second"></view> -->
|
|
<view class="hero-live daily-live" v-if="dailyQuestion.exists" @tap="goDailyQuestion">
|
|
<text class="live-dot"></text>
|
|
<text class="daily-live-tag">同频一题</text>
|
|
<text class="daily-live-text">{{ dailyQuestion.content }}</text>
|
|
<text class="daily-live-go">{{ dailyQuestion.answered ? '看答案' : '去回答' }} ›</text>
|
|
</view>
|
|
<view class="hero-profile" @tap="goUniverse">
|
|
<image class="profile-avatar-img" v-if="profile.avatarUrl" :src="profile.avatarUrl" mode="aspectFill"></image>
|
|
<view class="profile-avatar" v-else>{{ profile.avatarText || '我' }}</view>
|
|
<view class="profile-meta">
|
|
<view class="profile-name">{{ profile.anonymousName || '半匿名漂流者' }}</view>
|
|
<view class="profile-tags">{{ profileTagsText }}</view>
|
|
</view>
|
|
<view class="profile-arrow">›</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="drift-field">
|
|
<view class="spark spark-a">✦</view>
|
|
<view class="spark spark-b">✧</view>
|
|
<view class="spark spark-c">✦</view>
|
|
<view class="spark spark-d">✧</view>
|
|
|
|
<view class="danmu-lane lane-0">
|
|
<view class="lane-track">
|
|
<view class="danmu-item" v-for="(item,idx) in danmuLanes[0]" :key="idx"
|
|
:class="['tint-' + (idx % 4), item.type]" @tap="selectDrift(item)">
|
|
<text class="danmu-emoji">{{ moodEmoji(item) }}</text>
|
|
<text class="danmu-text">{{ item.text }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="danmu-lane lane-1">
|
|
<view class="lane-track">
|
|
<view class="danmu-item" v-for="(item,idx) in danmuLanes[1]" :key="idx"
|
|
:class="['tint-' + ((idx + 1) % 4), item.type]" @tap="selectDrift(item)">
|
|
<text class="danmu-emoji">{{ moodEmoji(item) }}</text>
|
|
<text class="danmu-text">{{ item.text }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="danmu-lane lane-2">
|
|
<view class="lane-track">
|
|
<view class="danmu-item" v-for="(item,idx) in danmuLanes[2]" :key="idx"
|
|
:class="['tint-' + ((idx + 2) % 4), item.type]" @tap="selectDrift(item)">
|
|
<text class="danmu-emoji">{{ moodEmoji(item) }}</text>
|
|
<text class="danmu-text">{{ item.text }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="signal-planet" :style="galaxyStyle" @touchstart.stop="startGalaxyDrag" @touchmove.stop="moveGalaxyDrag"
|
|
@touchend="endGalaxyDrag" @touchcancel="endGalaxyDrag">
|
|
<view class="galaxy-breath">
|
|
<view class="galaxy-ring ring-main"></view>
|
|
<view class="galaxy-ring ring-second"></view>
|
|
<view class="galaxy-ring ring-third"></view>
|
|
<view class="orbit-planet" v-for="(planet,index) in orbitPlanets" :key="planet.name"
|
|
:class="'orbit-planet-' + index" :style="orbitPlanetStyles[index]"></view>
|
|
<view class="galaxy-body">
|
|
<view class="liquid liquid-a"></view>
|
|
<view class="liquid liquid-b"></view>
|
|
<view class="soul-particle soul-a"></view>
|
|
<view class="soul-particle soul-b"></view>
|
|
<view class="soul-particle soul-c"></view>
|
|
<view class="planet-core">
|
|
<view class="planet-text">有人在等你</view>
|
|
<view class="planet-sub">{{ currentMode === 'i' ? '安静靠近' : '轻轻热闹' }}</view>
|
|
<view class="planet-cta">戳我 开始漂流 →</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="home-action-panel">
|
|
<view class="play-deck">
|
|
<view class="ticket" @tap="showTicketTip">
|
|
<view class="ticket-left">
|
|
<text class="ticket-icon">🎫</text>
|
|
<text class="ticket-label">今日漂流票</text>
|
|
</view>
|
|
<view class="ticket-divider"></view>
|
|
<view class="ticket-right">
|
|
<text class="ticket-num">{{ chancesLeft }}</text>
|
|
<text class="ticket-unit">张</text>
|
|
</view>
|
|
</view>
|
|
<view class="target-btn" @tap="openTargetPanel">
|
|
<text class="target-star">✦</text>
|
|
<text class="target-text">想遇见谁</text>
|
|
<text class="target-sub">偏好设置</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="daily-q-bar mood-copy-bar">
|
|
<text>“{{ displayMoodCopy }}”</text><text class="typing-cursor" v-if="displayMoodCopy.length < activeMood.copy.length"></text>
|
|
</view>
|
|
|
|
<view class="mood-strip">
|
|
<view class="mood-orbs">
|
|
<view class="mood-orb" v-for="item in moods" :key="item.key"
|
|
:class="{ active: currentMood === item.key }" @tap="changeMood(item.key)">
|
|
<view class="orb-face"><text class="orb-emoji">{{ item.icon }}</text></view>
|
|
<text class="orb-label">{{ item.label }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="target-mask" v-if="showTargetPanel" @tap="closeTargetPanel">
|
|
<view class="target-popup" @tap.stop>
|
|
<view class="target-popup-head">
|
|
<view>
|
|
<view class="target-popup-title">随机陪伴设置</view>
|
|
<view class="target-popup-sub">选择此刻想遇见的人,再开始漂流。</view>
|
|
</view>
|
|
<view class="target-close" @tap="closeTargetPanel">×</view>
|
|
</view>
|
|
<view class="target-title">找什么搭子(可选)</view>
|
|
<view class="target-row intent-row">
|
|
<view class="target-chip intent-chip" v-for="item in intents" :key="item.key"
|
|
:class="{ active: matchIntent === item.key }" @tap="toggleIntent(item.key)">
|
|
{{ item.icon }} {{ item.label }}
|
|
</view>
|
|
</view>
|
|
<view class="target-title gender-title">今天想遇见谁</view>
|
|
<view class="target-row">
|
|
<view class="target-chip" v-for="item in targetModes" :key="item.key"
|
|
:class="{ active: targetMode === item.key }" @tap="targetMode = item.key">
|
|
{{ item.label }}
|
|
</view>
|
|
</view>
|
|
<view class="target-title gender-title">匹配范围</view>
|
|
<view class="target-row">
|
|
<view class="target-chip scope-chip" v-for="item in matchScopes" :key="item.key"
|
|
:class="{ active: matchScope === item.key }" @tap="matchScope = item.key">
|
|
{{ item.label }}
|
|
</view>
|
|
</view>
|
|
<view class="target-title gender-title">想匹配的性别</view>
|
|
<view class="target-row">
|
|
<view class="target-chip gender-chip" v-for="item in targetGenders" :key="item.key"
|
|
:class="{ active: targetGender === item.key }" @tap="targetGender = item.key">
|
|
{{ item.label }}
|
|
</view>
|
|
</view>
|
|
<view class="start-match-btn" @tap="openMatch">开始随机陪伴</view>
|
|
</view>
|
|
</view>
|
|
|
|
<ie-bottom-tab active="index" :unread-count="unreadCount"></ie-bottom-tab>
|
|
|
|
<view class="match-mask" v-if="showMatch" @tap="closeMatch">
|
|
<view class="match-panel" @tap.stop>
|
|
<scroll-view scroll-y class="match-scroll">
|
|
<view class="match-banner">
|
|
<view class="match-banner-deco">✦ ✧ ✦</view>
|
|
<view class="match-label">缘分签 · 半匿名漂流者</view>
|
|
<view class="close" @tap="closeMatch">×</view>
|
|
</view>
|
|
<view class="match-body">
|
|
<view class="match-avatar-wrap">
|
|
<image class="companion-orb-img" v-if="matchedPerson.avatarUrl" :src="matchedPerson.avatarUrl" mode="aspectFill" @tap="previewMatchedPersona(0)"></image>
|
|
<view class="companion-orb" v-else :class="matchedPerson.mode || currentMode">{{ matchedPerson.avatar }}</view>
|
|
</view>
|
|
<view class="match-name">{{ matchedPerson.name }}</view>
|
|
<view class="match-online" v-if="matchedPerson.lastActiveText">
|
|
<view class="online-dot" :class="{ on: matchedOnline }"></view>
|
|
<text>{{ matchedPerson.lastActiveText }}</text>
|
|
</view>
|
|
<view class="match-intent" v-if="currentMatch && currentMatch.intentMatched">
|
|
⚡ TA 也在找{{ intentLabel(currentMatch.intent) }}
|
|
</view>
|
|
<view class="match-state">{{ modeText(matchedPerson.mode) }} · {{ genderText(matchedPerson.gender) }}</view>
|
|
<view class="match-region" v-if="matchedPerson.regionName">📍 {{ matchedPerson.regionName }}</view>
|
|
<view class="match-tags" v-if="matchedPerson.tags && matchedPerson.tags.length">
|
|
<text v-for="tag in matchedPerson.tags" :key="tag"># {{ tag }}</text>
|
|
</view>
|
|
<view class="match-state-text">{{ matchedPerson.state }}</view>
|
|
<view class="match-quote">{{ matchedPerson.quote }}</view>
|
|
<view class="match-persona" v-if="matchedPerson.personaImages && matchedPerson.personaImages.length">
|
|
<view class="match-section-title">人格卡片</view>
|
|
<scroll-view scroll-x class="match-persona-scroll">
|
|
<image class="match-persona-image" v-for="(img,index) in matchedPerson.personaImages" :key="img"
|
|
:src="img" mode="aspectFill" @tap="previewMatchedPersona(index)"></image>
|
|
</scroll-view>
|
|
</view>
|
|
<view class="match-actions">
|
|
<view class="ghost-btn" @tap="skipMatch">轻轻划过</view>
|
|
<view class="solid-btn" @tap="goChat">进入聊天 →</view>
|
|
</view>
|
|
<view class="match-groupbuy" v-if="showGroupBuyEntry" @tap="goGroupBuy">
|
|
🛍 搭子福利:一起拼一单更划算 →
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="profile-mask" v-if="showProfile" @tap="closeProfile">
|
|
<view class="profile-mini" @tap.stop>
|
|
<view class="mini-orb">◌</view>
|
|
<view class="mini-title">半匿名漂流者</view>
|
|
<view class="mini-sub">今天更适合:{{ currentMode === 'i' ? '慢一点靠近' : '轻轻热闹一下' }}</view>
|
|
<view class="mini-action" @tap="goUniverse">进入我的宇宙</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { ieHome, getIeUnreadCount, updateIeStatus, startIeMatch, getIeUserProfile, getIeDailyQuestion } from '@/common/ieApi.js'
|
|
import IeBottomTab from '@/components/ie-bottom-tab/ie-bottom-tab.vue'
|
|
|
|
export default {
|
|
components: { IeBottomTab },
|
|
data() {
|
|
return {
|
|
menuButtonInfo: { top: 44 },
|
|
hasShownOnce: false,
|
|
currentMood: 'quiet',
|
|
currentMode: 'i',
|
|
chancesLeft: 3,
|
|
unreadCount: 0,
|
|
showMatch: false,
|
|
now: new Date(),
|
|
awakeCount: 127,
|
|
onlineCountBase: 0,
|
|
displayAwakeCount: 0,
|
|
waitingCount: 49,
|
|
liveTimer: null,
|
|
unreadTimer: null,
|
|
countTimer: null,
|
|
showProfile: false,
|
|
showTargetPanel: false,
|
|
matching: false,
|
|
profileReady: false,
|
|
profile: {},
|
|
lowPowerMode: false,
|
|
targetMode: 'any',
|
|
targetGender: 'any',
|
|
matchScope: 'school',
|
|
matchIntent: '',
|
|
intents: [
|
|
{ key: 'milktea', icon: '🧋', label: '奶茶搭子' },
|
|
{ key: 'meal', icon: '🍚', label: '吃饭搭子' },
|
|
{ key: 'study', icon: '📚', label: '自习搭子' },
|
|
{ key: 'walk', icon: '🚶', label: '散步搭子' },
|
|
{ key: 'chat', icon: '💬', label: '只想聊聊' }
|
|
],
|
|
dailyQuestion: { exists: false },
|
|
activeDriftText: '',
|
|
displayMoodCopy: '对方没有催我讲话,沉默变得没那么尴尬',
|
|
moodTypeTimer: null,
|
|
galaxyRotateX: -8,
|
|
galaxyRotateY: 18,
|
|
galaxyDragging: false,
|
|
galaxyMoved: false,
|
|
galaxyStartX: 0,
|
|
galaxyStartY: 0,
|
|
galaxyLastMoveTime: 0,
|
|
galaxyAutoAngle: 0,
|
|
galaxyTimer: null,
|
|
orbitPlanets: [
|
|
{ name: 'mint', angle: 12, radiusX: 269, radiusY: 70, size: 22, speed: 1.05, color: 'rgba(169,255,231,.92)' },
|
|
{ name: 'violet', angle: 86, radiusX: 228, radiusY: 110, size: 31, speed: .72, color: 'rgba(162,155,254,.86)' },
|
|
{ name: 'peach', angle: 156, radiusX: 295, radiusY: 89, size: 18, speed: .9, color: 'rgba(255,184,209,.9)' },
|
|
{ name: 'lemon', angle: 218, radiusX: 242, radiusY: 132, size: 14, speed: 1.22, color: 'rgba(255,226,139,.88)' },
|
|
{ name: 'aqua', angle: 288, radiusX: 324, radiusY: 101, size: 26, speed: .62, color: 'rgba(132,233,255,.82)' },
|
|
{ name: 'snow', angle: 332, radiusX: 199, radiusY: 58, size: 12, speed: 1.38, color: 'rgba(255,255,255,.95)' }
|
|
],
|
|
doneText: "今天先到这里,平台下单可增加匹配次数",
|
|
moods: [{"key":"quiet","label":"想安静","icon":"🌙","copy":"对方没有催我讲话,沉默变得没那么尴尬。"},{"key":"talk","label":"想说话","icon":"💭","copy":"聊了一个很小的日常话题,心情被拉亮了一点。"},{"key":"listen","label":"听着呢","icon":"🎧","copy":"像有人坐在旁边,不需要解释为什么低落。"},{"key":"drift","label":"轻了一点","icon":"🫧","copy":"只是给今天留一点柔软的痕迹。"}],
|
|
targetModes: [{ key: 'i', label: '匹配 i 人' }, { key: 'e', label: '匹配 e 人' }, { key: 'any', label: '都可以' }],
|
|
targetGenders: [{ key: 'male', label: '男生' }, { key: 'female', label: '女生' }, { key: 'any', label: '不限' }],
|
|
matchScopes: [{ key: 'school', label: '本校区' }, { key: 'world', label: '世界用户' }],
|
|
companions: {"i":[{"name":"树荫下的风","avatar":"风","state":"在校园里发呆","quote":"可以安静待 15 分钟,不用急着找话题。"},{"name":"耳机里的云","avatar":"云","state":"刚从教室出来","quote":"今天只想慢慢说两句。"}],"e":[{"name":"便利店灯光","avatar":"光","state":"想聊点不重要的","quote":"要不要交换一句今天最荒唐的小事?"},{"name":"操场散步员","avatar":"跑","state":"刚从操场回来","quote":"我可以负责开场,你负责随便接。"}]},
|
|
matchedPerson: {},
|
|
currentMatch: null,
|
|
driftMessages: [
|
|
{ type: 'i', mood: 'quiet', text: '操场现在风很舒服' },
|
|
{ type: 'i', mood: 'listen', text: '有人在图书馆假装努力' },
|
|
{ type: 'e', mood: 'talk', text: '谁愿意陪我散步 10 分钟' },
|
|
{ type: 'i', mood: 'quiet', text: '刚刚有人有点低落' },
|
|
{ type: 'e', mood: 'talk', text: '想听一个不重要的故事' },
|
|
{ type: 'i', mood: 'drift', text: '走在路上突然有点空' }
|
|
]
|
|
}
|
|
},
|
|
computed: {
|
|
activeMood() {
|
|
return this.moods.find(item => item.key === this.currentMood) || this.moods[0]
|
|
},
|
|
matchedOnline() {
|
|
const text = this.matchedPerson.lastActiveText || ''
|
|
return text === '当前在线' || text === '刚刚在线'
|
|
},
|
|
showGroupBuyEntry() {
|
|
// 吃喝类搭子才挂拼团入口,意图越具体转化越自然
|
|
const intent = this.currentMatch && this.currentMatch.intent
|
|
return intent === 'milktea' || intent === 'meal'
|
|
},
|
|
profileTagsText() {
|
|
const tags = this.profile.interestTags || []
|
|
return tags.length ? tags.slice(0, 3).join(' · ') : (this.currentMode === 'i' ? '安静陪伴' : '轻轻热闹')
|
|
},
|
|
timeLabel() {
|
|
const hours = String(this.now.getHours()).padStart(2, '0')
|
|
const minutes = String(this.now.getMinutes()).padStart(2, '0')
|
|
return `${hours}:${minutes}`
|
|
},
|
|
greeting() {
|
|
const hour = this.now.getHours()
|
|
if (hour < 5) return '夜深了,漂流者'
|
|
if (hour < 11) return '早安,漂流者'
|
|
if (hour < 14) return '午安,漂流者'
|
|
if (hour < 18) return '下午好,漂流者'
|
|
if (hour < 23) return '晚上好,漂流者'
|
|
return '夜深了,漂流者'
|
|
},
|
|
danmuLanes() {
|
|
const lanes = [[], [], []]
|
|
this.driftMessages.forEach((item, index) => {
|
|
lanes[index % 3].push(item)
|
|
})
|
|
// Duplicate each lane so the marquee loops seamlessly.
|
|
return lanes.map(lane => lane.concat(lane))
|
|
},
|
|
galaxyStyle() {
|
|
return 'transform: translate(-50%, -50%);'
|
|
},
|
|
orbitPlanetStyles() {
|
|
return this.orbitPlanets.map((planet) => {
|
|
const angle = (planet.angle + this.galaxyRotateY + this.galaxyAutoAngle * planet.speed) * Math.PI / 180
|
|
const tilt = this.galaxyRotateX * Math.PI / 180
|
|
const depth = Math.sin(angle)
|
|
const x = Math.cos(angle) * planet.radiusX
|
|
const y = Math.sin(angle) * planet.radiusY * Math.cos(tilt) + Math.sin(tilt) * 20
|
|
const scale = 0.72 + (depth + 1) * 0.18
|
|
const opacity = 0.42 + (depth + 1) * 0.25
|
|
const zIndex = Math.round(8 + (depth + 1) * 7)
|
|
return [
|
|
`width: ${planet.size}rpx`,
|
|
`height: ${planet.size}rpx`,
|
|
`background: ${planet.color}`,
|
|
`color: ${planet.color}`,
|
|
`opacity: ${opacity}`,
|
|
`z-index: ${zIndex}`,
|
|
`transform: translate(-50%, -50%) translate(${x}rpx, ${y}rpx) scale(${scale})`
|
|
].join(';')
|
|
})
|
|
}
|
|
},
|
|
onLoad() {
|
|
if (uni.getMenuButtonBoundingClientRect) {
|
|
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
|
}
|
|
this.lowPowerMode = uni.getStorageSync('ieLowPowerMode') === '1'
|
|
this.pickCompanion()
|
|
this.loadHome()
|
|
this.loadDailyQuestion()
|
|
this.animateAwakeCount(this.awakeCount)
|
|
this.startPageTimers()
|
|
this.displayMoodCopy = this.activeMood.copy
|
|
},
|
|
onShow() {
|
|
this.startPageTimers()
|
|
if (this.hasShownOnce) {
|
|
this.loadHome()
|
|
this.loadDailyQuestion()
|
|
} else {
|
|
this.hasShownOnce = true
|
|
}
|
|
uni.authorize({
|
|
scope: 'scope.record',
|
|
success() {
|
|
|
|
},
|
|
fail() {
|
|
this.tui.toast("您未授权,语音功能可能会出现错误")
|
|
}
|
|
})
|
|
},
|
|
onHide() {
|
|
this.stopPageTimers()
|
|
},
|
|
onUnload() {
|
|
this.stopPageTimers()
|
|
},
|
|
methods: {
|
|
startPageTimers() {
|
|
if (!this.liveTimer) {
|
|
this.liveTimer = setInterval(() => {
|
|
this.now = new Date()
|
|
this.awakeCount = this.randomAwakeCount(this.onlineCountBase)
|
|
this.waitingCount = 39 + Math.floor(Math.random() * 18)
|
|
this.animateAwakeCount(this.awakeCount)
|
|
}, this.lowPowerMode ? 9000 : 4200)
|
|
}
|
|
if (!this.lowPowerMode && !this.galaxyTimer) {
|
|
this.galaxyTimer = setInterval(() => {
|
|
this.galaxyAutoAngle = (this.galaxyAutoAngle + 3.8) % 360
|
|
}, 160)
|
|
}
|
|
if (!this.unreadTimer) {
|
|
this.unreadTimer = setInterval(() => {
|
|
this.refreshUnreadCount()
|
|
}, 15000)
|
|
}
|
|
},
|
|
stopPageTimers() {
|
|
if (this.liveTimer) {
|
|
clearInterval(this.liveTimer)
|
|
this.liveTimer = null
|
|
}
|
|
if (this.unreadTimer) {
|
|
clearInterval(this.unreadTimer)
|
|
this.unreadTimer = null
|
|
}
|
|
if (this.countTimer) {
|
|
clearInterval(this.countTimer)
|
|
this.countTimer = null
|
|
}
|
|
if (this.galaxyTimer) {
|
|
clearInterval(this.galaxyTimer)
|
|
this.galaxyTimer = null
|
|
}
|
|
if (this.moodTypeTimer) {
|
|
clearInterval(this.moodTypeTimer)
|
|
this.moodTypeTimer = null
|
|
}
|
|
},
|
|
async refreshUnreadCount() {
|
|
const count = await getIeUnreadCount()
|
|
if (count === null || count === undefined) return
|
|
this.unreadCount = Number(count) || 0
|
|
},
|
|
randomBetween(min, max) {
|
|
return min + Math.floor(Math.random() * (max - min + 1))
|
|
},
|
|
randomAwakeCount(onlineCount) {
|
|
const count = Number(onlineCount) || 0
|
|
if (count > 1000) {
|
|
const min = Math.floor(count / 1000) * 1000
|
|
return this.randomBetween(min, min + 999)
|
|
}
|
|
return this.randomBetween(1000, 2000)
|
|
},
|
|
animateAwakeCount(target) {
|
|
if (this.countTimer) {
|
|
clearInterval(this.countTimer)
|
|
}
|
|
if (this.lowPowerMode) {
|
|
this.displayAwakeCount = target
|
|
return
|
|
}
|
|
const start = this.displayAwakeCount
|
|
const diff = target - start
|
|
let step = 0
|
|
this.countTimer = setInterval(() => {
|
|
step += 1
|
|
const progress = Math.min(step / 10, 1)
|
|
const eased = 1 - Math.pow(1 - progress, 3)
|
|
this.displayAwakeCount = Math.round(start + diff * eased)
|
|
if (progress >= 1) {
|
|
clearInterval(this.countTimer)
|
|
this.countTimer = null
|
|
}
|
|
}, 42)
|
|
},
|
|
pickCompanion() {
|
|
const list = this.companions[this.currentMode]
|
|
this.matchedPerson = list[Math.floor(Math.random() * list.length)]
|
|
},
|
|
toggleLowPowerMode() {
|
|
this.lowPowerMode = !this.lowPowerMode
|
|
uni.setStorageSync('ieLowPowerMode', this.lowPowerMode ? '1' : '0')
|
|
this.stopPageTimers()
|
|
this.startPageTimers()
|
|
uni.showToast({ title: this.lowPowerMode ? '已开启流畅模式' : '已开启氛围动效', icon: 'none' })
|
|
},
|
|
loadDailyQuestion() {
|
|
getIeDailyQuestion().then(res => {
|
|
if (res) this.dailyQuestion = res
|
|
}).catch(() => {})
|
|
},
|
|
goDailyQuestion() {
|
|
uni.navigateTo({ url: '/package1/ieBrowser/dailyQuestion' })
|
|
},
|
|
toggleIntent(key) {
|
|
this.matchIntent = this.matchIntent === key ? '' : key
|
|
},
|
|
intentLabel(key) {
|
|
const item = this.intents.find(intent => intent.key === key)
|
|
return item ? item.label : '搭子'
|
|
},
|
|
goGroupBuy() {
|
|
this.showMatch = false
|
|
uni.navigateTo({ url: '/package2/group/groupBuyList' })
|
|
},
|
|
async loadHome() {
|
|
const home = await ieHome()
|
|
if (!home) return
|
|
if (home.profileCompleted !== 1) {
|
|
uni.redirectTo({ url: '/package1/ieBrowser/profileSetup' })
|
|
return
|
|
}
|
|
this.profile = home.profile || {}
|
|
this.profileReady = true
|
|
this.onlineCountBase = Number(home.onlineCount) || 0
|
|
this.awakeCount = this.randomAwakeCount(this.onlineCountBase)
|
|
this.waitingCount = home.waitingCount || this.waitingCount
|
|
this.chancesLeft = Math.max((home.dailyQuota || 3) - (home.usedQuota || 0), 0)
|
|
this.unreadCount = home.unreadCount || 0
|
|
this.currentMode = home.currentMode || this.currentMode
|
|
this.currentMood = home.currentMood || this.currentMood
|
|
this.targetMode = home.targetModePreference || this.targetMode
|
|
this.targetGender = home.targetGenderPreference || this.targetGender
|
|
if (home.hotStatuses && home.hotStatuses.length) {
|
|
this.driftMessages = home.hotStatuses.slice(0, 6).map((text, index) => ({
|
|
type: index % 2 === 0 ? 'i' : 'e',
|
|
mood: this.moods[index % this.moods.length].key,
|
|
text
|
|
}))
|
|
}
|
|
this.animateAwakeCount(this.awakeCount)
|
|
this.syncStatus()
|
|
},
|
|
syncStatus() {
|
|
if (!this.profileReady) return
|
|
const areaInfo = this.getAreaInfo()
|
|
updateIeStatus({
|
|
mode: this.currentMode,
|
|
targetMode: this.targetMode,
|
|
targetGender: this.targetGender,
|
|
mood: this.currentMood,
|
|
statusText: this.activeMood.copy,
|
|
...areaInfo,
|
|
interestTags: [this.activeMood.label]
|
|
})
|
|
},
|
|
getAreaInfo() {
|
|
try {
|
|
const area = JSON.parse(uni.getStorageSync('area') || '{}')
|
|
return {
|
|
regionId: area.id || '',
|
|
regionName: area.title || ''
|
|
}
|
|
} catch (e) {
|
|
return { regionId: '', regionName: '' }
|
|
}
|
|
},
|
|
async openMatch() {
|
|
if (this.matching) return
|
|
this.showTargetPanel = false
|
|
if (this.chancesLeft === 0) {
|
|
uni.showToast({ title: this.doneText, icon: 'none' })
|
|
return
|
|
}
|
|
const areaInfo = this.getAreaInfo()
|
|
if (this.matchScope === 'school' && !areaInfo.regionId) {
|
|
uni.showToast({ title: '请先选择校区', icon: 'none' })
|
|
return
|
|
}
|
|
this.matching = true
|
|
try {
|
|
const match = await startIeMatch({
|
|
mode: this.currentMode,
|
|
targetMode: this.targetMode,
|
|
targetGender: this.targetGender,
|
|
matchScope: this.matchScope,
|
|
intent: this.matchIntent || '',
|
|
mood: this.currentMood,
|
|
...areaInfo,
|
|
interestTags: [this.activeMood.label]
|
|
})
|
|
if (!match || !match.roomId) {
|
|
uni.showToast({ title: (match && match.failReason) || '暂时没有同频的人', icon: 'none' })
|
|
return
|
|
}
|
|
this.currentMatch = match
|
|
this.matchedPerson = {
|
|
avatar: match.avatarText || '◌',
|
|
avatarUrl: match.avatarUrl || '',
|
|
name: match.anonymousName || '半匿名 漂流者',
|
|
mode: match.mode || this.currentMode,
|
|
gender: match.gender || '',
|
|
regionName: match.regionName || '',
|
|
tags: match.interestTags || [],
|
|
personaImages: match.personaImages || [],
|
|
state: match.stateText || '也在等一句轻轻的回应',
|
|
quote: match.quoteText || '可以先安静待一会,不用急着找话题。',
|
|
lastActiveText: match.lastActiveText || ''
|
|
}
|
|
await this.loadMatchedProfile(match.targetUserId)
|
|
// 匹配成功即消耗一次机会,与服务端 usedQuota 保持一致
|
|
this.chancesLeft = Math.max(this.chancesLeft - 1, 0)
|
|
this.showMatch = true
|
|
} finally {
|
|
this.matching = false
|
|
}
|
|
},
|
|
async loadMatchedProfile(targetUserId) {
|
|
if (!targetUserId) return
|
|
// 资料拉取失败不应阻断匹配成功弹窗,弹窗数据已有 match 兜底
|
|
const profile = await getIeUserProfile(targetUserId).catch(() => null)
|
|
if (!profile || profile.exists === false) return
|
|
this.matchedPerson = {
|
|
...this.matchedPerson,
|
|
avatar: profile.avatarText || this.matchedPerson.avatar,
|
|
avatarUrl: profile.avatarUrl || this.matchedPerson.avatarUrl || '',
|
|
name: profile.anonymousName || this.matchedPerson.name,
|
|
mode: profile.currentMode || this.matchedPerson.mode,
|
|
gender: profile.gender || this.matchedPerson.gender,
|
|
regionName: profile.regionName || this.matchedPerson.regionName || '',
|
|
tags: profile.interestTags || [],
|
|
personaImages: profile.personaImages || [],
|
|
state: this.profileStateText(profile),
|
|
quote: profile.intro || this.matchedPerson.quote
|
|
}
|
|
},
|
|
profileStateText(profile) {
|
|
const mode = profile.currentMode === 'e' ? '轻轻热闹' : '安静靠近'
|
|
const tags = profile.interestTags && profile.interestTags.length ? profile.interestTags.slice(0, 2).join(' · ') : '此刻在线'
|
|
return `${mode} · ${tags}`
|
|
},
|
|
modeText(mode) {
|
|
return mode === 'e' ? 'e 人' : 'i 人'
|
|
},
|
|
moodEmoji(item) {
|
|
const map = { quiet: '🌙', talk: '💭', listen: '🎧', drift: '🫧' }
|
|
return map[item.mood] || (item.type === 'e' ? '⚡' : '🌱')
|
|
},
|
|
genderText(gender) {
|
|
if (gender === 'male') return '男生'
|
|
if (gender === 'female') return '女生'
|
|
return '性别未设置'
|
|
},
|
|
previewMatchedPersona(index) {
|
|
const images = this.matchedPerson.personaImages || []
|
|
if (!images.length) return
|
|
uni.previewImage({ urls: images, current: images[index] })
|
|
},
|
|
closeMatch() { this.showMatch = false },
|
|
showTicketTip() {
|
|
uni.showToast({ title: '平台下单,订单完成可获得3张漂流票哦', icon: 'none' })
|
|
},
|
|
toggleMode() {
|
|
this.currentMode = this.currentMode === 'i' ? 'e' : 'i'
|
|
this.syncStatus()
|
|
},
|
|
changeMood(key) {
|
|
this.currentMood = key
|
|
this.playMoodCopy(this.activeMood.copy)
|
|
this.syncStatus()
|
|
},
|
|
selectDrift(item) {
|
|
this.currentMood = item.mood
|
|
this.currentMode = item.type
|
|
this.playMoodCopy(this.activeMood.copy)
|
|
this.syncStatus()
|
|
this.activeDriftText = this.activeDriftText === item.text ? '' : item.text
|
|
},
|
|
playMoodCopy(text) {
|
|
if (this.moodTypeTimer) {
|
|
clearInterval(this.moodTypeTimer)
|
|
this.moodTypeTimer = null
|
|
}
|
|
const chars = Array.from(text)
|
|
let index = 0
|
|
this.displayMoodCopy = ''
|
|
this.moodTypeTimer = setInterval(() => {
|
|
index += 1
|
|
this.displayMoodCopy = chars.slice(0, index).join('')
|
|
if (index >= chars.length) {
|
|
clearInterval(this.moodTypeTimer)
|
|
this.moodTypeTimer = null
|
|
}
|
|
}, 42)
|
|
},
|
|
replyDrift() {
|
|
uni.showToast({ title: '可以从一句话开始', icon: 'none' })
|
|
},
|
|
likeDrift() {
|
|
uni.showToast({ title: '已轻轻回应', icon: 'none' })
|
|
},
|
|
openProfile() {
|
|
this.goUniverse()
|
|
},
|
|
openTargetPanel() {
|
|
this.showTargetPanel = true
|
|
},
|
|
closeTargetPanel() {
|
|
this.showTargetPanel = false
|
|
},
|
|
closeProfile() {
|
|
this.showProfile = false
|
|
},
|
|
getGalaxyPoint(event) {
|
|
const touch = (event.touches && event.touches[0]) || (event.changedTouches && event.changedTouches[0])
|
|
if (!touch) return null
|
|
const x = touch.pageX !== undefined ? touch.pageX : touch.clientX
|
|
const y = touch.pageY !== undefined ? touch.pageY : touch.clientY
|
|
if (x === undefined || y === undefined) return null
|
|
return { x, y }
|
|
},
|
|
startGalaxyDrag(event) {
|
|
const point = this.getGalaxyPoint(event)
|
|
if (!point) return
|
|
this.galaxyDragging = true
|
|
this.galaxyMoved = false
|
|
this.galaxyStartX = point.x
|
|
this.galaxyStartY = point.y
|
|
},
|
|
moveGalaxyDrag(event) {
|
|
if (!this.galaxyDragging) return
|
|
const now = Date.now()
|
|
if (now - this.galaxyLastMoveTime < 32) return
|
|
this.galaxyLastMoveTime = now
|
|
const point = this.getGalaxyPoint(event)
|
|
if (!point) return
|
|
const deltaX = point.x - this.galaxyStartX
|
|
const deltaY = point.y - this.galaxyStartY
|
|
if (Math.abs(deltaX) + Math.abs(deltaY) > 4) {
|
|
this.galaxyMoved = true
|
|
}
|
|
this.galaxyRotateY = (this.galaxyRotateY + deltaX * 0.82) % 360
|
|
this.galaxyRotateX = Math.max(-48, Math.min(48, this.galaxyRotateX - deltaY * 0.28))
|
|
this.galaxyStartX = point.x
|
|
this.galaxyStartY = point.y
|
|
},
|
|
endGalaxyDrag() {
|
|
if (!this.galaxyDragging) return
|
|
this.galaxyDragging = false
|
|
if (!this.galaxyMoved) {
|
|
this.goMatch()
|
|
}
|
|
},
|
|
skipMatch() {
|
|
this.showMatch = false
|
|
uni.showToast({ title: "这次轻轻划过了", icon: 'none' })
|
|
},
|
|
goChat() {
|
|
this.showMatch = false
|
|
const room = this.currentMatch ? '&roomId=' + this.currentMatch.roomId + '&targetUserId=' + this.currentMatch.targetUserId +
|
|
'&name=' + encodeURIComponent(this.matchedPerson.name || '') +
|
|
'&avatar=' + encodeURIComponent(this.matchedPerson.avatar || '') +
|
|
'&avatarUrl=' + encodeURIComponent(this.matchedPerson.avatarUrl || '') +
|
|
'"e=' + encodeURIComponent(this.matchedPerson.quote || '') : ''
|
|
uni.navigateTo({ url: '/package1/ieBrowser/chat?mode=' + this.currentMode + '&mood=' + this.currentMood + room })
|
|
},
|
|
async goMatch() {
|
|
await this.openMatch()
|
|
},
|
|
goMatchPage() {
|
|
uni.navigateTo({ url: '/package1/ieBrowser/match?mode=' + this.currentMode + '&mood=' + this.currentMood + '&targetMode=' + this.targetMode + '&targetGender=' + this.targetGender + '&matchScope=' + this.matchScope + '&intent=' + (this.matchIntent || '') })
|
|
},
|
|
goRecords() { uni.navigateTo({ url: '/package1/ieBrowser/chatList' }) },
|
|
goArchive() { uni.navigateTo({ url: '/package1/ieBrowser/universe' }) },
|
|
goFate() { uni.navigateTo({ url: '/package1/ieBrowser/fate' }) },
|
|
goMessages() { uni.navigateTo({ url: '/package1/ieBrowser/messages?unreadCount=' + encodeURIComponent(String(this.unreadCount || 0)) }) },
|
|
goUniverse() { uni.navigateTo({ url: '/package1/ieBrowser/universe?unreadCount=' + encodeURIComponent(String(this.unreadCount || 0)) }) },
|
|
backHome() { uni.switchTab({ url: '/pages/index/index' }) }
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
page {
|
|
background: #f7f9ff;
|
|
}
|
|
|
|
/* ============ 页面底色:通透极光星系 ============ */
|
|
.ie-page {
|
|
position: relative;
|
|
min-height: 100vh;
|
|
padding: 0 32rpx 230rpx;
|
|
box-sizing: border-box;
|
|
color: #161b2e;
|
|
overflow: hidden;
|
|
background:
|
|
radial-gradient(circle at 12% 8%, rgba(221, 231, 255, .9), transparent 320rpx),
|
|
radial-gradient(circle at 90% 16%, rgba(169, 255, 231, .5), transparent 340rpx),
|
|
radial-gradient(circle at 16% 66%, rgba(255, 214, 165, .42), transparent 360rpx),
|
|
radial-gradient(circle at 88% 76%, rgba(255, 184, 209, .3), transparent 400rpx),
|
|
linear-gradient(180deg, #fbfdff 0%, #eef4ff 56%, #fff5ea 100%);
|
|
}
|
|
|
|
/* 星点纹理 */
|
|
.ie-page::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
opacity: .1;
|
|
background-image:
|
|
radial-gradient(circle, rgba(22, 27, 46, .4) 0 1rpx, transparent 1rpx),
|
|
radial-gradient(circle, rgba(108, 92, 231, .3) 0 1rpx, transparent 1rpx);
|
|
background-size: 46rpx 46rpx, 74rpx 74rpx;
|
|
}
|
|
|
|
.aurora {
|
|
position: absolute;
|
|
border-radius: 50%;
|
|
filter: blur(60rpx);
|
|
pointer-events: none;
|
|
animation: auroraDrift 10s ease-in-out infinite;
|
|
}
|
|
|
|
.aurora-a {
|
|
top: 140rpx;
|
|
right: -120rpx;
|
|
width: 380rpx;
|
|
height: 380rpx;
|
|
background: rgba(162, 155, 254, .3);
|
|
}
|
|
|
|
.aurora-b {
|
|
left: -160rpx;
|
|
top: 560rpx;
|
|
width: 420rpx;
|
|
height: 420rpx;
|
|
background: rgba(169, 255, 231, .4);
|
|
animation-delay: 2s;
|
|
}
|
|
|
|
.aurora-c {
|
|
right: -100rpx;
|
|
bottom: 240rpx;
|
|
width: 340rpx;
|
|
height: 340rpx;
|
|
background: rgba(255, 184, 209, .3);
|
|
animation-delay: 4s;
|
|
}
|
|
|
|
/* ============ 顶部悬浮条 ============ */
|
|
.float-bar {
|
|
position: relative;
|
|
z-index: 5;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-top: 14rpx;
|
|
}
|
|
|
|
.home-back {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 58rpx;
|
|
padding: 0 22rpx 0 12rpx;
|
|
border: 1rpx solid rgba(255, 255, 255, .88);
|
|
border-radius: 999rpx;
|
|
color: rgba(22, 27, 46, .66);
|
|
background: rgba(255, 255, 255, .66);
|
|
backdrop-filter: blur(20rpx);
|
|
box-shadow: 0 14rpx 36rpx rgba(96, 112, 160, .12), inset 0 1rpx 0 rgba(255, 255, 255, .95);
|
|
font-size: 23rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.home-back:active {
|
|
transform: scale(.95);
|
|
background: rgba(169, 255, 231, .7);
|
|
}
|
|
|
|
.home-back-icon {
|
|
margin-right: 6rpx;
|
|
padding-bottom: 6rpx;
|
|
font-size: 40rpx;
|
|
line-height: 50rpx;
|
|
font-weight: 400;
|
|
}
|
|
|
|
.perf-toggle {
|
|
flex-shrink: 0;
|
|
height: 52rpx;
|
|
line-height: 52rpx;
|
|
padding: 0 20rpx;
|
|
border-radius: 999rpx;
|
|
color: rgba(22, 27, 46, .58);
|
|
background: rgba(255, 255, 255, .66);
|
|
border: 1rpx solid rgba(255, 255, 255, .88);
|
|
box-shadow: 0 10rpx 26rpx rgba(96, 112, 160, .1);
|
|
font-size: 21rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.perf-toggle.active {
|
|
color: #11162a;
|
|
background: #a9ffe7;
|
|
}
|
|
|
|
/* ============ Hero 海报大字区 ============ */
|
|
.hero {
|
|
position: relative;
|
|
z-index: 4;
|
|
margin-top: 20rpx;
|
|
animation: riseIn .5s ease both;
|
|
}
|
|
|
|
.hero-top {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.hero-eyebrow {
|
|
display: inline-block;
|
|
padding: 8rpx 22rpx;
|
|
border-radius: 999rpx;
|
|
color: #5b4fd6;
|
|
background: rgba(139, 124, 255, .12);
|
|
font-size: 22rpx;
|
|
font-weight: 800;
|
|
letter-spacing: 2rpx;
|
|
}
|
|
|
|
.hero-statement {
|
|
margin-top: 14rpx;
|
|
font-size: 38rpx;
|
|
line-height: 54rpx;
|
|
font-weight: 900;
|
|
letter-spacing: -1rpx;
|
|
color: #161b2e;
|
|
}
|
|
|
|
.hero-statement.second {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.hero-num {
|
|
display: inline-block;
|
|
margin: 0 6rpx;
|
|
padding-right: 4rpx;
|
|
font-size: 54rpx;
|
|
font-weight: 900;
|
|
color: #6c5ce7;
|
|
background: linear-gradient(115deg, #6c5ce7 10%, #00cba9 55%, #ff7eb3 95%);
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
animation: countPop .42s ease;
|
|
}
|
|
|
|
.hero-live {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
max-width: 100%;
|
|
margin-top: 12rpx;
|
|
padding: 8rpx 22rpx;
|
|
border-radius: 999rpx;
|
|
color: rgba(22, 27, 46, .62);
|
|
background: rgba(255, 255, 255, .6);
|
|
border: 1rpx solid rgba(255, 255, 255, .88);
|
|
backdrop-filter: blur(16rpx);
|
|
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, .92), 0 10rpx 28rpx rgba(96, 112, 160, .08);
|
|
font-size: 23rpx;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.daily-live {
|
|
box-sizing: border-box;
|
|
gap: 10rpx;
|
|
padding-right: 18rpx;
|
|
}
|
|
|
|
.live-dot {
|
|
width: 14rpx;
|
|
height: 14rpx;
|
|
border-radius: 50%;
|
|
background: #2bd9a4;
|
|
animation: liveDotPulse 1.8s ease-out infinite;
|
|
}
|
|
|
|
.daily-live-tag,
|
|
.daily-live-go {
|
|
flex-shrink: 0;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.daily-live-tag {
|
|
color: #6c5ce7;
|
|
}
|
|
|
|
.daily-live-text {
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
color: rgba(22, 27, 46, .66);
|
|
}
|
|
|
|
.daily-live-go {
|
|
color: #8b7cff;
|
|
font-size: 21rpx;
|
|
}
|
|
|
|
.hero-profile {
|
|
display: flex;
|
|
align-items: center;
|
|
width: fit-content;
|
|
max-width: 600rpx;
|
|
margin-top: 14rpx;
|
|
padding: 10rpx 22rpx 10rpx 10rpx;
|
|
border-radius: 999rpx;
|
|
background: rgba(255, 255, 255, .56);
|
|
border: 1rpx solid rgba(255, 255, 255, .82);
|
|
box-shadow: 0 14rpx 40rpx rgba(96, 112, 160, .1);
|
|
transition: transform .16s ease;
|
|
}
|
|
|
|
.hero-profile:active {
|
|
transform: scale(.97);
|
|
}
|
|
|
|
.profile-avatar,
|
|
.profile-avatar-img {
|
|
width: 64rpx;
|
|
height: 64rpx;
|
|
margin-right: 16rpx;
|
|
border-radius: 50%;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.profile-avatar {
|
|
text-align: center;
|
|
line-height: 64rpx;
|
|
color: #11162a;
|
|
background: linear-gradient(145deg, #effffb, #a9ffe7);
|
|
font-size: 26rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.profile-name {
|
|
font-size: 26rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.profile-tags {
|
|
margin-top: 4rpx;
|
|
color: rgba(22, 27, 46, .44);
|
|
font-size: 20rpx;
|
|
}
|
|
|
|
.profile-arrow {
|
|
margin-left: 18rpx;
|
|
color: rgba(22, 27, 46, .35);
|
|
font-size: 36rpx;
|
|
font-weight: 300;
|
|
}
|
|
|
|
/* ============ 漂流星域:弹幕 + 星球 ============ */
|
|
.drift-field {
|
|
position: relative;
|
|
z-index: 3;
|
|
height: 470rpx;
|
|
margin: 36rpx -32rpx 0;
|
|
}
|
|
|
|
.spark {
|
|
position: absolute;
|
|
z-index: 1;
|
|
color: rgba(108, 92, 231, .55);
|
|
font-size: 24rpx;
|
|
animation: sparkTwinkle 2.6s ease-in-out infinite;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.spark-a { left: 92rpx; top: 168rpx; }
|
|
.spark-b { right: 70rpx; top: 120rpx; color: rgba(255, 158, 194, .7); font-size: 30rpx; animation-delay: .8s; }
|
|
.spark-c { right: 160rpx; bottom: 70rpx; color: rgba(43, 217, 164, .7); animation-delay: 1.6s; }
|
|
.spark-d { left: 60rpx; bottom: 150rpx; color: rgba(255, 214, 165, .9); font-size: 28rpx; animation-delay: 2.2s; }
|
|
|
|
/* 弹幕轨道:上下留出余量,避免倾斜的气泡被裁切 */
|
|
.danmu-lane {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 2;
|
|
padding: 14rpx 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.lane-0 { top: 0; }
|
|
.lane-1 { top: 188rpx; z-index: 1; }
|
|
.lane-2 { bottom: 0; }
|
|
|
|
.lane-track {
|
|
display: flex;
|
|
align-items: center;
|
|
width: max-content;
|
|
animation: laneScroll 26s linear infinite;
|
|
}
|
|
|
|
.lane-1 .lane-track {
|
|
animation-duration: 34s;
|
|
animation-direction: reverse;
|
|
opacity: .85;
|
|
}
|
|
|
|
.lane-2 .lane-track {
|
|
animation-duration: 22s;
|
|
}
|
|
|
|
.danmu-item {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
margin-right: 56rpx;
|
|
padding: 14rpx 26rpx;
|
|
border-radius: 999rpx;
|
|
border: 1rpx solid rgba(255, 255, 255, .9);
|
|
transition: transform .16s ease;
|
|
}
|
|
|
|
.danmu-item:active {
|
|
transform: scale(1.06);
|
|
}
|
|
|
|
.danmu-item.tint-0 { background: linear-gradient(135deg, rgba(217, 250, 240, .96), rgba(255, 255, 255, .9)); transform: rotate(-1.6deg); }
|
|
.danmu-item.tint-1 { background: linear-gradient(135deg, rgba(228, 235, 255, .96), rgba(255, 255, 255, .9)); transform: rotate(1.4deg); }
|
|
.danmu-item.tint-2 { background: linear-gradient(135deg, rgba(255, 235, 211, .96), rgba(255, 255, 255, .9)); transform: rotate(-1.2deg); }
|
|
.danmu-item.tint-3 { background: linear-gradient(135deg, rgba(255, 226, 237, .96), rgba(255, 255, 255, .9)); transform: rotate(1.8deg); }
|
|
|
|
.danmu-emoji {
|
|
margin-right: 12rpx;
|
|
font-size: 28rpx;
|
|
line-height: 1;
|
|
}
|
|
|
|
.danmu-text {
|
|
color: rgba(22, 27, 46, .76);
|
|
font-size: 24rpx;
|
|
font-weight: 600;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* 中央星球 */
|
|
.signal-planet {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
z-index: 5;
|
|
width: 410rpx;
|
|
height: 410rpx;
|
|
perspective: 1180rpx;
|
|
}
|
|
|
|
.galaxy-breath {
|
|
position: absolute;
|
|
inset: 0;
|
|
animation: galaxyBreath 4.2s ease-in-out infinite;
|
|
}
|
|
|
|
.galaxy-body {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
width: 260rpx;
|
|
height: 260rpx;
|
|
transform: translate(-50%, -50%) translateZ(34rpx);
|
|
border-radius: 47% 53% 44% 56% / 56% 42% 58% 44%;
|
|
background:
|
|
radial-gradient(circle at 28% 24%, rgba(255, 255, 255, .94), rgba(255, 255, 255, 0) 38%),
|
|
radial-gradient(circle at 70% 74%, rgba(162, 155, 254, .66), rgba(162, 155, 254, 0) 46%),
|
|
linear-gradient(135deg, rgba(169, 255, 231, .78), rgba(221, 231, 255, .76) 54%, rgba(255, 184, 209, .52));
|
|
box-shadow:
|
|
0 36rpx 96rpx rgba(108, 92, 231, .22),
|
|
inset 10rpx 12rpx 34rpx rgba(255, 255, 255, .64),
|
|
inset -20rpx -22rpx 42rpx rgba(108, 92, 231, .18);
|
|
overflow: hidden;
|
|
z-index: 12;
|
|
animation: blobMorph 9s ease-in-out infinite;
|
|
}
|
|
|
|
.galaxy-body::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 28rpx;
|
|
top: 22rpx;
|
|
width: 108rpx;
|
|
height: 86rpx;
|
|
border-radius: 50%;
|
|
background: radial-gradient(circle, rgba(255, 255, 255, .85), rgba(255, 255, 255, 0) 68%);
|
|
filter: blur(2rpx);
|
|
z-index: 1;
|
|
}
|
|
|
|
.galaxy-ring {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.ring-main {
|
|
width: 480rpx;
|
|
height: 148rpx;
|
|
margin-left: -240rpx;
|
|
margin-top: -74rpx;
|
|
border: 12rpx solid rgba(111, 231, 224, .36);
|
|
box-shadow: 0 0 34rpx rgba(169, 255, 231, .32), inset 0 0 22rpx rgba(255, 255, 255, .46);
|
|
transform: rotateX(66deg) rotateZ(-14deg);
|
|
animation: ringDrift 18s linear infinite;
|
|
}
|
|
|
|
.ring-second {
|
|
width: 396rpx;
|
|
height: 120rpx;
|
|
margin-left: -198rpx;
|
|
margin-top: -60rpx;
|
|
border: 4rpx solid rgba(162, 155, 254, .38);
|
|
transform: rotateX(72deg) rotateZ(24deg) translateZ(24rpx);
|
|
animation: ringDrift 24s linear infinite reverse;
|
|
}
|
|
|
|
.ring-third {
|
|
width: 318rpx;
|
|
height: 318rpx;
|
|
margin-left: -159rpx;
|
|
margin-top: -159rpx;
|
|
border: 3rpx solid rgba(255, 214, 165, .36);
|
|
transform: rotateX(18deg) rotateY(64deg);
|
|
animation: ringDrift 30s linear infinite;
|
|
}
|
|
|
|
.orbit-planet {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
box-shadow:
|
|
0 0 18rpx rgba(255, 255, 255, .72),
|
|
0 0 34rpx currentColor,
|
|
inset 3rpx 4rpx 8rpx rgba(255, 255, 255, .68),
|
|
inset -4rpx -5rpx 10rpx rgba(108, 92, 231, .18);
|
|
transition: transform .16s linear, opacity .16s linear;
|
|
}
|
|
|
|
.orbit-planet::after {
|
|
content: '';
|
|
position: absolute;
|
|
left: 18%;
|
|
top: 16%;
|
|
width: 34%;
|
|
height: 28%;
|
|
border-radius: 50%;
|
|
background: rgba(255, 255, 255, .86);
|
|
filter: blur(1rpx);
|
|
}
|
|
|
|
.liquid {
|
|
position: absolute;
|
|
border-radius: 45%;
|
|
filter: blur(2rpx);
|
|
}
|
|
|
|
.liquid-a {
|
|
left: -46rpx;
|
|
top: 16rpx;
|
|
width: 250rpx;
|
|
height: 226rpx;
|
|
background: rgba(169, 255, 231, .58);
|
|
animation: liquidMove 7s ease-in-out infinite;
|
|
}
|
|
|
|
.liquid-b {
|
|
right: -60rpx;
|
|
bottom: -20rpx;
|
|
width: 238rpx;
|
|
height: 232rpx;
|
|
background: rgba(139, 124, 255, .28);
|
|
animation: liquidMove 8s ease-in-out infinite reverse;
|
|
}
|
|
|
|
.soul-particle {
|
|
position: absolute;
|
|
width: 8rpx;
|
|
height: 8rpx;
|
|
border-radius: 50%;
|
|
background: rgba(255, 255, 255, .86);
|
|
box-shadow: 0 0 18rpx rgba(255, 255, 255, .8);
|
|
z-index: 2;
|
|
animation: soulFloat 5s ease-in-out infinite;
|
|
}
|
|
|
|
.soul-a { left: 78rpx; top: 66rpx; }
|
|
.soul-b { right: 70rpx; top: 116rpx; animation-delay: 1.2s; }
|
|
.soul-c { left: 142rpx; bottom: 70rpx; animation-delay: 2s; }
|
|
|
|
.planet-core {
|
|
position: relative;
|
|
z-index: 2;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-align: center;
|
|
}
|
|
|
|
.planet-text {
|
|
font-size: 32rpx;
|
|
line-height: 44rpx;
|
|
font-weight: 800;
|
|
color: #161b2e;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.planet-sub {
|
|
margin-top: 8rpx;
|
|
color: rgba(22, 27, 46, .5);
|
|
font-size: 23rpx;
|
|
animation: subBreath 3s ease-in-out infinite;
|
|
}
|
|
|
|
.planet-cta {
|
|
margin-top: 16rpx;
|
|
padding: 8rpx 20rpx;
|
|
border-radius: 999rpx;
|
|
color: #5b4fd6;
|
|
background: rgba(255, 255, 255, .78);
|
|
box-shadow: 0 8rpx 22rpx rgba(108, 92, 231, .2), inset 0 1rpx 0 rgba(255, 255, 255, .95);
|
|
font-size: 20rpx;
|
|
font-weight: 800;
|
|
letter-spacing: 1rpx;
|
|
animation: ctaBreath 2.2s ease-in-out infinite;
|
|
}
|
|
|
|
/* ============ 底部功能面板 ============ */
|
|
.home-action-panel {
|
|
position: relative;
|
|
z-index: 4;
|
|
margin-top: 26rpx;
|
|
padding: 14rpx 14rpx 18rpx;
|
|
border-radius: 32rpx;
|
|
background:
|
|
linear-gradient(180deg, rgba(255, 255, 255, .82), rgba(255, 255, 255, .68)),
|
|
radial-gradient(circle at 16% 0%, rgba(169, 255, 231, .28), transparent 220rpx),
|
|
radial-gradient(circle at 88% 22%, rgba(162, 155, 254, .2), transparent 240rpx);
|
|
border: 1rpx solid rgba(255, 255, 255, .9);
|
|
backdrop-filter: blur(22rpx);
|
|
box-shadow: 0 22rpx 70rpx rgba(96, 112, 160, .14), inset 0 1rpx 0 rgba(255, 255, 255, .92);
|
|
}
|
|
|
|
.play-deck {
|
|
display: flex;
|
|
align-items: stretch;
|
|
top: 12rpx;
|
|
gap: 12rpx;
|
|
}
|
|
|
|
.ticket {
|
|
flex: 1.3;
|
|
display: flex;
|
|
align-items: stretch;
|
|
min-height: 94rpx;
|
|
border-radius: 24rpx;
|
|
overflow: hidden;
|
|
background: #ffffff;
|
|
box-shadow: 0 12rpx 30rpx rgba(96, 112, 160, .12);
|
|
transition: transform .16s ease;
|
|
}
|
|
|
|
.ticket:active {
|
|
transform: scale(.95);
|
|
}
|
|
|
|
.ticket-left {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10rpx;
|
|
padding: 0 12rpx 0 18rpx;
|
|
background: linear-gradient(135deg, #dffef4, #aef5dd);
|
|
}
|
|
|
|
.ticket-icon {
|
|
font-size: 34rpx;
|
|
}
|
|
|
|
.ticket-label {
|
|
color: #0e4a35;
|
|
font-size: 22rpx;
|
|
font-weight: 900;
|
|
letter-spacing: 1rpx;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.ticket-divider {
|
|
position: relative;
|
|
width: 0;
|
|
margin: 14rpx 0;
|
|
border-left: 3rpx dashed rgba(22, 27, 46, .18);
|
|
}
|
|
|
|
.ticket-divider::before,
|
|
.ticket-divider::after {
|
|
content: '';
|
|
position: absolute;
|
|
left: -11rpx;
|
|
width: 20rpx;
|
|
height: 20rpx;
|
|
border-radius: 50%;
|
|
background: #f1f5fd;
|
|
}
|
|
|
|
.ticket-divider::before { top: -24rpx; }
|
|
.ticket-divider::after { bottom: -24rpx; }
|
|
|
|
.ticket-right {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6rpx;
|
|
min-width: 106rpx;
|
|
padding: 0 16rpx;
|
|
}
|
|
|
|
.ticket-num {
|
|
font-size: 46rpx;
|
|
font-weight: 900;
|
|
color: #6c5ce7;
|
|
background: linear-gradient(120deg, #6c5ce7, #00b894);
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
}
|
|
|
|
.ticket-unit {
|
|
color: rgba(22, 27, 46, .45);
|
|
font-size: 20rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.target-btn {
|
|
flex: 1;
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 4rpx;
|
|
min-height: 94rpx;
|
|
border-radius: 24rpx;
|
|
overflow: hidden;
|
|
color: #fff;
|
|
background: linear-gradient(135deg, #6c5ce7, #a29bfe);
|
|
box-shadow: 0 14rpx 34rpx rgba(108, 92, 231, .28);
|
|
transition: transform .16s ease;
|
|
animation: entryWiggle 5s ease-in-out infinite;
|
|
}
|
|
|
|
.target-btn:active {
|
|
transform: scale(.95);
|
|
}
|
|
|
|
.target-star {
|
|
position: absolute;
|
|
right: 16rpx;
|
|
top: 10rpx;
|
|
color: #ffe28b;
|
|
font-size: 26rpx;
|
|
animation: sparkTwinkle 1.6s ease-in-out infinite;
|
|
}
|
|
|
|
.target-text {
|
|
font-size: 27rpx;
|
|
font-weight: 900;
|
|
letter-spacing: 1rpx;
|
|
}
|
|
|
|
.target-sub {
|
|
color: rgba(255, 255, 255, .72);
|
|
font-size: 18rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* ============ 心情星球带 ============ */
|
|
.daily-q-bar {
|
|
position: relative;
|
|
z-index: 4;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12rpx;
|
|
margin-top: 28rpx;
|
|
padding: 22rpx 18rpx;
|
|
border-radius: 999rpx;
|
|
background: rgba(255, 255, 255, .76);
|
|
border: 1rpx solid rgba(255, 255, 255, .8);
|
|
box-shadow: 0 10rpx 26rpx rgba(96, 112, 160, .1);
|
|
}
|
|
|
|
.daily-q-bar:active {
|
|
transform: scale(.98);
|
|
}
|
|
|
|
.mood-copy-bar {
|
|
justify-content: center;
|
|
min-height: 58rpx;
|
|
color: rgba(22, 27, 46, .62);
|
|
font-size: 23rpx;
|
|
line-height: 32rpx;
|
|
text-align: center;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.daily-q-tag {
|
|
flex-shrink: 0;
|
|
padding: 6rpx 16rpx;
|
|
border-radius: 999rpx;
|
|
font-size: 20rpx;
|
|
font-weight: 800;
|
|
color: #fff;
|
|
background: linear-gradient(135deg, #7a4dff, #ff7eb3);
|
|
}
|
|
|
|
.daily-q-text {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
font-size: 24rpx;
|
|
font-weight: 700;
|
|
color: rgba(22, 27, 46, .76);
|
|
}
|
|
|
|
.daily-q-go {
|
|
flex-shrink: 0;
|
|
font-size: 22rpx;
|
|
font-weight: 800;
|
|
color: #7a4dff;
|
|
}
|
|
|
|
.mood-strip {
|
|
position: relative;
|
|
z-index: 4;
|
|
margin-top: 22rpx;
|
|
padding: 2rpx 4rpx 0;
|
|
}
|
|
|
|
.strip-tag {
|
|
display: inline-block;
|
|
padding: 8rpx 22rpx;
|
|
border-radius: 999rpx;
|
|
color: #7a4b12;
|
|
background: linear-gradient(135deg, #ffe9c9, #ffd6a5);
|
|
box-shadow: 0 10rpx 24rpx rgba(255, 195, 130, .3);
|
|
font-size: 22rpx;
|
|
font-weight: 900;
|
|
letter-spacing: 1rpx;
|
|
transform: rotate(-2deg);
|
|
}
|
|
|
|
.mood-orbs {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 0 8rpx;
|
|
}
|
|
|
|
.mood-orb {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 8rpx;
|
|
}
|
|
|
|
.orb-face {
|
|
position: relative;
|
|
width: 94rpx;
|
|
height: 94rpx;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #ffffff;
|
|
border: 1rpx solid rgba(255, 255, 255, .92);
|
|
box-shadow: 0 12rpx 28rpx rgba(96, 112, 160, .14), inset 0 -8rpx 14rpx rgba(139, 124, 255, .07);
|
|
transition: transform .2s cubic-bezier(.34, 1.56, .64, 1), background .24s ease, box-shadow .24s ease;
|
|
}
|
|
|
|
.mood-orb:active .orb-face {
|
|
transform: scale(.86);
|
|
}
|
|
|
|
.mood-orb.active .orb-face {
|
|
background: linear-gradient(145deg, #eafff8, #a9ffe7);
|
|
box-shadow: 0 16rpx 36rpx rgba(43, 217, 164, .34);
|
|
transform: translateY(-8rpx) scale(1.1);
|
|
}
|
|
|
|
.mood-orb.active .orb-face::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: -12rpx;
|
|
border-radius: 50%;
|
|
border: 3rpx dashed rgba(43, 217, 164, .6);
|
|
animation: orbSpin 9s linear infinite;
|
|
}
|
|
|
|
.orb-emoji {
|
|
font-size: 44rpx;
|
|
line-height: 1;
|
|
}
|
|
|
|
.mood-orb.active .orb-emoji {
|
|
animation: emojiBounce .42s cubic-bezier(.34, 1.56, .64, 1);
|
|
}
|
|
|
|
.orb-label {
|
|
color: rgba(22, 27, 46, .5);
|
|
font-size: 22rpx;
|
|
font-weight: 700;
|
|
transition: color .2s ease;
|
|
}
|
|
|
|
.mood-orb.active .orb-label {
|
|
color: #0e4a35;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.say-bubble {
|
|
position: relative;
|
|
width: fit-content;
|
|
max-width: 620rpx;
|
|
margin: 24rpx auto 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 12rpx 24rpx;
|
|
border-radius: 999rpx;
|
|
color: rgba(22, 27, 46, .58);
|
|
background: rgba(255, 255, 255, .76);
|
|
border: 1rpx solid rgba(255, 255, 255, .94);
|
|
box-shadow: 0 12rpx 34rpx rgba(139, 124, 255, .1), inset 0 1rpx 0 rgba(255, 255, 255, .95);
|
|
font-size: 23rpx;
|
|
line-height: 34rpx;
|
|
text-align: center;
|
|
font-weight: 700;
|
|
min-height: 34rpx;
|
|
}
|
|
|
|
.typing-cursor {
|
|
display: inline-block;
|
|
width: 3rpx;
|
|
height: 28rpx;
|
|
margin-left: 6rpx;
|
|
border-radius: 999rpx;
|
|
background: rgba(108, 92, 231, .58);
|
|
vertical-align: -4rpx;
|
|
animation: typingCursor .86s steps(1) infinite;
|
|
}
|
|
|
|
/* ============ 随机陪伴设置弹层 ============ */
|
|
.target-mask {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 30;
|
|
display: flex;
|
|
align-items: flex-end;
|
|
padding: 32rpx 30rpx 136rpx;
|
|
box-sizing: border-box;
|
|
background: rgba(22, 27, 46, .18);
|
|
backdrop-filter: blur(16rpx);
|
|
}
|
|
|
|
.target-popup {
|
|
width: 100%;
|
|
padding: 34rpx 30rpx 30rpx;
|
|
border-radius: 42rpx;
|
|
border: 1rpx solid rgba(255, 255, 255, .9);
|
|
background:
|
|
linear-gradient(135deg, rgba(255, 255, 255, .96), rgba(255, 255, 255, .8)),
|
|
radial-gradient(circle at 82% 0%, rgba(169, 255, 231, .28), transparent 220rpx);
|
|
box-shadow: 0 34rpx 100rpx rgba(96, 112, 160, .22);
|
|
box-sizing: border-box;
|
|
animation: targetUp .18s ease-out both;
|
|
}
|
|
|
|
.target-popup-head {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
margin-bottom: 28rpx;
|
|
}
|
|
|
|
.target-popup-title {
|
|
color: #161b2e;
|
|
font-size: 34rpx;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.target-popup-sub {
|
|
margin-top: 8rpx;
|
|
color: rgba(22, 27, 46, .46);
|
|
font-size: 23rpx;
|
|
}
|
|
|
|
.target-close {
|
|
width: 58rpx;
|
|
height: 58rpx;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
line-height: 54rpx;
|
|
color: rgba(22, 27, 46, .5);
|
|
background: rgba(238, 244, 255, .78);
|
|
font-size: 36rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.target-title {
|
|
color: rgba(22, 27, 46, .54);
|
|
font-size: 23rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.target-row {
|
|
display: flex;
|
|
margin-top: 18rpx;
|
|
}
|
|
|
|
.intent-row {
|
|
flex-wrap: wrap;
|
|
gap: 12rpx 0;
|
|
}
|
|
|
|
.intent-chip.active {
|
|
color: #fff;
|
|
background: linear-gradient(135deg, #ff8a54, #ff5f8f);
|
|
box-shadow: 0 10rpx 24rpx rgba(255, 110, 110, .3);
|
|
}
|
|
|
|
.target-chip {
|
|
height: 62rpx;
|
|
line-height: 62rpx;
|
|
padding: 0 24rpx;
|
|
margin-right: 14rpx;
|
|
border-radius: 999rpx;
|
|
color: rgba(22, 27, 46, .52);
|
|
background: rgba(238, 244, 255, .78);
|
|
font-size: 23rpx;
|
|
font-weight: 700;
|
|
transition: transform .14s ease;
|
|
}
|
|
|
|
.target-chip:active {
|
|
transform: scale(.94);
|
|
}
|
|
|
|
.target-chip.active {
|
|
color: #11162a;
|
|
background: #a9ffe7;
|
|
}
|
|
|
|
.gender-title {
|
|
margin-top: 24rpx;
|
|
}
|
|
|
|
.start-match-btn {
|
|
height: 92rpx;
|
|
line-height: 92rpx;
|
|
margin-top: 26rpx;
|
|
border-radius: 999rpx;
|
|
text-align: center;
|
|
color: #11162a;
|
|
background: linear-gradient(135deg, #effffb, #a9ffe7 62%, #ffd6a5);
|
|
box-shadow: 0 18rpx 46rpx rgba(169, 255, 231, .3);
|
|
font-size: 29rpx;
|
|
font-weight: 900;
|
|
animation: breathButton 2.8s ease-in-out infinite;
|
|
}
|
|
|
|
.start-match-btn:active {
|
|
transform: scale(.97);
|
|
}
|
|
|
|
/* ============ 缘分签弹层 ============ */
|
|
.match-mask {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 99;
|
|
display: flex;
|
|
align-items: flex-end;
|
|
padding: 30rpx;
|
|
background: rgba(22, 27, 46, .58);
|
|
backdrop-filter: blur(24rpx);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.match-panel {
|
|
width: 100%;
|
|
max-height: 80vh;
|
|
border: 1rpx solid rgba(255, 255, 255, .9);
|
|
border-radius: 46rpx;
|
|
background: #ffffff;
|
|
box-sizing: border-box;
|
|
box-shadow: 0 34rpx 110rpx rgba(22, 27, 46, .34);
|
|
overflow: hidden;
|
|
animation: targetUp .22s ease-out both;
|
|
}
|
|
|
|
.match-scroll {
|
|
max-height: 80vh;
|
|
box-sizing: border-box;
|
|
background: linear-gradient(180deg, #ffffff 0%, #f7f9ff 100%);
|
|
}
|
|
|
|
.match-banner {
|
|
position: relative;
|
|
padding: 30rpx 34rpx 64rpx;
|
|
background:
|
|
radial-gradient(circle at 80% 20%, rgba(255, 226, 139, .3), transparent 200rpx),
|
|
linear-gradient(135deg, rgba(108, 92, 231, .92), rgba(162, 155, 254, .88));
|
|
}
|
|
|
|
.match-banner-deco {
|
|
position: absolute;
|
|
right: 90rpx;
|
|
top: 26rpx;
|
|
color: rgba(255, 255, 255, .55);
|
|
font-size: 22rpx;
|
|
letter-spacing: 8rpx;
|
|
}
|
|
|
|
.match-label {
|
|
color: rgba(255, 255, 255, .92);
|
|
font-size: 24rpx;
|
|
font-weight: 800;
|
|
letter-spacing: 2rpx;
|
|
}
|
|
|
|
.close {
|
|
position: absolute;
|
|
right: 30rpx;
|
|
top: 24rpx;
|
|
width: 52rpx;
|
|
height: 52rpx;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
line-height: 48rpx;
|
|
color: #fff;
|
|
background: rgba(255, 255, 255, .2);
|
|
font-size: 36rpx;
|
|
}
|
|
|
|
.match-body {
|
|
position: relative;
|
|
z-index: 2;
|
|
padding: 0 34rpx 34rpx;
|
|
background: linear-gradient(180deg, #ffffff 0%, #f7f9ff 100%);
|
|
}
|
|
|
|
.match-avatar-wrap {
|
|
position: relative;
|
|
z-index: 3;
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-top: -52rpx;
|
|
}
|
|
|
|
.companion-orb,
|
|
.companion-orb-img {
|
|
width: 148rpx;
|
|
height: 148rpx;
|
|
border-radius: 50%;
|
|
border: 8rpx solid rgba(255, 255, 255, .96);
|
|
background: #ffffff;
|
|
box-shadow: 0 18rpx 46rpx rgba(108, 92, 231, .24);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.companion-orb {
|
|
text-align: center;
|
|
line-height: 132rpx;
|
|
font-size: 48rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.companion-orb.i {
|
|
color: #f7f4ff;
|
|
background: linear-gradient(145deg, #8b7cff, #dde7ff);
|
|
}
|
|
|
|
.companion-orb.e {
|
|
color: #11162a;
|
|
background: linear-gradient(145deg, #a9ffe7, #ffd6a5);
|
|
}
|
|
|
|
.match-name {
|
|
margin-top: 18rpx;
|
|
text-align: center;
|
|
font-size: 36rpx;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.match-intent {
|
|
margin: 12rpx auto 0;
|
|
width: fit-content;
|
|
padding: 8rpx 24rpx;
|
|
border-radius: 999rpx;
|
|
font-size: 23rpx;
|
|
font-weight: 800;
|
|
color: #ff5f3c;
|
|
background: rgba(255, 138, 84, .12);
|
|
border: 1rpx solid rgba(255, 138, 84, .32);
|
|
}
|
|
|
|
.match-groupbuy {
|
|
margin: -10rpx 34rpx 34rpx;
|
|
padding: 18rpx;
|
|
border-radius: 22rpx;
|
|
text-align: center;
|
|
font-size: 24rpx;
|
|
font-weight: 800;
|
|
color: #7a4b12;
|
|
background: linear-gradient(135deg, #ffe9c9, #ffd6a5);
|
|
}
|
|
|
|
.match-online {
|
|
margin: 10rpx auto 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 8rpx;
|
|
width: fit-content;
|
|
padding: 6rpx 20rpx;
|
|
border-radius: 999rpx;
|
|
background: rgba(22, 27, 46, .05);
|
|
font-size: 22rpx;
|
|
color: rgba(22, 27, 46, .55);
|
|
}
|
|
|
|
.online-dot {
|
|
width: 12rpx;
|
|
height: 12rpx;
|
|
border-radius: 50%;
|
|
background: #c2c8d6;
|
|
}
|
|
|
|
.online-dot.on {
|
|
background: #3ddc97;
|
|
box-shadow: 0 0 8rpx rgba(61, 220, 151, .8);
|
|
}
|
|
|
|
.match-state {
|
|
margin-top: 8rpx;
|
|
text-align: center;
|
|
color: rgba(22, 27, 46, .48);
|
|
font-size: 23rpx;
|
|
}
|
|
|
|
.match-region {
|
|
width: fit-content;
|
|
max-width: 520rpx;
|
|
margin: 14rpx auto 0;
|
|
padding: 8rpx 20rpx;
|
|
border-radius: 999rpx;
|
|
color: #6c69d8;
|
|
background: rgba(139, 124, 255, .1);
|
|
font-size: 22rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.match-tags {
|
|
margin-top: 16rpx;
|
|
padding: 0 34rpx;
|
|
text-align: center;
|
|
}
|
|
|
|
.match-tags text {
|
|
display: inline-block;
|
|
height: 46rpx;
|
|
line-height: 46rpx;
|
|
padding: 0 18rpx;
|
|
margin: 0 8rpx 10rpx;
|
|
border-radius: 999rpx;
|
|
color: #6c69d8;
|
|
background: rgba(139, 124, 255, .1);
|
|
font-size: 21rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.match-state-text {
|
|
margin-top: 8rpx;
|
|
text-align: center;
|
|
color: rgba(22, 27, 46, .54);
|
|
font-size: 23rpx;
|
|
}
|
|
|
|
.match-quote {
|
|
margin: 26rpx 34rpx 0;
|
|
padding: 26rpx;
|
|
border-radius: 8rpx 28rpx 28rpx 28rpx;
|
|
color: rgba(22, 27, 46, .72);
|
|
background: rgba(139, 124, 255, .08);
|
|
font-size: 26rpx;
|
|
line-height: 42rpx;
|
|
}
|
|
|
|
.match-persona {
|
|
margin: 22rpx 34rpx 0;
|
|
}
|
|
|
|
.match-section-title {
|
|
margin-bottom: 14rpx;
|
|
color: rgba(22, 27, 46, .62);
|
|
font-size: 24rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.match-persona-scroll {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.match-persona-image {
|
|
display: inline-block;
|
|
width: 168rpx;
|
|
height: 208rpx;
|
|
margin-right: 16rpx;
|
|
border-radius: 26rpx;
|
|
background: rgba(22, 27, 46, .06);
|
|
box-shadow: 0 14rpx 34rpx rgba(96, 112, 160, .12);
|
|
}
|
|
|
|
.match-actions {
|
|
display: flex;
|
|
gap: 18rpx;
|
|
margin: 30rpx 34rpx 34rpx;
|
|
}
|
|
|
|
.ghost-btn,
|
|
.solid-btn {
|
|
flex: 1;
|
|
height: 90rpx;
|
|
border-radius: 999rpx;
|
|
text-align: center;
|
|
line-height: 90rpx;
|
|
font-size: 26rpx;
|
|
font-weight: 800;
|
|
transition: transform .14s ease;
|
|
}
|
|
|
|
.ghost-btn:active,
|
|
.solid-btn:active {
|
|
transform: scale(.96);
|
|
}
|
|
|
|
.ghost-btn {
|
|
color: rgba(22, 27, 46, .55);
|
|
background: rgba(238, 244, 255, .85);
|
|
}
|
|
|
|
.solid-btn {
|
|
color: #11162a;
|
|
background: linear-gradient(135deg, #a9ffe7, #8ef0ff 60%, #c9c2ff);
|
|
box-shadow: 0 16rpx 38rpx rgba(120, 200, 230, .32);
|
|
}
|
|
|
|
/* ============ 个人浮层 ============ */
|
|
.profile-mask {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 30;
|
|
display: flex;
|
|
align-items: flex-end;
|
|
padding: 34rpx;
|
|
background: rgba(22, 27, 46, .12);
|
|
backdrop-filter: blur(18rpx);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.profile-mini {
|
|
width: 100%;
|
|
padding: 40rpx 34rpx;
|
|
border-radius: 44rpx;
|
|
background: rgba(255, 255, 255, .82);
|
|
border: 1rpx solid rgba(255, 255, 255, .9);
|
|
box-shadow: 0 30rpx 90rpx rgba(96, 112, 160, .18), inset 0 1rpx 0 rgba(255, 255, 255, .96);
|
|
text-align: center;
|
|
}
|
|
|
|
.mini-orb {
|
|
width: 104rpx;
|
|
height: 104rpx;
|
|
margin: 0 auto;
|
|
border-radius: 50%;
|
|
line-height: 104rpx;
|
|
color: #fff;
|
|
background: linear-gradient(135deg, #6c5ce7, #a29bfe);
|
|
font-size: 44rpx;
|
|
}
|
|
|
|
.mini-title {
|
|
margin-top: 22rpx;
|
|
font-size: 34rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.mini-sub {
|
|
margin-top: 10rpx;
|
|
color: rgba(22, 27, 46, .5);
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.mini-action {
|
|
margin-top: 28rpx;
|
|
height: 82rpx;
|
|
line-height: 82rpx;
|
|
border-radius: 999rpx;
|
|
color: #161b2e;
|
|
background: linear-gradient(135deg, #eafff8, #a9ffe7);
|
|
font-size: 26rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* ============ 动画 ============ */
|
|
@keyframes riseIn {
|
|
from { opacity: 0; transform: translateY(20rpx); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
@keyframes auroraDrift {
|
|
0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
|
|
50% { transform: translate3d(24rpx, -30rpx, 0) scale(1.1); }
|
|
}
|
|
|
|
@keyframes laneScroll {
|
|
from { transform: translateX(0); }
|
|
to { transform: translateX(-50%); }
|
|
}
|
|
|
|
@keyframes liveDotPulse {
|
|
0% { box-shadow: 0 0 0 0 rgba(43, 217, 164, .5); }
|
|
70% { box-shadow: 0 0 0 14rpx rgba(43, 217, 164, 0); }
|
|
100% { box-shadow: 0 0 0 0 rgba(43, 217, 164, 0); }
|
|
}
|
|
|
|
@keyframes entryWiggle {
|
|
0%, 86%, 100% { transform: rotate(0); }
|
|
90% { transform: rotate(-2deg); }
|
|
94% { transform: rotate(2deg); }
|
|
98% { transform: rotate(-1deg); }
|
|
}
|
|
|
|
@keyframes sparkTwinkle {
|
|
0%, 100% { opacity: .25; transform: scale(.8) rotate(0deg); }
|
|
50% { opacity: 1; transform: scale(1.15) rotate(20deg); }
|
|
}
|
|
|
|
@keyframes ctaBreath {
|
|
0%, 100% { transform: scale(1); opacity: .85; }
|
|
50% { transform: scale(1.06); opacity: 1; }
|
|
}
|
|
|
|
@keyframes countPop {
|
|
0% { transform: translateY(8rpx) scale(.96); opacity: .55; }
|
|
70% { transform: translateY(-3rpx) scale(1.04); opacity: 1; }
|
|
100% { transform: translateY(0) scale(1); }
|
|
}
|
|
|
|
@keyframes orbSpin {
|
|
from { transform: rotate(0deg); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
@keyframes emojiBounce {
|
|
0% { transform: scale(.6); }
|
|
60% { transform: scale(1.25); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
@keyframes blobMorph {
|
|
0%, 100% { border-radius: 47% 53% 44% 56% / 56% 42% 58% 44%; }
|
|
50% { border-radius: 58% 42% 55% 45% / 44% 58% 42% 56%; }
|
|
}
|
|
|
|
@keyframes soulFloat {
|
|
0%, 100% { transform: translate3d(0, 0, 0); opacity: .36; }
|
|
50% { transform: translate3d(12rpx, -18rpx, 0); opacity: .95; }
|
|
}
|
|
|
|
@keyframes subBreath {
|
|
0%, 100% { opacity: .75; }
|
|
50% { opacity: 1; }
|
|
}
|
|
|
|
@keyframes typingCursor {
|
|
0%, 48% { opacity: 1; }
|
|
49%, 100% { opacity: 0; }
|
|
}
|
|
|
|
@keyframes galaxyBreath {
|
|
0%, 100% { transform: scale(.98); }
|
|
50% { transform: scale(1.035); }
|
|
}
|
|
|
|
@keyframes ringDrift {
|
|
from { filter: hue-rotate(0deg); }
|
|
to { filter: hue-rotate(18deg); }
|
|
}
|
|
|
|
@keyframes breathButton {
|
|
0%, 100% { transform: scale(1); }
|
|
50% { transform: scale(1.015); }
|
|
}
|
|
|
|
@keyframes liquidMove {
|
|
0%, 100% { transform: translate(0, 0) rotate(0deg) scale(1); }
|
|
50% { transform: translate(22rpx, 18rpx) rotate(18deg) scale(1.12); }
|
|
}
|
|
|
|
@keyframes targetUp {
|
|
from { transform: translateY(42rpx); opacity: 0; }
|
|
to { transform: translateY(0); opacity: 1; }
|
|
}
|
|
|
|
/* ============ 流畅模式降级 ============ */
|
|
.low-performance::before,
|
|
.low-performance .aurora,
|
|
.low-performance .spark,
|
|
.low-performance .liquid,
|
|
.low-performance .soul-particle,
|
|
.low-performance .galaxy-ring,
|
|
.low-performance .orbit-planet::after {
|
|
display: none !important;
|
|
}
|
|
|
|
.low-performance .lane-track {
|
|
animation-duration: 60s;
|
|
}
|
|
|
|
.low-performance .galaxy-breath,
|
|
.low-performance .galaxy-body,
|
|
.low-performance .planet-sub,
|
|
.low-performance .planet-cta,
|
|
.low-performance .target-btn,
|
|
.low-performance .target-star,
|
|
.low-performance .mood-orb.active .orb-face::after,
|
|
.low-performance .live-dot,
|
|
.low-performance .hero-num,
|
|
.low-performance .start-match-btn,
|
|
.low-performance .typing-cursor {
|
|
animation: none !important;
|
|
}
|
|
|
|
.low-performance .galaxy-body {
|
|
box-shadow:
|
|
0 18rpx 48rpx rgba(108, 92, 231, .14),
|
|
inset 8rpx 10rpx 24rpx rgba(255, 255, 255, .52);
|
|
}
|
|
|
|
.low-performance .danmu-item,
|
|
.low-performance .hero-live,
|
|
.low-performance .home-back,
|
|
.low-performance .perf-toggle,
|
|
.low-performance .target-mask,
|
|
.low-performance .match-mask,
|
|
.low-performance .profile-mask {
|
|
backdrop-filter: none !important;
|
|
}
|
|
</style>
|
|
|