wangfukang 2 weeks ago
parent
commit
22b4dede81
  1. 115
      package1/ieBrowser/chat.vue
  2. 60
      package1/ieBrowser/messages.vue
  3. 11
      package1/ieBrowser/profileSetup.vue

115
package1/ieBrowser/chat.vue

@ -38,7 +38,7 @@
</view>
</view>
<scroll-view class="messages" scroll-y :scroll-into-view="scrollIntoView" :scroll-with-animation="scrollAnimation"
<scroll-view class="messages" scroll-y :style="messagesStyle" :scroll-into-view="scrollIntoView" :scroll-with-animation="scrollAnimation"
upper-threshold="80" @scrolltoupper="loadOlderMessages">
<view class="load-more" v-if="loadingMessages">正在加载更早消息...</view>
<view class="load-more" v-else-if="!hasMoreMessages && messages.length">没有更早的消息了</view>
@ -62,20 +62,21 @@
<view class="hesitate-line right" v-if="typingHint">{{ typingHint }}</view>
</scroll-view>
<view class="presence-row">
<view class="presence-row" :style="{ bottom: presenceBottom }">
<view class="presence-chip" v-for="item in presenceActions" :key="item" @tap="sendPresence(item)">
{{ item }}
</view>
</view>
<view class="emoji-panel" v-if="showEmoji">
<view class="emoji-panel" v-if="showEmoji" :style="{ bottom: emojiPanelBottom }">
<view class="emoji-item" v-for="item in emojis" :key="item" @tap="sendEmoji(item)">{{ item }}</view>
</view>
<view class="input-bar">
<view class="input-bar" :style="{ bottom: inputBarBottom }">
<view class="tool-btn" @tap="toggleEmoji"></view>
<view class="tool-btn" @tap="voiceMode = !voiceMode">{{ voiceMode ? '键' : '语' }}</view>
<input class="input" v-if="!voiceMode" v-model="draft" placeholder="轻轻说一句,或保持安静" />
<input class="input" v-if="!voiceMode" v-model="draft" placeholder="轻轻说一句,或保持安静"
:adjust-position="false" :cursor-spacing="20" @focus="handleInputFocus" @blur="handleInputBlur" />
<view class="voice-hold" v-else :class="{ recording: recording, cancelling: voiceCancelling }"
@touchstart.prevent="startRecord" @touchmove.prevent="moveRecord" @touchend="stopRecord" @touchcancel="cancelRecord">
{{ voiceHoldText }}
@ -99,6 +100,16 @@
<view class="profile-avatar" v-else>{{ targetProfile.avatarText || companion.avatar }}</view>
<view class="profile-name">{{ targetProfile.anonymousName || companion.name }}</view>
<view class="profile-mode">{{ targetProfile.currentMode === 'e' ? 'e 人 · 轻轻热闹' : 'i 人 · 安静陪伴' }}</view>
<view class="profile-info-grid">
<view class="profile-info">
<text class="profile-info-label">性别</text>
<text>{{ genderText(targetProfile.gender) }}</text>
</view>
<view class="profile-info">
<text class="profile-info-label">想遇见</text>
<text>{{ targetText(targetProfile.targetModePreference, targetProfile.targetGenderPreference) }}</text>
</view>
</view>
<view class="profile-intro">{{ targetProfile.intro || companion.prompt || '这个人还没有写介绍。' }}</view>
<view class="profile-tags" v-if="targetProfile.interestTags && targetProfile.interestTags.length">
<text v-for="tag in targetProfile.interestTags" :key="tag">{{ tag }}</text>
@ -144,6 +155,8 @@
innerAudioContext: null,
playingVoiceUrl: '',
voiceSwitching: false,
keyboardHeight: 0,
keyboardListener: null,
messages: [],
messagePage: 1,
messagePageSize: 20,
@ -189,6 +202,23 @@
voiceHoldText() {
if (!this.recording) return '按住说话'
return this.voiceCancelling ? '松开取消' : '松开发送,上滑取消'
},
keyboardBottomPx() {
return this.keyboardHeight > 0 ? (this.keyboardHeight + 8) + 'px' : '30rpx'
},
inputBarBottom() {
return this.keyboardBottomPx
},
presenceBottom() {
return this.keyboardHeight > 0 ? (this.keyboardHeight + 76) + 'px' : '132rpx'
},
emojiPanelBottom() {
return this.keyboardHeight > 0 ? (this.keyboardHeight + 82) + 'px' : '128rpx'
},
messagesStyle() {
return {
paddingBottom: this.keyboardHeight > 0 ? (this.keyboardHeight + 140) + 'px' : '24rpx'
}
}
},
onLoad(options) {
@ -216,16 +246,49 @@
this.loadLatestMessages()
this.initSocket()
this.startMessagePolling()
this.bindKeyboardListener()
},
onUnload() {
this.clearTimer()
this.stopMessagePolling()
this.unbindKeyboardListener()
if (this.innerAudioContext) {
this.innerAudioContext.destroy()
this.innerAudioContext = null
}
},
methods: {
bindKeyboardListener() {
if (!uni.onKeyboardHeightChange) return
this.keyboardListener = (res = {}) => {
this.keyboardHeight = res.height || 0
this.$nextTick(() => {
this.scrollToBottom(false)
})
}
uni.onKeyboardHeightChange(this.keyboardListener)
},
unbindKeyboardListener() {
if (!this.keyboardListener) return
if (uni.offKeyboardHeightChange) {
uni.offKeyboardHeightChange(this.keyboardListener)
}
this.keyboardListener = null
},
handleInputFocus(e) {
const height = e && e.detail ? e.detail.height : 0
if (height) {
this.keyboardHeight = height
}
this.$nextTick(() => {
this.scrollToBottom(false)
})
},
handleInputBlur() {
setTimeout(() => {
this.keyboardHeight = 0
}, 120)
},
startTimer() {
//
},
@ -569,6 +632,24 @@
this.innerAudioContext.play()
}, 80)
},
genderText(gender) {
if (gender === 'male') return '男生'
if (gender === 'female') return '女生'
return '未设置'
},
modePreferenceText(mode) {
if (mode === 'i') return 'i 人'
if (mode === 'e') return 'e 人'
return '都可以'
},
genderPreferenceText(gender) {
if (gender === 'male') return '男生'
if (gender === 'female') return '女生'
return '不限性别'
},
targetText(mode, gender) {
return this.modePreferenceText(mode) + ' · ' + this.genderPreferenceText(gender)
},
async openTargetProfile() {
await this.loadTargetProfile()
if (!this.targetProfile || !this.targetProfile.userId) {
@ -1262,6 +1343,30 @@
font-size: 23rpx;
}
.profile-info-grid {
display: flex;
gap: 18rpx;
margin-top: 26rpx;
}
.profile-info {
flex: 1;
padding: 18rpx 14rpx;
border-radius: 24rpx;
color: rgba(22, 27, 46, 0.72);
background: rgba(238, 244, 255, 0.72);
font-size: 24rpx;
font-weight: 800;
}
.profile-info-label {
display: block;
margin-bottom: 8rpx;
color: rgba(22, 27, 46, 0.38);
font-size: 20rpx;
font-weight: 600;
}
.profile-intro {
margin-top: 26rpx;
padding: 24rpx;

60
package1/ieBrowser/messages.vue

@ -10,7 +10,7 @@
<view class="title">消息</view>
<view class="sub">这里不是聊天列表只放未完成的陪伴</view>
</view>
<view class="room-card" v-for="item in requests" :key="item.id" @tap="openRecord(item)">
<view class="room-card" v-for="item in requests" :key="item.id" @tap="openRecord(item)" @longpress="confirmDelete(item)">
<image class="avatar-img" v-if="item.avatarUrl" :src="item.avatarUrl" mode="aspectFill"></image>
<view class="avatar" v-else>{{ item.avatar }}</view>
<view class="main">
@ -21,11 +21,26 @@
</view>
<view class="empty" v-if="!loading && !requests.length">没有未完成的关系也是一种轻松</view>
<view class="empty" v-else>{{ loading ? '正在加载...' : (hasMore ? '上滑加载更多' : '没有更多消息了') }}</view>
<view class="delete-mask" v-if="deleteDialogVisible" @tap="closeDeleteDialog">
<view class="delete-dialog" @tap.stop>
<view class="delete-icon">!</view>
<view class="delete-title">删除这段聊天记录</view>
<view class="delete-content">删除后无法找回对方再次发来消息时这段对话会重新出现在这里</view>
<view class="delete-target" v-if="deleteTarget">
<text>将删除与{{ deleteTarget.name }}的聊天入口</text>
</view>
<view class="delete-actions">
<view class="delete-btn cancel" @tap="closeDeleteDialog">再想想</view>
<view class="delete-btn danger" :class="{ disabled: deleting }" @tap="deleteRecordNow">{{ deleting ? '删除中...' : '确认删除' }}</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { pageIeRecords } from '@/common/ieApi.js'
import { pageIeRecords, deleteIeRecord } from '@/common/ieApi.js'
export default {
data() {
@ -35,7 +50,10 @@
pageNumber: 1,
pageSize: 10,
hasMore: true,
loading: false
loading: false,
deleteDialogVisible: false,
deleteTarget: null,
deleting: false
}
},
onLoad() {
@ -75,6 +93,30 @@
}
},
back() { uni.redirectTo({ url: '/package1/ieBrowser/index' }) },
confirmDelete(item) {
if (!item || !item.id) return
this.deleteTarget = item
this.deleteDialogVisible = true
},
closeDeleteDialog() {
if (this.deleting) return
this.deleteDialogVisible = false
this.deleteTarget = null
},
async deleteRecordNow() {
if (this.deleting || !this.deleteTarget || !this.deleteTarget.id) return
this.deleting = true
try {
const recordId = this.deleteTarget.id
await deleteIeRecord(recordId)
this.requests = this.requests.filter(record => record.id !== recordId)
this.deleteDialogVisible = false
this.deleteTarget = null
uni.showToast({ title: '已删除', icon: 'none' })
} finally {
this.deleting = false
}
},
openRecord(item) {
if (!item || !item.roomId) return
uni.navigateTo({
@ -112,5 +154,17 @@
.tag { padding: 8rpx 16rpx; border-radius: 999rpx; color: #11162a; background: #a9ffe7; font-size: 20rpx; }
.tag.soft { color: #7771d8; background: rgba(119,113,216,.1); }
.empty { margin-top: 42rpx; text-align: center; color: rgba(21,26,45,.36); font-size: 23rpx; }
.delete-mask { position: fixed; inset: 0; z-index: 99; display: flex; align-items: flex-end; justify-content: center; padding: 0 30rpx 54rpx; box-sizing: border-box; background: rgba(16,22,40,.28); backdrop-filter: blur(12rpx); }
.delete-dialog { width: 100%; padding: 42rpx 34rpx 30rpx; border-radius: 42rpx; box-sizing: border-box; text-align: center; background: linear-gradient(180deg, rgba(255,255,255,.96), rgba(248,251,255,.92)); border: 1rpx solid rgba(255,255,255,.9); box-shadow: 0 34rpx 90rpx rgba(42,50,86,.22); animation: dialogUp .18s ease-out; }
.delete-icon { width: 68rpx; height: 68rpx; margin: 0 auto 22rpx; border-radius: 50%; line-height: 68rpx; color: #fff; font-size: 36rpx; font-weight: 900; background: linear-gradient(135deg, #ff8ba0, #e85d75); box-shadow: 0 16rpx 34rpx rgba(232,93,117,.28); }
.delete-title { font-size: 34rpx; font-weight: 900; color: #151a2d; }
.delete-content { width: 86%; margin: 16rpx auto 0; color: rgba(21,26,45,.55); font-size: 25rpx; line-height: 40rpx; }
.delete-target { margin: 26rpx 0 6rpx; padding: 20rpx 24rpx; border-radius: 26rpx; color: rgba(21,26,45,.64); font-size: 24rpx; background: rgba(169,255,231,.32); }
.delete-actions { display: flex; gap: 18rpx; margin-top: 30rpx; }
.delete-btn { flex: 1; height: 86rpx; border-radius: 999rpx; line-height: 86rpx; font-size: 27rpx; font-weight: 800; }
.delete-btn.cancel { color: rgba(21,26,45,.72); background: rgba(21,26,45,.06); }
.delete-btn.danger { color: #fff; background: linear-gradient(135deg, #ff8ba0, #e85d75); box-shadow: 0 18rpx 38rpx rgba(232,93,117,.22); }
.delete-btn.disabled { opacity: .62; }
@keyframes breath { 0%, 100% { transform: scale(.9); opacity: .65; } 50% { transform: scale(1.04); opacity: 1; } }
@keyframes dialogUp { from { transform: translateY(36rpx); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
</style>

11
package1/ieBrowser/profileSetup.vue

@ -117,6 +117,17 @@
this.isEdit = options && options.edit === '1'
this.loadProfile()
},
onShow(){
uni.authorize({
scope: 'scope.writePhotosAlbum',
success() {
},
fail() {
this.tui.toast("您未授权,图片上传功能可能会出现错误")
}
})
},
methods: {
async loadProfile() {
const profile = await getIeProfile()

Loading…
Cancel
Save