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.
403 lines
9.6 KiB
403 lines
9.6 KiB
<template>
|
|
<view class="records-page">
|
|
<view class="glow glow-a"></view>
|
|
<view class="nav" :style="{ paddingTop: menuButtonInfo.top + 'px' }">
|
|
<view class="back" @tap="back">‹</view>
|
|
<view class="title">感受记录</view>
|
|
<view class="filter">仅自己可见</view>
|
|
</view>
|
|
|
|
<view class="summary-card">
|
|
<view>
|
|
<view class="summary-label">Companion Chat</view>
|
|
<view class="summary-title">已匹配的人可以继续聊</view>
|
|
<view class="summary-sub">每天 3 次是新的随机匹配机会,已经匹配成功的聊天会保留在这里。</view>
|
|
</view>
|
|
<view class="moon">月</view>
|
|
</view>
|
|
|
|
<view class="feeling-picker">
|
|
<view class="section-title">结束后,你现在感觉</view>
|
|
<view class="feeling-row">
|
|
<view class="feeling-chip" v-for="item in feelings" :key="item"
|
|
:class="{ active: currentFeeling === item }" @tap="currentFeeling = item">
|
|
{{ item }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="record-card" v-for="item in records" :key="item.id" @tap="openChat(item)">
|
|
<view class="record-top">
|
|
<image class="record-orb-img" v-if="item.avatarUrl" :src="item.avatarUrl" mode="aspectFill"></image>
|
|
<view class="record-orb" v-else :class="item.type">{{ item.avatar }}</view>
|
|
<view>
|
|
<view class="record-name">{{ item.name }}</view>
|
|
<view class="record-meta">{{ item.time }} · {{ item.duration }}</view>
|
|
</view>
|
|
<view class="unread-dot" v-if="item.unread">未读</view>
|
|
</view>
|
|
<view class="record-text">{{ item.feeling }}</view>
|
|
<view class="record-tags">
|
|
<text v-for="tag in item.tags" :key="tag">{{ tag }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="empty-note" v-if="!loading && !records.length">还没有聊天记录。匹配成功后,对方会出现在这里,可以继续对话。</view>
|
|
<view class="empty-note" v-else>{{ loading ? '正在加载...' : (hasMore ? '上滑加载更多' : '没有更多记录了') }}</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { pageIeRecords, getIeUserProfile } from '@/common/ieApi.js'
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
menuButtonInfo: {
|
|
top: 24
|
|
},
|
|
currentFeeling: '轻了一点',
|
|
feelings: ['轻了一点', '还是安静', '被听见了', '想睡了'],
|
|
records: [],
|
|
pageNumber: 1,
|
|
pageSize: 10,
|
|
hasMore: true,
|
|
loading: false
|
|
}
|
|
},
|
|
onLoad() {
|
|
if (uni.getMenuButtonBoundingClientRect) {
|
|
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
|
}
|
|
this.refreshRecords()
|
|
},
|
|
onReachBottom() {
|
|
this.loadRecords()
|
|
},
|
|
methods: {
|
|
formatTime(value) {
|
|
if (!value) return ''
|
|
const date = new Date(value)
|
|
if (Number.isNaN(date.getTime())) return ''
|
|
const now = new Date()
|
|
const sameDay = date.toDateString() === now.toDateString()
|
|
const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1).toDateString()
|
|
if (sameDay) return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
|
if (date.toDateString() === yesterday) return '昨天'
|
|
return `${date.getMonth() + 1}/${date.getDate()}`
|
|
},
|
|
formatDuration(seconds) {
|
|
const minutes = Math.max(1, Math.round((seconds || 0) / 60))
|
|
return `${minutes} 分钟`
|
|
},
|
|
parseTags(tags) {
|
|
if (!tags) return ['半匿名']
|
|
if (Array.isArray(tags)) return tags
|
|
return String(tags).split(/[,,]/).filter(Boolean)
|
|
},
|
|
normalizeRecord(item) {
|
|
return {
|
|
id: item.id,
|
|
roomId: item.roomId,
|
|
targetUserId: item.targetUserId,
|
|
type: item.mode || 'i',
|
|
name: item.anonymousName || '半匿名漂流者',
|
|
avatar: item.avatarText || (item.mode === 'e' ? '光' : '月'),
|
|
avatarUrl: item.avatarUrl || '',
|
|
time: this.formatTime(item.createTime),
|
|
duration: this.formatDuration(item.durationSeconds),
|
|
feeling: item.feeling || item.summary || '你们已经匹配成功,可以继续这段轻陪伴。',
|
|
tags: this.parseTags(item.tags),
|
|
unread: item.unreadCount > 0 || item.hasUnread === true
|
|
}
|
|
},
|
|
openChat(item) {
|
|
if (!item || !item.roomId) return
|
|
uni.navigateTo({
|
|
url: '/package1/ieBrowser/chat?mode=' + item.type +
|
|
'&roomId=' + item.roomId +
|
|
'&targetUserId=' + (item.targetUserId || '') +
|
|
'&name=' + encodeURIComponent(item.name || '半匿名漂流者') +
|
|
'&avatar=' + encodeURIComponent(item.type || '◌') +
|
|
'"e=' + encodeURIComponent(item.feeling || '')
|
|
})
|
|
},
|
|
async refreshRecords() {
|
|
this.pageNumber = 1
|
|
this.hasMore = true
|
|
this.records = []
|
|
await this.loadRecords()
|
|
},
|
|
async loadRecords() {
|
|
if (this.loading || !this.hasMore) return
|
|
this.loading = true
|
|
try {
|
|
const page = await pageIeRecords(this.pageNumber, this.pageSize)
|
|
const list = page && page.records ? page.records.map(this.normalizeRecord) : []
|
|
await this.fillTargetProfiles(list)
|
|
const exists = new Set(this.records.map(item => item.id))
|
|
this.records = this.records.concat(list.filter(item => !exists.has(item.id)))
|
|
this.hasMore = page ? (page.current || this.pageNumber) < (page.pages || this.pageNumber) : false
|
|
this.pageNumber += 1
|
|
} finally {
|
|
this.loading = false
|
|
}
|
|
},
|
|
async fillTargetProfiles(list) {
|
|
const tasks = list
|
|
.filter(item => item.targetUserId)
|
|
.map(async (item) => {
|
|
const profile = await getIeUserProfile(item.targetUserId)
|
|
if (!profile) return
|
|
item.name = profile.anonymousName || item.name
|
|
item.avatar = profile.avatarText || item.avatar
|
|
item.avatarUrl = profile.avatarUrl || ''
|
|
})
|
|
await Promise.all(tasks)
|
|
},
|
|
back() {
|
|
uni.redirectTo({ url: '/package1/ieBrowser/index' })
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
page {
|
|
background: #f7f9ff;
|
|
}
|
|
|
|
.records-page {
|
|
min-height: 100vh;
|
|
padding: 0 28rpx 56rpx;
|
|
box-sizing: border-box;
|
|
color: #161b2e;
|
|
background:
|
|
radial-gradient(circle at 14% 8%, rgba(139, 124, 255, 0.2), rgba(139, 124, 255, 0) 280rpx),
|
|
radial-gradient(circle at 86% 18%, rgba(169, 255, 231, 0.38), rgba(169, 255, 231, 0) 320rpx),
|
|
linear-gradient(180deg, #fbfdff 0%, #eef4ff 62%, #fff4e8 100%);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.glow {
|
|
position: absolute;
|
|
right: -120rpx;
|
|
top: 240rpx;
|
|
width: 320rpx;
|
|
height: 320rpx;
|
|
border-radius: 50%;
|
|
background: rgba(255, 184, 209, 0.26);
|
|
filter: blur(10rpx);
|
|
}
|
|
|
|
.nav {
|
|
position: relative;
|
|
z-index: 1;
|
|
height: 92rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.back {
|
|
width: 58rpx;
|
|
color: rgba(22, 27, 46, 0.62);
|
|
font-size: 56rpx;
|
|
line-height: 56rpx;
|
|
}
|
|
|
|
.title {
|
|
flex: 1;
|
|
font-size: 34rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.filter {
|
|
height: 54rpx;
|
|
line-height: 54rpx;
|
|
padding: 0 22rpx;
|
|
border-radius: 999rpx;
|
|
color: #09101f;
|
|
background: #a9ffe7;
|
|
font-size: 22rpx;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.summary-card,
|
|
.feeling-picker,
|
|
.record-card {
|
|
position: relative;
|
|
z-index: 1;
|
|
border: 1rpx solid rgba(255, 255, 255, 0.78);
|
|
background: rgba(255, 255, 255, 0.62);
|
|
backdrop-filter: blur(24rpx);
|
|
box-shadow: 0 20rpx 64rpx rgba(96, 112, 160, 0.12);
|
|
}
|
|
|
|
.summary-card {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 34rpx;
|
|
border-radius: 42rpx;
|
|
}
|
|
|
|
.summary-label {
|
|
color: #6c69d8;
|
|
font-size: 21rpx;
|
|
letter-spacing: 3rpx;
|
|
}
|
|
|
|
.summary-title {
|
|
margin-top: 14rpx;
|
|
font-size: 40rpx;
|
|
line-height: 52rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.summary-sub {
|
|
width: 460rpx;
|
|
margin-top: 12rpx;
|
|
color: rgba(22, 27, 46, 0.52);
|
|
font-size: 24rpx;
|
|
line-height: 38rpx;
|
|
}
|
|
|
|
.moon {
|
|
width: 104rpx;
|
|
height: 104rpx;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
line-height: 104rpx;
|
|
color: #09101f;
|
|
background: linear-gradient(145deg, #effffb, #a9ffe7);
|
|
font-size: 34rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.feeling-picker {
|
|
margin-top: 28rpx;
|
|
padding: 28rpx;
|
|
border-radius: 34rpx;
|
|
}
|
|
|
|
.section-title {
|
|
margin-bottom: 20rpx;
|
|
font-size: 28rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.feeling-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.feeling-chip {
|
|
height: 58rpx;
|
|
line-height: 58rpx;
|
|
padding: 0 22rpx;
|
|
margin: 0 14rpx 14rpx 0;
|
|
border-radius: 999rpx;
|
|
color: rgba(22, 27, 46, 0.55);
|
|
background: rgba(255, 255, 255, 0.58);
|
|
font-size: 23rpx;
|
|
}
|
|
|
|
.feeling-chip.active {
|
|
color: #09101f;
|
|
background: #a9ffe7;
|
|
}
|
|
|
|
.record-card {
|
|
margin-top: 22rpx;
|
|
padding: 28rpx;
|
|
border-radius: 34rpx;
|
|
}
|
|
|
|
.record-top {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.record-orb {
|
|
width: 78rpx;
|
|
height: 78rpx;
|
|
margin-right: 18rpx;
|
|
border-radius: 50%;
|
|
text-align: center;
|
|
line-height: 78rpx;
|
|
font-size: 30rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.record-orb-img {
|
|
width: 78rpx;
|
|
height: 78rpx;
|
|
margin-right: 18rpx;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.record-orb.i {
|
|
color: #f7f4ff;
|
|
background: linear-gradient(145deg, #8b7cff, #dde7ff);
|
|
}
|
|
|
|
.record-orb.e {
|
|
color: #07101e;
|
|
background: linear-gradient(145deg, #a9ffe7, #fff0b8);
|
|
}
|
|
|
|
.record-name {
|
|
font-size: 29rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.record-meta {
|
|
margin-top: 8rpx;
|
|
color: rgba(22, 27, 46, 0.44);
|
|
font-size: 22rpx;
|
|
}
|
|
|
|
.unread-dot {
|
|
margin-left: auto;
|
|
padding: 8rpx 14rpx;
|
|
border-radius: 999rpx;
|
|
color: #fff;
|
|
background: #ff6b8a;
|
|
font-size: 20rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.record-text {
|
|
margin-top: 22rpx;
|
|
color: rgba(22, 27, 46, 0.72);
|
|
font-size: 26rpx;
|
|
line-height: 42rpx;
|
|
}
|
|
|
|
.record-tags {
|
|
margin-top: 20rpx;
|
|
}
|
|
|
|
.record-tags text {
|
|
display: inline-block;
|
|
height: 42rpx;
|
|
line-height: 42rpx;
|
|
padding: 0 16rpx;
|
|
margin: 0 10rpx 10rpx 0;
|
|
border-radius: 999rpx;
|
|
color: #6c69d8;
|
|
background: rgba(139, 124, 255, 0.1);
|
|
font-size: 20rpx;
|
|
}
|
|
|
|
.empty-note {
|
|
position: relative;
|
|
z-index: 1;
|
|
width: 560rpx;
|
|
margin: 34rpx auto 0;
|
|
text-align: center;
|
|
color: rgba(22, 27, 46, 0.36);
|
|
font-size: 23rpx;
|
|
line-height: 38rpx;
|
|
}
|
|
</style>
|
|
|