213 lines
4.6 KiB
Plaintext
213 lines
4.6 KiB
Plaintext
<template>
|
|
<view class="page">
|
|
<view class="-status-bar"></view>
|
|
<view class="header">
|
|
<text class="title">消息通知</text>
|
|
</view>
|
|
<scroll-view direction="vertical" :show-scrollbar="false" style="flex:1;">
|
|
<view v-if="list.length === 0 && !loading" class="empty">
|
|
<uni-icons type="chat" size="64" color="#e0e0e0"></uni-icons>
|
|
<text class="empty-text">暂无消息</text>
|
|
</view>
|
|
<view class="conv-item" v-for="(item, idx) in list" :key="item.peer_id" @click="openChat(item)">
|
|
<view class="avatar-wrap">
|
|
<image class="avatar" :src="avatarUrl(item.avatar)" mode="aspectFill"></image>
|
|
<view v-if="item.online" class="online-dot"></view>
|
|
<view v-if="item.unread_count > 0" class="badge">{{ item.unread_count > 99 ? '99+' : item.unread_count }}</view>
|
|
</view>
|
|
<view class="conv-main">
|
|
<view class="conv-top">
|
|
<text class="name">{{ item.nickname }}</text>
|
|
<text class="time">{{ formatTime(item.last_time) }}</text>
|
|
</view>
|
|
<text class="last">{{ item.is_self ? '我: ' : '' }}{{ item.last_content }}</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import Api from '@/common/api-service.uts'
|
|
|
|
type IConv = {
|
|
peer_id : number
|
|
nickname : string
|
|
avatar : string
|
|
online : boolean
|
|
last_content : string
|
|
last_content_type : number
|
|
last_time : number
|
|
unread_count : number
|
|
is_self : boolean
|
|
}
|
|
|
|
const BASE = 'https://dev.xixingwl.cn'
|
|
const loading = ref<boolean>(false)
|
|
const list = reactive<IConv[]>([])
|
|
|
|
const avatarUrl = (avatar : string) : string => {
|
|
if (avatar == null || avatar == '') return ''
|
|
if (avatar.startsWith('http')) return avatar
|
|
return BASE + avatar
|
|
}
|
|
|
|
function loadData() {
|
|
if (loading.value) return
|
|
loading.value = true
|
|
Api.message.conversations()
|
|
.then((res : UTSJSONObject) => {
|
|
const arr = (res.get('list') as Array<IConv>) ?? []
|
|
list.splice(0, list.length)
|
|
arr.forEach((c : IConv) => list.push(c))
|
|
})
|
|
.catch(() => {
|
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
|
})
|
|
.finally(() => { loading.value = false })
|
|
}
|
|
|
|
function openChat(item : IConv) {
|
|
uni.navigateTo({ url: `/pages/chat/chat?userId=${item.peer_id}&userName=${item.nickname}` })
|
|
}
|
|
|
|
function formatTime(ts : number) : string {
|
|
if (!ts) return ''
|
|
const now = Math.floor(Date.now() / 1000)
|
|
const diff = now - ts
|
|
if (diff < 60) return '刚刚'
|
|
if (diff < 3600) return Math.floor(diff / 60) + '分钟前'
|
|
if (diff < 86400) return Math.floor(diff / 3600) + '小时前'
|
|
if (diff < 7 * 86400) return Math.floor(diff / 86400) + '天前'
|
|
const d = new Date(ts * 1000)
|
|
return (d.getMonth() + 1) + '/' + d.getDate()
|
|
}
|
|
|
|
onMounted(() => { loadData() })
|
|
onShow(() => { loadData() })
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.page {
|
|
flex: 1;
|
|
background-color: #f7f7f7;
|
|
}
|
|
|
|
.-status-bar {
|
|
height: var(--status-bar-height);
|
|
background: linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%);
|
|
}
|
|
|
|
.header {
|
|
background: linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%);
|
|
padding: 24rpx 30rpx 36rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.title {
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
color: #fff;
|
|
}
|
|
|
|
.empty {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: 140rpx 0;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 28rpx;
|
|
color: #bbb;
|
|
margin-top: 20rpx;
|
|
}
|
|
|
|
.conv-item {
|
|
display: flex;
|
|
flex-flow: row nowrap;
|
|
align-items: center;
|
|
padding: 28rpx 30rpx;
|
|
background-color: #fff;
|
|
border-bottom: 1rpx solid #f2f2f2;
|
|
}
|
|
|
|
.conv-item:active {
|
|
background-color: #f8f8f8;
|
|
}
|
|
|
|
.avatar-wrap {
|
|
position: relative;
|
|
margin-right: 24rpx;
|
|
}
|
|
|
|
.avatar {
|
|
width: 96rpx;
|
|
height: 96rpx;
|
|
border-radius: 50%;
|
|
background-color: #f0f0f0;
|
|
}
|
|
|
|
.online-dot {
|
|
position: absolute;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 22rpx;
|
|
height: 22rpx;
|
|
border-radius: 50%;
|
|
background-color: #4CD964;
|
|
border: 4rpx solid #fff;
|
|
}
|
|
|
|
.badge {
|
|
position: absolute;
|
|
top: -8rpx;
|
|
right: -8rpx;
|
|
min-width: 32rpx;
|
|
height: 32rpx;
|
|
padding: 0 6rpx;
|
|
border-radius: 16rpx;
|
|
background-color: #FF3B30;
|
|
color: #fff;
|
|
font-size: 20rpx;
|
|
line-height: 32rpx;
|
|
text-align: center;
|
|
border: 2rpx solid #fff;
|
|
}
|
|
|
|
.conv-main {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-width: 0;
|
|
}
|
|
|
|
.conv-top {
|
|
display: flex;
|
|
flex-flow: row nowrap;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.name {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.time {
|
|
font-size: 22rpx;
|
|
color: #bbb;
|
|
}
|
|
|
|
.last {
|
|
font-size: 26rpx;
|
|
color: #999;
|
|
margin-top: 8rpx;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
</style>
|