wangfukang 3 weeks ago
parent
commit
66b8524585
  1. 117
      package1/ieBrowser/chat.vue
  2. 4
      package1/ieBrowser/chatList.vue
  3. 37
      package1/ieBrowser/fate.vue
  4. 115
      package1/ieBrowser/index.vue

117
package1/ieBrowser/chat.vue

@ -32,11 +32,11 @@
<view class="timer-pill">已连接</view>
</view>
<view class="silent-modes">
<!-- <view class="silent-modes">
<view class="silent-chip" v-for="item in silentModes" :key="item" @tap="sendPresence(item)">
{{ item }}
</view>
</view>
</view> -->
<scroll-view class="messages" scroll-y :style="messagesStyle" :scroll-into-view="scrollIntoView" :scroll-with-animation="scrollAnimation"
upper-threshold="80" @scrolltoupper="loadOlderMessages">
@ -124,7 +124,7 @@
<script>
import ieSocket from '@/common/ieSocket.js'
import { finishIeRoom, reportIeRoom, blockIeUser, sendIePresence, pageIeMessages, sendIeMessage, getIeUserProfile } from '@/common/ieApi.js'
import { finishIeRoom, reportIeRoom, blockIeUser, pageIeMessages, sendIeMessage, getIeUserProfile } from '@/common/ieApi.js'
import tui from '@/common/httpRequest.js'
export default {
@ -396,11 +396,8 @@
},
sendPresence(text) {
if (!this.roomId) return
const data = { roomId: Number(this.roomId), eventType: 'presence', eventText: text }
ieSocket.sendPresence(data)
sendIePresence(this.roomId, data)
this.messages.push({ domId: 'presence-' + Date.now(), content: text, mine: true, clientMsgId: 'p-' + Date.now() })
this.scrollToBottom()
this.showEmoji = false
this.sendChatContent(text, 1)
},
toggleEmoji() {
this.voiceMode = false
@ -663,12 +660,24 @@
if (!this.targetUserId) return
const profile = await getIeUserProfile(this.targetUserId)
if (!profile) return
this.targetProfile = profile
const profileCompleted = profile.profileCompleted === 1 || !!profile.intro || !!profile.avatarUrl || (profile.interestTags && profile.interestTags.length)
const usableProfile = profile.exists !== false && profileCompleted
this.targetProfile = usableProfile ? profile : {
...profile,
anonymousName: this.companion.name,
avatarText: this.companion.avatar,
avatarUrl: this.companion.avatarUrl,
intro: this.companion.prompt,
currentMode: this.roomMode,
interestTags: profile.interestTags || [],
personaImages: profile.personaImages || []
}
if (!usableProfile) return
this.companions[this.roomMode] = {
...this.companion,
name: profile.anonymousName || this.companion.name,
avatar: profile.avatarText || this.companion.avatar,
avatarUrl: profile.avatarUrl || '',
avatarUrl: profile.avatarUrl || this.companion.avatarUrl || '',
prompt: profile.intro || this.companion.prompt
}
},
@ -747,7 +756,7 @@
.room-page {
min-height: 100vh;
padding: 0 28rpx 176rpx;
padding: 0 24rpx 176rpx;
box-sizing: border-box;
color: #161b2e;
background:
@ -793,10 +802,12 @@
.nav {
position: relative;
z-index: 1;
height: 96rpx;
z-index: 12;
min-height: 86rpx;
padding-bottom: 12rpx;
display: flex;
align-items: center;
box-sizing: content-box;
}
.back,
@ -813,25 +824,25 @@
}
.nav-avatar-wrap {
width: 66rpx;
height: 66rpx;
margin-right: 14rpx;
width: 54rpx;
height: 54rpx;
margin-right: 12rpx;
border-radius: 50%;
}
.nav-avatar,
.nav-avatar-img {
width: 66rpx;
height: 66rpx;
width: 54rpx;
height: 54rpx;
border-radius: 50%;
}
.nav-avatar {
text-align: center;
line-height: 66rpx;
line-height: 54rpx;
color: #11162a;
background: linear-gradient(145deg, #ffffff, #a9ffe7);
font-size: 26rpx;
font-size: 23rpx;
font-weight: 800;
}
@ -841,20 +852,20 @@
}
.room-name {
font-size: 31rpx;
font-size: 28rpx;
font-weight: 800;
}
.room-meta {
margin-top: 8rpx;
margin-top: 4rpx;
color: rgba(22, 27, 46, 0.46);
font-size: 21rpx;
font-size: 20rpx;
}
.timer-card,
.topic-card {
position: relative;
z-index: 1;
z-index: 2;
border: 1rpx solid rgba(255, 255, 255, 0.78);
background: rgba(255, 255, 255, 0.62);
backdrop-filter: blur(24rpx);
@ -865,19 +876,19 @@
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 22rpx;
padding: 30rpx;
border-radius: 34rpx;
margin-top: 14rpx;
padding: 22rpx 24rpx;
border-radius: 30rpx;
}
.radio-room {
position: relative;
z-index: 1;
z-index: 2;
display: flex;
align-items: center;
margin-top: 18rpx;
padding: 34rpx;
border-radius: 44rpx;
margin-top: 24rpx;
padding: 22rpx 24rpx;
border-radius: 34rpx;
background: rgba(255,255,255,.58);
border: 1rpx solid rgba(255,255,255,.78);
backdrop-filter: blur(24rpx);
@ -889,23 +900,23 @@
position: absolute;
right: -40rpx;
top: -60rpx;
width: 260rpx;
height: 260rpx;
width: 190rpx;
height: 190rpx;
border-radius: 50%;
border: 1rpx solid rgba(139,124,255,.16);
animation: radioSpin 16s linear infinite;
}
.radio-core {
width: 108rpx;
height: 108rpx;
margin-right: 24rpx;
width: 78rpx;
height: 78rpx;
margin-right: 20rpx;
border-radius: 50%;
text-align: center;
line-height: 108rpx;
line-height: 78rpx;
color: #11162a;
background: linear-gradient(145deg, #ffffff, #a9ffe7);
font-size: 30rpx;
font-size: 26rpx;
font-weight: 800;
box-shadow: 0 18rpx 48rpx rgba(169,255,231,.3);
animation: breathe 3s ease-in-out infinite;
@ -917,14 +928,14 @@
}
.radio-title {
font-size: 32rpx;
font-size: 28rpx;
font-weight: 800;
}
.radio-sub {
margin-top: 10rpx;
margin-top: 6rpx;
color: rgba(22,27,46,.52);
font-size: 24rpx;
font-size: 22rpx;
}
.silent-modes {
@ -955,20 +966,20 @@
}
.timer-title {
margin-top: 12rpx;
font-size: 30rpx;
margin-top: 8rpx;
font-size: 27rpx;
font-weight: 800;
}
.timer-pill {
width: 126rpx;
height: 70rpx;
width: 112rpx;
height: 60rpx;
border-radius: 999rpx;
text-align: center;
line-height: 70rpx;
line-height: 60rpx;
color: #09101f;
background: #dffef4;
font-size: 28rpx;
font-size: 25rpx;
font-weight: 800;
}
@ -988,8 +999,8 @@
.messages {
position: relative;
z-index: 1;
height: 58vh;
padding-top: 34rpx;
height: 64vh;
padding-top: 22rpx;
padding-bottom: 24rpx;
box-sizing: border-box;
}
@ -1005,11 +1016,11 @@
.system-line {
width: 560rpx;
margin: 0 auto 30rpx;
margin: 0 auto 22rpx;
text-align: center;
color: rgba(22, 27, 46, 0.36);
font-size: 22rpx;
line-height: 34rpx;
font-size: 20rpx;
line-height: 32rpx;
}
.hesitate-line {
@ -1030,7 +1041,7 @@
.msg-row {
display: flex;
align-items: flex-start;
margin-bottom: 30rpx;
margin-bottom: 24rpx;
}
.msg-row.mine {

4
package1/ieBrowser/chatList.vue

@ -150,9 +150,11 @@
.map(async (item) => {
const profile = await getIeUserProfile(item.targetUserId)
if (!profile) return
const usableProfile = profile.exists !== false && (profile.profileCompleted === 1 || profile.intro || profile.avatarUrl || (profile.interestTags && profile.interestTags.length))
if (!usableProfile) return
item.name = profile.anonymousName || item.name
item.avatar = profile.avatarText || item.avatar
item.avatarUrl = profile.avatarUrl || ''
item.avatarUrl = profile.avatarUrl || item.avatarUrl || ''
item.type = profile.currentMode || item.type
item.feeling = profile.intro || item.feeling
})

37
package1/ieBrowser/fate.vue

@ -12,7 +12,7 @@
</view>
<view class="timeline">
<view class="line"></view>
<view class="fate-card" v-for="item in fates" :key="item.id">
<view class="fate-card" v-for="item in fates" :key="item.id" @tap="openChat(item)">
<view class="node" :class="item.type">{{ item.type }}</view>
<view class="card-main">
<view class="card-top">
@ -20,7 +20,7 @@
<text class="time">{{ item.time }}</text>
</view>
<view class="feeling">{{ item.feeling }}</view>
<view class="remeet" v-if="item.remeet">24 小时内可再遇见一次</view>
<view class="remeet" v-if="item.remeet">10分钟后可再遇见一次</view>
</view>
</view>
</view>
@ -29,7 +29,7 @@
</template>
<script>
import { pageIeRecords } from '@/common/ieApi.js'
import { pageIeMatches } from '@/common/ieApi.js'
export default {
data() {
@ -70,23 +70,42 @@
const date = new Date(item.createTime)
return {
id: item.id,
matchId: item.matchId,
roomId: item.roomId,
targetUserId: item.targetUserId,
type: item.currentMode || item.mode || 'i',
type: item.mode || 'i',
name: item.anonymousName || '半匿名漂流者',
avatar: item.avatarText || (item.mode === 'e' ? '光' : '月'),
avatarUrl: item.avatarUrl || '',
time: this.formatTime(item.createTime),
rawDate: Number.isNaN(date.getTime()) ? null : date,
feeling: item.intro || item.feeling || item.summary || '这次连接只留下了一点情绪轨迹。',
remeet: item.remeetAvailable === 1
feeling: item.quoteText || item.stateText || item.failReason || '这次连接只留下了一点情绪轨迹。',
remeet: item.status === 3
}
},
openChat(item) {
if (!item || !item.roomId) {
uni.showToast({ title: '这条缘分还没有聊天入口', icon: 'none' })
return
}
uni.navigateTo({
url: '/package1/ieBrowser/chat?mode=' + item.type +
'&roomId=' + item.roomId +
'&targetUserId=' + (item.targetUserId || '') +
'&name=' + encodeURIComponent(item.name || '半匿名漂流者') +
'&avatar=' + encodeURIComponent(item.avatar || item.type || '◌') +
'&avatarUrl=' + encodeURIComponent(item.avatarUrl || '') +
'&quote=' + encodeURIComponent(item.feeling || '')
})
},
async loadFates() {
if (this.loading || !this.hasMore) return
this.loading = true
try {
const page = await pageIeRecords(this.pageNumber, this.pageSize)
const page = await pageIeMatches(this.pageNumber, this.pageSize)
const list = page && page.records ? page.records.map(this.normalizeRecord) : []
const exists = new Set(this.fates.map(item => item.id))
this.fates = this.fates.concat(list.filter(item => !exists.has(item.id)))
const exists = new Set(this.fates.map(item => item.matchId || item.id))
this.fates = this.fates.concat(list.filter(item => !exists.has(item.matchId || item.id)))
this.hasMore = page ? (page.current || this.pageNumber) < (page.pages || this.pageNumber) : false
this.pageNumber += 1
} finally {

115
package1/ieBrowser/index.vue

@ -5,7 +5,12 @@
<view class="top-safe" :style="{ height: menuButtonInfo.top + 'px' }"></view>
<view class="status-head">
<view class="time-row">
<view class="time-line">{{ timeLabel }}</view>
<view class="perf-toggle" :class="{ active: lowPowerMode }" @tap="toggleLowPowerMode">
{{ lowPowerMode ? '流畅' : '性能' }}
</view>
</view>
<view class="profile-line" @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>
@ -16,13 +21,10 @@
</view>
<view class="live-line">此刻有 <text class="count-num">{{ displayAwakeCount }}</text> 个灵魂在线漂流</view>
<view class="sub-line">{{ waitingCount }} 个人正在等一句话</view>
<view class="archive-entry planet-entry" @tap="openProfile">
<view class="archive-entry planet-entry" @tap="openTargetPanel">
<view class="planet-ring"></view>
<view class="planet-icon"></view>
</view>
<view class="perf-toggle" :class="{ active: lowPowerMode }" @tap="toggleLowPowerMode">
{{ lowPowerMode ? '流畅' : '性能' }}
</view>
</view>
<view class="drift-field">
@ -32,10 +34,10 @@
:class="['fragment-' + index, item.type, item.mood]" @tap="selectDrift(item)">
<view class="fragment-dot"></view>
<view class="fragment-text">{{ item.text }}</view>
<view class="bubble-actions" v-if="activeDriftText === item.text" @tap.stop>
<!-- <view class="bubble-actions" v-if="activeDriftText === item.text" @tap.stop>
<view @tap="replyDrift">回复</view>
<view @tap="likeDrift">轻轻赞</view>
</view>
</view> -->
</view>
<view class="signal-planet" :style="galaxyStyle" @touchstart.stop="startGalaxyDrag" @touchmove.stop="moveGalaxyDrag"
@touchend="endGalaxyDrag" @touchcancel="endGalaxyDrag">
@ -52,7 +54,7 @@
<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-text">有人在等你</view>
<view class="planet-sub">{{ currentMode === 'i' ? '安静靠近' : '轻轻热闹' }}</view>
</view>
</view>
@ -70,12 +72,19 @@
:class="{ active: currentMood === item.key }" @tap="changeMood(item.key)">
<text class="mood-icon">{{ item.icon }}</text>{{ item.label }}
</view>
<view class="mode-switch" @tap="toggleMode">{{ currentMode }} · {{ currentMode === 'i' ? '慢一点' : '亮一点' }}</view>
</view>
</scroll-view>
</view>
<view class="target-dock">
<view class="target-mask" v-if="showTargetPanel" @tap="closeTargetPanel">
<view class="target-dock 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">
<view class="target-chip" v-for="item in targetModes" :key="item.key"
@ -92,6 +101,7 @@
</view>
<view class="start-match-btn" @tap="openMatch">开始随机陪伴</view>
</view>
</view>
<view class="bottom-actions">
<view class="tab-glow"></view>
@ -148,6 +158,7 @@
liveTimer: null,
countTimer: null,
showProfile: false,
showTargetPanel: false,
profileReady: false,
profile: {},
lowPowerMode: false,
@ -174,7 +185,7 @@
{ name: 'snow', angle: 332, radiusX: 166, radiusY: 48, size: 10, speed: 1.38, color: 'rgba(255,255,255,.95)' }
],
matchText: "随机遇见一个人",
doneText: "今天先到这里",
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: '不限' }],
@ -375,6 +386,7 @@
})
},
async openMatch() {
this.showTargetPanel = false
if (this.chancesLeft === 0) {
uni.showToast({ title: this.doneText, icon: 'none' })
return
@ -443,6 +455,12 @@
openProfile() {
this.goUniverse()
},
openTargetPanel() {
this.showTargetPanel = true
},
closeTargetPanel() {
this.showTargetPanel = false
},
closeProfile() {
this.showProfile = false
},
@ -492,7 +510,6 @@
uni.showToast({ title: "这次轻轻划过了", icon: 'none' })
},
goChat() {
this.chancesLeft = Math.max(this.chancesLeft - 1, 0)
this.showMatch = false
const room = this.currentMatch ? '&roomId=' + this.currentMatch.roomId + '&targetUserId=' + this.currentMatch.targetUserId +
'&name=' + encodeURIComponent(this.matchedPerson.name || '') +
@ -1091,6 +1108,12 @@
padding-top: 74rpx;
}
.time-row {
display: flex;
align-items: center;
gap: 18rpx;
}
.time-line {
font-size: 46rpx;
line-height: 58rpx;
@ -1169,10 +1192,6 @@
}
.perf-toggle {
position: absolute;
right: 0;
top: 148rpx;
z-index: 4;
height: 48rpx;
line-height: 48rpx;
padding: 0 18rpx;
@ -1370,7 +1389,6 @@
.target-dock {
position: relative;
z-index: 3;
margin-top: 22rpx;
padding: 24rpx 28rpx;
border-radius: 36rpx;
background: rgba(255,255,255,.66);
@ -1379,6 +1397,62 @@
backdrop-filter: blur(12rpx);
}
.target-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 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%;
margin-top: 0;
padding: 34rpx 30rpx 30rpx;
border-radius: 42rpx;
background: linear-gradient(135deg, rgba(255,255,255,.94), rgba(255,255,255,.76)), radial-gradient(circle at 82% 0%, rgba(169,255,231,.28), transparent 220rpx);
box-shadow: 0 34rpx 100rpx rgba(96,112,160,.22);
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;
@ -1420,6 +1494,15 @@
font-weight: 900;
}
.gender-title {
margin-top: 24rpx;
}
@keyframes targetUp {
from { transform: translateY(42rpx); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.dock-scroll {
width: 100%;
margin-top: 20rpx;

Loading…
Cancel
Save