306 lines
6.7 KiB
Plaintext
306 lines
6.7 KiB
Plaintext
<template>
|
|
<view class="page">
|
|
<view class="nav-bar">
|
|
<view class="nav-back" @click="goBack">
|
|
<uni-icons type="left" size="22" color="#333"></uni-icons>
|
|
</view>
|
|
<text class="nav-title">我的好友</text>
|
|
<view class="nav-right"></view>
|
|
</view>
|
|
|
|
<view class="add-bar">
|
|
<input class="add-input" v-model="newUid" type="number" placeholder="输入对方用户ID添加好友" />
|
|
<button class="add-btn" @click="sendRequest">添加</button>
|
|
</view>
|
|
|
|
<scroll-view class="tabs" direction="horizontal" :show-scrollbar="false">
|
|
<text class="tab" :class="{ active: tab == 0 }" @click="tab = 0">好友 ({{ friends.length }})</text>
|
|
<text class="tab" :class="{ active: tab == 1 }" @click="tab = 1">请求 ({{ requests.length }})</text>
|
|
</scroll-view>
|
|
|
|
<list-view class="list" v-if="tab == 0">
|
|
<list-item v-for="(f, i) in friends" :key="f.uid" class="item">
|
|
<image class="avatar" :src="f.avatar" mode="aspectFill"></image>
|
|
<view class="info">
|
|
<text class="name">{{ f.nickname }}</text>
|
|
<text class="meta">{{ f.remark && f.remark.length > 0 ? f.remark : '好友' }}</text>
|
|
</view>
|
|
<button class="del-btn" @click="removeFriend(f.friend_id)">删除</button>
|
|
</list-item>
|
|
<view v-if="friends.length == 0" class="empty">
|
|
<text>还没有好友,去真人匹配认识一下吧</text>
|
|
</view>
|
|
</list-view>
|
|
|
|
<list-view class="list" v-else>
|
|
<list-item v-for="(r, i) in requests" :key="r.uid" class="item">
|
|
<image class="avatar" :src="r.avatar" mode="aspectFill"></image>
|
|
<view class="info">
|
|
<text class="name">{{ r.nickname }}</text>
|
|
<text class="meta">请求添加你为好友</text>
|
|
</view>
|
|
<button class="ok-btn" @click="respond(r.friend_id, 1)">接受</button>
|
|
<button class="del-btn" @click="respond(r.friend_id, 2)">拒绝</button>
|
|
</list-item>
|
|
<view v-if="requests.length == 0" class="empty">
|
|
<text>暂无新的好友请求</text>
|
|
</view>
|
|
</list-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { Api } from '@/common/api-service.uts'
|
|
|
|
const friends = ref<UTSJSONObject[]>([])
|
|
const requests = ref<UTSJSONObject[]>([])
|
|
const tab = ref(0)
|
|
const newUid = ref('')
|
|
|
|
const loadFriends = async () => {
|
|
try {
|
|
const data = await Api.friend.list({})
|
|
const list = data.getJSONArray('list')
|
|
const arr : UTSJSONObject[] = []
|
|
if (list != null) {
|
|
for (let i = 0; i < list.size(); i++) {
|
|
const it = list.get(i) as UTSJSONObject
|
|
if (it != null) {
|
|
arr.push({
|
|
uid: it.getNumber('uid') ?? 0,
|
|
nickname: it.getString('nickname') ?? '',
|
|
avatar: it.getString('avatar') ?? '',
|
|
remark: it.getString('remark') ?? '',
|
|
friend_id: it.getNumber('friend_id') ?? 0
|
|
} as UTSJSONObject)
|
|
}
|
|
}
|
|
}
|
|
friends.value = arr
|
|
} catch (e) {
|
|
console.warn('加载好友列表失败', e)
|
|
}
|
|
}
|
|
|
|
const loadRequests = async () => {
|
|
try {
|
|
const data = await Api.friend.requests({})
|
|
const list = data.getJSONArray('list')
|
|
const arr : UTSJSONObject[] = []
|
|
if (list != null) {
|
|
for (let i = 0; i < list.size(); i++) {
|
|
const it = list.get(i) as UTSJSONObject
|
|
if (it != null) {
|
|
arr.push({
|
|
uid: it.getNumber('uid') ?? 0,
|
|
nickname: it.getString('nickname') ?? '',
|
|
avatar: it.getString('avatar') ?? '',
|
|
friend_id: it.getNumber('friend_id') ?? 0
|
|
} as UTSJSONObject)
|
|
}
|
|
}
|
|
}
|
|
requests.value = arr
|
|
} catch (e) {
|
|
console.warn('加载好友请求失败', e)
|
|
}
|
|
}
|
|
|
|
const sendRequest = () => {
|
|
const fid = parseInt(newUid.value)
|
|
if (!fid || fid <= 0) {
|
|
uni.showToast({ title: '请输入有效ID', icon: 'none' })
|
|
return
|
|
}
|
|
Api.friend.create({ fid: fid }).then(() => {
|
|
uni.showToast({ title: '请求已发送', icon: 'success' })
|
|
newUid.value = ''
|
|
loadRequests()
|
|
}).catch((err : any) => {
|
|
uni.showToast({ title: err?.message ?? '失败', icon: 'none' })
|
|
})
|
|
}
|
|
|
|
const respond = (id : number, action : number) => {
|
|
Api.friend.respond(id, action).then(() => {
|
|
uni.showToast({ title: action == 1 ? '已添加' : '已拒绝', icon: 'success' })
|
|
loadRequests()
|
|
loadFriends()
|
|
}).catch((err : any) => {
|
|
uni.showToast({ title: err?.message ?? '失败', icon: 'none' })
|
|
})
|
|
}
|
|
|
|
const removeFriend = (id : number) => {
|
|
Api.friend.delete(id).then(() => {
|
|
uni.showToast({ title: '已删除', icon: 'success' })
|
|
loadFriends()
|
|
}).catch((err : any) => {
|
|
uni.showToast({ title: err?.message ?? '失败', icon: 'none' })
|
|
})
|
|
}
|
|
|
|
const goBack = () => {
|
|
uni.navigateBack()
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadFriends()
|
|
loadRequests()
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
.page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background-color: #f6f6f6;
|
|
min-height: 100%;
|
|
}
|
|
|
|
.nav-bar {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
padding: 20rpx 24rpx;
|
|
padding-top: 60rpx;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.nav-back {
|
|
width: 60rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.nav-title {
|
|
flex: 1;
|
|
text-align: center;
|
|
font-size: 34rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.nav-right {
|
|
width: 60rpx;
|
|
}
|
|
|
|
.add-bar {
|
|
display: flex;
|
|
flex-direction: row;
|
|
padding: 20rpx 24rpx;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.add-input {
|
|
flex: 1;
|
|
background-color: #f2f2f2;
|
|
border-radius: 40rpx;
|
|
padding: 18rpx 28rpx;
|
|
font-size: 26rpx;
|
|
margin-right: 16rpx;
|
|
}
|
|
|
|
.add-btn {
|
|
background: linear-gradient(to bottom right, #FF6B6B, #FF8E53);
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 40rpx;
|
|
font-size: 26rpx;
|
|
padding: 0 36rpx;
|
|
}
|
|
|
|
.tabs {
|
|
display: flex;
|
|
flex-direction: row;
|
|
background-color: #fff;
|
|
padding: 10rpx 24rpx;
|
|
border-top: 1rpx solid #f0f0f0;
|
|
}
|
|
|
|
.tab {
|
|
font-size: 28rpx;
|
|
color: #888;
|
|
margin-right: 40rpx;
|
|
padding: 12rpx 0;
|
|
}
|
|
|
|
.tab.active {
|
|
color: #FF6B6B;
|
|
font-weight: bold;
|
|
border-bottom: 4rpx solid #FF6B6B;
|
|
}
|
|
|
|
.list {
|
|
flex: 1;
|
|
}
|
|
|
|
.item {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
background-color: #fff;
|
|
margin: 16rpx 24rpx;
|
|
padding: 24rpx;
|
|
border-radius: 20rpx;
|
|
}
|
|
|
|
.avatar {
|
|
width: 88rpx;
|
|
height: 88rpx;
|
|
border-radius: 50%;
|
|
background-color: #eee;
|
|
}
|
|
|
|
.info {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-left: 24rpx;
|
|
}
|
|
|
|
.name {
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.meta {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
margin-top: 8rpx;
|
|
}
|
|
|
|
.ok-btn {
|
|
background-color: #4CD964;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 40rpx;
|
|
font-size: 24rpx;
|
|
padding: 8rpx 24rpx;
|
|
margin-right: 12rpx;
|
|
}
|
|
|
|
.del-btn {
|
|
background-color: #ff3b30;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 40rpx;
|
|
font-size: 24rpx;
|
|
padding: 8rpx 24rpx;
|
|
}
|
|
|
|
.empty {
|
|
padding: 80rpx 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.empty text {
|
|
font-size: 26rpx;
|
|
color: #aaa;
|
|
}
|
|
</style>
|