mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-09-03 16:19:22 +00:00
Implement data migration tool and enhance KV storage support. Add automatic redirection for legacy data providers, improve user interface for migration settings, and update data handling for Classworks cloud storage. Refactor components for better integration with new storage options.
This commit is contained in:
parent
c0e33dcbf9
commit
a542e9b91f
36
src/App.vue
36
src/App.vue
@ -10,17 +10,51 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { onMounted, watch } from 'vue';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { getSetting } from '@/utils/settings';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
onMounted(() => {
|
||||
// 应用保存的主题设置
|
||||
const savedTheme = getSetting('theme.mode');
|
||||
theme.global.name.value = savedTheme;
|
||||
|
||||
// 检查存储提供者类型
|
||||
checkProviderType();
|
||||
});
|
||||
|
||||
// 检查存储提供者类型,如果是已废弃的类型则重定向
|
||||
function checkProviderType() {
|
||||
const currentProvider = getSetting('server.provider');
|
||||
|
||||
// 如果是旧的提供者类型且当前不在迁移页面,则重定向到数据迁移页面
|
||||
if ((currentProvider === 'server' || currentProvider === 'indexedDB') &&
|
||||
route.path !== '/datamigration') {
|
||||
console.log('检测到旧的数据提供者类型,正在重定向到数据迁移页面...');
|
||||
router.push({
|
||||
path: '/datamigration',
|
||||
query: {
|
||||
reason: 'legacy_provider',
|
||||
provider: currentProvider
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 当路由变化时再次检查,确保用户不会绕过重定向
|
||||
watch(
|
||||
() => route.path,
|
||||
(newPath) => {
|
||||
if (newPath !== '/datamigration') {
|
||||
checkProviderType();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style>
|
||||
|
||||
|
@ -82,14 +82,14 @@
|
||||
<!-- 统一的数据显示卡片 -->
|
||||
<v-card class="mb-6">
|
||||
<v-card-title class="d-flex align-center">
|
||||
<span>{{ migrationType === 'local' ? '本地数据库内容' : '服务器数据预览' }}</span>
|
||||
<span>{{ migrationType === 'local' ? '本地数据库内容' : '服务器数据内容' }}</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="migrationType === 'local' ? scanLocalDatabase() : previewServerData()"
|
||||
:loading="loading || scanning"
|
||||
>
|
||||
{{ migrationType === 'local' ? '扫描数据' : '预览数据' }}
|
||||
{{ migrationType === 'local' ? '扫描数据' : '加载数据' }}
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
@ -99,7 +99,7 @@
|
||||
>
|
||||
{{ migrationType === 'local'
|
||||
? '尚未扫描本地数据或未找到可迁移的数据。点击"扫描数据"按钮开始扫描。'
|
||||
: '尚未预览服务器数据或未找到可迁移的数据。点击"预览数据"按钮开始查询。'
|
||||
: '尚未预览服务器数据或未找到可迁移的数据。点击"加载数据"按钮开始查询。'
|
||||
}}
|
||||
</v-alert>
|
||||
|
||||
@ -478,7 +478,8 @@ export default {
|
||||
const res = await axios.get(homeworkUrl, {
|
||||
headers: this.getRequestHeaders()
|
||||
});
|
||||
if (res.data) {
|
||||
if (res.data&&res.data.status!=false) {
|
||||
console.log(res.data);
|
||||
this.serverItems.push({
|
||||
type: 'homework',
|
||||
key: `homework_${this.classNumber}_${dateStr}`,
|
||||
@ -624,7 +625,7 @@ export default {
|
||||
|
||||
if (itemType === 'config') {
|
||||
// 配置键名: classNumber/classworks-config
|
||||
await db.put("kv", JSON.stringify(value), `${this.classNumber}/classworks-config`);
|
||||
await db.put("kv", JSON.stringify(value), `classworks-config`);
|
||||
return { success: true, message: '配置已迁移' };
|
||||
} else {
|
||||
// 数据键名: classNumber/classworks-data-YYYYMMDD
|
||||
@ -644,7 +645,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
await db.put("kv", JSON.stringify(value), `${this.classNumber}/classworks-data-${dateStr}`);
|
||||
await db.put("kv", JSON.stringify(value), `classworks-data-${dateStr}`);
|
||||
return { success: true, message: `${dateStr} 数据已迁移` };
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -169,10 +169,9 @@ export default {
|
||||
'dark': '深色'
|
||||
},
|
||||
'server.provider': {
|
||||
'server': '远程服务器',
|
||||
'indexedDB': '本地存储',
|
||||
'kv-local': 'KV本地存储',
|
||||
'kv-server': 'KV远程服务器'
|
||||
'kv-server': 'KV远程服务器',
|
||||
'classworkscloud': 'Classworks云端存储'
|
||||
}
|
||||
},
|
||||
// 默认图标映射,按设置类型
|
||||
|
@ -2,7 +2,7 @@
|
||||
<settings-card title="数据源设置" icon="mdi-database-cog">
|
||||
<v-list>
|
||||
<!-- 服务器模式设置 -->
|
||||
<template v-if="currentProvider === 'server' || currentProvider === 'kv-server'">
|
||||
<template v-if="currentProvider === 'kv-server' || currentProvider === 'classworkscloud'">
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-lan-connect" class="mr-3" />
|
||||
@ -13,17 +13,29 @@
|
||||
测试连接
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item><!-- 数据迁移,仅对KV本地存储有效 -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database-import" class="mr-3" />
|
||||
</template>
|
||||
<v-list-item-title>迁移旧数据</v-list-item-title>
|
||||
<v-list-item-subtitle>将旧的存储格式数据转移到新的KV存储</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn :loading="migrateLoading" variant="tonal" @click="migrateData">
|
||||
迁移
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<!-- IndexedDB设置 -->
|
||||
<template v-if="currentProvider === 'indexedDB' || currentProvider === 'kv-local'">
|
||||
<!-- 本地存储设置 -->
|
||||
<template v-if="currentProvider === 'kv-local'">
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database" class="mr-3" />
|
||||
</template>
|
||||
<v-list-item-title>清除数据库缓存</v-list-item-title>
|
||||
<v-list-item-subtitle>这将清除所有IndexedDB中的数据</v-list-item-subtitle>
|
||||
<v-list-item-subtitle>这将清除所有本地数据库中的数据</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn color="error" variant="tonal" @click="confirmClearIndexedDB">
|
||||
清除
|
||||
@ -40,8 +52,8 @@
|
||||
</template>
|
||||
</v-list-item>
|
||||
|
||||
<!-- 显示机器ID,仅对KV本地存储有效 -->
|
||||
<v-list-item v-if="currentProvider === 'kv-local'">
|
||||
<!-- 显示机器ID -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-identifier" class="mr-3" />
|
||||
</template>
|
||||
@ -76,31 +88,6 @@
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database-sync" class="mr-3" />
|
||||
</template>
|
||||
<v-list-item-title>高级数据迁移工具</v-list-item-title>
|
||||
<v-list-item-subtitle>更强大的数据迁移工具,支持从本地或服务器迁移到KV存储</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" color="primary" to="/datamigration">
|
||||
打开
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-lan-connect" class="mr-3" />
|
||||
</template>
|
||||
<v-list-item-title>CSES转WakeUP工具</v-list-item-title>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" to="/cses2wakeup">
|
||||
查看
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<!-- 确认对话框 -->
|
||||
@ -122,7 +109,6 @@
|
||||
import SettingsCard from "@/components/SettingsCard.vue";
|
||||
import { getSetting } from "@/utils/settings";
|
||||
import axios from "axios";
|
||||
import { getMachineId } from "@/utils/providers/kvProvider";
|
||||
|
||||
export default {
|
||||
name: "DataProviderSettingsCard",
|
||||
@ -147,7 +133,7 @@ export default {
|
||||
},
|
||||
|
||||
isKvProvider() {
|
||||
return this.currentProvider === 'kv-local' || this.currentProvider === 'kv-server';
|
||||
return this.currentProvider === 'kv-local' || this.currentProvider === 'kv-server' || this.currentProvider === 'classworkscloud';
|
||||
}
|
||||
},
|
||||
|
||||
@ -155,7 +141,7 @@ export default {
|
||||
// 如果是KV本地存储,获取机器ID
|
||||
if (this.currentProvider === 'kv-local') {
|
||||
try {
|
||||
this.machineId = await getMachineId();
|
||||
this.machineId = getSetting('device.uuid');
|
||||
} catch (error) {
|
||||
console.error("获取机器ID失败:", error);
|
||||
}
|
||||
|
@ -12,12 +12,18 @@
|
||||
</p>
|
||||
</v-alert>
|
||||
|
||||
<v-alert v-if="isClassworksCloud" type="info" color="success" variant="tonal" class="my-2">
|
||||
<v-alert-title>Classworks云端存储</v-alert-title>
|
||||
<p>Classworks云端存储是官方提供的存储解决方案,自动配置了最优的访问设置。</p>
|
||||
<p>使用此选项时,服务器域名和网站令牌将自动配置,无需手动设置。</p>
|
||||
</v-alert>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="server.domain" title="服务器域名" />
|
||||
<setting-item setting-key="server.domain" title="服务器域名" :disabled="isClassworksCloud" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="server.classNumber" title="班号" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="server.siteKey" title="网站令牌">
|
||||
<setting-item setting-key="server.siteKey" title="网站令牌" :disabled="isClassworksCloud">
|
||||
<template #description>
|
||||
用于后端验证请求的安全令牌。如需要,请从系统管理员获取。
|
||||
</template>
|
||||
@ -53,8 +59,11 @@ export default {
|
||||
isKvProvider() {
|
||||
return this.currentProvider === 'kv-local' || this.currentProvider === 'kv-server';
|
||||
},
|
||||
isClassworksCloud() {
|
||||
return this.currentProvider === 'classworkscloud';
|
||||
},
|
||||
useServer() {
|
||||
return this.currentProvider === 'server' || this.currentProvider === 'kv-server';
|
||||
return this.currentProvider === 'server' || this.currentProvider === 'kv-server' || this.currentProvider === 'classworkscloud';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -3,36 +3,205 @@
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<div class="d-flex align-center mb-6">
|
||||
<v-icon size="x-large" color="primary" class="mr-3">mdi-database-sync</v-icon>
|
||||
<v-icon size="x-large" color="primary" class="mr-3"
|
||||
>mdi-database-sync</v-icon
|
||||
>
|
||||
<div>
|
||||
<h1 class="text-h4">数据迁移工具</h1>
|
||||
<div class="text-subtitle-1 text-grey">将现有数据迁移至 KV 存储系统</div>
|
||||
<div class="text-subtitle-1 text-grey">
|
||||
将现有数据迁移至 KV 存储系统
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-card class="mb-6" variant="tonal" color="info" density="compact">
|
||||
<v-card-text class="d-flex align-center">
|
||||
<v-icon color="info" class="mr-2">mdi-information-outline</v-icon>
|
||||
<span>使用此工具可以将数据从旧存储系统迁移到新的 KV 存储系统,选择本地或云端迁移,以确保数据不会丢失。</span>
|
||||
<span
|
||||
>使用此工具可以将数据从旧存储系统迁移到新的 KV
|
||||
存储系统,选择本地或云端迁移,以确保数据不会丢失。</span
|
||||
>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<MigrationTool />
|
||||
<MigrationTool ref="migrationTool" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- 一键迁移对话框 -->
|
||||
<v-dialog v-model="showMigrationDialog" max-width="500" persistent>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5 d-flex align-center">
|
||||
<v-icon color="primary" size="large" class="mr-3"
|
||||
>mdi-database-sync</v-icon
|
||||
>
|
||||
一键数据迁移
|
||||
</v-card-title>
|
||||
<v-card-text class="mt-4">
|
||||
<p>
|
||||
系统将自动读取您的配置,并将过去半年的数据迁移至Classworks
|
||||
KV数据库中
|
||||
</p>
|
||||
|
||||
<v-alert
|
||||
color="info"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
class="mt-4"
|
||||
icon="mdi-information-outline"
|
||||
>
|
||||
<ul class="ml-3 mt-1">
|
||||
<li>数据源: {{ dataSourceText }}</li>
|
||||
<li>班级: {{ classNumber }}</li>
|
||||
<li>服务器: {{ serverDomain || "本地存储" }}</li>
|
||||
<li>
|
||||
迁移范围: {{ formatDate(sixMonthsAgo) }} 至
|
||||
{{ formatDate(today) }}
|
||||
</li>
|
||||
</ul>
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
color="grey-darken-1"
|
||||
variant="text"
|
||||
@click="showMigrationDialog = false"
|
||||
>
|
||||
稍后再说
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
size="large"
|
||||
variant="elevated"
|
||||
@click="startAutoMigration"
|
||||
:loading="isAutoMigrating"
|
||||
:disabled="isAutoMigrating"
|
||||
>
|
||||
<v-icon left class="mr-2">mdi-database-export</v-icon>
|
||||
开始一键迁移
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MigrationTool from '@/components/MigrationTool.vue';
|
||||
import MigrationTool from "@/components/MigrationTool.vue";
|
||||
import { getSetting, setSetting } from "@/utils/settings";
|
||||
|
||||
export default {
|
||||
name: 'DataMigrationPage',
|
||||
name: "DataMigrationPage",
|
||||
components: {
|
||||
MigrationTool
|
||||
MigrationTool,
|
||||
},
|
||||
data() {
|
||||
const today = new Date();
|
||||
const sixMonthsAgo = new Date();
|
||||
sixMonthsAgo.setMonth(today.getMonth() - 3);
|
||||
|
||||
return {
|
||||
showMigrationDialog: false,
|
||||
isAutoMigrating: false,
|
||||
today,
|
||||
sixMonthsAgo,
|
||||
classNumber: "",
|
||||
serverDomain: "",
|
||||
dataProvider: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dataSourceText() {
|
||||
switch (this.dataProvider) {
|
||||
case "server":
|
||||
return "服务器";
|
||||
case "indexeddb":
|
||||
return "本地数据库";
|
||||
case "kv-local":
|
||||
return "本地 KV 存储";
|
||||
case "kv-server":
|
||||
return "远程 KV 存储";
|
||||
case "classworkscloud":
|
||||
return "Classworks 云";
|
||||
default:
|
||||
return "未知来源";
|
||||
}
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.loadSettings();
|
||||
if (this.serverDomain == "https://class.wuyuan.dev") {
|
||||
await this.startAutoMigration();
|
||||
this.$router.push("/");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadSettings() {
|
||||
this.classNumber = getSetting("server.classNumber");
|
||||
this.serverDomain = getSetting("server.domain");
|
||||
this.dataProvider = getSetting("server.provider");
|
||||
|
||||
this.showMigrationDialog =
|
||||
this.dataProvider === "server" || this.dataProvider === "indexeddb";
|
||||
},
|
||||
formatDate(date) {
|
||||
return date.toLocaleDateString();
|
||||
},
|
||||
async startAutoMigration() {
|
||||
if (!this.$refs.migrationTool) {
|
||||
console.error("MigrationTool组件引用不可用");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isAutoMigrating = true;
|
||||
|
||||
try {
|
||||
// 设置迁移工具的参数
|
||||
const migrationTool = this.$refs.migrationTool;
|
||||
migrationTool.classNumber = this.classNumber;
|
||||
migrationTool.migrationType =
|
||||
this.dataProvider === "server" ? "server" : "local";
|
||||
migrationTool.serverUrl = this.serverDomain;
|
||||
migrationTool.targetStorage = "kv-server";
|
||||
//migrationTool.targetServerUrl = this.serverDomain;
|
||||
|
||||
// 设置半年的日期范围
|
||||
migrationTool.startDate = this.formatDateString(this.sixMonthsAgo);
|
||||
migrationTool.endDate = this.formatDateString(this.today);
|
||||
|
||||
// 根据数据源类型进行相应操作
|
||||
if (this.dataProvider === "server") {
|
||||
// 预览服务器数据
|
||||
await migrationTool.previewServerData();
|
||||
} else {
|
||||
// 扫描本地数据库
|
||||
await migrationTool.scanLocalDatabase();
|
||||
}
|
||||
|
||||
// 开始迁移
|
||||
if (migrationTool.displayItems.length > 0) {
|
||||
await migrationTool.startMigration();
|
||||
} else {
|
||||
console.warn("没有找到可迁移的数据");
|
||||
}
|
||||
setSetting("server.provider", "classworkscloud");
|
||||
} catch (error) {
|
||||
console.error("自动迁移失败:", error);
|
||||
} finally {
|
||||
this.isAutoMigrating = false;
|
||||
this.showMigrationDialog = false;
|
||||
}
|
||||
},
|
||||
formatDateString(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
return `${year}-${month}-${day}`;
|
||||
},
|
||||
},
|
||||
metaInfo: {
|
||||
title: '数据迁移工具'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
title: "数据迁移工具",
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -625,6 +625,7 @@
|
||||
import MessageLog from "@/components/MessageLog.vue";
|
||||
import RandomPicker from "@/components/RandomPicker.vue"; // 导入随机点名组件
|
||||
import dataProvider from "@/utils/dataProvider";
|
||||
import { kvProvider } from "@/utils/providers/kvProvider";
|
||||
import {
|
||||
getSetting,
|
||||
watchSettings,
|
||||
@ -1086,7 +1087,6 @@ export default {
|
||||
try {
|
||||
this.loading.download = true;
|
||||
const response = await dataProvider.loadData(
|
||||
this.provider,
|
||||
this.dataKey,
|
||||
this.state.dateString
|
||||
);
|
||||
@ -1192,10 +1192,9 @@ export default {
|
||||
try {
|
||||
this.loading.upload = true;
|
||||
const response = await dataProvider.saveData(
|
||||
this.provider,
|
||||
this.dataKey,
|
||||
this.state.boardData,
|
||||
this.state.dateString // 添加dateString参数
|
||||
this.state.dateString
|
||||
);
|
||||
|
||||
if (!response.success) {
|
||||
@ -1211,10 +1210,16 @@ export default {
|
||||
|
||||
async loadConfig() {
|
||||
try {
|
||||
const response = await dataProvider.loadConfig(
|
||||
this.provider,
|
||||
this.dataKey
|
||||
);
|
||||
// 使用新的kvProvider直接加载配置
|
||||
const provider = getSetting("server.provider");
|
||||
const useServer = provider === "kv-server" || provider === "classworkscloud";
|
||||
let response;
|
||||
|
||||
if (useServer) {
|
||||
response = await kvProvider.server.loadConfig();
|
||||
} else {
|
||||
response = await kvProvider.local.loadConfig();
|
||||
}
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
@ -1325,7 +1330,7 @@ export default {
|
||||
const classNum = getSetting("server.classNumber");
|
||||
|
||||
this.provider = provider;
|
||||
this.dataKey = provider === "server" ? `${domain}/${classNum}` : classNum;
|
||||
this.dataKey = provider === "server" || provider === "classworkscloud" ? `${domain}/${classNum}` : classNum;
|
||||
this.state.classNumber = classNum;
|
||||
},
|
||||
|
||||
|
@ -127,7 +127,7 @@
|
||||
:is-mobile="isMobile"
|
||||
:unsaved-changes="hasUnsavedChanges"
|
||||
@save="saveStudents"
|
||||
@reload="loadStudentList"
|
||||
@reload="loadStudents"
|
||||
@update:modelValue="handleStudentDataChange"
|
||||
/>
|
||||
</v-col>
|
||||
@ -187,7 +187,7 @@ import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import StudentListCard from '@/components/settings/StudentListCard.vue';
|
||||
import AboutCard from '@/components/settings/AboutCard.vue';
|
||||
import '../styles/settings.scss';
|
||||
import dataProvider from '@/utils/dataProvider';
|
||||
import { kvProvider } from '@/utils/providers/kvProvider';
|
||||
import SettingsExplorer from '@/components/settings/SettingsExplorer.vue';
|
||||
import SettingsLinkGenerator from '@/components/SettingsLinkGenerator.vue';
|
||||
export default {
|
||||
@ -306,7 +306,7 @@ export default {
|
||||
this.unwatchSettings = watchSettings(() => {
|
||||
this.loadAllSettings();
|
||||
});
|
||||
this.loadStudentList();
|
||||
this.loadStudents();
|
||||
this.refreshDebugConfig();
|
||||
|
||||
// 检查开发者选项,如果未启用则关闭相关功能
|
||||
@ -366,30 +366,34 @@ export default {
|
||||
this.$message.error(title, content);
|
||||
},
|
||||
|
||||
async loadStudentList() {
|
||||
async loadStudents() {
|
||||
this.studentsError = null;
|
||||
try {
|
||||
this.loading.students = true;
|
||||
this.studentsError = null;
|
||||
|
||||
const domain = getSetting('server.domain');
|
||||
const classNum = getSetting('server.classNumber');
|
||||
const provider = getSetting('server.provider');
|
||||
|
||||
if (!classNum) {
|
||||
throw new Error('请先设置班号');
|
||||
}
|
||||
|
||||
const key = provider === 'server' ? `${domain}/${classNum}` : classNum;
|
||||
const res = await dataProvider.loadConfig(provider, key);
|
||||
const provider = getSetting('server.provider');
|
||||
const useServer = provider === 'kv-server' || provider === 'classworkscloud';
|
||||
let response;
|
||||
|
||||
if (!res.success) {
|
||||
throw new Error(res.error.message);
|
||||
if (useServer) {
|
||||
response = await kvProvider.server.loadConfig();
|
||||
} else {
|
||||
response = await kvProvider.local.loadConfig();
|
||||
}
|
||||
|
||||
if (res.data && Array.isArray(res.data.studentList)) {
|
||||
this.studentData.list = res.data.studentList;
|
||||
this.studentData.text = res.data.studentList.join('\n');
|
||||
this.lastSavedData = [...res.data.studentList];
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
|
||||
if (response.data && Array.isArray(response.data.studentList)) {
|
||||
this.studentData.list = response.data.studentList;
|
||||
this.studentData.text = response.data.studentList.join('\n');
|
||||
this.lastSavedData = [...response.data.studentList];
|
||||
this.hasUnsavedChanges = false;
|
||||
}
|
||||
} catch (error) {
|
||||
@ -403,21 +407,28 @@ export default {
|
||||
|
||||
async saveStudents() {
|
||||
try {
|
||||
const domain = getSetting('server.domain');
|
||||
const classNum = getSetting('server.classNumber');
|
||||
const provider = getSetting('server.provider');
|
||||
|
||||
if (!classNum) {
|
||||
throw new Error('请先设置班号');
|
||||
}
|
||||
|
||||
const key = provider === 'server' ? `${domain}/${classNum}` : classNum;
|
||||
const res = await dataProvider.saveConfig(provider, key, {
|
||||
studentList: this.studentData.list,
|
||||
});
|
||||
const provider = getSetting('server.provider');
|
||||
const useServer = provider === 'kv-server' || provider === 'classworkscloud';
|
||||
let response;
|
||||
|
||||
if (!res.success) {
|
||||
throw new Error(res.error.message);
|
||||
if (useServer) {
|
||||
response = await kvProvider.server.saveConfig({
|
||||
studentList: this.studentData.list,
|
||||
});
|
||||
} else {
|
||||
response = await kvProvider.local.saveConfig({
|
||||
studentList: this.studentData.list,
|
||||
});
|
||||
}
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
|
||||
// 更新保存状态
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { serverProvider } from "./providers/server";
|
||||
import { indexedDBProvider } from "./providers/indexedDB";
|
||||
import { kvProvider } from "./providers/kvProvider";
|
||||
import { getSetting } from "./settings";
|
||||
|
||||
@ -14,84 +12,28 @@ export const formatError = (message, code = "UNKNOWN_ERROR") => ({
|
||||
error: { code, message },
|
||||
});
|
||||
|
||||
// Legacy providers
|
||||
const legacyProviders = {
|
||||
server: serverProvider,
|
||||
indexedDB: indexedDBProvider,
|
||||
};
|
||||
|
||||
// New KV provider
|
||||
const newProviders = {
|
||||
kv: kvProvider,
|
||||
};
|
||||
|
||||
// Main data provider with support for both legacy and new API
|
||||
// Main data provider with simplified API
|
||||
export default {
|
||||
// Provider API methods
|
||||
loadData: (provider, key, date) => {
|
||||
if (legacyProviders[provider]) {
|
||||
return legacyProviders[provider]?.loadData(key, date);
|
||||
}
|
||||
loadData: async (key, date) => {
|
||||
const provider = getSetting("server.provider");
|
||||
const useServer = provider === "kv-server" || provider === "classworkscloud";
|
||||
|
||||
// If using new KV provider
|
||||
if (provider === "kv-local") {
|
||||
const classNumber = key.split("/").pop();
|
||||
return newProviders.kv.local.loadData(classNumber, date);
|
||||
} else if (provider === "kv-server") {
|
||||
const classNumber = key.split("/").pop();
|
||||
const serverUrl = getSetting("server.domain");
|
||||
return newProviders.kv.server.loadData(serverUrl, classNumber, date);
|
||||
if (useServer) {
|
||||
return kvProvider.server.loadData(key, date);
|
||||
} else {
|
||||
return kvProvider.local.loadData(date);
|
||||
}
|
||||
},
|
||||
|
||||
saveData: (provider, key, data, date) => {
|
||||
if (legacyProviders[provider]) {
|
||||
return legacyProviders[provider]?.saveData(key, data, date);
|
||||
}
|
||||
saveData: async (key, data, date) => {
|
||||
const provider = getSetting("server.provider");
|
||||
const useServer = provider === "kv-server" || provider === "classworkscloud";
|
||||
|
||||
// If using new KV provider
|
||||
if (provider === "kv-local") {
|
||||
const classNumber = key.split("/").pop();
|
||||
return newProviders.kv.local.saveData(classNumber, data, date);
|
||||
} else if (provider === "kv-server") {
|
||||
const classNumber = key.split("/").pop();
|
||||
const serverUrl = getSetting("server.domain");
|
||||
return newProviders.kv.server.saveData(
|
||||
serverUrl,
|
||||
classNumber,
|
||||
data,
|
||||
date
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
loadConfig: (provider, key) => {
|
||||
if (legacyProviders[provider]) {
|
||||
return legacyProviders[provider]?.loadConfig(key);
|
||||
}
|
||||
|
||||
// If using new KV provider
|
||||
if (provider === "kv-local") {
|
||||
const classNumber = key.split("/").pop();
|
||||
return newProviders.kv.local.loadConfig(classNumber);
|
||||
} else if (provider === "kv-server") {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
return newProviders.kv.server.loadConfig(serverUrl);
|
||||
}
|
||||
},
|
||||
|
||||
saveConfig: (provider, key, config) => {
|
||||
if (legacyProviders[provider]) {
|
||||
return legacyProviders[provider]?.saveConfig(key, config);
|
||||
}
|
||||
|
||||
// If using new KV provider
|
||||
if (provider === "kv-local") {
|
||||
const classNumber = key.split("/").pop();
|
||||
return newProviders.kv.local.saveConfig(classNumber, config);
|
||||
} else if (provider === "kv-server") {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
return newProviders.kv.server.saveConfig(serverUrl, config);
|
||||
if (useServer) {
|
||||
return kvProvider.server.saveData(key, data, date);
|
||||
} else {
|
||||
return kvProvider.local.saveData(data, date);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -23,11 +23,6 @@ const getHeaders = () => {
|
||||
return headers;
|
||||
};
|
||||
|
||||
// Get machine UUID from settings
|
||||
const getMachineId = () => {
|
||||
return getSetting("device.uuid");
|
||||
};
|
||||
|
||||
// Removed migrateToKvStorage function - now handled by the dedicated migration tool
|
||||
|
||||
const initDB = async () => {
|
||||
@ -58,17 +53,13 @@ const formatDateForKey = (date) => {
|
||||
export const kvProvider = {
|
||||
// Local storage provider
|
||||
local: {
|
||||
async loadData(classNumber, date) {
|
||||
async loadData(date) {
|
||||
try {
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const formattedDate = formatDateForKey(date);
|
||||
const key = `${DATA_KEY_PREFIX}${formattedDate}`;
|
||||
|
||||
const db = await initDB();
|
||||
const data = await db.get("kv", `${classNumber}/${key}`);
|
||||
const data = await db.get("kv", key);
|
||||
|
||||
if (!data) {
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
@ -91,31 +82,23 @@ export const kvProvider = {
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(classNumber, data, date) {
|
||||
async saveData(data, date) {
|
||||
try {
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const formattedDate = formatDateForKey(date);
|
||||
const key = `${DATA_KEY_PREFIX}${formattedDate}`;
|
||||
|
||||
const db = await initDB();
|
||||
await db.put("kv", JSON.stringify(data), `${classNumber}/${key}`);
|
||||
await db.put("kv", JSON.stringify(data), key);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存本地数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(classNumber) {
|
||||
async loadConfig() {
|
||||
try {
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const config = await db.get("kv", `${classNumber}/${CONFIG_KEY}`);
|
||||
const config = await db.get("kv", CONFIG_KEY);
|
||||
|
||||
if (!config) {
|
||||
return formatResponse({
|
||||
@ -134,14 +117,10 @@ export const kvProvider = {
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(classNumber, config) {
|
||||
async saveConfig(config) {
|
||||
try {
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
await db.put("kv", JSON.stringify(config), `${classNumber}/${CONFIG_KEY}`);
|
||||
await db.put("kv", JSON.stringify(config), CONFIG_KEY);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存本地配置失败:" + error);
|
||||
@ -151,9 +130,10 @@ export const kvProvider = {
|
||||
|
||||
// Server storage provider
|
||||
server: {
|
||||
async loadData(serverUrl, classNumber, date) {
|
||||
async loadData(classNumber, date) {
|
||||
try {
|
||||
const machineId = getMachineId();
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
const formattedDate = formatDateForKey(date);
|
||||
const key = `${DATA_KEY_PREFIX}${formattedDate}`;
|
||||
|
||||
@ -185,9 +165,10 @@ export const kvProvider = {
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(serverUrl, classNumber, data, date) {
|
||||
async saveData(classNumber, data, date) {
|
||||
try {
|
||||
const machineId = getMachineId();
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
const formattedDate = formatDateForKey(date);
|
||||
const key = `${DATA_KEY_PREFIX}${formattedDate}`;
|
||||
|
||||
@ -203,9 +184,10 @@ export const kvProvider = {
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(serverUrl) {
|
||||
async loadConfig() {
|
||||
try {
|
||||
const machineId = getMachineId();
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
const res = await axios.get(`${serverUrl}/${machineId}/${CONFIG_KEY}`, {
|
||||
headers: getHeaders()
|
||||
});
|
||||
@ -230,9 +212,10 @@ export const kvProvider = {
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(serverUrl, config) {
|
||||
async saveConfig(config) {
|
||||
try {
|
||||
const machineId = getMachineId();
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
await axios.post(`${serverUrl}/${machineId}/${CONFIG_KEY}`, config, {
|
||||
headers: getHeaders()
|
||||
});
|
||||
@ -247,4 +230,3 @@ export const kvProvider = {
|
||||
}
|
||||
};
|
||||
|
||||
export { getMachineId };
|
@ -74,6 +74,12 @@ function generateUUID() {
|
||||
});
|
||||
}
|
||||
|
||||
// 新增: Classworks云端存储的默认设置
|
||||
const classworksCloudDefaults = {
|
||||
"server.domain": "http://localhost:3030",
|
||||
"server.siteKey": "123456",
|
||||
};
|
||||
|
||||
/**
|
||||
* 所有配置项的定义
|
||||
* @type {Object.<string, SettingDefinition>}
|
||||
@ -182,11 +188,11 @@ const settingsDefinitions = {
|
||||
},
|
||||
"server.provider": {
|
||||
type: "string",
|
||||
default: "indexedDB",
|
||||
validate: (value) => ["server", "indexedDB", "kv-local", "kv-server"].includes(value),
|
||||
default: "kv-local",
|
||||
validate: (value) => ["kv-local", "kv-server", "classworkscloud"].includes(value),
|
||||
description: "数据提供者",
|
||||
icon: "mdi-database",
|
||||
// 选择数据存储方式:使用本地IndexedDB或远程服务器
|
||||
// 选择数据存储方式:使用本地存储或远程服务器
|
||||
},
|
||||
|
||||
// 刷新设置
|
||||
@ -480,6 +486,13 @@ class SettingsManagerClass {
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否使用Classworks云端存储,并覆盖特定设置
|
||||
if (this.settingsCache["server.provider"] === "classworkscloud") {
|
||||
if (classworksCloudDefaults[key] !== undefined) {
|
||||
return classworksCloudDefaults[key];
|
||||
}
|
||||
}
|
||||
|
||||
const value = this.settingsCache[key];
|
||||
return value !== undefined ? value : definition.default;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user