623 lines
14 KiB
Plaintext
623 lines
14 KiB
Plaintext
<template>
|
|
<!-- #ifdef APP -->
|
|
<scroll-view style="flex: 1;" enable-back-to-top="true">
|
|
<!-- #endif -->
|
|
<view class="page">
|
|
<view class="-status-bar"></view>
|
|
<!-- 功能模块入口(彩色区块) -->
|
|
<scroll-view class="function-modules" direction="horizontal" :show-scrollbar="false">
|
|
<view v-for="(module, index) in functionModules" :key="index" class="module-item"
|
|
:style="{ backgroundColor: module.bgColor }" @click="navigateToModule(module.path)">
|
|
<image class="module-icon" :src="module.icon" mode="aspectFit"></image>
|
|
<text class="module-name">{{ module.name }}</text>
|
|
<text class="module-desc">{{ module.desc }}</text>
|
|
</view>
|
|
</scroll-view>
|
|
<!-- 同城/附近切换栏 -->
|
|
<view class="tabsbox" style="justify-content: space-between;">
|
|
<text v-for="(tab, index) in tabs" :key="index" class="tabsbox-txt" style="flex:1"
|
|
:class="{ ' tabsbox-active-txt': activeTab === index }" @click="activeTab = index">
|
|
{{ tab }}
|
|
</text>
|
|
</view>
|
|
<list-view style="flex: 1;">
|
|
<list-item v-for="(user, index) in filteredUsers" :key="user.id" @click="viewUserProfile(user.id)">
|
|
<view class="chat-item">
|
|
<view class="chat-item-left">
|
|
<image class="avatar-square" :src="user.avatar" mode="aspectFill"></image>
|
|
</view>
|
|
<view class="chat-item-center" style="flex-direction: column; align-items: flex-start;">
|
|
<view style="flex-flow: row;">
|
|
<text class="user-name">{{ user.nickname }}</text>
|
|
<view class="user-badges">
|
|
<text v-if="user.vip" class="user-badge" style="background-color: #FFCC00;">V</text>
|
|
<text v-if="user.verified" class="user-badge" style="background-color: #09b400;">
|
|
R</text>
|
|
<text v-if="user.live" class="user-badge"
|
|
style="background-color: #FF3B30;">L</text>
|
|
</view>
|
|
</view>
|
|
<view class="user-info">
|
|
<text v-if="user.location" class="user-info-i"> {{ user.location }} </text>
|
|
<text v-if="user.age" class="user-info-i"> {{ user.age }}岁 </text>
|
|
<text v-if="user.height" class="user-info-i"> {{ user.height }}cm </text>
|
|
<text v-if="user.profession" class="user-info-i"> {{ user.profession }} </text>
|
|
</view>
|
|
<text v-if="user.signature" class="user-signature">{{ user.signature }}</text>
|
|
</view>
|
|
<view class="chat-item-right">
|
|
<button class="user-chat-btn" @click.stop="startChat(user.id)">搭讪</button>
|
|
</view>
|
|
</view>
|
|
</list-item>
|
|
</list-view>
|
|
<!-- 你可能感兴趣的人(右下角提示框) -->
|
|
<view class="interest-tip" @click="showInterestUsers">
|
|
<text class="tip-text">你可能感兴趣的人</text>
|
|
<uni-icons type="arrowright" size="16" color="#fff"></uni-icons>
|
|
</view>
|
|
</view>
|
|
<!-- #ifdef APP -->
|
|
</scroll-view>
|
|
<!-- #endif -->
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, reactive, computed, onMounted } from 'vue'
|
|
import { IGrid, IUser } from '@/types/index.uts'
|
|
|
|
import { Api } from "@/common/api-service.uts"
|
|
// 功能模块数据(参考第1张图彩色模块)
|
|
const functionModules = reactive<IGrid[]>([
|
|
{
|
|
name: '心动聊天',
|
|
desc: '玩游戏交朋友',
|
|
bgColor: '#FF6B6B',
|
|
icon: '/static/icons/chatroom.png',
|
|
path: '/pages/chatroom/index'
|
|
},
|
|
{
|
|
name: '免费群聊',
|
|
desc: '多人实时聊天',
|
|
bgColor: '#4CD964',
|
|
icon: '/static/icons/group.png',
|
|
path: '/pages/group-chat/index'
|
|
},
|
|
{
|
|
name: '神兽宠物',
|
|
desc: '养宠物交朋友',
|
|
bgColor: '#5AC8FA',
|
|
icon: '/static/icons/pet.png',
|
|
path: '/pages/pet-social/index'
|
|
},
|
|
{
|
|
name: '真人匹配',
|
|
desc: '真人线上奔现',
|
|
bgColor: '#FFCC00',
|
|
icon: '/static/icons/match.png',
|
|
path: '/pages/real-match/index'
|
|
},
|
|
{
|
|
name: '我的好友',
|
|
desc: '好友与请求',
|
|
bgColor: '#9B59B6',
|
|
icon: '/static/logo.png',
|
|
path: '/pages/friend/index'
|
|
}
|
|
] as IGrid[])
|
|
|
|
// 同城/附近切换标签
|
|
const tabs = ref(['同城', '附近'])
|
|
const activeTab = ref(0) // 0:同城, 1:附近
|
|
|
|
// 在线匹配数据
|
|
const matchInfo = reactive({
|
|
distance: '25.05km',
|
|
onlineCount: 473
|
|
})
|
|
|
|
// 用户卡片数据(整合三张图用户信息)
|
|
const users = reactive<IUser[]>([
|
|
{
|
|
id: 1,
|
|
nickname: '萌小依',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 21,
|
|
height: 170,
|
|
profession: '研发',
|
|
signature: '我是个坚定的缘分信徒。相信在茫茫人海中...',
|
|
avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 2,
|
|
nickname: '董小姐',
|
|
realname: true,
|
|
location: '德阳',
|
|
age: 26,
|
|
height: 163,
|
|
profession: '',
|
|
signature: '人生苦短,三万天而已,烂事就得...',
|
|
avatar: 'https://randomuser.me/api/portraits/women/68.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 3,
|
|
nickname: '贝儿妹妹',
|
|
realname: true,
|
|
location: '沈阳',
|
|
age: 27,
|
|
height: 163,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/women/23.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: true // 直播中
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 5,
|
|
nickname: '萌小依',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 21,
|
|
height: 170,
|
|
profession: '研发',
|
|
signature: '我是个坚定的缘分信徒。相信在茫茫人海中...',
|
|
avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 6,
|
|
nickname: '董小姐',
|
|
realname: true,
|
|
location: '德阳',
|
|
age: 26,
|
|
height: 163,
|
|
profession: '',
|
|
signature: '人生苦短,三万天而已,烂事就得...',
|
|
avatar: 'https://randomuser.me/api/portraits/women/68.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 7,
|
|
nickname: '贝儿妹妹',
|
|
realname: true,
|
|
location: '沈阳',
|
|
age: 27,
|
|
height: 163,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/women/23.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: true // 直播中
|
|
},
|
|
{
|
|
id: 8,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 9,
|
|
nickname: '萌小依',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 21,
|
|
height: 170,
|
|
profession: '研发',
|
|
signature: '我是个坚定的缘分信徒。相信在茫茫人海中...',
|
|
avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 10,
|
|
nickname: '董小姐',
|
|
realname: true,
|
|
location: '德阳',
|
|
age: 26,
|
|
height: 163,
|
|
profession: '',
|
|
signature: '人生苦短,三万天而已,烂事就得...',
|
|
avatar: 'https://randomuser.me/api/portraits/women/68.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 3,
|
|
nickname: '贝儿妹妹',
|
|
realname: true,
|
|
location: '沈阳',
|
|
age: 27,
|
|
height: 163,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/women/23.jpg',
|
|
vip: false,
|
|
verified: true,
|
|
live: true // 直播中
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
},
|
|
{
|
|
id: 4,
|
|
nickname: '积极的红薯',
|
|
realname: true,
|
|
location: '南充',
|
|
age: 31,
|
|
height: 167,
|
|
profession: '',
|
|
signature: '',
|
|
avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
|
|
vip: true,
|
|
verified: true,
|
|
live: false
|
|
}
|
|
] as IUser[])
|
|
|
|
// 默认选中"交友"
|
|
const activeNav = ref(0)
|
|
|
|
// 计算属性:根据切换标签过滤用户(简化示例)
|
|
const filteredUsers = computed<IUser[]>(() => {
|
|
return users
|
|
})
|
|
|
|
// 将后端 user_profile 列表项映射为前端展示用的 IUser
|
|
const mapUser = (item : UTSJSONObject) : IUser => {
|
|
const city = item.getString('residecity') ?? ''
|
|
const province = item.getString('resideprovince') ?? ''
|
|
const location = city.length > 0 ? city : province
|
|
const age = item.getNumber('age') ?? 0
|
|
const height = item.getNumber('height') ?? 0
|
|
const isOnline = item.getBoolean('is_online') ?? false
|
|
return {
|
|
id: item.getNumber('uid') ?? 0,
|
|
nickname: item.getString('nickname') ?? '',
|
|
realname: false,
|
|
location: location,
|
|
age: age,
|
|
height: height,
|
|
profession: '',
|
|
signature: item.getString('bio') ?? '',
|
|
avatar: item.getString('avatar') ?? '',
|
|
vip: false,
|
|
verified: false,
|
|
live: isOnline
|
|
} as IUser
|
|
}
|
|
|
|
// 拉取附近/同城真实用户,成功则替换列表,失败保留默认假数据
|
|
const loadNearbyUsers = async () => {
|
|
try {
|
|
let data : UTSJSONObject | null = null
|
|
try {
|
|
data = await Api.user.local({})
|
|
} catch (e) {
|
|
console.warn('本地同城加载失败,尝试在线列表', e)
|
|
}
|
|
// 本地同城为空(如未设置城市)时,回退到在线活跃用户
|
|
const localList = data == null ? null : data.getJSONArray('list')
|
|
if (localList == null || localList.size() == 0) {
|
|
try {
|
|
data = await Api.user.online({})
|
|
} catch (e) {
|
|
console.warn('在线列表加载失败', e)
|
|
}
|
|
}
|
|
const list = data == null ? null : data.getJSONArray('list')
|
|
if (list != null && list.size() > 0) {
|
|
const mapped : IUser[] = []
|
|
for (let i = 0; i < list.size(); i++) {
|
|
const item = list.get(i) as UTSJSONObject
|
|
if (item != null) {
|
|
mapped.push(mapUser(item))
|
|
}
|
|
}
|
|
if (mapped.length > 0) {
|
|
users.splice(0, users.length, ...mapped)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.warn('加载附近用户失败,使用默认数据', error)
|
|
}
|
|
}
|
|
|
|
// 方法:导航到功能模块
|
|
const navigateToModule = (path : string) => {
|
|
uni.navigateTo({
|
|
"url": path
|
|
})
|
|
}
|
|
|
|
// 方法:开始匹配
|
|
const startMatching = () => {
|
|
uni.showToast({ title: '开始匹配附近的人...', icon: 'loading' })
|
|
// 实际项目中调用匹配API
|
|
}
|
|
|
|
// 方法:发起聊天
|
|
const startChat = (userId : number) => {
|
|
|
|
uni.navigateTo({ url: `/pages/chat/chat?userId=${userId}` })
|
|
}
|
|
|
|
// 方法:查看用户资料
|
|
const viewUserProfile = (userId : number) => {
|
|
uni.navigateTo({ url: `/pages/user/profile?id=${userId}` })
|
|
}
|
|
|
|
// 方法:显示感兴趣的人
|
|
const showInterestUsers = () => {
|
|
uni.showToast({ title: '显示你可能感兴趣的人', icon: 'none' })
|
|
}
|
|
|
|
onMounted(() => {
|
|
console.log('社交交友页面加载完成')
|
|
loadNearbyUsers()
|
|
})
|
|
onLoad(() => {
|
|
loadNearbyUsers()
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
/* 功能模块区(彩色区块) */
|
|
.function-modules {
|
|
display: flex;
|
|
flex-flow: row nowrap;
|
|
}
|
|
|
|
.module-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
box-shadow: 0 5rpx 15rpx rgba(0, 0, 0, 0.1);
|
|
border-radius: 20rpx;
|
|
margin: 20rpx 10rpx;
|
|
padding: 15rpx;
|
|
}
|
|
|
|
.module-icon {
|
|
width: 64rpx;
|
|
height: 64rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.module-name {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
margin-bottom: 10rpx;
|
|
}
|
|
|
|
.module-desc {
|
|
font-size: 24rpx;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* 同城/附近切换栏 */
|
|
.tab-switch {
|
|
display: flex;
|
|
flex-flow: row nowrap;
|
|
justify-content: center;
|
|
align-items: center;
|
|
margin: 0 10rpx;
|
|
margin-bottom: 10rpx;
|
|
border-radius: 50rpx;
|
|
padding: 10rpx;
|
|
}
|
|
|
|
.tab-item {
|
|
flex: 1;
|
|
text-align: center;
|
|
padding: 10rpx 0;
|
|
border-radius: 40rpx;
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.tabactive {
|
|
background-color: #FF6B6B;
|
|
color: #fff;
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* 用户列表 */
|
|
.user-name {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
margin-right: 15rpx;
|
|
color: #5f5f5f;
|
|
}
|
|
|
|
.user-badges {
|
|
display: flex;
|
|
flex-flow: row nowrap;
|
|
}
|
|
|
|
.user-badge {
|
|
padding: 3rpx 9rpx;
|
|
margin: 3rpx;
|
|
border-radius: 15rpx;
|
|
font-size: 14rpx;
|
|
color: #fff;
|
|
}
|
|
|
|
.user-info {
|
|
|
|
flex-flow: row nowrap;
|
|
}
|
|
|
|
.user-info-i {
|
|
margin: 5rpx 3rpx;
|
|
padding: 3rpx 6rpx;
|
|
border-radius: 25rpx;
|
|
background: rgba(255, 255, 255, 0.3);
|
|
font-size: 18rpx;
|
|
}
|
|
|
|
.user-signature {
|
|
font-size: 16rpx;
|
|
color: #333;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.user-chat-btn {
|
|
background-color: #FF6B6B;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 50rpx;
|
|
padding: 5rpx 15rpx;
|
|
font-size: 16rpx;
|
|
}
|
|
|
|
|
|
|
|
/* 你可能感兴趣的人提示框 */
|
|
.interest-tip {
|
|
position: fixed;
|
|
right: 30rpx;
|
|
bottom: 150rpx;
|
|
background-color: #FF6B6B;
|
|
padding: 15rpx 25rpx;
|
|
border-radius: 50rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
box-shadow: 0 5rpx 15rpx rgba(255, 107, 107, 0.3);
|
|
}
|
|
|
|
.tip-text {
|
|
font-size: 26rpx;
|
|
}
|
|
</style> |