feat: Add ReadOnlyTokenWarning component and implement student name management dialog

- Introduced ReadOnlyTokenWarning.vue to alert users when using a read-only token.
- Added StudentNameManager.vue for managing student names with a dialog interface.
- Implemented AlternativeCodeDialog.vue for entering alternative codes (functionality pending).
- Created DeviceAuthDialog.vue for device authentication using namespace and password.
- Developed FirstTimeGuide.vue to guide users through the initial setup of Classworks KV.
- Added TokenInputDialog.vue for manual input of KV authorization tokens.
- Updated settings.vue to include a button for opening Classworks KV.
- Enhanced error handling and user feedback across components.
This commit is contained in:
SunWuyuan
2025-11-01 19:31:41 +08:00
parent a2b0cc9e08
commit df3c8e5a12
12 changed files with 2003 additions and 154 deletions
+111
View File
@@ -7,6 +7,30 @@
<v-spacer />
<template #append>
<!-- 只读 Token 警告 -->
<v-chip
v-if="tokenDisplayInfo.readonly"
color="warning"
variant="tonal"
class="mx-2"
prepend-icon="mdi-lock-alert"
>
只读
</v-chip>
<!-- 学生名称显示 chip(始终蓝色) -->
<v-chip
v-if="tokenDisplayInfo.show"
color="primary"
variant="tonal"
class="mx-2"
prepend-icon="mdi-account"
:style="{ cursor: tokenDisplayInfo.disabled ? 'default' : 'pointer' }"
@click="handleTokenChipClick"
>
{{ tokenDisplayInfo.text }}
</v-chip>
<v-btn icon="mdi-chat" variant="text" @click="isChatOpen = true" />
<v-btn
icon="mdi-bell"
@@ -21,6 +45,13 @@
<!-- 初始化选择卡片,仅在首页且需要授权时显示;不影响顶栏 -->
<init-service-chooser v-if="shouldShowInit" @done="settingsTick++" />
<!-- 学生姓名管理组件 -->
<StudentNameManager
v-if="!shouldShowInit"
ref="studentNameManager"
@token-info-updated="updateTokenDisplayInfo"
/>
<div v-if="!shouldShowInit" class="d-flex">
<!-- 主要内容区域 -->
<v-container class="main-window flex-grow-1 no-select" fluid>
@@ -629,6 +660,7 @@ import FloatingICP from "@/components/FloatingICP.vue";
import ChatWidget from "@/components/ChatWidget.vue";
import HomeworkEditDialog from "@/components/HomeworkEditDialog.vue";
import InitServiceChooser from "@/components/InitServiceChooser.vue";
import StudentNameManager from "@/components/StudentNameManager.vue";
import dataProvider from "@/utils/dataProvider";
import {
getSetting,
@@ -662,6 +694,7 @@ export default {
HomeworkEditDialog,
InitServiceChooser,
ChatWidget,
StudentNameManager,
},
data() {
const defaultSubjects = [
@@ -745,6 +778,16 @@ export default {
settingsTick: 0,
isChatOpen: false,
highlightedCards: {}, // 记录哪些卡片需要高亮
// Token 显示信息(统一显示 token 信息和学生姓名)
tokenDisplayInfo: {
show: false,
readonly: false, // 是否是只读 token
text: '',
color: 'primary',
variant: 'tonal',
icon: 'mdi-account',
disabled: false
},
// 实时刷新信息
realtimeInfo: {
show: false,
@@ -999,6 +1042,24 @@ export default {
this.updateSettings();
});
// 连接学生姓名管理组件
this.$nextTick(() => {
const studentNameManager = this.$refs.studentNameManager;
if (studentNameManager) {
this.studentNameInfo.name = studentNameManager.currentStudentName;
this.studentNameInfo.isStudent = studentNameManager.isStudentToken;
this.studentNameInfo.openDialog = () => studentNameManager.openDialog();
// 监听学生姓名变化
this.$watch(() => studentNameManager.currentStudentName, (newName) => {
this.studentNameInfo.name = newName;
});
this.$watch(() => studentNameManager.isStudentToken, (isStudent) => {
this.studentNameInfo.isStudent = isStudent;
});
}
});
document.addEventListener(
"fullscreenchange",
this.fullscreenChangeHandler
@@ -1022,6 +1083,11 @@ export default {
// 实时频道:加入设备房间并监听键变化
this.setupRealtimeChannel();
// 初始化 Token 显示信息
this.$nextTick(() => {
this.updateTokenDisplayInfo();
});
} catch (err) {
console.error("初始化失败:", err);
this.showError("初始化失败,请刷新页面重试");
@@ -1066,6 +1132,51 @@ export default {
},
methods: {
// 更新 Token 显示信息
updateTokenDisplayInfo() {
const manager = this.$refs.studentNameManager
if (!manager || !manager.hasToken) {
this.tokenDisplayInfo.show = false
this.tokenDisplayInfo.readonly = false
return
}
const displayName = manager.displayName
const isReadOnly = manager.isReadOnly
const isStudent = manager.isStudentToken
// 设置只读状态(对所有类型的 token 都显示)
this.tokenDisplayInfo.readonly = isReadOnly
// 只有学生类型的 token 才显示名称 chip
if (!isStudent) {
this.tokenDisplayInfo.show = false
return
}
// 设置学生名称显示(始终蓝色)
this.tokenDisplayInfo.text = displayName
this.tokenDisplayInfo.color = 'primary'
this.tokenDisplayInfo.icon = 'mdi-account'
this.tokenDisplayInfo.disabled = isReadOnly // 只读时不可点击
this.tokenDisplayInfo.show = true
},
// 处理 Token Chip 点击
handleTokenChipClick() {
console.log('Token chip clicked')
const manager = this.$refs.studentNameManager
console.log('Manager:', manager)
console.log('Is student token:', manager?.isStudentToken)
if (manager && manager.isStudentToken) {
console.log('Opening dialog...')
manager.openDialog()
} else {
console.log('Cannot open dialog - conditions not met')
}
},
ensureDate(dateInput) {
if (dateInput instanceof Date) {
return dateInput;
+4
View File
@@ -62,6 +62,7 @@
class="text-none"
append-icon="mdi-arrow-right"
rounded="xl"
@click="openClassworksKV"
>
打开 Classworks KV
</v-btn>
@@ -464,6 +465,9 @@ export default {
},
methods: {
openClassworksKV() {
window.open(getSetting("server.authDomain"), "_blank");
},
loadAllSettings() {
Object.keys(this.settings).forEach((section) => {
Object.keys(this.settings[section]).forEach((key) => {