diff --git a/UNIFIED_LINK_GENERATOR.md b/UNIFIED_LINK_GENERATOR.md deleted file mode 100644 index 68bea2d..0000000 --- a/UNIFIED_LINK_GENERATOR.md +++ /dev/null @@ -1,159 +0,0 @@ -# 统一链接生成器功能测试 - -## 功能概述 - -新的统一链接生成器将预配置认证信息和设置分享功能合并到一个链接中,用户可以: - -1. 输入命名空间和认证码(预配置认证) -2. 选择需要分享的设置项 -3. 生成包含两种信息的统一链接 - -## 核心特性 - -### ✅ **统一链接生成** -- 同时包含预配置认证参数和设置配置 -- 一个链接完成设备认证和设置应用 -- 自动编码和参数组合 - -### ✅ **智能界面设计** -- 分层式界面:预配置认证 + 设置分享 + 链接生成 -- 实时预览和状态显示 -- 安全提醒和敏感信息保护 - -### ✅ **安全优化** -- 数据源设置和已变更设置默认排除 `server.kvToken` -- 敏感设置项标记和值遮盖 -- 多重安全提醒 - -## 链接格式 - -### 基础预配置链接 -``` -https://domain.com/?namespace=classroom-001&authCode=pass123&autoExecute=true -``` - -### 包含设置的统一链接 -``` -https://domain.com/?namespace=classroom-001&authCode=pass123&autoExecute=true&config=eyJ... -``` - -其中: -- `namespace`: 设备命名空间 -- `authCode`: 认证码(可选) -- `autoExecute`: 是否自动执行认证 -- `config`: Base64编码的设置JSON对象 - -## 使用流程 - -1. **输入预配置信息** - - 命名空间(必填) - - 认证码(可选) - - 是否自动执行认证 - -2. **选择设置项** - - 快速选择:数据源设置、已变更设置、全选 - - 手动选择:通过详细列表选择特定设置 - - 安全保护:敏感设置默认不选中 - -3. **生成统一链接** - - 点击"生成统一链接"按钮 - - 链接实时生成和预览 - - 一键复制和测试 - -## 技术实现 - -### 参数组合逻辑 -```javascript -// 1. 添加预配置参数 -params.append("namespace", namespace); -params.append("authCode", authCode); -params.append("autoExecute", "true"); - -// 2. 添加设置配置 -if (selectedSettings.length > 0) { - const configObj = {}; - selectedSettings.forEach(key => { - configObj[key] = allSettings[key]; - }); - - const base64Config = btoa(JSON.stringify(configObj)); - params.append("config", base64Config); -} -``` - -### 自动更新机制 -- 监听预配置表单变化 -- 监听设置选择变化 -- 实时生成统一链接 - -## 使用场景 - -### 1. **设备批量部署 + 环境配置** -``` -https://classworks.example.com/?namespace=classroom-01&authCode=device01&autoExecute=true&config=eyJzZXJ2ZXIuZG9tYWluIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20ifQ== -``` -- 自动认证为指定设备 -- 自动配置服务器地址等设置 - -### 2. **演示环境快速部署** -``` -https://classworks.example.com/?namespace=demo&autoExecute=true&config=eyJkaXNwbGF5LnRoZW1lIjoiZGFyayIsImVkaXQubW9kZSI6InJlYWRvbmx5In0= -``` -- 自动认证为演示账号 -- 自动应用演示环境设置 - -### 3. **培训环境标准化** -``` -https://classworks.example.com/?namespace=training&authCode=train123&config=eyJkaXNwbGF5LnNob3dIZWxwIjp0cnVlLCJlZGl0LmVuYWJsZUd1aWRlIjp0cnVlfQ== -``` -- 预配置培训账号 -- 启用帮助和引导功能 - -## 安全考虑 - -### ✅ **默认安全** -- Token等敏感信息默认不包含 -- 快速选择按钮智能排除敏感设置 -- 明确的安全警告和提醒 - -### ✅ **用户控制** -- 用户仍可手动选择包含敏感设置 -- 敏感设置有明确标记 -- 提供充分的风险提示 - -### ✅ **传输安全** -- 建议HTTPS传输 -- URL参数会被自动清理 -- 设置信息经过Base64编码 - -## 兼容性 - -- ✅ 向后兼容现有的预配置功能 -- ✅ 向后兼容现有的设置分享功能 -- ✅ 新增统一链接格式 -- ✅ 保持所有现有API接口 - -## 测试建议 - -1. **基础功能测试** - - 仅预配置信息的链接生成 - - 预配置 + 设置的统一链接生成 - - 链接复制和测试功能 - -2. **安全功能测试** - - 验证敏感设置默认不选中 - - 验证敏感设置标记显示 - - 验证安全提醒展示 - -3. **兼容性测试** - - 测试生成的链接是否正常工作 - - 测试预配置认证是否正常 - - 测试设置应用是否正常 - -## 优势总结 - -1. **用户体验**: 一个链接完成所有配置,无需多步操作 -2. **部署效率**: 批量设备部署更加便捷 -3. **管理简化**: 减少链接管理复杂度 -4. **安全平衡**: 在便捷性和安全性之间找到平衡 -5. **功能完整**: 涵盖认证和配置的完整解决方案 \ No newline at end of file diff --git a/package.json b/package.json index 4cb18b1..2f4e86c 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "dev": "vite --host", "build": "vite build", "preview": "vite preview", - "lint": "eslint . --fix" + "lint": "eslint . --fix", + "prebuild": "node scripts/generate-sound-list.js" }, "dependencies": { "@fingerprintjs/fingerprintjs": "^5.0.1", diff --git a/scripts/generate-sound-list.js b/scripts/generate-sound-list.js new file mode 100644 index 0000000..45a796d --- /dev/null +++ b/scripts/generate-sound-list.js @@ -0,0 +1,149 @@ +/** + * 自动生成音频文件列表脚本 + * 读取 src/assets/sounds 文件夹中的所有音频文件并生成列表 + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// 音频文件路径 +const soundsDir = path.join(__dirname, '../src/assets/sounds'); +const outputFile = path.join(__dirname, '../src/utils/soundList.js'); + +// 读取音频文件 +function getSoundFiles() { + try { + const files = fs.readdirSync(soundsDir); + // 过滤出音频文件(.mp3, .wav, .ogg等) + const audioFiles = files.filter(file => { + const ext = path.extname(file).toLowerCase(); + return ['.mp3', '.wav', '.ogg', '.m4a', '.aac'].includes(ext); + }); + + return audioFiles.sort(); + } catch (error) { + console.error('读取音频文件夹失败:', error); + return []; + } +} + +// 生成文件内容 +function generateSoundList() { + const soundFiles = getSoundFiles(); + + const fileContent = `/** + * 自动生成的音频文件列表 + * 由 scripts/generate-sound-list.js 生成 + * 请勿手动修改此文件 + */ + +// 所有可用的音频文件列表 +export const soundFiles = ${JSON.stringify(soundFiles, null, 2)}; + +// 默认的单次通知铃声 +export const defaultSingleSound = 'Teams 默认.mp3'; + +// 默认的持续通知铃声 +export const defaultUrgentSound = 'Teams 默认通话铃.mp3'; + +// 获取音频文件的完整路径 +export function getSoundPath(filename) { + if (!filename) return null; + // 使用动态路径,避免Vite在构建时加载所有音频文件 + // 这样只有在真正需要播放时才会加载对应的音频文件 + return \`/src/assets/sounds/\${filename}\`; +} + +// 播放音频文件 +export function playSound(filename, loop = false) { + const path = getSoundPath(filename); + if (!path) { + console.warn('音频文件不存在:', filename); + return null; + } + + try { + // eslint-disable-next-line no-undef + const audio = new Audio(path); + audio.loop = loop; + + // 尝试播放,但不阻止返回audio对象 + const playPromise = audio.play(); + if (playPromise !== undefined) { + playPromise.catch(err => { + // 静默处理错误,调用者应该自己处理 + console.warn('播放音频失败:', err.name, err.message); + }); + } + + return audio; + } catch (error) { + console.error('创建音频对象失败:', error); + return null; + } +} + +// 播放音频文件(Promise版本,用于更好的错误处理) +export function playSoundAsync(filename, loop = false) { + return new Promise((resolve, reject) => { + const path = getSoundPath(filename); + if (!path) { + reject(new Error('音频文件不存在')); + return; + } + + try { + // eslint-disable-next-line no-undef + const audio = new Audio(path); + audio.loop = loop; + + // 预加载音频文件 + audio.preload = 'auto'; + + audio.play() + .then(() => resolve(audio)) + .catch(err => reject(err)); + } catch (error) { + reject(error); + } + }); +} + +// 停止音频播放 +export function stopSound(audio) { + if (audio) { + audio.pause(); + audio.currentTime = 0; + } +} +`; + + return fileContent; +} + +// 写入文件 +function writeSoundList() { + try { + const content = generateSoundList(); + + // 确保输出目录存在 + const outputDir = path.dirname(outputFile); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + fs.writeFileSync(outputFile, content, 'utf-8'); + console.log('✓ 音频文件列表生成成功:', outputFile); + console.log('✓ 共找到', getSoundFiles().length, '个音频文件'); + } catch (error) { + console.error('✗ 生成音频列表失败:', error); + process.exit(1); + } +} + +// 执行生成 +writeSoundList(); diff --git a/src/assets/sounds/Teams Ping.mp3 b/src/assets/sounds/Teams Ping.mp3 new file mode 100644 index 0000000..5f3e1c2 Binary files /dev/null and b/src/assets/sounds/Teams Ping.mp3 differ diff --git a/src/assets/sounds/Teams Remix.mp3 b/src/assets/sounds/Teams Remix.mp3 new file mode 100644 index 0000000..f50f267 Binary files /dev/null and b/src/assets/sounds/Teams Remix.mp3 differ diff --git a/src/assets/sounds/Teams bounce.mp3 b/src/assets/sounds/Teams bounce.mp3 new file mode 100644 index 0000000..0b4e136 Binary files /dev/null and b/src/assets/sounds/Teams bounce.mp3 differ diff --git a/src/assets/sounds/Teams incoming-ringtone-level30.mp3 b/src/assets/sounds/Teams incoming-ringtone-level30.mp3 new file mode 100644 index 0000000..ce9c3b8 Binary files /dev/null and b/src/assets/sounds/Teams incoming-ringtone-level30.mp3 differ diff --git a/src/assets/sounds/Teams incoming-ringtone-level40.mp3 b/src/assets/sounds/Teams incoming-ringtone-level40.mp3 new file mode 100644 index 0000000..41e1ef5 Binary files /dev/null and b/src/assets/sounds/Teams incoming-ringtone-level40.mp3 differ diff --git a/src/assets/sounds/Teams meetup_ring.mp3 b/src/assets/sounds/Teams meetup_ring.mp3 new file mode 100644 index 0000000..16ff8f7 Binary files /dev/null and b/src/assets/sounds/Teams meetup_ring.mp3 differ diff --git a/src/assets/sounds/Teams screenshare_ring.mp3 b/src/assets/sounds/Teams screenshare_ring.mp3 new file mode 100644 index 0000000..0e19996 Binary files /dev/null and b/src/assets/sounds/Teams screenshare_ring.mp3 differ diff --git a/src/assets/sounds/Teams teams_meet_up_reminder.mp3 b/src/assets/sounds/Teams teams_meet_up_reminder.mp3 new file mode 100644 index 0000000..0e19996 Binary files /dev/null and b/src/assets/sounds/Teams teams_meet_up_reminder.mp3 differ diff --git a/src/assets/sounds/Teams teams_notification.mp3 b/src/assets/sounds/Teams teams_notification.mp3 new file mode 100644 index 0000000..f4a0a3f Binary files /dev/null and b/src/assets/sounds/Teams teams_notification.mp3 differ diff --git a/src/assets/sounds/Teams 优先处理.mp3 b/src/assets/sounds/Teams 优先处理.mp3 new file mode 100644 index 0000000..910efd0 Binary files /dev/null and b/src/assets/sounds/Teams 优先处理.mp3 differ diff --git a/src/assets/sounds/Teams 共鸣.mp3 b/src/assets/sounds/Teams 共鸣.mp3 new file mode 100644 index 0000000..7f46f4e Binary files /dev/null and b/src/assets/sounds/Teams 共鸣.mp3 differ diff --git a/src/assets/sounds/Teams 召唤.mp3 b/src/assets/sounds/Teams 召唤.mp3 new file mode 100644 index 0000000..0b4aae2 Binary files /dev/null and b/src/assets/sounds/Teams 召唤.mp3 differ diff --git a/src/assets/sounds/Teams 叮铃.mp3 b/src/assets/sounds/Teams 叮铃.mp3 new file mode 100644 index 0000000..a099399 Binary files /dev/null and b/src/assets/sounds/Teams 叮铃.mp3 differ diff --git a/src/assets/sounds/Teams 增强.mp3 b/src/assets/sounds/Teams 增强.mp3 new file mode 100644 index 0000000..03f7249 Binary files /dev/null and b/src/assets/sounds/Teams 增强.mp3 differ diff --git a/src/assets/sounds/Teams 尤里卡.mp3 b/src/assets/sounds/Teams 尤里卡.mp3 new file mode 100644 index 0000000..fb5cdb8 Binary files /dev/null and b/src/assets/sounds/Teams 尤里卡.mp3 differ diff --git a/src/assets/sounds/Teams 弹拨.mp3 b/src/assets/sounds/Teams 弹拨.mp3 new file mode 100644 index 0000000..a31cd6c Binary files /dev/null and b/src/assets/sounds/Teams 弹拨.mp3 differ diff --git a/src/assets/sounds/Teams 提醒.mp3 b/src/assets/sounds/Teams 提醒.mp3 new file mode 100644 index 0000000..fce78c9 Binary files /dev/null and b/src/assets/sounds/Teams 提醒.mp3 differ diff --git a/src/assets/sounds/Teams 摇摆.mp3 b/src/assets/sounds/Teams 摇摆.mp3 new file mode 100644 index 0000000..65fd935 Binary files /dev/null and b/src/assets/sounds/Teams 摇摆.mp3 differ diff --git a/src/assets/sounds/Teams 时空.mp3 b/src/assets/sounds/Teams 时空.mp3 new file mode 100644 index 0000000..bcf62e7 Binary files /dev/null and b/src/assets/sounds/Teams 时空.mp3 differ diff --git a/src/assets/sounds/Teams 气泡(大声).mp3 b/src/assets/sounds/Teams 气泡(大声).mp3 new file mode 100644 index 0000000..212db3a Binary files /dev/null and b/src/assets/sounds/Teams 气泡(大声).mp3 differ diff --git a/src/assets/sounds/Teams 气泡.mp3 b/src/assets/sounds/Teams 气泡.mp3 new file mode 100644 index 0000000..92896fe Binary files /dev/null and b/src/assets/sounds/Teams 气泡.mp3 differ diff --git a/src/assets/sounds/Teams 波普.mp3 b/src/assets/sounds/Teams 波普.mp3 new file mode 100644 index 0000000..ee69f22 Binary files /dev/null and b/src/assets/sounds/Teams 波普.mp3 differ diff --git a/src/assets/sounds/Teams 波纹.mp3 b/src/assets/sounds/Teams 波纹.mp3 new file mode 100644 index 0000000..966701b Binary files /dev/null and b/src/assets/sounds/Teams 波纹.mp3 differ diff --git a/src/assets/sounds/Teams 滴水.mp3 b/src/assets/sounds/Teams 滴水.mp3 new file mode 100644 index 0000000..e61ad75 Binary files /dev/null and b/src/assets/sounds/Teams 滴水.mp3 differ diff --git a/src/assets/sounds/Teams 点击.mp3 b/src/assets/sounds/Teams 点击.mp3 new file mode 100644 index 0000000..fadcfa5 Binary files /dev/null and b/src/assets/sounds/Teams 点击.mp3 differ diff --git a/src/assets/sounds/Teams 蜂鸣声.mp3 b/src/assets/sounds/Teams 蜂鸣声.mp3 new file mode 100644 index 0000000..765e504 Binary files /dev/null and b/src/assets/sounds/Teams 蜂鸣声.mp3 differ diff --git a/src/assets/sounds/Teams 警报.mp3 b/src/assets/sounds/Teams 警报.mp3 new file mode 100644 index 0000000..c5da548 Binary files /dev/null and b/src/assets/sounds/Teams 警报.mp3 differ diff --git a/src/assets/sounds/Teams 赋予希望.mp3 b/src/assets/sounds/Teams 赋予希望.mp3 new file mode 100644 index 0000000..7562489 Binary files /dev/null and b/src/assets/sounds/Teams 赋予希望.mp3 differ diff --git a/src/assets/sounds/Teams 轻弹.mp3 b/src/assets/sounds/Teams 轻弹.mp3 new file mode 100644 index 0000000..f509a4e Binary files /dev/null and b/src/assets/sounds/Teams 轻弹.mp3 differ diff --git a/src/assets/sounds/Teams 进阶.mp3 b/src/assets/sounds/Teams 进阶.mp3 new file mode 100644 index 0000000..9c1d68e Binary files /dev/null and b/src/assets/sounds/Teams 进阶.mp3 differ diff --git a/src/assets/sounds/Teams 重复振铃.mp3 b/src/assets/sounds/Teams 重复振铃.mp3 new file mode 100644 index 0000000..7cd5fcf Binary files /dev/null and b/src/assets/sounds/Teams 重复振铃.mp3 differ diff --git a/src/assets/sounds/Teams 颤振.mp3 b/src/assets/sounds/Teams 颤振.mp3 new file mode 100644 index 0000000..9ff2793 Binary files /dev/null and b/src/assets/sounds/Teams 颤振.mp3 differ diff --git a/src/assets/sounds/Teams 高分.mp3 b/src/assets/sounds/Teams 高分.mp3 new file mode 100644 index 0000000..53d2891 Binary files /dev/null and b/src/assets/sounds/Teams 高分.mp3 differ diff --git a/src/assets/sounds/Teams 默认.mp3 b/src/assets/sounds/Teams 默认.mp3 new file mode 100644 index 0000000..639c092 Binary files /dev/null and b/src/assets/sounds/Teams 默认.mp3 differ diff --git a/src/assets/sounds/Teams 默认通话铃.mp3 b/src/assets/sounds/Teams 默认通话铃.mp3 new file mode 100644 index 0000000..36d569f Binary files /dev/null and b/src/assets/sounds/Teams 默认通话铃.mp3 differ diff --git a/src/components/StudentNameManager.vue b/src/components/StudentNameManager.vue index d5b6ecf..fe8742c 100644 --- a/src/components/StudentNameManager.vue +++ b/src/components/StudentNameManager.vue @@ -1,32 +1,92 @@ @@ -81,15 +152,25 @@ const saving = ref(false) const error = ref('') const tokenInfo = ref(null) +// 教师相关状态 +const teacherList = ref([]) +const selectedTeacherName = ref('') +const currentTeacherName = ref('') +const teacherForm = ref({ name: '', isHeadTeacher: false, subjects: [] }) + const isStudentToken = computed(() => tokenInfo.value?.deviceType === 'student') +const isTeacherToken = computed(() => tokenInfo.value?.deviceType === 'teacher') const isReadOnly = computed(() => tokenInfo.value?.isReadOnly === true) const displayName = computed(() => tokenInfo.value?.note || '设置名称') const hasToken = computed(() => !!kvToken.value) const kvToken = computed(() => getSetting('server.kvToken')) const provider = computed(() => getSetting('server.provider')) const isKvProvider = computed(() => provider.value === 'kv-server' || provider.value === 'classworkscloud') +const dialogTitle = computed(() => (isStudentToken.value ? '设置学生姓名' : isTeacherToken.value ? '设置教师姓名' : '设置姓名')) +// 教师建议列表(显示所有教师) +const filteredTeacherSuggestions = computed(() => teacherList.value) -// 检查是否需要设置学生姓名 +// 检查是否需要设置姓名(学生/教师) const checkStudentNameStatus = async () => { if (!isKvProvider.value || !kvToken.value) { return @@ -108,37 +189,57 @@ const checkStudentNameStatus = async () => { tokenInfo.value = tokenResponse.data - // 如果不是学生类型,不需要处理 - if (tokenInfo.value.deviceType !== 'student') { - return - } + // 学生设备处理 + if (tokenInfo.value.deviceType === 'student') { + currentStudentName.value = tokenInfo.value.note || '' - // 保存当前学生姓名 - currentStudentName.value = tokenInfo.value.note || '' + const listResponse = await axios.get(`${serverUrl}/kv/classworks-list-main`, { + headers: { Authorization: `Bearer ${kvToken.value}` } + }) + const list = listResponse.data.value || [] + studentList.value = Array.isArray(list) ? list : [] - // 获取学生列表 - const listResponse = await axios.get(`${serverUrl}/kv/classworks-list-main`, { - headers: { - Authorization: `Bearer ${kvToken.value}` + if (studentList.value.length > 0) { + const currentNote = tokenInfo.value.note || '' + const nameExists = studentList.value.some(s => s.name === currentNote) + if (!currentNote || !nameExists) { + showDialog.value = true + selectedName.value = '' + } } - }) - - const list = listResponse.data.value || [] - studentList.value = Array.isArray(list) ? list : [] - - // 如果学生列表为空,不需要提示 - if (studentList.value.length === 0) { return } - // 检查当前姓名是否在学生列表中 - const currentNote = tokenInfo.value.note || '' - const nameExists = studentList.value.some(student => student.name === currentNote) + // 教师设备处理 + if (tokenInfo.value.deviceType === 'teacher') { + currentTeacherName.value = tokenInfo.value.note || '' - // 如果姓名为空或不在列表中,显示对话框 - if (!currentNote || !nameExists) { - showDialog.value = true - selectedName.value = '' + try { + const listResponse = await axios.get(`${serverUrl}/kv/classworks-list-teacher`, { + headers: { Authorization: `Bearer ${kvToken.value}` } + }) + const list = listResponse.data.value || [] + teacherList.value = Array.isArray(list) ? list : [] + } catch (err) { + // 如果列表不存在(404),初始化为空数组 + if (err?.response?.status === 404) { + console.log('教师列表不存在,初始化为空') + teacherList.value = [] + } else { + console.error('加载教师列表失败:', err) + teacherList.value = [] + } + } + + if (teacherList.value.length > 0) { + const currentNote = tokenInfo.value.note || '' + const nameExists = teacherList.value.some(t => t.name === currentNote) + if (!currentNote || !nameExists) { + showDialog.value = true + selectedTeacherName.value = '' + } + } + return } } catch (err) { @@ -187,6 +288,74 @@ const saveStudentName = async () => { } } +// 保存教师姓名 +const saveTeacherName = async () => { + if (!teacherForm.value.name || saving.value) return + error.value = '' + saving.value = true + + try { + const serverUrl = getSetting('server.domain') + const token = kvToken.value + + // 构建教师数据 + const entry = { + name: teacherForm.value.name.trim(), + isHeadTeacher: !!teacherForm.value.isHeadTeacher, + subjects: Array.isArray(teacherForm.value.subjects) + ? teacherForm.value.subjects.filter(s => s && String(s).trim()).map(s => String(s).trim()) + : [] + } + + // 先更新本地列表 + const idx = teacherList.value.findIndex(t => t.name === entry.name) + if (idx >= 0) { + teacherList.value[idx] = entry + } else { + teacherList.value.push(entry) + } + + // 保存列表到 KV + const res = await dataProvider.saveData('classworks-list-teacher', teacherList.value) + if (res?.success === false) { + throw new Error(res?.error?.message || '保存列表失败') + } + + // 设置教师名称 + const response = await axios.post( + `${serverUrl}/apps/tokens/${token}/set-teacher-name`, + { name: entry.name } + ) + + if (response.data.success) { + currentTeacherName.value = entry.name + showDialog.value = false + await checkStudentNameStatus() + emit('token-info-updated') + } + } catch (err) { + const status = err?.response?.status + if (status === 400) { + error.value = '该名称不在教师列表中,请选择正确的姓名' + } else if (status === 403) { + error.value = '只有教师类型的 Token 可以设置姓名' + } else if (status === 404) { + error.value = '设备未设置教师列表或 Token 不存在' + } else { + error.value = err?.response?.data?.error?.message || err?.message || '设置失败,请稍后重试' + } + } finally { + saving.value = false + } +} + +// 从建议中选择教师,自动填充班主任和科目 +const selectTeacherFromSuggestion = (teacher) => { + teacherForm.value.name = teacher.name + teacherForm.value.isHeadTeacher = teacher.isHeadTeacher || false + teacherForm.value.subjects = Array.isArray(teacher.subjects) ? [...teacher.subjects] : [] +} + // 跳过设置 const skipSetting = () => { showDialog.value = false @@ -199,29 +368,46 @@ const openDialog = async () => { console.log('studentList.length:', studentList.value.length) console.log('currentStudentName:', currentStudentName.value) - if (!isStudentToken.value) { - console.log('Not a student token, cannot open dialog') + if (isStudentToken.value) { + const resp = await dataProvider.loadData('classworks-list-main') + studentList.value = Array.isArray(resp?.value) ? resp.value : (Array.isArray(resp) ? resp : []) + if (studentList.value.length === 0) { + console.log('Student list is empty, trying to load...') + await checkStudentNameStatus() + selectedName.value = currentStudentName.value + showDialog.value = true + } else { + selectedName.value = currentStudentName.value + showDialog.value = true + } return } - studentList.value = await dataProvider.loadData('classworks-list-main') - // 如果是学生 token,即使列表为空也应该打开对话框 - // 可能是列表还在加载中 - if (studentList.value.length === 0) { - console.log('Student list is empty, trying to load...') - // 重新加载学生列表 - checkStudentNameStatus().then(() => { - if (studentList.value.length > 0) { - selectedName.value = currentStudentName.value - showDialog.value = true - } else { - console.warn('Student list is still empty after reload') + + if (isTeacherToken.value) { + try { + const resp = await dataProvider.loadData('classworks-list-teacher') + teacherList.value = Array.isArray(resp?.value) ? resp.value : (Array.isArray(resp) ? resp : []) + } catch { + // 如果列表不存在,初始化为空 + console.log('教师列表不存在或加载失败,允许手动创建') + teacherList.value = [] + } + // 重置教师表单 + teacherForm.value = { name: currentTeacherName.value, isHeadTeacher: false, subjects: [] } + // 如果当前有教师名称,尝试从列表中读取班主任和科目信息 + if (currentTeacherName.value) { + const found = teacherList.value.find(t => t.name === currentTeacherName.value) + if (found) { + teacherForm.value.isHeadTeacher = found.isHeadTeacher || false + teacherForm.value.subjects = Array.isArray(found.subjects) ? [...found.subjects] : [] } - }) - } else { - selectedName.value = currentStudentName.value + } showDialog.value = true - console.log('Dialog opened, showDialog:', showDialog.value) + console.log('Dialog opened (teacher), showDialog:', showDialog.value) + return } + + console.log('Not a student/teacher token, cannot open dialog') } // 监听 token 变化 @@ -249,7 +435,9 @@ defineExpose({ checkStudentNameStatus, openDialog, currentStudentName, + currentTeacherName, isStudentToken, + isTeacherToken, isReadOnly, displayName, hasToken, diff --git a/src/components/UrgentNotification.vue b/src/components/UrgentNotification.vue index a34ceec..c32ae37 100644 --- a/src/components/UrgentNotification.vue +++ b/src/components/UrgentNotification.vue @@ -15,40 +15,11 @@
{{ currentNotification?.content?.message || "无内容" }}
+
+ {{ senderName }} {{ deviceType }} {{ formatTime(currentNotification?.timestamp) }} +
+ - - - 发送者信息 - - - mdi-account - {{ senderName }} - - - mdi-devices - {{ deviceType }} - - - mdi-clock - {{ formatTime(currentNotification?.timestamp) }} - - -