From bf6496b755d85261595c0da305e5273155cc14f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=BC=A0?= <2091066548@qq.com> Date: Sun, 21 Sep 2025 04:12:09 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9Abug=E7=BB=9F=E4=B8=80=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/modules/exam.ts | 114 +++++ src/components/layout/AppHeader.vue | 16 +- src/views/CourseExchanged.vue | 190 +++++--- src/views/Home.vue | 32 +- .../ExamPages/QuestionBankManagement.vue | 431 +++++++++++++++++- 5 files changed, 711 insertions(+), 72 deletions(-) diff --git a/src/api/modules/exam.ts b/src/api/modules/exam.ts index 7dc8ca1..fb9d6d5 100644 --- a/src/api/modules/exam.ts +++ b/src/api/modules/exam.ts @@ -1305,6 +1305,120 @@ export class ExamApi { return response } + // ========== 题库权限管理相关接口 ========== + + /** + * 搜索用户列表(用于权限分配) + */ + static async searchUsers(params: { + repoId: string // 必需参数 + employeeNumber?: string + username?: string + }): Promise> { + console.log('🚀 搜索用户列表:', params) + + // 构建查询参数,确保参数格式正确 + const queryParams: Record = { + repoId: params.repoId + } + if (params.employeeNumber) { + queryParams.employeeNumber = params.employeeNumber + } + if (params.username) { + queryParams.username = params.username + } + + console.log('📤 发送请求参数:', queryParams) + + const response = await ApiRequest.get('/aiol/aiolRepo/userList', queryParams) + console.log('✅ 搜索用户列表成功:', response) + return response as ApiResponse<{ + success: boolean + code: number + message: string + result: { + userId: string + userName: string + userAvatar: string + permission: boolean + }[] + timestamp: number + }> + } + + /** + * 获取题库有权限的用户列表 + */ + static async getUsersByRepoId(repoId: string): Promise> { + console.log('🚀 获取题库有权限的用户列表:', { repoId }) + const response = await ApiRequest.get(`/aiol/aiolRepo/userListByRepoId/${repoId}`) + console.log('✅ 获取题库有权限的用户列表成功:', response) + return response as ApiResponse<{ + success: boolean + code: number + message: string + result: { + userId: string + userName: string + userAvatar: string + permission: boolean + }[] + timestamp: number + }> + } + + /** + * 添加或删除题库权限 + */ + static async addOrDeletePermission(params: { + repoId: string + type: 'add' | 'delete' + userId: string + }): Promise> { + console.log('🚀 添加或删除题库权限:', params) + + // 构建路径参数的URL + const url = `/aiol/aiolRepo/addOrDeletePermission?repoId=${params.repoId}&type=${params.type}&userId=${params.userId}` + + const response = await ApiRequest.post(url) + console.log('✅ 添加或删除题库权限成功:', response) + return response as ApiResponse<{ + success: boolean + code: number + message: string + result: string + timestamp: number + }> + } + // ========== 阅卷中心相关接口 ========== /** diff --git a/src/components/layout/AppHeader.vue b/src/components/layout/AppHeader.vue index b0b50f7..20f7cc2 100644 --- a/src/components/layout/AppHeader.vue +++ b/src/components/layout/AppHeader.vue @@ -179,6 +179,12 @@ watch(() => userStore.user?.avatar, (newAvatar) => { console.log('🖼️ AppHeader - 头像URL变化:', newAvatar) }, { immediate: true }) +// 监听用户角色变化 +watch(() => userStore.isTeacher, (isTeacher) => { + console.log('👨‍🏫 AppHeader - 用户是否为教师:', isTeacher) + console.log('👤 AppHeader - 用户角色:', userStore.user?.role) +}, { immediate: true }) + // 移动端菜单状态 const mobileMenuOpen = ref(false) @@ -548,13 +554,13 @@ const userMenuOptions = computed(() => [ }, [ h('img', { src: '/images/personal/用户_user备份@2x.png', - alt: '个人资料', + alt: '个人中心', style: 'width: 18px; height: 18px; object-fit: contain;' }) ]), h('span', { style: 'font-size: 14px; color: #333; font-weight: 500;' - }, '个人资料') + }, '个人中心') ]) ]), @@ -563,8 +569,8 @@ const userMenuOptions = computed(() => [ class: 'user-menu-footer', style: 'display: flex; justify-content: space-between; align-items: center; padding-top: 12px; border-top: 1px solid #f0f0f0;' }, [ - // 切换教师端 - h('div', { + // 切换教师端 - 只有teacher角色才显示 + ...(userStore.isTeacher ? [h('div', { class: 'footer-action', style: 'display: flex; align-items: center; gap: 4px; cursor: pointer; padding: 4px 8px; border-radius: 4px; transition: background-color 0.2s;', onClick: () => handleUserMenuSelect('teacher') @@ -577,7 +583,7 @@ const userMenuOptions = computed(() => [ h('span', { style: 'font-size: 12px; color: #666;' }, '切换教师端') - ]), + ])] : []), // 安全退出 h('div', { diff --git a/src/views/CourseExchanged.vue b/src/views/CourseExchanged.vue index 3fc3fc2..a8aacfb 100644 --- a/src/views/CourseExchanged.vue +++ b/src/views/CourseExchanged.vue @@ -64,7 +64,7 @@
{{ comment.content }}
-
- - - + @@ -689,13 +686,14 @@ +6
-
-
- 笔记 - 笔记 -
+ @@ -1662,9 +1660,15 @@ const commentsCount = computed(() => { return comments.value.length }) -// 自动调整textarea高度 +// 自动调整textarea高度(但不影响固定高度的textarea) const adjustTextareaHeight = (event: Event) => { const textarea = event.target as HTMLTextAreaElement + // 如果textarea有comment-textarea类且在发布评论区域,保持固定高度36px + if (textarea.classList.contains('comment-textarea') && textarea.closest('.post-comment-section')) { + textarea.style.height = '36px' + return + } + // 其他textarea正常调整高度 textarea.style.height = 'auto' textarea.style.height = textarea.scrollHeight + 'px' } @@ -1672,7 +1676,12 @@ const adjustTextareaHeight = (event: Event) => { // 点击textarea时调整高度 const handleTextareaClick = (event: MouseEvent) => { const textarea = event.target as HTMLTextAreaElement - // 如果当前高度是40px,则调整到60px + // 如果textarea有comment-textarea类且在发布评论区域,保持固定高度36px + if (textarea.classList.contains('comment-textarea') && textarea.closest('.post-comment-section')) { + textarea.style.height = '36px' + return + } + // 其他textarea正常调整高度 if (textarea.style.height === '40px' || textarea.style.height === '') { textarea.style.height = '60px' } @@ -1773,6 +1782,22 @@ const cancelReply = () => { replyText.value = '' } +// 返回到视频页面 +const goBackToVideo = () => { + // 退出练习模式和讨论模式,返回到正常的课程视频页面 + practiceMode.value = false + discussionMode.value = false + practiceStarted.value = false + practiceFinished.value = false + + // 清除当前练习相关状态 + currentPracticeSection.value = null + currentQuestionIndex.value = 0 + + + console.log('🔙 返回到视频页面') +} + const submitReply = () => { if (replyText.value.trim() && replyingTo.value) { const newReplyObj = { @@ -3252,7 +3277,7 @@ onActivated(() => { width: 300px; flex-shrink: 0; align-self: flex-start; - margin-top: 72px; /* 与提示区域顶部对齐 */ + margin-top: 54px; /* 与广告区域齐平 */ } /* 面包屑导航样式 */ @@ -3279,6 +3304,15 @@ onActivated(() => { cursor: pointer; white-space: nowrap; /* 一行展示,不换行 */ /* 移除固定宽度,让内容完全展示 */ + transition: color 0.3s ease; +} + +.breadcrumb-course.clickable { + color: #333333; /* 保持原来的颜色 */ +} + +.breadcrumb-course.clickable:hover { + /* 悬停时保持原样,不改变颜色和样式 */ } .breadcrumb-separator { @@ -6926,11 +6960,15 @@ onActivated(() => { /* 发布评论区域 */ .post-comment-section { margin-bottom: 10px; + background: transparent; /* 无背景 */ + border: none; /* 无边框 */ } .comment-input-wrapper { display: flex; gap: 12px; + background: transparent; /* 无背景 */ + border: none; /* 无边框 */ } .user-avatar img { @@ -6943,20 +6981,47 @@ onActivated(() => { .comment-input-area { flex: 1; + background: transparent; /* 无背景 */ + border: none; /* 无边框 */ } .comment-textarea { - width: 100%; - border: 1px solid #E6E6E6; - padding: 10px; - font-size: 14px; - resize: none; - font-family: inherit; - height: 40px; - min-height: 40px; - box-sizing: border-box; - overflow: hidden; - transition: height 0.3s ease; + width: 100% !important; + border: 1px solid #E6E6E6 !important; + border-radius: 2px !important; + padding: 8px 12px !important; + font-size: 14px !important; + resize: none !important; /* 强制禁用调整大小功能 */ + font-family: PingFangSC, PingFang SC !important; + height: 36px !important; /* 强制设置高度为36px */ + min-height: 36px !important; + max-height: 36px !important; + box-sizing: border-box !important; + overflow: hidden !important; + background: transparent !important; /* 透明背景 */ + outline: none !important; + line-height: 20px !important; + /* 完全移除 resize handle */ + -webkit-appearance: none !important; + -moz-appearance: none !important; + appearance: none !important; +} + +/* 针对外面评论区域的 textarea 强制移除 resize handle */ +.comment-textarea::-webkit-resizer { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + width: 0 !important; + height: 0 !important; +} + +.comment-textarea::-moz-resizer { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + width: 0 !important; + height: 0 !important; } .comment-textarea:focus { @@ -6973,6 +7038,8 @@ onActivated(() => { display: flex; justify-content: space-between; align-items: center; + padding-top: 1px; /* 与讨论区域一致的间距 */ + } .toolbar-left { @@ -6981,10 +7048,11 @@ onActivated(() => { } .toolbar-btn { - background: none; - border: none; width: 24px; height: 20px; + border-radius: 2px; + border: 1px solid #E6E6E6; + background: transparent; /* 透明背景 */ cursor: pointer; display: flex; align-items: center; @@ -6997,9 +7065,9 @@ onActivated(() => { } .toolbar-icon { - width: 12px; - height: 12px; - object-fit: contain; + width: 16px; /* 调整图标大小 */ + height: 16px; + /* 移除蓝色边框 */ } .toolbar-right { @@ -7011,11 +7079,17 @@ onActivated(() => { background: #0088D1; color: white; border: none; + border-radius: 2px; /* 添加圆角 */ padding: 3px 10px; cursor: pointer; font-size: 14px; transition: background-color 0.3s; font-weight: 500; + width: 48px; /* 与讨论区域一致的宽度 */ + height: 24px; /* 与讨论区域一致的高度 */ + font-family: PingFangSC, PingFang SC; + text-align: center; + line-height: 20px; } .btn-submit:hover:not(:disabled) { @@ -7079,7 +7153,7 @@ onActivated(() => { border: none; padding: 10px; font-size: 14px; - resize: none; + resize: none !important; /* 强制禁用调整大小功能 */ font-family: inherit; height: 40px; min-height: 40px; @@ -7087,6 +7161,10 @@ onActivated(() => { overflow: hidden; transition: height 0.3s ease; background: transparent; + /* 完全移除 resize handle */ + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } .reply-textarea:focus { @@ -7099,6 +7177,23 @@ onActivated(() => { color: #999; } +/* 针对回复区域的 textarea 强制移除 resize handle */ +.reply-textarea::-webkit-resizer { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + width: 0 !important; + height: 0 !important; +} + +.reply-textarea::-moz-resizer { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + width: 0 !important; + height: 0 !important; +} + .reply-toolbar { display: flex; justify-content: space-between; @@ -8374,28 +8469,9 @@ onActivated(() => { margin-bottom: 32px; } -.comment-input-wrapper { - border: 1px solid #d9d9d9; - border-radius: 8px; - overflow: hidden; - background: white; -} +/* 移除重复的 comment-input-wrapper 样式,使用上面的定义 */ -.comment-textarea { - width: 100%; - padding: 16px; - border: none; - outline: none; - resize: vertical; - min-height: 80px; - font-size: 14px; - line-height: 1.6; - font-family: inherit; -} - -.comment-textarea::placeholder { - color: #bfbfbf; -} +/* 移除重复的 comment-textarea 样式,使用上面的定义 */ .comment-actions { display: flex; diff --git a/src/views/Home.vue b/src/views/Home.vue index a8d75c7..110dfcd 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -503,7 +503,7 @@
-
+
客服
+
+
+
权限管理
+
+ + 管理用户权限 + +
+
+ + + +
+ + + +
+
+ +
+ + 移除权限 + +
+
+
+
+ +
+
+ + + + + +
+
+ +
+ + {{ user.permission ? '移除权限' : '添加权限' }} + +
+
+
+
+ +
+
+ +
+
+
+
+ + +