111
This commit is contained in:
+6
-257
@@ -1,271 +1,20 @@
|
||||
import axios from "axios";
|
||||
import { openDB } from "idb";
|
||||
import { serverProvider } from './providers/server';
|
||||
import { indexedDBProvider } from './providers/indexedDB';
|
||||
|
||||
const DB_NAME = "HomeworkDB";
|
||||
const DB_VERSION = 1;
|
||||
|
||||
const initDB = async () => {
|
||||
return openDB(DB_NAME, DB_VERSION, {
|
||||
upgrade(db) {
|
||||
if (!db.objectStoreNames.contains("homework")) {
|
||||
db.createObjectStore("homework");
|
||||
}
|
||||
if (!db.objectStoreNames.contains("config")) {
|
||||
db.createObjectStore("config");
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const formatResponse = (data, message = null) => ({
|
||||
export const formatResponse = (data, message = null) => ({
|
||||
success: true,
|
||||
data,
|
||||
message,
|
||||
});
|
||||
|
||||
const formatError = (message, code = "UNKNOWN_ERROR") => ({
|
||||
export const formatError = (message, code = "UNKNOWN_ERROR") => ({
|
||||
success: false,
|
||||
error: { code, message },
|
||||
});
|
||||
|
||||
const providers = {
|
||||
localStorage: {
|
||||
async loadData(key, date) {
|
||||
try {
|
||||
// 检查是否设置了班号
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
// 使用班号作为本地存储的前缀
|
||||
const storageKey = `homework_${classNumber}_${date}`;
|
||||
const rawData = localStorage.getItem(storageKey);
|
||||
|
||||
if (!rawData) {
|
||||
// 如果是今天的数据且没有找到,返回空结构而不是null
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
if (date === today) {
|
||||
return formatResponse({
|
||||
homework: {},
|
||||
attendance: { absent: [], late: [] },
|
||||
});
|
||||
}
|
||||
return formatError("数据不存在", "NOT_FOUND");
|
||||
}
|
||||
|
||||
return formatResponse(JSON.parse(rawData));
|
||||
} catch (error) {
|
||||
return formatError("读取本地数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(key, data, date) {
|
||||
try {
|
||||
// 检查是否设置了班号
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
// 使用班号作为本地存储的前缀
|
||||
const storageKey = `homework_${classNumber}_${date}`; // 使用传入的date参数
|
||||
localStorage.setItem(storageKey, JSON.stringify(data));
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存本地数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(key) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const storageKey = `config_${classNumber}`;
|
||||
const rawData = localStorage.getItem(storageKey);
|
||||
|
||||
if (!rawData) {
|
||||
return formatResponse({
|
||||
studentList: [],
|
||||
displayOptions: {},
|
||||
});
|
||||
}
|
||||
|
||||
return formatResponse(JSON.parse(rawData));
|
||||
} catch (error) {
|
||||
return formatError("读取本地配置失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(key, config) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const storageKey = `config_${classNumber}`;
|
||||
localStorage.setItem(storageKey, JSON.stringify(config));
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存本地配置失败:" + error);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
server: {
|
||||
async loadData(key, date) {
|
||||
try {
|
||||
const res = await axios.get(`${key}/homework?date=${date}`);
|
||||
if (res.data?.status === false) {
|
||||
return formatError(res.data.msg || "获取数据失败", "SERVER_ERROR");
|
||||
}
|
||||
return formatResponse(res.data);
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "服务器连接失败",
|
||||
"NETWORK_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(key, data, date) {
|
||||
try {
|
||||
// 添加date参数到URL
|
||||
const url = date ? `${key}/homework?date=${date}` : `${key}/homework`;
|
||||
await axios.post(url, data);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "保存失败",
|
||||
"SAVE_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(key) {
|
||||
try {
|
||||
const res = await axios.get(`${key}/config`);
|
||||
if (res.data?.status === false) {
|
||||
return formatError(res.data.msg || "获取配置失败", "SERVER_ERROR");
|
||||
}
|
||||
return formatResponse(res.data);
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "服务器连接失败",
|
||||
"NETWORK_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(key, config) {
|
||||
try {
|
||||
const res = await axios.put(`${key}/config`, config);
|
||||
if (res.data?.status === false) {
|
||||
return formatError(res.data.msg || "保存失败", "SAVE_ERROR");
|
||||
}
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "保存失败",
|
||||
"SAVE_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
indexedDB: {
|
||||
async loadData(key, date) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `homework_${classNumber}_${date}`;
|
||||
const data = await db.get("homework", storageKey);
|
||||
|
||||
if (!data) {
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
if (date === today) {
|
||||
return formatResponse({
|
||||
homework: {},
|
||||
attendance: { absent: [], late: [] },
|
||||
});
|
||||
}
|
||||
return formatError("数据不存在", "NOT_FOUND");
|
||||
}
|
||||
|
||||
// 从字符串解析数据
|
||||
return formatResponse(JSON.parse(data));
|
||||
} catch (error) {
|
||||
return formatError("读取IndexedDB数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(key, data, date) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `homework_${classNumber}_${date}`; // 使用传入的date参数
|
||||
// 将数据序列化为字符串存储
|
||||
await db.put("homework", JSON.stringify(data), storageKey);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存IndexedDB数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(key) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `config_${classNumber}`;
|
||||
const config = await db.get("config", storageKey);
|
||||
|
||||
if (!config) {
|
||||
return formatResponse({
|
||||
studentList: [],
|
||||
displayOptions: {},
|
||||
});
|
||||
}
|
||||
|
||||
// 从字符串解析配置
|
||||
return formatResponse(JSON.parse(config));
|
||||
} catch (error) {
|
||||
return formatError("读取IndexedDB配置失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(key, config) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `config_${classNumber}`;
|
||||
// 将配置序列化为字符串存储
|
||||
await db.put("config", JSON.stringify(config), storageKey);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存IndexedDB配置失败:" + error);
|
||||
}
|
||||
},
|
||||
},
|
||||
server: serverProvider,
|
||||
indexedDB: indexedDBProvider,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
const DB_NAME = 'homeworkboard';
|
||||
const DB_VERSION = 1;
|
||||
const LOG_STORE = 'message_logs';
|
||||
|
||||
class LogDB {
|
||||
constructor() {
|
||||
this.db = null;
|
||||
this.ready = this.initDB();
|
||||
}
|
||||
|
||||
async initDB() {
|
||||
try {
|
||||
this.db = await new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onupgradeneeded = (event) => {
|
||||
const db = event.target.result;
|
||||
if (!db.objectStoreNames.contains(LOG_STORE)) {
|
||||
const store = db.createObjectStore(LOG_STORE, {
|
||||
keyPath: 'id'
|
||||
});
|
||||
// 只保留时间和类型索引
|
||||
store.createIndex('timestamp', 'timestamp');
|
||||
store.createIndex('type', 'type');
|
||||
}
|
||||
};
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('初始化日志数据库失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async ensureDB() {
|
||||
if (!this.db) {
|
||||
await this.ready;
|
||||
}
|
||||
if (!this.db) {
|
||||
throw new Error('数据库未初始化');
|
||||
}
|
||||
}
|
||||
|
||||
async addLog(message) {
|
||||
await this.ensureDB();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = this.db.transaction([LOG_STORE], 'readwrite');
|
||||
const store = transaction.objectStore(LOG_STORE);
|
||||
|
||||
const request = store.add(message);
|
||||
|
||||
transaction.oncomplete = () => resolve(request.result);
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
});
|
||||
}
|
||||
|
||||
async getLogs(limit = 20) {
|
||||
await this.ensureDB();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = this.db.transaction([LOG_STORE], 'readonly');
|
||||
const store = transaction.objectStore(LOG_STORE);
|
||||
const index = store.index('timestamp');
|
||||
|
||||
const request = index.getAll(null, limit);
|
||||
|
||||
request.onsuccess = () => resolve(request.result.reverse());
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
|
||||
async deleteLog(messageId) {
|
||||
await this.ensureDB();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = this.db.transaction([LOG_STORE], 'readwrite');
|
||||
const store = transaction.objectStore(LOG_STORE);
|
||||
|
||||
const request = store.delete(messageId);
|
||||
|
||||
transaction.oncomplete = () => resolve(true);
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
});
|
||||
}
|
||||
|
||||
async clearLogs() {
|
||||
await this.ensureDB();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = this.db.transaction([LOG_STORE], 'readwrite');
|
||||
const store = transaction.objectStore(LOG_STORE);
|
||||
|
||||
const request = store.clear();
|
||||
|
||||
transaction.oncomplete = () => resolve(true);
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new LogDB();
|
||||
+21
-1
@@ -1,6 +1,26 @@
|
||||
import logDB from './db';
|
||||
import { getSetting } from './settings';
|
||||
|
||||
class LogDB {
|
||||
constructor() {
|
||||
this.logs = [];
|
||||
}
|
||||
|
||||
async addLog(message) {
|
||||
this.logs.push(message);
|
||||
// 只保留最近100条消息
|
||||
if (this.logs.length > 100) {
|
||||
this.logs.shift();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async getLogs(limit = 20) {
|
||||
return this.logs.slice(-limit).reverse();
|
||||
}
|
||||
}
|
||||
|
||||
const logDB = new LogDB();
|
||||
|
||||
const messages = [];
|
||||
let snackbarCallback = null;
|
||||
let logCallback = null;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import { openDB } from 'idb';
|
||||
import { formatResponse, formatError } from '../dataProvider';
|
||||
|
||||
const DB_NAME = "HomeworkDB";
|
||||
const DB_VERSION = 1;
|
||||
|
||||
const initDB = async () => {
|
||||
return openDB(DB_NAME, DB_VERSION, {
|
||||
upgrade(db) {
|
||||
if (!db.objectStoreNames.contains("homework")) {
|
||||
db.createObjectStore("homework");
|
||||
}
|
||||
if (!db.objectStoreNames.contains("config")) {
|
||||
db.createObjectStore("config");
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const indexedDBProvider = {
|
||||
async loadData(key, date) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `homework_${classNumber}_${date}`;
|
||||
const data = await db.get("homework", storageKey);
|
||||
|
||||
if (!data) {
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
if (date === today) {
|
||||
return formatResponse({
|
||||
homework: {},
|
||||
attendance: { absent: [], late: [] },
|
||||
});
|
||||
}
|
||||
return formatError("数据不存在", "NOT_FOUND");
|
||||
}
|
||||
|
||||
return formatResponse(JSON.parse(data));
|
||||
} catch (error) {
|
||||
return formatError("读取IndexedDB数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(key, data, date) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `homework_${classNumber}_${date}`;
|
||||
await db.put("homework", JSON.stringify(data), storageKey);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存IndexedDB数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(key) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `config_${classNumber}`;
|
||||
const config = await db.get("config", storageKey);
|
||||
|
||||
if (!config) {
|
||||
return formatResponse({
|
||||
studentList: [],
|
||||
displayOptions: {},
|
||||
});
|
||||
}
|
||||
|
||||
return formatResponse(JSON.parse(config));
|
||||
} catch (error) {
|
||||
return formatError("读取IndexedDB配置失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(key, config) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const db = await initDB();
|
||||
const storageKey = `config_${classNumber}`;
|
||||
await db.put("config", JSON.stringify(config), storageKey);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存IndexedDB配置失败:" + error);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
import { formatResponse, formatError } from '../dataProvider';
|
||||
|
||||
export const localStorageProvider = {
|
||||
async loadData(key, date) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const storageKey = `homework_${classNumber}_${date}`;
|
||||
const rawData = localStorage.getItem(storageKey);
|
||||
|
||||
if (!rawData) {
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
if (date === today) {
|
||||
return formatResponse({
|
||||
homework: {},
|
||||
attendance: { absent: [], late: [] },
|
||||
});
|
||||
}
|
||||
return formatError("数据不存在", "NOT_FOUND");
|
||||
}
|
||||
|
||||
return formatResponse(JSON.parse(rawData));
|
||||
} catch (error) {
|
||||
return formatError("读取本地数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(key, data, date) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const storageKey = `homework_${classNumber}_${date}`; // 使用传入的date参数
|
||||
localStorage.setItem(storageKey, JSON.stringify(data));
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存本地数据失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(key) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const storageKey = `config_${classNumber}`;
|
||||
const rawData = localStorage.getItem(storageKey);
|
||||
|
||||
if (!rawData) {
|
||||
return formatResponse({
|
||||
studentList: [],
|
||||
displayOptions: {},
|
||||
});
|
||||
}
|
||||
|
||||
return formatResponse(JSON.parse(rawData));
|
||||
} catch (error) {
|
||||
return formatError("读取本地配置失败:" + error);
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(key, config) {
|
||||
try {
|
||||
const classNumber = key.split("/").pop();
|
||||
if (!classNumber) {
|
||||
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||
}
|
||||
|
||||
const storageKey = `config_${classNumber}`;
|
||||
localStorage.setItem(storageKey, JSON.stringify(config));
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError("保存本地配置失败:" + error);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
import axios from 'axios';
|
||||
import { formatResponse, formatError } from '../dataProvider';
|
||||
|
||||
export const serverProvider = {
|
||||
async loadData(key, date) {
|
||||
try {
|
||||
const res = await axios.get(`${key}/homework?date=${date}`);
|
||||
if (res.data?.status === false) {
|
||||
return formatError(res.data.msg || "获取数据失败", "SERVER_ERROR");
|
||||
}
|
||||
return formatResponse(res.data);
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "服务器连接失败",
|
||||
"NETWORK_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async saveData(key, data, date) {
|
||||
try {
|
||||
// 添加date参数到URL
|
||||
const url = date ? `${key}/homework?date=${date}` : `${key}/homework`;
|
||||
await axios.post(url, data);
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "保存失败",
|
||||
"SAVE_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async loadConfig(key) {
|
||||
try {
|
||||
const res = await axios.get(`${key}/config`);
|
||||
if (res.data?.status === false) {
|
||||
return formatError(res.data.msg || "获取配置失败", "SERVER_ERROR");
|
||||
}
|
||||
return formatResponse(res.data);
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "服务器连接失败",
|
||||
"NETWORK_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async saveConfig(key, config) {
|
||||
try {
|
||||
const res = await axios.put(`${key}/config`, config);
|
||||
if (res.data?.status === false) {
|
||||
return formatError(res.data.msg || "保存失败", "SAVE_ERROR");
|
||||
}
|
||||
return formatResponse(null, "保存成功");
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "保存失败",
|
||||
"SAVE_ERROR"
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -90,7 +90,7 @@ const settingsDefinitions = {
|
||||
type: "string",
|
||||
default: "indexedDB",
|
||||
validate: (value) =>
|
||||
["server", "localStorage", "indexedDB"].includes(value),
|
||||
["server", "indexedDB"].includes(value),
|
||||
description: "数据提供者,用于决定数据存储方式",
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user