mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-07-03 01:39:22 +00:00
1
This commit is contained in:
parent
6ab280e484
commit
efd622f819
@ -2,9 +2,7 @@
|
|||||||
<v-navigation-drawer v-model="drawer" location="right" temporary width="400">
|
<v-navigation-drawer v-model="drawer" location="right" temporary width="400">
|
||||||
<v-toolbar color="primary">
|
<v-toolbar color="primary">
|
||||||
<v-toolbar-title>消息记录</v-toolbar-title>
|
<v-toolbar-title>消息记录</v-toolbar-title>
|
||||||
<template #append>
|
|
||||||
<v-btn icon="mdi-delete" variant="text" @click="clearMessages" />
|
|
||||||
</template>
|
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
|
|
||||||
<v-list>
|
<v-list>
|
||||||
@ -21,14 +19,7 @@
|
|||||||
{{ new Date(msg.timestamp).toLocaleTimeString() }}
|
{{ new Date(msg.timestamp).toLocaleTimeString() }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<template #append>
|
|
||||||
<v-btn
|
|
||||||
icon="mdi-delete"
|
|
||||||
variant="text"
|
|
||||||
size="small"
|
|
||||||
@click="deleteMessage(msg.id)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item v-if="!messages.length">
|
<v-list-item v-if="!messages.length">
|
||||||
|
215
src/components/settings/cards/DataProviderSettingsCard.vue
Normal file
215
src/components/settings/cards/DataProviderSettingsCard.vue
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
<template>
|
||||||
|
<settings-card
|
||||||
|
title="数据源设置"
|
||||||
|
icon="mdi-database-cog"
|
||||||
|
>
|
||||||
|
<v-list>
|
||||||
|
<!-- 服务器模式设置 -->
|
||||||
|
<template v-if="currentProvider === 'server'">
|
||||||
|
<v-list-item>
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon icon="mdi-lan-connect" class="mr-3" />
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>检查服务器连接</v-list-item-title>
|
||||||
|
<template #append>
|
||||||
|
<v-btn
|
||||||
|
:loading="loading"
|
||||||
|
variant="tonal"
|
||||||
|
size="small"
|
||||||
|
@click="checkServerConnection"
|
||||||
|
>
|
||||||
|
测试连接
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- IndexedDB设置 -->
|
||||||
|
<template v-if="currentProvider === 'indexedDB'">
|
||||||
|
<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>
|
||||||
|
<template #append>
|
||||||
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="tonal"
|
||||||
|
size="small"
|
||||||
|
@click="confirmClearIndexedDB"
|
||||||
|
>
|
||||||
|
清除
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item>
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon icon="mdi-database-export" class="mr-3" />
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>导出数据库</v-list-item-title>
|
||||||
|
<template #append>
|
||||||
|
<v-btn
|
||||||
|
variant="tonal"
|
||||||
|
size="small"
|
||||||
|
@click="exportData"
|
||||||
|
>
|
||||||
|
导出
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
</template>
|
||||||
|
</v-list>
|
||||||
|
|
||||||
|
<!-- 确认对话框 -->
|
||||||
|
<v-dialog v-model="confirmDialog" max-width="400">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>{{ confirmTitle }}</v-card-title>
|
||||||
|
<v-card-text>{{ confirmMessage }}</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="grey" variant="text" @click="confirmDialog = false">取消</v-btn>
|
||||||
|
<v-btn color="error" variant="tonal" @click="handleConfirm">确认</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</settings-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SettingsCard from '@/components/SettingsCard.vue';
|
||||||
|
import { getSetting } from '@/utils/settings';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DataProviderSettingsCard',
|
||||||
|
components: { SettingsCard },
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
confirmDialog: false,
|
||||||
|
confirmTitle: '',
|
||||||
|
confirmMessage: '',
|
||||||
|
confirmAction: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
currentProvider() {
|
||||||
|
return getSetting('server.provider');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async checkServerConnection() {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
const domain = getSetting('server.domain');
|
||||||
|
const response = await fetch(`${domain}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: { 'Accept': 'application/json' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
this.$message.success('连接成功', '服务器连接正常');
|
||||||
|
} else {
|
||||||
|
throw new Error('服务器响应异常');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('连接失败', error.message || '无法连接到服务器');
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmClearLocalStorage() {
|
||||||
|
this.confirmTitle = '确认清除';
|
||||||
|
this.confirmMessage = '此操作将清除所有本地存储的数据,确定要继续吗?';
|
||||||
|
this.confirmAction = this.clearLocalStorage;
|
||||||
|
this.confirmDialog = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearLocalStorage() {
|
||||||
|
try {
|
||||||
|
localStorage.clear();
|
||||||
|
this.$message.success('清除成功', '本地存储数据已清除');
|
||||||
|
this.confirmDialog = false;
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('清除失败', error.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmClearIndexedDB() {
|
||||||
|
this.confirmTitle = '确认清除';
|
||||||
|
this.confirmMessage = '此操作将清除所有IndexedDB中的数据,确定要继续吗?';
|
||||||
|
this.confirmAction = this.clearIndexedDB;
|
||||||
|
this.confirmDialog = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
async clearIndexedDB() {
|
||||||
|
try {
|
||||||
|
const DBName = 'HomeworkDB';
|
||||||
|
// 删除整个数据库
|
||||||
|
await window.indexedDB.deleteDatabase(DBName);
|
||||||
|
this.$message.success('清除成功', '数据库缓存已清除');
|
||||||
|
this.confirmDialog = false;
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('清除失败', error.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async exportData() {
|
||||||
|
try {
|
||||||
|
const DBName = 'HomeworkDB';
|
||||||
|
const data = { indexedDB: {} };
|
||||||
|
|
||||||
|
// 打开数据库
|
||||||
|
const db = await new Promise((resolve, reject) => {
|
||||||
|
const request = window.indexedDB.open(DBName);
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
|
request.onsuccess = () => resolve(request.result);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取所有存储对象
|
||||||
|
const stores = Array.from(db.objectStoreNames);
|
||||||
|
|
||||||
|
// 导出每个存储对象的数据
|
||||||
|
for (const storeName of stores) {
|
||||||
|
const transaction = db.transaction(storeName, 'readonly');
|
||||||
|
const store = transaction.objectStore(storeName);
|
||||||
|
|
||||||
|
// 获取存储对象中的所有数据
|
||||||
|
const storeData = await new Promise((resolve, reject) => {
|
||||||
|
const request = store.getAll();
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
|
request.onsuccess = () => resolve(request.result);
|
||||||
|
});
|
||||||
|
|
||||||
|
data.indexedDB[storeName] = storeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建并下载文件
|
||||||
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
const timestamp = new Date().toISOString().split('T')[0];
|
||||||
|
a.href = url;
|
||||||
|
a.download = `homework-indexeddb-${timestamp}.json`;
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
this.$message.success('导出成功', 'IndexedDB数据已导出');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('导出失败:', error);
|
||||||
|
this.$message.error('导出失败', error.message || '无法导出数据库数据');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleConfirm() {
|
||||||
|
if (this.confirmAction) {
|
||||||
|
this.confirmAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
0
src/pages/guide.vue
Normal file
0
src/pages/guide.vue
Normal file
@ -627,6 +627,7 @@ export default {
|
|||||||
if (response.error.code === "NOT_FOUND") {
|
if (response.error.code === "NOT_FOUND") {
|
||||||
this.state.showNoDataMessage = true;
|
this.state.showNoDataMessage = true;
|
||||||
this.state.noDataMessage = response.error.message;
|
this.state.noDataMessage = response.error.message;
|
||||||
|
// 确保数据结构完整
|
||||||
this.state.boardData = {
|
this.state.boardData = {
|
||||||
homework: {},
|
homework: {},
|
||||||
attendance: { absent: [], late: [], exclude: [] },
|
attendance: { absent: [], late: [], exclude: [] },
|
||||||
@ -635,12 +636,25 @@ export default {
|
|||||||
throw new Error(response.error.message);
|
throw new Error(response.error.message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.state.boardData = response.data;
|
// 确保数据结构完整
|
||||||
|
this.state.boardData = {
|
||||||
|
homework: response.data.homework || {},
|
||||||
|
attendance: {
|
||||||
|
absent: response.data.attendance?.absent || [],
|
||||||
|
late: response.data.attendance?.late || [],
|
||||||
|
exclude: response.data.attendance?.exclude || [],
|
||||||
|
},
|
||||||
|
};
|
||||||
this.state.synced = true;
|
this.state.synced = true;
|
||||||
this.state.showNoDataMessage = false;
|
this.state.showNoDataMessage = false;
|
||||||
this.$message.success("下载成功", "数据已更新");
|
this.$message.success("下载成功", "数据已更新");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// 发生错误时也要确保数据结构完整
|
||||||
|
this.state.boardData = {
|
||||||
|
homework: {},
|
||||||
|
attendance: { absent: [], late: [], exclude: [] },
|
||||||
|
};
|
||||||
this.$message.error("下载失败", error.message);
|
this.$message.error("下载失败", error.message);
|
||||||
} finally {
|
} finally {
|
||||||
this.loading.download = false;
|
this.loading.download = false;
|
||||||
|
@ -15,26 +15,32 @@
|
|||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="6">
|
<v-col cols="12" md="6">
|
||||||
<server-settings-card
|
<server-settings-card
|
||||||
|
border
|
||||||
:loading="loading.server"
|
:loading="loading.server"
|
||||||
@saved="onSettingsSaved"
|
@saved="onSettingsSaved"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12" md="6">
|
<v-col cols="12" md="6">
|
||||||
<edit-settings-card @saved="onSettingsSaved" />
|
<data-provider-settings-card border />
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12" md="6">
|
<v-col cols="12" md="6">
|
||||||
<refresh-settings-card @saved="onSettingsSaved" />
|
<edit-settings-card @saved="onSettingsSaved" border/>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12" md="6">
|
<v-col cols="12" md="6">
|
||||||
<display-settings-card @saved="onSettingsSaved" />
|
<refresh-settings-card @saved="onSettingsSaved" border/>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<display-settings-card @saved="onSettingsSaved" border/>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 开发者选项卡片 -->
|
<!-- 开发者选项卡片 -->
|
||||||
<v-col :cols="12" :md="settings.developer.enabled ? 12 : 6">
|
<v-col :cols="12" :md="settings.developer.enabled ? 12 : 6">
|
||||||
<settings-card
|
<settings-card
|
||||||
|
border
|
||||||
title="开发者选项"
|
title="开发者选项"
|
||||||
icon="mdi-developer-board"
|
icon="mdi-developer-board"
|
||||||
>
|
>
|
||||||
@ -139,6 +145,7 @@ import ServerSettingsCard from '@/components/settings/cards/ServerSettingsCard.v
|
|||||||
import EditSettingsCard from '@/components/settings/cards/EditSettingsCard.vue';
|
import EditSettingsCard from '@/components/settings/cards/EditSettingsCard.vue';
|
||||||
import RefreshSettingsCard from '@/components/settings/cards/RefreshSettingsCard.vue';
|
import RefreshSettingsCard from '@/components/settings/cards/RefreshSettingsCard.vue';
|
||||||
import DisplaySettingsCard from '@/components/settings/cards/DisplaySettingsCard.vue';
|
import DisplaySettingsCard from '@/components/settings/cards/DisplaySettingsCard.vue';
|
||||||
|
import DataProviderSettingsCard from '@/components/settings/cards/DataProviderSettingsCard.vue';
|
||||||
import {
|
import {
|
||||||
getSetting,
|
getSetting,
|
||||||
setSetting,
|
setSetting,
|
||||||
@ -162,7 +169,8 @@ export default {
|
|||||||
MessageLog,
|
MessageLog,
|
||||||
SettingsCard,
|
SettingsCard,
|
||||||
StudentListCard,
|
StudentListCard,
|
||||||
AboutCard
|
AboutCard,
|
||||||
|
DataProviderSettingsCard
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { mobile } = useDisplay();
|
const { mobile } = useDisplay();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user