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.
640 lines
16 KiB
640 lines
16 KiB
<template>
|
|
<view class="daily-page">
|
|
<view class="top-safe" :style="{ height: menuButtonInfo.top + 'px' }"></view>
|
|
<view class="nav">
|
|
<view class="back" @tap="back">‹</view>
|
|
<view class="title">每日同频一题</view>
|
|
<view class="ghost"></view>
|
|
</view>
|
|
|
|
<view class="question-card" v-if="question.exists">
|
|
<view class="q-deco">✦ 今日全校同题 ✦</view>
|
|
<view class="q-text">{{ question.content }}</view>
|
|
<view class="q-count">已有 {{ question.answerCount }} 人回答</view>
|
|
</view>
|
|
<view class="question-card" v-else>
|
|
<view class="q-text">{{ loading ? '正在取今天的题目...' : '今天还没有题目,明天再来吧' }}</view>
|
|
</view>
|
|
|
|
<view class="answer-box" v-if="question.exists && !question.answered">
|
|
<textarea class="answer-input" v-model="draft" maxlength="200"
|
|
placeholder="写下你的回答,答完就能看到大家的答案(200字以内)"></textarea>
|
|
<view class="answer-submit" :class="{ disabled: submitDisabled }" @tap="submit">
|
|
提交回答,解锁大家的答案 ✨
|
|
</view>
|
|
</view>
|
|
|
|
<view class="my-answer" v-if="question.exists && question.answered">
|
|
<view class="my-answer-label">我的回答</view>
|
|
<view class="my-answer-text">{{ question.myAnswer }}</view>
|
|
</view>
|
|
|
|
<view class="feed" v-if="question.answered">
|
|
<view class="feed-title">大家的回答</view>
|
|
<view class="answer-card" v-for="item in answers" :key="item.id">
|
|
<view class="card-head">
|
|
<view class="card-avatar" :class="item.displayMode">{{ item.displayMode }}</view>
|
|
<view class="card-user">
|
|
<view class="card-name">
|
|
{{ item.displayTitle }}
|
|
<text class="school-badge" v-if="item.sameSchool">同校</text>
|
|
<text class="mine-badge" v-if="item.mine">我</text>
|
|
</view>
|
|
<view class="card-mode">{{ item.displaySubTitle }}</view>
|
|
</view>
|
|
<view class="card-chat" v-if="!item.mine" :class="{ disabled: matching }" @tap="chatWith(item)">和TA聊聊</view>
|
|
</view>
|
|
<view class="card-content">{{ item.content }}</view>
|
|
</view>
|
|
<view class="feed-status">{{ loadingAnswers ? '正在加载...' : (hasMore ? '上滑加载更多' : (answers.length ? '今天先到这里' : '还没有人回答,抢个沙发')) }}</view>
|
|
</view>
|
|
<view class="locked-tip" v-else-if="question.exists">
|
|
<view class="locked-icon">🔒</view>
|
|
<view class="locked-text">回答之后才能看到大家的答案</view>
|
|
</view>
|
|
|
|
<view class="creating-mask" v-if="matching">
|
|
<view class="creating-card">
|
|
<view class="creating-orbit">
|
|
<view class="creating-dot dot-a"></view>
|
|
<view class="creating-dot dot-b"></view>
|
|
<view class="creating-core">{{ matchingMode }}</view>
|
|
</view>
|
|
<view class="creating-title">感受到Ta的同频</view>
|
|
<view class="creating-sub">正在轻轻靠近,请稍等一下</view>
|
|
<view class="creating-progress"><view></view></view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { getIeDailyQuestion, answerIeDailyQuestion, pageIeDailyAnswers, matchIeByAnswer } from '@/common/ieApi.js'
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
menuButtonInfo: { top: 44 },
|
|
loading: true,
|
|
question: { exists: false },
|
|
draft: '',
|
|
submitting: false,
|
|
answers: [],
|
|
pageNumber: 1,
|
|
hasMore: true,
|
|
loadingAnswers: false,
|
|
matching: false,
|
|
matchingAnswerId: null,
|
|
matchingMode: 'i'
|
|
}
|
|
},
|
|
computed: {
|
|
submitDisabled() {
|
|
return !this.draft.trim() || this.submitting
|
|
}
|
|
},
|
|
onLoad() {
|
|
if (uni.getMenuButtonBoundingClientRect) {
|
|
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
|
}
|
|
this.loadQuestion()
|
|
},
|
|
onReachBottom() {
|
|
if (this.question.answered && this.hasMore && !this.loadingAnswers) {
|
|
this.loadAnswers()
|
|
}
|
|
},
|
|
methods: {
|
|
back() {
|
|
uni.navigateBack({ fail: () => uni.redirectTo({ url: '/package1/ieBrowser/index' }) })
|
|
},
|
|
async loadQuestion() {
|
|
this.loading = true
|
|
const res = await getIeDailyQuestion().catch(() => null)
|
|
this.loading = false
|
|
if (!res) return
|
|
this.question = res
|
|
if (res.answered) {
|
|
this.pageNumber = 1
|
|
this.answers = []
|
|
this.hasMore = true
|
|
this.loadAnswers()
|
|
}
|
|
},
|
|
async submit() {
|
|
const content = this.draft.trim()
|
|
if (!content || this.submitting) return
|
|
this.submitting = true
|
|
try {
|
|
const res = await answerIeDailyQuestion(content)
|
|
if (!res) return
|
|
this.draft = ''
|
|
uni.showToast({ title: '已提交,去看看大家的回答', icon: 'none' })
|
|
this.loadQuestion()
|
|
} finally {
|
|
this.submitting = false
|
|
}
|
|
},
|
|
async loadAnswers() {
|
|
if (this.loadingAnswers) return
|
|
this.loadingAnswers = true
|
|
try {
|
|
const res = await pageIeDailyAnswers(this.pageNumber, 10)
|
|
if (!res) return
|
|
const records = (res.records || []).map(item => this.normalizeAnswer(item))
|
|
this.answers = this.pageNumber === 1 ? records : this.answers.concat(records)
|
|
this.hasMore = this.answers.length < (res.total || 0)
|
|
this.pageNumber += 1
|
|
} finally {
|
|
this.loadingAnswers = false
|
|
}
|
|
},
|
|
normalizeAnswer(item) {
|
|
const mode = item && item.currentMode === 'e' ? 'e' : 'i'
|
|
const modeText = mode === 'e' ? '会主动递一句话' : '愿意慢慢听你说'
|
|
const scopeText = item && item.sameSchool ? '同校频率' : '此刻同频'
|
|
return {
|
|
...item,
|
|
displayMode: mode,
|
|
displayTitle: mode === 'e' ? '轻轻热闹的 e 人' : '安静靠近的 i 人',
|
|
displaySubTitle: `${scopeText} · ${modeText}`
|
|
}
|
|
},
|
|
answerMode(item) {
|
|
return item && item.displayMode ? item.displayMode : (item && item.currentMode === 'e' ? 'e' : 'i')
|
|
},
|
|
answerTitle(item) {
|
|
return item && item.displayTitle ? item.displayTitle : (this.answerMode(item) === 'e' ? '轻轻热闹的 e 人' : '安静靠近的 i 人')
|
|
},
|
|
answerSubTitle(item) {
|
|
const modeText = this.answerMode(item) === 'e' ? '会主动递一句话' : '愿意慢慢听你说'
|
|
const scopeText = item && item.sameSchool ? '同校频率' : '此刻同频'
|
|
return `${scopeText} · ${modeText}`
|
|
},
|
|
wait(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms))
|
|
},
|
|
async chatWith(item) {
|
|
if (!item || item.mine || this.matching) return
|
|
this.matching = true
|
|
this.matchingAnswerId = item.id
|
|
this.matchingMode = this.answerMode(item)
|
|
try {
|
|
const matchAnimation = this.wait(2000)
|
|
const match = await matchIeByAnswer(item.id)
|
|
await matchAnimation
|
|
if (!match || !match.roomId) return
|
|
uni.navigateTo({
|
|
url: '/package1/ieBrowser/chat?mode=' + (match.mode || 'i') +
|
|
'&roomId=' + match.roomId +
|
|
'&targetUserId=' + match.targetUserId +
|
|
'&name=' + encodeURIComponent(match.anonymousName || this.answerTitle(item) || '') +
|
|
'&avatar=' + encodeURIComponent(match.avatarText || this.answerMode(item) || '') +
|
|
'&avatarUrl=' + encodeURIComponent(match.avatarUrl || item.avatarUrl || '') +
|
|
'"e=' + encodeURIComponent(match.quoteText || '')
|
|
})
|
|
} finally {
|
|
this.matching = false
|
|
this.matchingAnswerId = null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.daily-page {
|
|
position: relative;
|
|
min-height: 100vh;
|
|
padding: 0 32rpx 60rpx;
|
|
box-sizing: border-box;
|
|
color: #161b2e;
|
|
overflow: hidden;
|
|
background:
|
|
radial-gradient(circle at 18% 8%, rgba(169, 255, 231, .42), transparent 330rpx),
|
|
radial-gradient(circle at 88% 18%, rgba(167, 139, 250, .3), transparent 340rpx),
|
|
radial-gradient(circle at 22% 72%, rgba(255, 214, 165, .3), transparent 360rpx),
|
|
linear-gradient(180deg, #fbfdff, #eef4ff 62%, #fff4e8);
|
|
}
|
|
|
|
.daily-page::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
opacity: .1;
|
|
background-image: radial-gradient(circle, rgba(22, 27, 46, .42) 0 1rpx, transparent 1rpx);
|
|
background-size: 52rpx 52rpx;
|
|
}
|
|
|
|
.nav {
|
|
position: relative;
|
|
z-index: 2;
|
|
display: flex;
|
|
align-items: center;
|
|
height: 88rpx;
|
|
}
|
|
|
|
.back {
|
|
width: 62rpx;
|
|
font-size: 52rpx;
|
|
color: rgba(22, 27, 46, .62);
|
|
}
|
|
|
|
.title {
|
|
flex: 1;
|
|
text-align: center;
|
|
font-size: 31rpx;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.ghost {
|
|
width: 62rpx;
|
|
}
|
|
|
|
.question-card {
|
|
position: relative;
|
|
z-index: 2;
|
|
margin-top: 18rpx;
|
|
padding: 40rpx 32rpx 36rpx;
|
|
border-radius: 38rpx;
|
|
background:
|
|
linear-gradient(180deg, rgba(255, 255, 255, .92), rgba(255, 255, 255, .72)),
|
|
radial-gradient(circle at 82% 0%, rgba(169, 255, 231, .36), transparent 240rpx);
|
|
border: 1rpx solid rgba(255, 255, 255, .9);
|
|
box-shadow: 0 24rpx 70rpx rgba(96, 112, 160, .16), inset 0 1rpx 0 rgba(255, 255, 255, .95);
|
|
text-align: center;
|
|
backdrop-filter: blur(20rpx);
|
|
}
|
|
|
|
.q-deco {
|
|
font-size: 22rpx;
|
|
font-weight: 800;
|
|
color: #7a4dff;
|
|
letter-spacing: 4rpx;
|
|
}
|
|
|
|
.q-text {
|
|
margin-top: 16rpx;
|
|
font-size: 36rpx;
|
|
font-weight: 800;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.q-count {
|
|
margin-top: 14rpx;
|
|
font-size: 23rpx;
|
|
color: rgba(22, 27, 46, .5);
|
|
}
|
|
|
|
.answer-box {
|
|
position: relative;
|
|
z-index: 2;
|
|
margin-top: 24rpx;
|
|
}
|
|
|
|
.answer-input {
|
|
width: 100%;
|
|
height: 220rpx;
|
|
padding: 24rpx;
|
|
box-sizing: border-box;
|
|
border-radius: 28rpx;
|
|
background: rgba(255, 255, 255, .85);
|
|
border: 1rpx solid rgba(255, 255, 255, .9);
|
|
font-size: 26rpx;
|
|
}
|
|
|
|
.answer-submit {
|
|
margin-top: 20rpx;
|
|
height: 92rpx;
|
|
line-height: 92rpx;
|
|
text-align: center;
|
|
border-radius: 999rpx;
|
|
font-size: 28rpx;
|
|
font-weight: 800;
|
|
color: #fff;
|
|
background: linear-gradient(135deg, #7a4dff, #ff7eb3);
|
|
box-shadow: 0 16rpx 36rpx rgba(122, 77, 255, .3);
|
|
}
|
|
|
|
.answer-submit.disabled {
|
|
opacity: .5;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.my-answer {
|
|
position: relative;
|
|
z-index: 2;
|
|
margin-top: 24rpx;
|
|
padding: 24rpx 26rpx;
|
|
border-radius: 30rpx;
|
|
background: linear-gradient(135deg, rgba(139, 124, 255, .1), rgba(169, 255, 231, .16));
|
|
border: 1rpx solid rgba(122, 77, 255, .16);
|
|
}
|
|
|
|
.my-answer-label {
|
|
font-size: 22rpx;
|
|
font-weight: 800;
|
|
color: #7a4dff;
|
|
}
|
|
|
|
.my-answer-text {
|
|
margin-top: 8rpx;
|
|
font-size: 26rpx;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.feed {
|
|
position: relative;
|
|
z-index: 2;
|
|
margin-top: 28rpx;
|
|
}
|
|
|
|
.feed-title {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 28rpx;
|
|
font-weight: 800;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.feed-title::before {
|
|
content: '';
|
|
width: 12rpx;
|
|
height: 12rpx;
|
|
margin-right: 12rpx;
|
|
border-radius: 50%;
|
|
background: #a9ffe7;
|
|
box-shadow: 0 0 18rpx rgba(43, 217, 164, .58);
|
|
}
|
|
|
|
.answer-card {
|
|
position: relative;
|
|
margin-bottom: 18rpx;
|
|
padding: 26rpx;
|
|
border-radius: 34rpx;
|
|
overflow: hidden;
|
|
background:
|
|
linear-gradient(135deg, rgba(255, 255, 255, .94), rgba(255, 255, 255, .76)),
|
|
radial-gradient(circle at 10% 0%, rgba(169, 255, 231, .24), transparent 190rpx);
|
|
border: 1rpx solid rgba(255, 255, 255, .94);
|
|
box-shadow: 0 16rpx 42rpx rgba(96, 112, 160, .12), inset 0 1rpx 0 rgba(255, 255, 255, .95);
|
|
backdrop-filter: blur(18rpx);
|
|
}
|
|
|
|
.answer-card::after {
|
|
content: '✦';
|
|
position: absolute;
|
|
right: 26rpx;
|
|
bottom: 18rpx;
|
|
color: rgba(139, 124, 255, .16);
|
|
font-size: 42rpx;
|
|
}
|
|
|
|
.card-head {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.card-avatar {
|
|
width: 82rpx;
|
|
height: 82rpx;
|
|
border-radius: 28rpx;
|
|
flex-shrink: 0;
|
|
line-height: 82rpx;
|
|
text-align: center;
|
|
font-size: 42rpx;
|
|
font-weight: 900;
|
|
box-shadow: 0 14rpx 32rpx rgba(96, 112, 160, .16), inset 0 1rpx 0 rgba(255, 255, 255, .8);
|
|
}
|
|
|
|
.card-avatar.i {
|
|
color: #fff;
|
|
background: linear-gradient(145deg, #7771d8, #a29bfe);
|
|
}
|
|
|
|
.card-avatar.e {
|
|
color: #11162a;
|
|
background: linear-gradient(145deg, #a9ffe7, #ffd6a5);
|
|
}
|
|
|
|
.card-user {
|
|
flex: 1;
|
|
margin-left: 16rpx;
|
|
min-width: 0;
|
|
}
|
|
|
|
.card-name {
|
|
font-size: 28rpx;
|
|
font-weight: 900;
|
|
color: #151a2d;
|
|
}
|
|
|
|
.school-badge,
|
|
.mine-badge {
|
|
margin-left: 10rpx;
|
|
padding: 2rpx 12rpx;
|
|
border-radius: 999rpx;
|
|
font-size: 18rpx;
|
|
font-weight: 800;
|
|
vertical-align: 4rpx;
|
|
}
|
|
|
|
.school-badge {
|
|
color: #1d7a4f;
|
|
background: rgba(61, 220, 151, .16);
|
|
}
|
|
|
|
.mine-badge {
|
|
color: #7a4dff;
|
|
background: rgba(122, 77, 255, .12);
|
|
}
|
|
|
|
.card-mode {
|
|
margin-top: 8rpx;
|
|
font-size: 22rpx;
|
|
color: rgba(22, 27, 46, .46);
|
|
}
|
|
|
|
.card-chat {
|
|
flex-shrink: 0;
|
|
padding: 13rpx 24rpx;
|
|
border-radius: 999rpx;
|
|
font-size: 22rpx;
|
|
font-weight: 800;
|
|
color: #11162a;
|
|
background: linear-gradient(135deg, #effffb, #a9ffe7 62%, #ffd6a5);
|
|
box-shadow: 0 12rpx 28rpx rgba(169, 255, 231, .28);
|
|
}
|
|
|
|
.card-chat.disabled {
|
|
opacity: .68;
|
|
}
|
|
|
|
.card-content {
|
|
position: relative;
|
|
z-index: 1;
|
|
margin-top: 20rpx;
|
|
padding: 18rpx 20rpx;
|
|
border-radius: 22rpx;
|
|
background: rgba(238, 244, 255, .58);
|
|
font-size: 27rpx;
|
|
line-height: 1.6;
|
|
color: rgba(22, 27, 46, .82);
|
|
}
|
|
|
|
.feed-status {
|
|
padding: 24rpx 0 10rpx;
|
|
text-align: center;
|
|
font-size: 23rpx;
|
|
color: rgba(22, 27, 46, .42);
|
|
}
|
|
|
|
.locked-tip {
|
|
position: relative;
|
|
z-index: 2;
|
|
margin-top: 60rpx;
|
|
text-align: center;
|
|
}
|
|
|
|
.locked-icon {
|
|
font-size: 64rpx;
|
|
}
|
|
|
|
.locked-text {
|
|
margin-top: 14rpx;
|
|
font-size: 25rpx;
|
|
color: rgba(22, 27, 46, .5);
|
|
}
|
|
|
|
.creating-mask {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 80;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 48rpx;
|
|
box-sizing: border-box;
|
|
background: rgba(20, 26, 46, .24);
|
|
backdrop-filter: blur(18rpx);
|
|
}
|
|
|
|
.creating-card {
|
|
width: 100%;
|
|
padding: 52rpx 40rpx 42rpx;
|
|
border-radius: 44rpx;
|
|
text-align: center;
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, .96), rgba(247, 249, 255, .9));
|
|
border: 1rpx solid rgba(255, 255, 255, .92);
|
|
box-shadow: 0 34rpx 100rpx rgba(42, 50, 86, .22);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.creating-orbit {
|
|
position: relative;
|
|
width: 132rpx;
|
|
height: 132rpx;
|
|
margin: 0 auto;
|
|
border-radius: 50%;
|
|
background: radial-gradient(circle, #effffb 0%, #a9ffe7 58%, rgba(169, 255, 231, .2) 100%);
|
|
box-shadow: 0 20rpx 54rpx rgba(96, 200, 170, .26), inset 0 2rpx 0 rgba(255, 255, 255, .9);
|
|
animation: creatingPulse 1.8s ease-in-out infinite;
|
|
}
|
|
|
|
.creating-orbit::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: -18rpx;
|
|
border-radius: 50%;
|
|
border: 3rpx dashed rgba(108, 105, 216, .24);
|
|
animation: creatingSpin 5s linear infinite;
|
|
}
|
|
|
|
.creating-core {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
color: #151a2d;
|
|
font-size: 48rpx;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.creating-dot {
|
|
position: absolute;
|
|
width: 18rpx;
|
|
height: 18rpx;
|
|
border-radius: 50%;
|
|
background: #8b7cff;
|
|
box-shadow: 0 0 24rpx rgba(139, 124, 255, .45);
|
|
}
|
|
|
|
.dot-a {
|
|
right: 2rpx;
|
|
top: 22rpx;
|
|
animation: dotFloatA 1.7s ease-in-out infinite;
|
|
}
|
|
|
|
.dot-b {
|
|
left: 8rpx;
|
|
bottom: 26rpx;
|
|
background: #ff9fc1;
|
|
animation: dotFloatB 1.9s ease-in-out infinite;
|
|
}
|
|
|
|
.creating-title {
|
|
margin-top: 34rpx;
|
|
font-size: 36rpx;
|
|
font-weight: 900;
|
|
color: #151a2d;
|
|
}
|
|
|
|
.creating-sub {
|
|
margin-top: 12rpx;
|
|
color: rgba(21, 26, 45, .52);
|
|
font-size: 24rpx;
|
|
line-height: 38rpx;
|
|
}
|
|
|
|
.creating-progress {
|
|
height: 10rpx;
|
|
margin-top: 34rpx;
|
|
border-radius: 999rpx;
|
|
overflow: hidden;
|
|
background: rgba(21, 26, 45, .06);
|
|
}
|
|
|
|
.creating-progress view {
|
|
width: 44%;
|
|
height: 100%;
|
|
border-radius: 999rpx;
|
|
background: linear-gradient(90deg, #a9ffe7, #8b7cff, #ff9fc1);
|
|
animation: loadingSlide 1.2s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes creatingSpin {
|
|
from { transform: rotate(0); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
@keyframes creatingPulse {
|
|
0%, 100% { transform: scale(.98); }
|
|
50% { transform: scale(1.04); }
|
|
}
|
|
|
|
@keyframes dotFloatA {
|
|
0%, 100% { transform: translate(0, 0); }
|
|
50% { transform: translate(-10rpx, 8rpx); }
|
|
}
|
|
|
|
@keyframes dotFloatB {
|
|
0%, 100% { transform: translate(0, 0); }
|
|
50% { transform: translate(12rpx, -8rpx); }
|
|
}
|
|
|
|
@keyframes loadingSlide {
|
|
0% { transform: translateX(-120%); }
|
|
100% { transform: translateX(230%); }
|
|
}
|
|
</style>
|
|
|