upload project
This commit is contained in:
commit
06961cae04
422 changed files with 110626 additions and 0 deletions
434
subpackages/group/group-members/group-members.js
Normal file
434
subpackages/group/group-members/group-members.js
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
// 👥 群成员管理页面逻辑
|
||||
const app = getApp();
|
||||
const groupChatManager = require('../../../utils/group-chat-manager.js');
|
||||
const apiClient = require('../../../utils/api-client.js');
|
||||
const screen =require('../../../utils/screen-adapter')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
stros:[{
|
||||
nickname:'Guodong Chow',
|
||||
avatar:'../../../images/group/testImg.jpg'
|
||||
}],
|
||||
// 系统信息
|
||||
statusBarHeight: 44,
|
||||
navBarHeight: 88,
|
||||
|
||||
// 群信息
|
||||
groupId: '',
|
||||
groupInfo: {},
|
||||
|
||||
// 成员数据
|
||||
allMembers: [],
|
||||
groupOwner: null,
|
||||
admins: [],
|
||||
members: [],
|
||||
|
||||
// 筛选后的数据
|
||||
filteredAdmins: [],
|
||||
filteredMembers: [],
|
||||
|
||||
// 统计数据
|
||||
memberCount: 0,
|
||||
adminCount: 0,
|
||||
normalMemberCount: 0,
|
||||
|
||||
// 用户权限
|
||||
currentUserId: '',
|
||||
userRole: 'member',
|
||||
isOwner: false,
|
||||
isOwnerOrAdmin: false,
|
||||
canInviteMembers: false,
|
||||
|
||||
// 搜索和筛选
|
||||
searchKeyword: '',
|
||||
currentFilter: 'all', // all, admin, member
|
||||
|
||||
// 成员操作
|
||||
showMemberActionModal: false,
|
||||
selectedMember: {},
|
||||
canRemoveMember: false,
|
||||
|
||||
// 加载状态
|
||||
loading: false,
|
||||
loadingText: '加载中...'
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
const {stros} = this.data
|
||||
let testArrs= Array(20).fill(stros).flat();
|
||||
console.log('testArrs------',testArrs);
|
||||
this.setData({
|
||||
testArrs
|
||||
})
|
||||
|
||||
screen.init(this)
|
||||
console.log('123---------123',this.data);
|
||||
// 获取系统信息
|
||||
this.getSystemInfo();
|
||||
|
||||
// 获取群ID
|
||||
if (options.groupId) {
|
||||
this.setData({
|
||||
groupId: options.groupId
|
||||
});
|
||||
|
||||
// 加载群成员
|
||||
this.loadGroupMembers();
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '群聊ID不能为空',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
|
||||
// 刷新成员列表
|
||||
if (this.data.groupId) {
|
||||
this.loadGroupMembers();
|
||||
}
|
||||
},
|
||||
|
||||
// 获取系统信息
|
||||
getSystemInfo() {
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
console.log('systemInfo-------systemInfo',systemInfo);
|
||||
this.setData({
|
||||
statusBarHeight: systemInfo.statusBarHeight || 44,
|
||||
navBarHeight: 88,
|
||||
currentUserId: wx.getStorageSync('userId')
|
||||
});
|
||||
},
|
||||
|
||||
// 加载群成员
|
||||
async loadGroupMembers() {
|
||||
try {
|
||||
this.setData({
|
||||
loading: true,
|
||||
loadingText: '加载成员列表中...'
|
||||
});
|
||||
|
||||
// 获取群基本信息
|
||||
const groupResponse = await apiClient.request({
|
||||
url: `/api/v1/groups/${this.data.groupId}`,
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
if (!groupResponse.success) {
|
||||
throw new Error(groupResponse.error || '获取群信息失败');
|
||||
}
|
||||
|
||||
// 获取群成员列表
|
||||
const membersResult = await groupChatManager.getGroupMembers(this.data.groupId, false);
|
||||
|
||||
if (!membersResult.success) {
|
||||
throw new Error(membersResult.error || '获取群成员失败');
|
||||
}
|
||||
|
||||
const allMembers = membersResult.data;
|
||||
|
||||
// 分类成员
|
||||
const groupOwner = allMembers.find(member => member.role === 'owner');
|
||||
const admins = allMembers.filter(member => member.role === 'admin');
|
||||
const members = allMembers.filter(member => member.role === 'member');
|
||||
|
||||
// 获取当前用户角色
|
||||
const currentUser = allMembers.find(member => member.userId === this.data.currentUserId);
|
||||
const userRole = currentUser ? currentUser.role : 'member';
|
||||
|
||||
// 计算权限
|
||||
const isOwner = userRole === 'owner';
|
||||
const isOwnerOrAdmin = userRole === 'owner' || userRole === 'admin';
|
||||
const canInviteMembers = isOwnerOrAdmin || groupResponse.data.settings?.allowMemberInvite;
|
||||
|
||||
this.setData({
|
||||
groupInfo: groupResponse.data,
|
||||
allMembers: allMembers,
|
||||
groupOwner: groupOwner,
|
||||
admins: admins,
|
||||
members: members,
|
||||
memberCount: allMembers.length,
|
||||
adminCount: admins.length + (groupOwner ? 1 : 0),
|
||||
normalMemberCount: members.length,
|
||||
userRole: userRole,
|
||||
isOwner: isOwner,
|
||||
isOwnerOrAdmin: isOwnerOrAdmin,
|
||||
canInviteMembers: canInviteMembers,
|
||||
loading: false
|
||||
});
|
||||
|
||||
// 应用当前筛选
|
||||
this.applyFilter();
|
||||
|
||||
} catch (error) {
|
||||
this.setData({
|
||||
loading: false
|
||||
});
|
||||
|
||||
console.error('❌ 加载群成员失败:', error);
|
||||
wx.showToast({
|
||||
title: error.message || '加载群成员失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 🔍 ===== 搜索和筛选 =====
|
||||
|
||||
// 搜索输入
|
||||
onSearchInput(e) {
|
||||
const keyword = e.detail.value;
|
||||
this.setData({
|
||||
searchKeyword: keyword
|
||||
});
|
||||
this.applyFilter();
|
||||
},
|
||||
|
||||
// 清除搜索
|
||||
clearSearch() {
|
||||
this.setData({
|
||||
searchKeyword: ''
|
||||
});
|
||||
this.applyFilter();
|
||||
},
|
||||
|
||||
// 切换筛选
|
||||
switchFilter(e) {
|
||||
const filter = e.currentTarget.dataset.filter;
|
||||
|
||||
this.setData({
|
||||
currentFilter: filter
|
||||
});
|
||||
this.applyFilter();
|
||||
},
|
||||
|
||||
// 应用筛选
|
||||
applyFilter() {
|
||||
const keyword = this.data.searchKeyword.toLowerCase();
|
||||
|
||||
// 筛选管理员
|
||||
let filteredAdmins = this.data.admins;
|
||||
if (keyword) {
|
||||
filteredAdmins = this.data.admins.filter(member => {
|
||||
const name = (member.nickname || member.username || '').toLowerCase();
|
||||
return name.includes(keyword);
|
||||
});
|
||||
}
|
||||
|
||||
// 筛选普通成员
|
||||
let filteredMembers = this.data.members;
|
||||
if (keyword) {
|
||||
filteredMembers = this.data.members.filter(member => {
|
||||
const name = (member.nickname || member.username || '').toLowerCase();
|
||||
return name.includes(keyword);
|
||||
});
|
||||
}
|
||||
|
||||
this.setData({
|
||||
filteredAdmins: filteredAdmins,
|
||||
filteredMembers: filteredMembers
|
||||
});
|
||||
},
|
||||
|
||||
// 👤 ===== 成员操作 =====
|
||||
|
||||
// 邀请成员
|
||||
inviteMembers() {
|
||||
if (!this.data.canInviteMembers) {
|
||||
wx.showToast({
|
||||
title: '没有邀请权限',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳转到邀请成员页面
|
||||
wx.navigateTo({
|
||||
url: `/subpackages/group/create-group-chat/create-group-chat?groupId=${this.data.groupId}`
|
||||
});
|
||||
},
|
||||
|
||||
// 查看成员资料
|
||||
viewMemberProfile(e) {
|
||||
const userId = e.currentTarget.dataset.userId;
|
||||
|
||||
// 关闭操作弹窗
|
||||
this.closeMemberActionModal();
|
||||
|
||||
if (userId === this.data.currentUserId) {
|
||||
// 查看自己的资料
|
||||
wx.navigateTo({
|
||||
url: '/subpackages/profile/profile/profile'
|
||||
});
|
||||
} else {
|
||||
// 查看其他成员资料
|
||||
wx.navigateTo({
|
||||
url: `/subpackages/social/user-detail/user-detail?customId=${userId}`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 显示成员操作菜单
|
||||
showMemberActions(e) {
|
||||
const member = e.currentTarget.dataset.member;
|
||||
|
||||
if (!member || member.userId === this.data.currentUserId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算是否可以移除成员
|
||||
const canRemoveMember = this.data.isOwnerOrAdmin &&
|
||||
member.role !== 'owner' &&
|
||||
(this.data.isOwner || member.role !== 'admin');
|
||||
|
||||
this.setData({
|
||||
selectedMember: member,
|
||||
canRemoveMember: canRemoveMember,
|
||||
showMemberActionModal: true
|
||||
});
|
||||
},
|
||||
|
||||
// 关闭成员操作弹窗
|
||||
closeMemberActionModal() {
|
||||
this.setData({
|
||||
showMemberActionModal: false,
|
||||
selectedMember: {},
|
||||
canRemoveMember: false
|
||||
});
|
||||
},
|
||||
|
||||
// 发送消息给成员
|
||||
sendMessageToMember() {
|
||||
const member = this.data.selectedMember;
|
||||
|
||||
// 关闭弹窗
|
||||
this.closeMemberActionModal();
|
||||
|
||||
// 跳转到私聊页面
|
||||
wx.navigateTo({
|
||||
url: `/pages/message/chat/chat?chatType=0&targetId=${member.userId}&chatName=${encodeURIComponent(member.nickname || member.username)}`
|
||||
});
|
||||
},
|
||||
|
||||
// 切换成员管理员状态
|
||||
async toggleMemberAdmin() {
|
||||
const member = this.data.selectedMember;
|
||||
const isAdmin = member.role === 'admin';
|
||||
|
||||
try {
|
||||
this.setData({
|
||||
loading: true,
|
||||
loadingText: isAdmin ? '取消管理员中...' : '设置管理员中...'
|
||||
});
|
||||
|
||||
const result = await groupChatManager.setAdmin(this.data.groupId, member.userId, !isAdmin);
|
||||
|
||||
this.setData({
|
||||
loading: false
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
wx.showToast({
|
||||
title: isAdmin ? '已取消管理员' : '已设为管理员',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 关闭弹窗
|
||||
this.closeMemberActionModal();
|
||||
|
||||
// 刷新成员列表
|
||||
this.loadGroupMembers();
|
||||
} else {
|
||||
throw new Error(result.error || '操作失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
this.setData({
|
||||
loading: false
|
||||
});
|
||||
|
||||
console.error('❌ 切换管理员状态失败:', error);
|
||||
wx.showToast({
|
||||
title: error.message || '操作失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 移出群聊
|
||||
removeMemberFromGroup() {
|
||||
const member = this.data.selectedMember;
|
||||
|
||||
wx.showModal({
|
||||
title: '移出群聊',
|
||||
content: `确定要将"${member.nickname || member.username}"移出群聊吗?`,
|
||||
confirmText: '移出',
|
||||
confirmColor: '#FF3B30',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.performRemoveMember(member);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 执行移出成员
|
||||
async performRemoveMember(member) {
|
||||
try {
|
||||
this.setData({
|
||||
loading: true,
|
||||
loadingText: '移出成员中...'
|
||||
});
|
||||
|
||||
const result = await groupChatManager.removeMember(this.data.groupId, member.userId);
|
||||
|
||||
this.setData({
|
||||
loading: false
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
wx.showToast({
|
||||
title: '成员已移出',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 关闭弹窗
|
||||
this.closeMemberActionModal();
|
||||
|
||||
// 刷新成员列表
|
||||
this.loadGroupMembers();
|
||||
} else {
|
||||
throw new Error(result.error || '移出成员失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
this.setData({
|
||||
loading: false
|
||||
});
|
||||
|
||||
console.error('❌ 移出成员失败:', error);
|
||||
wx.showToast({
|
||||
title: error.message || '移出成员失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 阻止事件冒泡
|
||||
stopPropagation() {
|
||||
// 阻止点击事件冒泡
|
||||
},
|
||||
|
||||
// 🧭 ===== 页面导航 =====
|
||||
|
||||
// 返回上一页
|
||||
goBack() {
|
||||
wx.navigateBack();
|
||||
}
|
||||
});
|
||||
|
||||
7
subpackages/group/group-members/group-members.json
Normal file
7
subpackages/group/group-members/group-members.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#000000",
|
||||
"backgroundTextStyle": "dark",
|
||||
"enablePullDownRefresh": false,
|
||||
"onReachBottomDistance": 50
|
||||
}
|
||||
302
subpackages/group/group-members/group-members.wxml
Normal file
302
subpackages/group/group-members/group-members.wxml
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
<!-- 👥 群成员管理页面 -->
|
||||
<view class="group-members-container">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar" style="padding-top: {{menuButtonInfo.top}}px;">
|
||||
<view class="navbar-content" style="height: {{menuButtonHeight}}px;">
|
||||
<view class="navbar-aran">
|
||||
<view class="navbar-left" bindtap="goBack">
|
||||
<!-- <text class="back-icon">‹</text> -->
|
||||
<image class="back-icon" src="../../../images/back_arrow.svg" mode="" />
|
||||
</view>
|
||||
<view class="navbar-title">
|
||||
<!-- <text class="title-text">群成员 ({{memberCount}})</text> -->
|
||||
<view class="title-text">群成员管理</view>
|
||||
</view>
|
||||
<view class="menu-rigth">
|
||||
<image class="menu-icon" src="../../../images/group/menu.svg" mode="" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="navbar-right" wx:if="{{canInviteMembers}}" bindtap="inviteMembers">
|
||||
<text class="invite-text">邀请</text>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="members-conten">
|
||||
<view class="conten-aran">
|
||||
<view class="members-aran-img">
|
||||
<image class="aran-img" src="../../../images/group/testImg.jpg" mode="" />
|
||||
<view>
|
||||
欢乐谷
|
||||
<image class="aran-edit" src="../../../images/group/edit.svg" mode="" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="member-text-conten">
|
||||
<view class="text-conten"> 已选择
|
||||
<view class="member-count">10</view>
|
||||
/20个成员
|
||||
</view>
|
||||
</view>
|
||||
<view class="member-action">
|
||||
<view class="member-btn">移出群聊</view>
|
||||
<view class="member-btn">添加成员</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="member-out">
|
||||
<scroll-view scroll-y="true" class="scroll-container">
|
||||
<view class="member-arrs">
|
||||
<view class="arrs-aran" wx:for="{{testArrs}}" wx:key="index">
|
||||
<view class="arrs-aran-img">
|
||||
<image class="aran-img-avatar" src="{{item.avatar}}" mode=""/>
|
||||
</view>
|
||||
<view class="arrs-aran-title">{{item.nickname}}</view>
|
||||
<view class="arrs-aran-selected">
|
||||
<view class="aran-selected"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 页面内容 -->
|
||||
<!-- <view class="page-content"> -->
|
||||
<!-- 搜索栏 -->
|
||||
<!-- <view class="search-container">
|
||||
<view class="search-input-wrapper">
|
||||
<text class="search-icon">🔍</text>
|
||||
<input class="search-input"
|
||||
placeholder="搜索群成员"
|
||||
value="{{searchKeyword}}"
|
||||
bindinput="onSearchInput" />
|
||||
<view wx:if="{{searchKeyword}}"
|
||||
class="clear-search"
|
||||
bindtap="clearSearch">
|
||||
<text class="clear-icon">✕</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 成员筛选 -->
|
||||
<!-- <view class="filter-container">
|
||||
<view class="filter-tabs">
|
||||
<view class="filter-tab {{currentFilter === 'all' ? 'active' : ''}}"
|
||||
bindtap="switchFilter"
|
||||
data-filter="all">
|
||||
<text class="tab-text">全部 ({{memberCount}})</text>
|
||||
</view>
|
||||
<view class="filter-tab {{currentFilter === 'admin' ? 'active' : ''}}"
|
||||
bindtap="switchFilter"
|
||||
data-filter="admin">
|
||||
<text class="tab-text">管理员 ({{adminCount}})</text>
|
||||
</view>
|
||||
<view class="filter-tab {{currentFilter === 'member' ? 'active' : ''}}"
|
||||
bindtap="switchFilter"
|
||||
data-filter="member">
|
||||
<text class="tab-text">成员 ({{normalMemberCount}})</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 成员列表 -->
|
||||
<!-- <scroll-view class="members-list" scroll-y="true"> -->
|
||||
<!-- 群主 -->
|
||||
<!-- <view wx:if="{{groupOwner && (currentFilter === 'all' || currentFilter === 'admin')}}"
|
||||
class="member-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">群主</text>
|
||||
</view>
|
||||
|
||||
<view class="member-item owner"
|
||||
bindtap="viewMemberProfile"
|
||||
data-user-id="{{groupOwner.userId}}">
|
||||
<view class="member-avatar-container">
|
||||
<image class="member-avatar"
|
||||
src="{{groupOwner.avatar || '/images/default-avatar.svg'}}"
|
||||
mode="aspectFill" />
|
||||
<view class="role-badge owner">
|
||||
<text class="role-text">群主</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="member-info">
|
||||
<text class="member-name">{{groupOwner.nickname || groupOwner.username}}</text>
|
||||
<text class="member-status">{{groupOwner.status || ''}}</text>
|
||||
</view>
|
||||
|
||||
<view class="member-actions">
|
||||
<text class="action-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 管理员 -->
|
||||
<!-- <view wx:if="{{filteredAdmins.length > 0 && (currentFilter === 'all' || currentFilter === 'admin')}}"
|
||||
class="member-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">管理员</text>
|
||||
</view>
|
||||
|
||||
<view class="member-item admin"
|
||||
wx:for="{{filteredAdmins}}"
|
||||
wx:key="userId"
|
||||
bindtap="viewMemberProfile"
|
||||
data-user-id="{{item.userId}}"
|
||||
bindlongpress="showMemberActions"
|
||||
data-member="{{item}}">
|
||||
<view class="member-avatar-container">
|
||||
<image class="member-avatar"
|
||||
src="{{item.avatar || '/images/default-avatar.svg'}}"
|
||||
mode="aspectFill" />
|
||||
<view class="role-badge admin">
|
||||
<text class="role-text">管理员</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="member-info">
|
||||
<text class="member-name">{{item.nickname || item.username}}</text>
|
||||
<text class="member-status">{{item.status || ''}}</text>
|
||||
</view>
|
||||
|
||||
<view class="member-actions">
|
||||
<view wx:if="{{isOwner && item.userId !== currentUserId}}"
|
||||
class="action-btn"
|
||||
bindtap="showMemberActions"
|
||||
data-member="{{item}}"
|
||||
catchtap="stopPropagation">
|
||||
<text class="action-icon">⋯</text>
|
||||
</view>
|
||||
<text class="action-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 普通成员 -->
|
||||
<!-- <view wx:if="{{filteredMembers.length > 0 && (currentFilter === 'all' || currentFilter === 'member')}}"
|
||||
class="member-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">成员</text>
|
||||
</view>
|
||||
|
||||
<view class="member-item member"
|
||||
wx:for="{{filteredMembers}}"
|
||||
wx:key="userId"
|
||||
bindtap="viewMemberProfile"
|
||||
data-user-id="{{item.userId}}"
|
||||
bindlongpress="showMemberActions"
|
||||
data-member="{{item}}">
|
||||
<view class="member-avatar-container">
|
||||
<image class="member-avatar"
|
||||
src="{{item.avatar || '/images/default-avatar.svg'}}"
|
||||
mode="aspectFill" />
|
||||
</view>
|
||||
|
||||
<view class="member-info">
|
||||
<text class="member-name">{{item.nickname || item.username}}</text>
|
||||
<text class="member-status">{{item.status || ''}}</text>
|
||||
</view>
|
||||
|
||||
<view class="member-actions">
|
||||
<view wx:if="{{isOwnerOrAdmin && item.userId !== currentUserId}}"
|
||||
class="action-btn"
|
||||
bindtap="showMemberActions"
|
||||
data-member="{{item}}"
|
||||
catchtap="stopPropagation">
|
||||
<text class="action-icon">⋯</text>
|
||||
</view>
|
||||
<text class="action-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
-->
|
||||
<!-- 空状态 -->
|
||||
<!-- <view class="empty-state" wx:if="{{filteredMembers.length === 0 && filteredAdmins.length === 0 && !groupOwner}}">
|
||||
<text class="empty-icon">👥</text>
|
||||
<text class="empty-text">{{searchKeyword ? '没有找到相关成员' : '暂无成员'}}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 成员操作菜单 -->
|
||||
<!-- <view class="member-action-modal" wx:if="{{showMemberActionModal}}" bindtap="closeMemberActionModal">
|
||||
<view class="modal-content" catchtap="stopPropagation">
|
||||
<view class="modal-header">
|
||||
<view class="member-info-header">
|
||||
<image class="member-avatar-large"
|
||||
src="{{selectedMember.avatar || '/images/default-avatar.svg'}}"
|
||||
mode="aspectFill" />
|
||||
<view class="member-details">
|
||||
<text class="member-name-large">{{selectedMember.nickname || selectedMember.username}}</text>
|
||||
<text class="member-role-text">{{selectedMember.role === 'admin' ? '管理员' : '成员'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="close-btn" bindtap="closeMemberActionModal">
|
||||
<text class="close-icon">✕</text>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- <view class="action-list">
|
||||
查看资料
|
||||
<view class="action-item" bindtap="viewMemberProfile" data-user-id="{{selectedMember.userId}}">
|
||||
<view class="action-icon-wrapper">
|
||||
<text class="action-icon">👤</text>
|
||||
</view>
|
||||
<text class="action-title">查看资料</text>
|
||||
</view>
|
||||
|
||||
发送消息
|
||||
<view class="action-item" bindtap="sendMessageToMember">
|
||||
<view class="action-icon-wrapper">
|
||||
<text class="action-icon">💬</text>
|
||||
</view>
|
||||
<text class="action-title">发送消息</text>
|
||||
</view>
|
||||
|
||||
设置/取消管理员
|
||||
<view wx:if="{{isOwner && selectedMember.role !== 'owner'}}"
|
||||
class="action-item"
|
||||
bindtap="toggleMemberAdmin">
|
||||
<view class="action-icon-wrapper">
|
||||
<text class="action-icon">{{selectedMember.role === 'admin' ? '👤' : '👑'}}</text>
|
||||
</view>
|
||||
<text class="action-title">{{selectedMember.role === 'admin' ? '取消管理员' : '设为管理员'}}</text>
|
||||
</view>
|
||||
|
||||
移出群聊
|
||||
<view wx:if="{{canRemoveMember}}"
|
||||
class="action-item danger"
|
||||
bindtap="removeMemberFromGroup">
|
||||
<view class="action-icon-wrapper">
|
||||
<text class="action-icon">🚫</text>
|
||||
</view>
|
||||
<text class="action-title">移出群聊</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 加载提示 -->
|
||||
<!-- <view class="loading-overlay" wx:if="{{loading}}">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">{{loadingText}}</text>
|
||||
</view>
|
||||
</view> -->
|
||||
785
subpackages/group/group-members/group-members.wxss
Normal file
785
subpackages/group/group-members/group-members.wxss
Normal file
|
|
@ -0,0 +1,785 @@
|
|||
/* 👥 群成员管理页面样式 */
|
||||
|
||||
/* CSS变量定义 */
|
||||
page {
|
||||
--primary-color: #007AFF;
|
||||
--primary-light: #5AC8FA;
|
||||
--primary-dark: #0051D5;
|
||||
--success-color: #34C759;
|
||||
--danger-color: #FF3B30;
|
||||
--warning-color: #FF9500;
|
||||
--background-color: #F2F2F7;
|
||||
--surface-color: #FFFFFF;
|
||||
--text-primary: #000000;
|
||||
--text-secondary: #8E8E93;
|
||||
--text-tertiary: #C7C7CC;
|
||||
--border-color: #E5E5EA;
|
||||
--shadow-light: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
|
||||
--shadow-medium: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
--radius-small: 8rpx;
|
||||
--radius-medium: 12rpx;
|
||||
--radius-large: 20rpx;
|
||||
}
|
||||
|
||||
/* 🌙 深色模式支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
page {
|
||||
--primary-color: #0A84FF;
|
||||
--primary-light: #64D2FF;
|
||||
--primary-dark: #0056CC;
|
||||
--success-color: #30D158;
|
||||
--danger-color: #FF453A;
|
||||
--warning-color: #FF9F0A;
|
||||
--background-color: #000000;
|
||||
--surface-color: #1C1C1E;
|
||||
--text-primary: #FFFFFF;
|
||||
--text-secondary: #8E8E93;
|
||||
--text-tertiary: #48484A;
|
||||
--border-color: #38383A;
|
||||
--shadow-light: 0 1rpx 3rpx rgba(0, 0, 0, 0.3);
|
||||
--shadow-medium: 0 4rpx 12rpx rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.group-members-container {
|
||||
height: 100vh;
|
||||
background: var(--background-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 🎨 自定义导航栏 */
|
||||
.custom-navbar {
|
||||
/* background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 100%); */
|
||||
/* box-shadow: var(--shadow-medium); */
|
||||
z-index: 1000;
|
||||
box-sizing: border-box;
|
||||
background-color: black;
|
||||
/* border: 10px solid red; */
|
||||
}
|
||||
|
||||
.navbar-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
/* border: 2px solid rgb(6, 235, 101); */
|
||||
width: 80%;
|
||||
}
|
||||
.navbar-aran{
|
||||
width: 96%;
|
||||
/* border: 1px solid black; */
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navbar-left, .navbar-right {
|
||||
margin-left: 10rpx;
|
||||
border-radius: var(--radius-medium);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* .navbar-left {
|
||||
justify-content: flex-start;
|
||||
} */
|
||||
|
||||
/* .navbar-right {
|
||||
justify-content: flex-end;
|
||||
} */
|
||||
|
||||
/* .navbar-left:active, .navbar-right:active {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
transform: scale(0.95);
|
||||
} */
|
||||
|
||||
.back-icon {
|
||||
width: 34rpx;
|
||||
height: 34rpx;
|
||||
}
|
||||
.menu-icon{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.navbar-title {
|
||||
display: flex;
|
||||
justify-content:center;
|
||||
/* width: 400rpx; */
|
||||
padding-left: 180rpx;
|
||||
|
||||
/* border: 1px solid red; */
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.title-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
|
||||
/* padding-left: 40rpx; */
|
||||
}
|
||||
|
||||
.members-conten{
|
||||
background-color: black;
|
||||
height: 100vh;
|
||||
/* border: 1px solid red; */
|
||||
color: white;
|
||||
}
|
||||
|
||||
.conten-aran{
|
||||
/* border: 1px solid white; */
|
||||
}
|
||||
|
||||
.members-aran-img{
|
||||
/* border: 1px solid red; */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.aran-img{
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
.aran-edit{
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.member-text-conten{
|
||||
/* border: 1px solid rgb(9, 240, 97); */
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
width: 90%;
|
||||
margin: 10rpx auto;
|
||||
|
||||
|
||||
}
|
||||
.member-count{
|
||||
background: linear-gradient(to bottom, #FF6460, #EC42C8 14.28%, #435CFF 64%, #00D5FF 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.text-conten{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
|
||||
}
|
||||
.member-action{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 60rpx;
|
||||
/* border: 1px solid rgb(9, 240, 97); */
|
||||
width: 90%;
|
||||
margin: 20rpx auto;
|
||||
}
|
||||
.member-btn{
|
||||
width: 320rpx;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(87.7deg, rgba(104, 249, 254, 0.9) 2.48%, rgba(170, 147, 237, 0.9) 98.18%);
|
||||
border-radius: 40rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: 700;
|
||||
font-size: 32rpx;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.member-out{
|
||||
height: 100vh;
|
||||
/* border: 10px solid darkcyan; */
|
||||
background: #111D25;
|
||||
}
|
||||
.scroll-container{
|
||||
height: 80vh;
|
||||
width: 100%;
|
||||
|
||||
/* border: 1px solid red; */
|
||||
|
||||
}
|
||||
.member-arrs{
|
||||
box-sizing: border-box;
|
||||
width: 700rpx;
|
||||
margin-left: 25rpx;
|
||||
margin-top: 20rpx;
|
||||
padding-bottom: 200rpx;
|
||||
}
|
||||
.arrs-aran{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 90%;
|
||||
margin: 10rpx auto;
|
||||
background: #FFFFFF1A;
|
||||
border-radius: 24rpx;
|
||||
padding: 16rpx;
|
||||
}
|
||||
.aran-img-avatar{
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 24rpx;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.arrs-aran-title{
|
||||
width: 380rpx;
|
||||
height: 36rpx;
|
||||
font-weight: 700;
|
||||
font-family: 'SF Pro';
|
||||
font-size: 32rpx;
|
||||
color: #F4F6FA;
|
||||
}
|
||||
|
||||
.arrs-aran-selected{
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
opacity: 1;
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
border: 4rpx solid #F4F0EB;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
.aran-selected{
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
opacity: 1;
|
||||
border-radius: 4rpx;
|
||||
background: #4DD1A1;
|
||||
}
|
||||
|
||||
.invite-text {
|
||||
font-size: 32rpx;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* 🎨 页面内容 */
|
||||
.page-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 🎨 搜索栏 */
|
||||
.search-container {
|
||||
padding: 24rpx 32rpx;
|
||||
background: var(--surface-color);
|
||||
border-bottom: 1rpx solid var(--border-color);
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--background-color);
|
||||
border: 1rpx solid var(--border-color);
|
||||
border-radius: var(--radius-small);
|
||||
padding: 0 24rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.search-input-wrapper:focus-within {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 4rpx rgba(0, 122, 255, 0.1);
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-secondary);
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.clear-search {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 24rpx;
|
||||
background: var(--text-tertiary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.clear-search:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
font-size: 24rpx;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 🎨 筛选标签 */
|
||||
.filter-container {
|
||||
background: var(--surface-color);
|
||||
border-bottom: 1rpx solid var(--border-color);
|
||||
}
|
||||
|
||||
.filter-tabs {
|
||||
display: flex;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
|
||||
.filter-tab {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-bottom: 4rpx solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.filter-tab:active {
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.filter-tab.active {
|
||||
border-bottom-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.filter-tab.active .tab-text {
|
||||
color: var(--primary-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 🎨 成员列表 */
|
||||
.members-list {
|
||||
flex: 1;
|
||||
background: var(--surface-color);
|
||||
}
|
||||
|
||||
.member-section {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 24rpx 32rpx 16rpx;
|
||||
background: var(--background-color);
|
||||
border-bottom: 1rpx solid var(--border-color);
|
||||
}
|
||||
|
||||
.section-title .title-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.member-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 32rpx;
|
||||
border-bottom: 1rpx solid var(--border-color);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.member-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.member-item:active {
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.member-item.owner {
|
||||
background: rgba(255, 149, 0, 0.05);
|
||||
}
|
||||
|
||||
.member-item.admin {
|
||||
background: rgba(0, 122, 255, 0.05);
|
||||
}
|
||||
|
||||
.member-avatar-container {
|
||||
position: relative;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.member-avatar {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 48rpx;
|
||||
border: 2rpx solid var(--border-color);
|
||||
}
|
||||
|
||||
.role-badge {
|
||||
position: absolute;
|
||||
bottom: -6rpx;
|
||||
right: -6rpx;
|
||||
padding: 4rpx 8rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid var(--surface-color);
|
||||
}
|
||||
|
||||
.role-badge.owner {
|
||||
background: var(--warning-color);
|
||||
}
|
||||
|
||||
.role-badge.admin {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
||||
.role-text {
|
||||
font-size: 20rpx;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.member-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-status {
|
||||
font-size: 26rpx;
|
||||
color: var(--text-secondary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 32rpx;
|
||||
background: var(--background-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
background: var(--border-color);
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.action-arrow {
|
||||
font-size: 32rpx;
|
||||
color: var(--text-tertiary);
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
/* 🎨 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* 🎨 成员操作弹窗 */
|
||||
.member-action-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 100%;
|
||||
background: var(--surface-color);
|
||||
border-radius: var(--radius-large) var(--radius-large) 0 0;
|
||||
box-shadow: var(--shadow-medium);
|
||||
animation: slideUp 0.3s ease-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 32rpx;
|
||||
border-bottom: 1rpx solid var(--border-color);
|
||||
}
|
||||
|
||||
.member-info-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.member-avatar-large {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
border: 2rpx solid var(--border-color);
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.member-details {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.member-name-large {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-role-text {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 32rpx;
|
||||
background: var(--background-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.close-btn:active {
|
||||
background: var(--border-color);
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.action-list {
|
||||
padding: 24rpx 0;
|
||||
}
|
||||
|
||||
.action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 32rpx;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.action-item:active {
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.action-item.danger {
|
||||
background: rgba(255, 59, 48, 0.05);
|
||||
}
|
||||
|
||||
.action-item.danger:active {
|
||||
background: rgba(255, 59, 48, 0.1);
|
||||
}
|
||||
|
||||
.action-icon-wrapper {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: var(--background-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.action-item.danger .action-icon-wrapper {
|
||||
background: rgba(255, 59, 48, 0.1);
|
||||
}
|
||||
|
||||
.action-item .action-icon {
|
||||
font-size: 32rpx;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.action-item.danger .action-icon {
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
.action-title {
|
||||
font-size: 32rpx;
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.action-item.danger .action-title {
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
/* 🎨 加载状态 */
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 9999;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
background: var(--surface-color);
|
||||
border-radius: var(--radius-medium);
|
||||
padding: 48rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
box-shadow: var(--shadow-medium);
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid var(--border-color);
|
||||
border-top: 4rpx solid var(--primary-color);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 📱 响应式设计 */
|
||||
@media screen and (max-width: 375px) {
|
||||
.search-container,
|
||||
.member-item {
|
||||
padding-left: 24rpx;
|
||||
padding-right: 24rpx;
|
||||
}
|
||||
|
||||
.member-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
}
|
||||
|
||||
.member-avatar-large {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 414px) {
|
||||
.search-container,
|
||||
.member-item {
|
||||
padding-left: 40rpx;
|
||||
padding-right: 40rpx;
|
||||
}
|
||||
|
||||
.member-avatar {
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
border-radius: 56rpx;
|
||||
}
|
||||
|
||||
.member-avatar-large {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border-radius: 70rpx;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue