适配ClassworksKV

This commit is contained in:
SunWuyuan
2025-10-06 14:30:32 +08:00
parent 6cf67d17c6
commit 68d6582ae0
13 changed files with 835 additions and 1207 deletions
+74
View File
@@ -0,0 +1,74 @@
<template>
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<v-col cols="12" sm="8" md="6">
<v-card>
<v-card-title class="text-h5">
{{ status === 'processing' ? '正在处理授权...' : status === 'success' ? '授权成功' : '授权失败' }}
</v-card-title>
<v-card-text>
<v-progress-linear
v-if="status === 'processing'"
indeterminate
color="primary"
class="mb-4"
></v-progress-linear>
<p>{{ message }}</p>
</v-card-text>
<v-card-actions v-if="status !== 'processing'">
<v-spacer></v-spacer>
<v-btn color="primary" @click="goToHome">返回首页</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { getSetting, setSetting } from '@/utils/settings';
const route = useRoute();
const router = useRouter();
const status = ref('processing');
const message = ref('正在验证授权信息...');
onMounted(async () => {
try {
const token = route.query.token;
if (!token) {
status.value = 'error';
message.value = '未获取到授权令牌';
return;
}
// 保存token到设置
setSetting('server.kvToken', token);
const uuid = getSetting('device.uuid');
if (uuid && uuid !== '00000000-0000-4000-8000-000000000000') {
// 设置uuid为默认值,标记迁移完成
setSetting('device.uuid', '00000000-0000-4000-8000-000000000000');
message.value = '授权成功!已完成数据迁移。';
} else {
message.value = '授权成功!';
}
status.value = 'success';
router.push('/');
} catch (error) {
console.error('授权处理失败:', error);
status.value = 'error';
message.value = `授权失败: ${error.message}`;
}
});
const goToHome = () => {
router.push('/');
};
</script>
+132
View File
@@ -0,0 +1,132 @@
<template>
<v-container>
<v-row>
<v-col
cols="12"
md="6"
>
<v-card>
<v-card-title>KvInitialize 调试面板</v-card-title>
<v-card-text>
<v-form>
<v-text-field
v-model="provider"
label="server.provider (kv-server/classworkscloud/other)"
/>
<v-text-field
v-model="kvToken"
label="server.kvToken (空表示未授权)"
/>
<v-text-field
v-model="uuid"
label="device.uuid"
/>
<v-text-field
v-model="authDomain"
label="server.authDomain"
/>
</v-form>
<v-divider class="my-4" />
<v-btn
color="primary"
class="me-2"
@click="applySettings"
>
应用设置
</v-btn>
<v-btn
color="secondary"
class="me-2"
@click="clearGuard"
>
清除重定向守卫
</v-btn>
<v-btn
color="error"
@click="simulateLoadError"
>
模拟命名空间加载错误
</v-btn>
<v-list two-line>
<v-list-item>
<v-list-item-content>
<v-list-item-title>当前 sessionGuard</v-list-item-title>
<v-list-item-subtitle>{{ guardRaw }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-list-item>
<v-list-item-content>
<v-list-item-title>当前 settings</v-list-item-title>
<v-list-item-subtitle>{{ settingsDump }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-col>
<v-col
cols="12"
md="6"
>
<v-card>
<v-card-title>KvInitialize 预览</v-card-title>
<v-card-text>
<kv-initialize />
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script setup>
import { ref, computed } from 'vue'
import KvInitialize from '@/components/KvInitialize.vue'
import { getSetting, setSetting } from '@/utils/settings'
import { kvServerProvider } from '@/utils/providers/kvServerProvider'
const REDIRECT_GUARD_KEY = 'kvinit.redirecting'
const provider = ref(getSetting('server.provider') || 'kv-server')
const kvToken = ref(getSetting('server.kvToken') || '')
const uuid = ref(getSetting('device.uuid') || '00000000-0000-4000-8000-000000000000')
const authDomain = ref(getSetting('server.authDomain') || 'https://cs.example.com')
const applySettings = () => {
setSetting('server.provider', provider.value)
setSetting('server.kvToken', kvToken.value)
setSetting('device.uuid', uuid.value)
setSetting('server.authDomain', authDomain.value)
// reload to let app re-evaluate
location.reload()
}
const clearGuard = () => {
try { sessionStorage.removeItem(REDIRECT_GUARD_KEY) } catch (e) { console.debug(e) }
}
const simulateLoadError = () => {
// Monkey-patch kvServerProvider.loadNamespaceInfo to throw once
kvServerProvider.loadNamespaceInfo = async () => {
throw new Error('模拟加载错误')
}
// reload to apply
location.reload()
}
const guardRaw = computed(() => {
try { return sessionStorage.getItem(REDIRECT_GUARD_KEY) } catch (e) { return String(e) }
})
const settingsDump = computed(() => {
return JSON.stringify({
provider: getSetting('server.provider'),
kvToken: getSetting('server.kvToken'),
uuid: getSetting('device.uuid'),
authDomain: getSetting('server.authDomain')
}, null, 2)
})
</script>
+1 -3
View File
@@ -7,7 +7,7 @@
<v-spacer />
<template #append>
<namespace-access /> <v-btn
<v-btn
icon="mdi-bell"
variant="text"
:badge="unreadCount || undefined"
@@ -615,7 +615,6 @@
<script>
import MessageLog from "@/components/MessageLog.vue";
import RandomPicker from "@/components/RandomPicker.vue";
import NamespaceAccess from "@/components/NamespaceAccess.vue";
import FloatingToolbar from "@/components/FloatingToolbar.vue";
import FloatingICP from "@/components/FloatingICP.vue";
import HomeworkEditDialog from "@/components/HomeworkEditDialog.vue";
@@ -639,7 +638,6 @@ export default {
components: {
MessageLog,
RandomPicker,
NamespaceAccess,
FloatingToolbar,
FloatingICP,
HomeworkEditDialog,
+1 -26
View File
@@ -104,16 +104,9 @@
@saved="onSettingsSaved"
/>
<data-provider-settings-card border class="mt-4" />
<kv-database-card border class="mt-4" />
<kv-database-card border class="mt-4" />
</v-tabs-window-item>
<v-tabs-window-item value="namespace">
<namespace-settings-card
border
:loading="loading.namespace"
@saved="onSettingsSaved"
/>
</v-tabs-window-item>
<v-tabs-window-item value="student">
<student-list-card border :is-mobile="isMobile" />
</v-tabs-window-item>
@@ -238,7 +231,6 @@ import AboutCard from "@/components/settings/AboutCard.vue";
import "../styles/settings.scss";
import SettingsExplorer from "@/components/settings/SettingsExplorer.vue";
import SettingsLinkGenerator from "@/components/SettingsLinkGenerator.vue";
import NamespaceSettingsCard from "@/components/settings/cards/NamespaceSettingsCard.vue";
import RandomPickerCard from "@/components/settings/cards/RandomPickerCard.vue";
import HomeworkTemplateCard from "@/components/settings/cards/HomeworkTemplateCard.vue";
import SubjectManagementCard from "@/components/settings/cards/SubjectManagementCard.vue";
@@ -259,7 +251,6 @@ export default {
EchoChamberCard,
SettingsExplorer,
SettingsLinkGenerator,
NamespaceSettingsCard,
RandomPickerCard,
HomeworkTemplateCard,
SubjectManagementCard,
@@ -271,8 +262,6 @@ export default {
},
data() {
const provider = getSetting("server.provider");
const showNamespaceSettings =
provider === "kv-server" || provider === "classworkscloud";
const settings = {
server: {
@@ -280,11 +269,6 @@ export default {
classNumber: getSetting("server.classNumber"),
provider: getSetting("server.provider"),
},
namespace: {
name: getSetting("namespace.name"),
accessType: getSetting("namespace.accessType"),
password: getSetting("namespace.password"),
},
refresh: {
auto: getSetting("refresh.auto"),
interval: getSetting("refresh.interval"),
@@ -357,15 +341,6 @@ export default {
icon: "mdi-server",
value: "server",
},
...(showNamespaceSettings
? [
{
title: "命名空间",
icon: "mdi-database-lock",
value: "namespace",
},
]
: []),
{
title: "科目",
icon: "mdi-book-edit",