feat:朋友页

This commit is contained in:
ctw committed 2025-11-26 16:23:18 +08:00
1 parent 1a30a4d497
commit 298bc6babe
7 files changed
+322 -75

No files matched your search

+2 -2
View File
@@ -510,10 +510,10 @@
this.closeSplashscreen(1000); // 延迟1s,避免用户看到页面跳转
uni.setStorageSync('loginInfo', {
accessToken:
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyIiwiZXhwIjoxNzY0MDU5ODk2LCJpbmZvIjoie1wibmlja05hbWVcIjpcInd3d1wiLFwidGVybWluYWxcIjoxLFwidXNlcklkXCI6MixcInVzZXJOYW1lXCI6XCJ3d3dcIn0ifQ.xBfQJg6FFHQGzkK_IUGZUjVN8g5tex3VtWsTr1gGjzg',
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyIiwiZXhwIjoxNzY0MTQ1MDQyLCJpbmZvIjoie1wibmlja05hbWVcIjpcInd3d1wiLFwidGVybWluYWxcIjoxLFwidXNlcklkXCI6MixcInVzZXJOYW1lXCI6XCJ3d3dcIn0ifQ.yO8o-DM4mied_C5PFzqentfiETV38jmVjFzLVljouz4',
accessTokenExpiresIn: 1800,
refreshToken:
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyIiwiZXhwIjoxNzY0NjYyODk2LCJpbmZvIjoie1wibmlja05hbWVcIjpcInd3d1wiLFwidGVybWluYWxcIjoxLFwidXNlcklkXCI6MixcInVzZXJOYW1lXCI6XCJ3d3dcIn0ifQ.o87SSm-pWBkPKROeNBP45VmpBVSdw__Kps4YfiJPZwg',
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyIiwiZXhwIjoxNzY0NzQ4MDQyLCJpbmZvIjoie1wibmlja05hbWVcIjpcInd3d1wiLFwidGVybWluYWxcIjoxLFwidXNlcklkXCI6MixcInVzZXJOYW1lXCI6XCJ3d3dcIn0ifQ.O2Ge2P-n3JSjEqr7P5sH5jaSWZosopHycsuS-vk-WEU',
refreshTokenExpiresIn: 604800,
});
// 登录状态校验
+85 -70
View File
@@ -1,82 +1,97 @@
<template>
<view class="friend-item" @click="showFriendInfo()">
<head-image :name="friend.nickName" :online="friend.online" :url="friend.headImage" size="small"></head-image>
<view class="friend-info">
<view class="friend-name">{{ friend.nickName }}</view>
<view class="friend-online">
<image v-show="friend.onlineWeb" class="online" src="/static/image/online_web.png" title="电脑设备在线" />
<image v-show="friend.onlineApp" class="online" src="/static/image/online_app.png" title="移动设备在线" />
</view>
<slot></slot>
</view>
</view>
<view class="friend-item" @click="showFriendInfo()">
<head-image
:name="friend.nickName"
:online="friend.online"
:url="friend.headImage"
size="small"
></head-image>
<view class="friend-info">
<view class="friend-name">{{ friend.nickName }}</view>
<view class="friend-online">
<image
v-show="friend.onlineWeb"
class="online"
src="/static/image/online_web.png"
title="电脑设备在线"
/>
<image
v-show="friend.onlineApp"
class="online"
src="/static/image/online_app.png"
title="移动设备在线"
/>
</view>
<slot></slot>
</view>
</view>
</template>
<script>
export default {
name: "frined-item",
data() {
return {}
},
methods: {
showFriendInfo() {
if (this.detail) {
uni.navigateTo({
url: "/pages/common/user-info?id=" + this.friend.id
})
}
}
},
props: {
friend: {
type: Object
},
detail: {
type: Boolean,
default: true
}
}
}
export default {
name: 'frined-item',
data() {
return {};
},
methods: {
showFriendInfo() {
if (this.detail) {
uni.navigateTo({
url: '/pages/message/user-info?id=' + this.friend.id,
});
}
},
},
props: {
friend: {
type: Object,
},
detail: {
type: Boolean,
default: true,
},
},
};
</script>
<style scope lang="scss">
.friend-item {
height: 90rpx;
display: flex;
margin-bottom: 1rpx;
position: relative;
padding: 10rpx;
padding-left: 20rpx;
align-items: center;
background-color: white;
white-space: nowrap;
.friend-item {
height: 90rpx;
display: flex;
margin-bottom: 1rpx;
position: relative;
padding: 10rpx;
padding-left: 20rpx;
align-items: center;
background-color: $im-bg-linear;
white-space: nowrap;
&:hover {
background-color: $im-bg;
}
&:hover {
background-color: $im-bg-active-light;
}
.friend-info {
flex: 1;
display: flex;
padding-left: 20rpx;
text-align: left;
.friend-info {
flex: 1;
display: flex;
padding-left: 20rpx;
text-align: left;
.friend-name {
flex: 1;
font-size: $im-font-size;
white-space: nowrap;
overflow: hidden;
}
.friend-name {
flex: 1;
font-size: $im-font-size;
white-space: nowrap;
overflow: hidden;
}
.friend-online {
margin-top: 4rpx;
.friend-online {
margin-top: 4rpx;
.online {
padding-right: 4rpx;
width: 24rpx;
height: 24rpx;
}
}
}
}
</style>
.online {
padding-right: 4rpx;
width: 24rpx;
height: 24rpx;
}
}
}
}
</style>
+1 -1
View File
@@ -62,4 +62,4 @@ $im-title-size: 26px;
$im-title-size-1: 22px;
$im-title-size-2: 18px;
$im-nav-bar-height: 50px;
$im-nav-bar-height: 44px;
+7
View File
@@ -171,6 +171,13 @@
"navigationBarTitleText": "用户信息",
"navigationStyle": "custom"
}
},
{
"path": "friend",
"style": {
"navigationBarTitleText": "朋友",
"navigationStyle": "custom"
}
}
]
},
+216
View File
@@ -0,0 +1,216 @@
<template>
<view class="tab-page friend">
<wd-config-provider theme="dark">
<wd-navbar title="友友" fixed safeAreaInsetTop :bordered="false">
<template #left>
<navigator open-type="navigateBack" hover-class="navigator-hover">
<uni-icons type="back" size="30" color="#ffcd32"></uni-icons>
</navigator>
</template>
<template #right>
<uni-icons type="search" color="#ffcd32" size="24" @click="showSearch = !showSearch" />
</template>
</wd-navbar>
<view class="p-4" v-if="showSearch">
<wd-input
v-model="searchText"
placeholder="搜索好友"
prefix-icon="search"
clearable
:maxlength="10"
:focus="true"
/>
</view>
<view class="friend-tip" v-if="!hasFriends">
<view class="tip-icon">
<text class="iconfont icon-add-friend"></text>
</view>
<view class="tip-title">还没有好友</view>
<view class="tip-content">添加好友,开始精彩的聊天之旅</view>
<!-- <button type="primary" @click="onAddNewFriends">添加好友</button> -->
</view>
<view class="friend-items" v-else>
<!-- <up-index-list :index-list="friendIdx" :sticky="false" :custom-nav-height="customNavHeight">
<template v-for="(friends, i) in friendGroups">
<up-index-item>
<up-index-anchor :text="friendIdx[i] == '*' ? '在线' : friendIdx[i]"></up-index-anchor>
<view v-for="(friend, idx) in friends" :key="idx">
<friend-item :friend="friend"></friend-item>
</view>
</up-index-item>
</template>
</up-index-list> -->
<wd-index-bar sticky>
<view v-for="(friends, i) in friendGroups" :key="i">
<wd-index-anchor :index="friendIdx[i] == '*' ? '在线' : friendIdx[i]" />
<view v-for="(friend, idx) in friends" :key="idx">
<friend-item :friend="friend"></friend-item>
</view>
</view>
</wd-index-bar>
</view>
</wd-config-provider>
</view>
</template>
<script>
import { pinyin } from 'pinyin-pro';
export default {
data() {
return {
showSearch: false,
searchText: '',
};
},
methods: {
onAddNewFriends() {
uni.navigateTo({
url: '/pages/friend/friend-add',
});
},
firstLetter(strText) {
// 使用pinyin-pro库将中文转换为拼音
let pinyinOptions = {
toneType: 'none', // 无声调
type: 'normal', // 普通拼音
};
let pyText = pinyin(strText, pinyinOptions);
return pyText[0];
},
isEnglish(character) {
return /^[A-Za-z]+$/.test(character);
},
},
computed: {
friendGroupMap() {
// 按首字母分组
let groupMap = new Map();
this.friendStore.friends.forEach((f) => {
if (f.deleted || (this.searchText && !f.nickName.includes(this.searchText))) {
return;
}
let letter = this.firstLetter(f.nickName).toUpperCase();
// 非英文一律为#组
if (!this.isEnglish(letter)) {
letter = '#';
}
if (f.online) {
letter = '*';
}
if (groupMap.has(letter)) {
groupMap.get(letter).push(f);
} else {
groupMap.set(letter, [f]);
}
});
// 排序
let arrayObj = Array.from(groupMap);
arrayObj.sort((a, b) => {
// #组在最后面
if (a[0] == '#' || b[0] == '#') {
return b[0].localeCompare(a[0]);
}
return a[0].localeCompare(b[0]);
});
groupMap = new Map(arrayObj.map((i) => [i[0], i[1]]));
return groupMap;
},
friendIdx() {
return Array.from(this.friendGroupMap.keys());
},
friendGroups() {
return Array.from(this.friendGroupMap.values());
},
hasFriends() {
return this.friendStore.friends.some((f) => !f.deleted);
},
customNavHeight() {
let h = 50;
// #ifdef APP-PLUS
h += uni.getSystemInfoSync().statusBarHeight;
// #endif
console.log('customNavHeight:', h);
return h;
},
},
};
</script>
<style lang="scss" scoped>
.friend {
position: relative;
display: flex;
flex-direction: column;
:deep(.u-index-anchor) {
height: 60rpx !important;
background-color: unset !important;
border-bottom: none !important;
}
:deep(.u-index-anchor__text) {
color: $im-text-color !important;
}
.friend-tip {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
padding: 60rpx 40rpx;
text-align: center;
width: 80%;
max-width: 500rpx;
.tip-icon {
width: 120rpx;
height: 120rpx;
background: linear-gradient(135deg, #333, #555);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 40rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
border: 2rpx solid $im-bg-active;
.iconfont {
font-size: 56rpx;
color: #6c757d;
opacity: 0.8;
}
}
.tip-title {
font-size: $im-font-size-large;
color: $im-text-color;
font-weight: 500;
margin-bottom: 20rpx;
}
.tip-content {
font-size: $im-font-size-smaller;
color: $im-text-color-lighter;
line-height: 1.6;
margin-bottom: 50rpx;
}
}
.friend-items {
flex: 1;
padding: 0;
overflow: hidden;
position: relative;
.scroll-bar {
height: 100%;
}
}
}
</style>
+7 -1
View File
@@ -5,7 +5,13 @@
<template #left>
<view class="flex items-center text-base">
<text class="mr-4 c-#FFCD32">消息</text>
<text>缘友</text>
<navigator
url="/pages/message/friend"
open-type="navigate"
hover-class="navigator-hover"
>
<text>友友</text>
</navigator>
</view>
</template>
<template #right>
+4 -1
View File
@@ -26,7 +26,10 @@
<view class="flex-1">
<view class="mb-1 text-base">{{ userInfo.nickname }}</view>
<view class="mb-2 text-xs text-#ffffff80">ID: {{ userInfo.id }}</view>
<text class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1 truncate">
<text
v-if="userCity?.t"
class="bg-#333 text-color-theme-dark text-xs px-2 py-1 rounded-1 truncate"
>
{{ userCity?.t || '' }}
</text>
</view>