美化样式

This commit is contained in:
2026-03-16 08:54:03 +08:00
parent 85ea1396bb
commit b850830f3f
5 changed files with 222 additions and 95 deletions

View File

@ -291,10 +291,10 @@ export class MeetingWebSocketGateway implements OnGatewayConnection, OnGatewayDi
const validSocketIds: string[] = []; const validSocketIds: string[] = [];
for (const result of validationResults) { for (const result of validationResults) {
if (result.isValid && result.sockets) { if (result.isValid && result.sockets) {
this.server?.to(result.oldSocketId).emit('message', { // this.server?.to(result.oldSocketId).emit('message', {
type: 'sev_device_conflict', // type: 'sev_device_conflict',
data: { fromRoomId: roomId, reason: '您已在其他设备进入相同入口', targetUid: shortUid }, // data: { fromRoomId: roomId, reason: '您已在其他设备进入相同入口', targetUid: shortUid },
} satisfies SucceedMessage); // } satisfies SucceedMessage);
result.sockets.forEach((s) => s.disconnect(true)); result.sockets.forEach((s) => s.disconnect(true));
validSocketIds.push(result.oldSocketId); validSocketIds.push(result.oldSocketId);
} }

View File

@ -1,12 +1,4 @@
/** // 会议室控制栏按钮 (.control-btn) 用于底部控制栏的功能按钮(上课/下课、静音、视频等)
* 统一按钮样式规范
* 适用于项目中所有的按钮组件
*/
/* ========================================
会议室控制栏按钮 (.control-btn)
用于底部控制栏的功能按钮(上课/下课、静音、视频等)
======================================== */
.control-btn { .control-btn {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -19,12 +11,11 @@
line-height: 1.5; line-height: 1.5;
color: var(--el-color-primary); color: var(--el-color-primary);
cursor: pointer; cursor: pointer;
user-select: none;
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
border: 1px solid var(--el-color-primary-light-7); border: 1px solid var(--el-color-primary-light-7);
border-radius: 12px; border-radius: 12px;
transition: all 0.3s ease; transition: all 0.3s ease;
user-select: none;
-webkit-user-select: none;
svg { svg {
width: 24px; width: 24px;
@ -90,8 +81,8 @@
&:hover:not(:disabled) { &:hover:not(:disabled) {
background: linear-gradient(135deg, #5568d3 0%, #63408a 100%); background: linear-gradient(135deg, #5568d3 0%, #63408a 100%);
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4); box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
transform: translateY(-3px);
} }
&:active:not(:disabled) { &:active:not(:disabled) {
@ -100,12 +91,10 @@
} }
} }
/* ======================================== // 视频用户控制按钮 (.control-icon-btn) 用于视频卡片右上角的图标按钮(设为主讲、禁麦、禁视频、踢人等)
视频用户控制按钮 (.control-icon-btn)
用于视频卡片右上角的图标按钮(设为主讲、禁麦、禁视频、踢人等)
======================================== */
.control-icon-btn { .control-icon-btn {
display: flex; display: flex;
flex-shrink: 0;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 32px; width: 32px;
@ -113,13 +102,11 @@
padding: 0; padding: 0;
color: #ffffff; color: #ffffff;
cursor: pointer; cursor: pointer;
user-select: none;
background: rgba(0, 0, 0, 0.6); background: rgba(0, 0, 0, 0.6);
border: none; border: none;
border-radius: 8px; border-radius: 8px;
transition: all 0.3s ease; transition: all 0.3s ease;
user-select: none;
-webkit-user-select: none;
flex-shrink: 0;
svg { svg {
width: 18px; width: 18px;
@ -177,24 +164,20 @@
} }
} }
/* ======================================== // 窗口控制按钮 (.operating-button) 用于窗口标题栏的控制按钮(最小化、最大化、关闭、返回等)
窗口控制按钮 (.operating-button)
用于窗口标题栏的控制按钮(最小化、最大化、关闭、返回等)
======================================== */
.operating-button { .operating-button {
display: flex; display: flex;
flex-shrink: 0;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 20px; width: 20px;
height: 20px; height: 20px;
margin-right: 15px; margin-right: 15px;
cursor: pointer; cursor: pointer;
user-select: none;
background-color: var(--button-bg); background-color: var(--button-bg);
border-radius: 50%; border-radius: 50%;
transition: all 0.2s ease; transition: all 0.2s ease;
user-select: none;
-webkit-user-select: none;
flex-shrink: 0;
svg { svg {
width: 12px; width: 12px;
@ -203,8 +186,8 @@
} }
&:hover { &:hover {
transform: scale(1.15);
filter: brightness(1.1); filter: brightness(1.1);
transform: scale(1.15);
} }
&:active { &:active {
@ -244,62 +227,53 @@
} }
} }
/* ======================================== // Element Plus 按钮覆盖样式 用于登录页面等使用 el-button 的场景
Element Plus 按钮覆盖样式 .el-button.login-btn {
用于登录页面等使用 el-button 的场景 display: flex;
======================================== */ align-items: center;
.el-button { justify-content: center;
&.login-btn { width: 100%;
display: flex; height: 40px;
align-items: center; font-size: 16px;
justify-content: center; font-weight: 600;
width: 100%; background: linear-gradient(93deg, #74e8ff 0%, #306fff 100%);
height: 40px; border: transparent;
font-size: 16px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
font-weight: 600; transition: all 0.3s ease;
background: linear-gradient(93deg, #74e8ff 0%, #306fff 100%);
border: transparent;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
&:hover:not(:disabled) { &:hover:not(:disabled) {
background: linear-gradient(93deg, #5dd6ff 0%, #2560e8 100%); background: linear-gradient(93deg, #5dd6ff 0%, #2560e8 100%);
transform: translateY(-2px); box-shadow: 0 4px 16px 0 rgba(48, 111, 255, 0.3);
box-shadow: 0 4px 16px 0 rgba(48, 111, 255, 0.3); transform: translateY(-2px);
} }
&:active:not(:disabled) { &:active:not(:disabled) {
transform: translateY(0); transform: translateY(0);
} }
&:disabled { &:disabled {
opacity: 0.6; cursor: not-allowed;
cursor: not-allowed; opacity: 0.6;
}
} }
} }
/* ======================================== // 黑名单解除按钮 (.remove-btn) 用于黑名单列表中的解除按钮
黑名单解除按钮 (.remove-btn)
用于黑名单列表中的解除按钮
======================================== */
.remove-btn { .remove-btn {
padding: 4px 12px; padding: 4px 12px;
font-size: 12px; font-size: 12px;
line-height: 1.5; line-height: 1.5;
color: #ffffff; color: #ffffff;
cursor: pointer; cursor: pointer;
user-select: none;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none; border: none;
border-radius: 6px; border-radius: 6px;
transition: all 0.3s ease; transition: all 0.3s ease;
user-select: none;
-webkit-user-select: none;
&:hover { &:hover {
background: linear-gradient(135deg, #5568d3 0%, #63408a 100%); background: linear-gradient(135deg, #5568d3 0%, #63408a 100%);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
transform: translateY(-1px);
} }
&:active { &:active {
@ -307,9 +281,7 @@
} }
} }
/* ======================================== // 响应式适配
响应式适配
======================================== */
@media (max-width: 768px) { @media (max-width: 768px) {
.control-btn { .control-btn {
min-width: 56px; min-width: 56px;

View File

@ -564,7 +564,7 @@
.loading-text { .loading-text {
margin-top: 20px; margin-top: 20px;
font-size: 16px; font-size: 16px;
color: #999; color: #999999;
} }
} }

View File

@ -149,14 +149,28 @@
<span class="btn-text">离开</span> <span class="btn-text">离开</span>
</button> </button>
</div> </div>
<el-drawer v-model="blacklistVisible" title="黑名单" size="30%"> <el-drawer v-model="blacklistVisible" title="黑名单" size="30%" closeOnClickModal>
<div v-if="blacklist.length === 0" class="empty">暂无黑名单</div> <div v-if="blacklist.length === 0" class="empty">
<ul v-else class="blacklist"> <icon-mdi-account-off class="empty-icon"></icon-mdi-account-off>
<li v-for="item in blacklist" :key="item.shortUid" class="blacklist-item"> <span class="empty-text">暂无黑名单</span>
<span class="user-info">{{ item.userName }} (ID: {{ item.shortUid }})</span> </div>
<button class="remove-btn" @click="removeFromBlacklist(item.shortUid)">解除</button> <el-scrollbar v-else class="blacklist-scrollbar">
</li> <ul class="blacklist">
</ul> <li v-for="item in blacklist" :key="item.shortUid" class="blacklist-item">
<div class="user-avatar">
<icon-mdi-account class="avatar-icon"></icon-mdi-account>
</div>
<div class="user-details">
<span class="user-name">{{ item.userName }}</span>
<span class="user-id">ID: {{ item.shortUid }}</span>
</div>
<button class="remove-btn" @click="removeFromBlacklist(item.shortUid)">
<icon-mdi-delete class="remove-icon"></icon-mdi-delete>
<span>解除</span>
</button>
</li>
</ul>
</el-scrollbar>
</el-drawer> </el-drawer>
<!-- 学生列表排序弹窗 --> <!-- 学生列表排序弹窗 -->
<student-sort-dialog v-model="studentSortDialogVisible" :roomId="courseRoomId" :students="studentListForSort"></student-sort-dialog> <student-sort-dialog v-model="studentSortDialogVisible" :roomId="courseRoomId" :students="studentListForSort"></student-sort-dialog>
@ -168,6 +182,8 @@
import { playPromptTone } from '@/utils/prompt-tone'; import { playPromptTone } from '@/utils/prompt-tone';
import { useResizeObserver } from '@vueuse/core'; import { useResizeObserver } from '@vueuse/core';
import IconMdiAccount from '~icons/mdi/account'; import IconMdiAccount from '~icons/mdi/account';
import IconMdiAccountOff from '~icons/mdi/account-off';
import IconMdiDelete from '~icons/mdi/delete';
import IconMdiExitToApp from '~icons/mdi/exit-to-app'; import IconMdiExitToApp from '~icons/mdi/exit-to-app';
import IconMdiLoading from '~icons/mdi/loading'; import IconMdiLoading from '~icons/mdi/loading';
import IconMdiMicrophone from '~icons/mdi/microphone'; import IconMdiMicrophone from '~icons/mdi/microphone';
@ -1078,7 +1094,7 @@
.loading-text { .loading-text {
margin-top: 20px; margin-top: 20px;
font-size: 16px; font-size: 16px;
color: #999; color: #999999;
} }
} }
@ -1397,4 +1413,142 @@
// 使用统一按钮样式,移除重复的 .control-btn 定义 // 使用统一按钮样式,移除重复的 .control-btn 定义
} }
// 黑名单抽屉样式
:deep(.el-drawer__header) {
padding-bottom: 16px;
margin-bottom: 16px;
border-bottom: 1px solid #ebeef5;
.el-drawer__title {
font-size: 18px;
font-weight: 600;
color: #303133;
}
}
:deep(.el-drawer__body) {
padding: 0;
}
.empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 20px;
color: #909399;
.empty-icon {
width: 80px;
height: 80px;
margin-bottom: 16px;
color: #c0c4cc;
}
.empty-text {
font-size: 14px;
}
}
.blacklist-scrollbar {
max-height: calc(100vh - 120px);
padding: 16px;
}
.blacklist {
display: flex;
flex-direction: column;
gap: 12px;
padding: 0;
margin: 0;
list-style: none;
.blacklist-item {
display: flex;
gap: 12px;
align-items: center;
padding: 12px 16px;
background: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
&:hover {
background: #f5f7fa;
border-color: #667eea;
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.2);
transform: translateX(4px);
}
.user-avatar {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
.avatar-icon {
width: 24px;
height: 24px;
color: #ffffff;
}
}
.user-details {
display: flex;
flex: 1;
flex-direction: column;
gap: 4px;
min-width: 0;
.user-name {
overflow: hidden;
font-size: 14px;
font-weight: 500;
color: #303133;
text-overflow: ellipsis;
white-space: nowrap;
}
.user-id {
font-size: 12px;
color: #909399;
}
}
.remove-btn {
display: flex;
gap: 4px;
align-items: center;
padding: 6px 12px;
font-size: 12px;
color: #ffffff;
white-space: nowrap;
cursor: pointer;
background: linear-gradient(135deg, #f56c6c 0%, #e74c3c 100%);
border: none;
border-radius: 6px;
transition: all 0.3s ease;
.remove-icon {
width: 14px;
height: 14px;
}
&:hover {
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
box-shadow: 0 4px 12px rgba(245, 108, 108, 0.4);
transform: scale(1.05);
}
&:active {
transform: scale(0.98);
}
}
}
}
</style> </style>

View File

@ -109,8 +109,8 @@
<style scoped lang="scss"> <style scoped lang="scss">
.student-sort-container { .student-sort-container {
padding: 10px 0;
position: relative; position: relative;
padding: 10px 0;
} }
.slick-list { .slick-list {
@ -123,16 +123,17 @@
align-items: center; align-items: center;
padding: 12px 16px; padding: 12px 16px;
margin-bottom: 8px; margin-bottom: 8px;
background: #f5f7fa;
border-radius: 8px;
cursor: move; cursor: move;
border: 2px solid transparent;
user-select: none; user-select: none;
background: #f5f7fa;
border: 1px solid #409eff;
border-radius: 8px;
box-shadow: 0 6px 16px rgba(54, 137, 246, 0.12);
.drag-handle { .drag-handle {
margin-right: 12px;
font-size: 20px; font-size: 20px;
color: #909399; color: #909399;
margin-right: 12px;
cursor: grab; cursor: grab;
} }
@ -142,12 +143,12 @@
justify-content: center; justify-content: center;
width: 28px; width: 28px;
height: 28px; height: 28px;
background: #409eff;
color: #fff;
border-radius: 50%;
font-weight: bold;
margin-right: 12px; margin-right: 12px;
font-size: 14px; font-size: 14px;
font-weight: bold;
color: #ffffff;
background: #409eff;
border-radius: 50%;
} }
.student-name { .student-name {
@ -164,7 +165,7 @@
.dialog-footer { .dialog-footer {
display: flex; display: flex;
justify-content: center;
gap: 16px; gap: 16px;
justify-content: center;
} }
</style> </style>