mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-07-05 02:59:23 +00:00
1
This commit is contained in:
parent
9bb3f06ba1
commit
c6b6bd2ce5
@ -77,4 +77,4 @@ This project is built with [Vuetify](https://vuetifyjs.com/en/), a UI Library wi
|
|||||||
[MIT](http://opensource.org/licenses/MIT)
|
[MIT](http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
Copyright (c) 2016-present Vuetify, LLC
|
Copyright (c) 2016-present Vuetify, LLC
|
||||||
# homeworkpage-frontend
|
# classworks-frontend
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "HomeworkPage",
|
"name": "ClassworkS",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
|
@ -23,11 +23,11 @@
|
|||||||
—
|
—
|
||||||
<a
|
<a
|
||||||
class="text-decoration-none on-surface"
|
class="text-decoration-none on-surface"
|
||||||
href="https://github.com/sunwuyuan/homeworkpage-frontend"
|
href="https://github.com/sunwuyuan/classworks-frontend"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
HomeworkPage
|
ClassworkS
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</v-footer>
|
</v-footer>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
{
|
{
|
||||||
title: 'GitHub',
|
title: 'GitHub',
|
||||||
icon: 'mdi-github',
|
icon: 'mdi-github',
|
||||||
href: 'https://github.com/sunwuyuan/homeworkpage-frontend',
|
href: 'https://github.com/sunwuyuan/classworks-frontend',
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
/>
|
/>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
|
|
||||||
<h2 class="text-h5 mb-2">HomeworkPage</h2>
|
<h2 class="text-h5 mb-2">ClassworkS</h2>
|
||||||
<p class="text-body-1 mb-4">
|
<p class="text-body-1 mb-4">
|
||||||
由 <a
|
由 <a
|
||||||
href="https://github.com/sunwuyuan"
|
href="https://github.com/sunwuyuan"
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
href="https://github.com/SunWuyuan/homeworkpage-frontend"
|
href="https://github.com/SunWuyuan/classworks-frontend"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
prepend-icon="mdi-github"
|
prepend-icon="mdi-github"
|
||||||
>
|
>
|
||||||
@ -39,7 +39,7 @@
|
|||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
href="https://github.com/SunWuyuan/homeworkpage-backend"
|
href="https://github.com/SunWuyuan/classworks-backend"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
prepend-icon="mdi-github"
|
prepend-icon="mdi-github"
|
||||||
>
|
>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
href="https://github.com/SunWuyuan/homeworkpage-backend/issues"
|
href="https://github.com/SunWuyuan/classworks-backend/issues"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
prepend-icon="mdi-bug"
|
prepend-icon="mdi-bug"
|
||||||
>
|
>
|
||||||
|
@ -589,7 +589,7 @@ export default {
|
|||||||
this.provider,
|
this.provider,
|
||||||
this.dataKey,
|
this.dataKey,
|
||||||
this.state.boardData,
|
this.state.boardData,
|
||||||
this.state.dateString
|
this.state.dateString // 添加dateString参数
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
@ -937,7 +937,7 @@ export default {
|
|||||||
|
|
||||||
async saveAttendance() {
|
async saveAttendance() {
|
||||||
try {
|
try {
|
||||||
await this.uploadData();
|
await this.uploadData(); // 现在会自动使用当前选中的日期
|
||||||
this.state.attendanceDialog = false;
|
this.state.attendanceDialog = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("保存出勤状态失败:", error);
|
console.error("保存出勤状态失败:", error);
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import axios from 'axios';
|
import axios from "axios";
|
||||||
import { openDB } from 'idb';
|
import { openDB } from "idb";
|
||||||
|
|
||||||
const DB_NAME = 'HomeworkDB';
|
const DB_NAME = "HomeworkDB";
|
||||||
const DB_VERSION = 1;
|
const DB_VERSION = 1;
|
||||||
|
|
||||||
const initDB = async () => {
|
const initDB = async () => {
|
||||||
return openDB(DB_NAME, DB_VERSION, {
|
return openDB(DB_NAME, DB_VERSION, {
|
||||||
upgrade(db) {
|
upgrade(db) {
|
||||||
if (!db.objectStoreNames.contains('homework')) {
|
if (!db.objectStoreNames.contains("homework")) {
|
||||||
db.createObjectStore('homework');
|
db.createObjectStore("homework");
|
||||||
}
|
}
|
||||||
if (!db.objectStoreNames.contains('config')) {
|
if (!db.objectStoreNames.contains("config")) {
|
||||||
db.createObjectStore('config');
|
db.createObjectStore("config");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -20,12 +20,12 @@ const initDB = async () => {
|
|||||||
const formatResponse = (data, message = null) => ({
|
const formatResponse = (data, message = null) => ({
|
||||||
success: true,
|
success: true,
|
||||||
data,
|
data,
|
||||||
message
|
message,
|
||||||
});
|
});
|
||||||
|
|
||||||
const formatError = (message, code = 'UNKNOWN_ERROR') => ({
|
const formatError = (message, code = "UNKNOWN_ERROR") => ({
|
||||||
success: false,
|
success: false,
|
||||||
error: { code, message }
|
error: { code, message },
|
||||||
});
|
});
|
||||||
|
|
||||||
const providers = {
|
const providers = {
|
||||||
@ -33,9 +33,9 @@ const providers = {
|
|||||||
async loadData(key, date) {
|
async loadData(key, date) {
|
||||||
try {
|
try {
|
||||||
// 检查是否设置了班号
|
// 检查是否设置了班号
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用班号作为本地存储的前缀
|
// 使用班号作为本地存储的前缀
|
||||||
@ -44,45 +44,44 @@ const providers = {
|
|||||||
|
|
||||||
if (!rawData) {
|
if (!rawData) {
|
||||||
// 如果是今天的数据且没有找到,返回空结构而不是null
|
// 如果是今天的数据且没有找到,返回空结构而不是null
|
||||||
const today = new Date().toISOString().split('T')[0];
|
const today = new Date().toISOString().split("T")[0];
|
||||||
if (date === today) {
|
if (date === today) {
|
||||||
return formatResponse({
|
return formatResponse({
|
||||||
homework: {},
|
homework: {},
|
||||||
attendance: { absent: [], late: [] }
|
attendance: { absent: [], late: [] },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return formatError('数据不存在', 'NOT_FOUND');
|
return formatError("数据不存在", "NOT_FOUND");
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatResponse(JSON.parse(rawData));
|
return formatResponse(JSON.parse(rawData));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
return formatError("读取本地数据失败:" + error);
|
||||||
return formatError('读取本地数据失败:'+error);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveData(key, data, date) {
|
async saveData(key, data, date) {
|
||||||
try {
|
try {
|
||||||
// 检查是否设置了班号
|
// 检查是否设置了班号
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用班号作为本地存储的前缀
|
// 使用班号作为本地存储的前缀
|
||||||
const storageKey = `homework_${classNumber}_${date}`;
|
const storageKey = `homework_${classNumber}_${date}`; // 使用传入的date参数
|
||||||
localStorage.setItem(storageKey, JSON.stringify(data));
|
localStorage.setItem(storageKey, JSON.stringify(data));
|
||||||
return formatResponse(null, '保存成功');
|
return formatResponse(null, "保存成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError('保存本地数据失败:'+error);
|
return formatError("保存本地数据失败:" + error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadConfig(key) {
|
async loadConfig(key) {
|
||||||
try {
|
try {
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
const storageKey = `config_${classNumber}`;
|
const storageKey = `config_${classNumber}`;
|
||||||
@ -91,30 +90,30 @@ const providers = {
|
|||||||
if (!rawData) {
|
if (!rawData) {
|
||||||
return formatResponse({
|
return formatResponse({
|
||||||
studentList: [],
|
studentList: [],
|
||||||
displayOptions: {}
|
displayOptions: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatResponse(JSON.parse(rawData));
|
return formatResponse(JSON.parse(rawData));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError('读取本地配置失败:'+error);
|
return formatError("读取本地配置失败:" + error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveConfig(key, config) {
|
async saveConfig(key, config) {
|
||||||
try {
|
try {
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
const storageKey = `config_${classNumber}`;
|
const storageKey = `config_${classNumber}`;
|
||||||
localStorage.setItem(storageKey, JSON.stringify(config));
|
localStorage.setItem(storageKey, JSON.stringify(config));
|
||||||
return formatResponse(null, '保存成功');
|
return formatResponse(null, "保存成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError('保存本地配置失败:'+error);
|
return formatError("保存本地配置失败:" + error);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
@ -122,25 +121,27 @@ const providers = {
|
|||||||
try {
|
try {
|
||||||
const res = await axios.get(`${key}/homework?date=${date}`);
|
const res = await axios.get(`${key}/homework?date=${date}`);
|
||||||
if (res.data?.status === false) {
|
if (res.data?.status === false) {
|
||||||
return formatError(res.data.msg || '获取数据失败', 'SERVER_ERROR');
|
return formatError(res.data.msg || "获取数据失败", "SERVER_ERROR");
|
||||||
}
|
}
|
||||||
return formatResponse(res.data);
|
return formatResponse(res.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError(
|
return formatError(
|
||||||
error.response?.data?.message || '服务器连接失败',
|
error.response?.data?.message || "服务器连接失败",
|
||||||
'NETWORK_ERROR'
|
"NETWORK_ERROR"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveData(key, data) {
|
async saveData(key, data, date) {
|
||||||
try {
|
try {
|
||||||
await axios.post(`${key}/homework`, data);
|
// 添加date参数到URL
|
||||||
return formatResponse(null, '保存成功');
|
const url = date ? `${key}/homework?date=${date}` : `${key}/homework`;
|
||||||
|
await axios.post(url, data);
|
||||||
|
return formatResponse(null, "保存成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError(
|
return formatError(
|
||||||
error.response?.data?.message || '保存失败',
|
error.response?.data?.message || "保存失败",
|
||||||
'SAVE_ERROR'
|
"SAVE_ERROR"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -149,13 +150,13 @@ const providers = {
|
|||||||
try {
|
try {
|
||||||
const res = await axios.get(`${key}/config`);
|
const res = await axios.get(`${key}/config`);
|
||||||
if (res.data?.status === false) {
|
if (res.data?.status === false) {
|
||||||
return formatError(res.data.msg || '获取配置失败', 'SERVER_ERROR');
|
return formatError(res.data.msg || "获取配置失败", "SERVER_ERROR");
|
||||||
}
|
}
|
||||||
return formatResponse(res.data);
|
return formatResponse(res.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError(
|
return formatError(
|
||||||
error.response?.data?.message || '服务器连接失败',
|
error.response?.data?.message || "服务器连接失败",
|
||||||
'NETWORK_ERROR'
|
"NETWORK_ERROR"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -164,121 +165,123 @@ const providers = {
|
|||||||
try {
|
try {
|
||||||
const res = await axios.put(`${key}/config`, config);
|
const res = await axios.put(`${key}/config`, config);
|
||||||
if (res.data?.status === false) {
|
if (res.data?.status === false) {
|
||||||
return formatError(res.data.msg || '保存失败', 'SAVE_ERROR');
|
return formatError(res.data.msg || "保存失败", "SAVE_ERROR");
|
||||||
}
|
}
|
||||||
return formatResponse(null, '保存成功');
|
return formatResponse(null, "保存成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError(
|
return formatError(
|
||||||
error.response?.data?.message || '保存失败',
|
error.response?.data?.message || "保存失败",
|
||||||
'SAVE_ERROR'
|
"SAVE_ERROR"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
indexedDB: {
|
indexedDB: {
|
||||||
async loadData(key, date) {
|
async loadData(key, date) {
|
||||||
try {
|
try {
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = await initDB();
|
const db = await initDB();
|
||||||
const storageKey = `homework_${classNumber}_${date}`;
|
const storageKey = `homework_${classNumber}_${date}`;
|
||||||
const data = await db.get('homework', storageKey);
|
const data = await db.get("homework", storageKey);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
const today = new Date().toISOString().split('T')[0];
|
const today = new Date().toISOString().split("T")[0];
|
||||||
if (date === today) {
|
if (date === today) {
|
||||||
return formatResponse({
|
return formatResponse({
|
||||||
homework: {},
|
homework: {},
|
||||||
attendance: { absent: [], late: [] }
|
attendance: { absent: [], late: [] },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return formatError('数据不存在', 'NOT_FOUND');
|
return formatError("数据不存在", "NOT_FOUND");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从字符串解析数据
|
// 从字符串解析数据
|
||||||
return formatResponse(JSON.parse(data));
|
return formatResponse(JSON.parse(data));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError('读取IndexedDB数据失败:' + error);
|
return formatError("读取IndexedDB数据失败:" + error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveData(key, data, date) {
|
async saveData(key, data, date) {
|
||||||
try {
|
try {
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = await initDB();
|
const db = await initDB();
|
||||||
const storageKey = `homework_${classNumber}_${date}`;
|
const storageKey = `homework_${classNumber}_${date}`; // 使用传入的date参数
|
||||||
// 将数据序列化为字符串存储
|
// 将数据序列化为字符串存储
|
||||||
await db.put('homework', JSON.stringify(data), storageKey);
|
await db.put("homework", JSON.stringify(data), storageKey);
|
||||||
return formatResponse(null, '保存成功');
|
return formatResponse(null, "保存成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError('保存IndexedDB数据失败:' + error);
|
return formatError("保存IndexedDB数据失败:" + error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadConfig(key) {
|
async loadConfig(key) {
|
||||||
try {
|
try {
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = await initDB();
|
const db = await initDB();
|
||||||
const storageKey = `config_${classNumber}`;
|
const storageKey = `config_${classNumber}`;
|
||||||
const config = await db.get('config', storageKey);
|
const config = await db.get("config", storageKey);
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return formatResponse({
|
return formatResponse({
|
||||||
studentList: [],
|
studentList: [],
|
||||||
displayOptions: {}
|
displayOptions: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从字符串解析配置
|
// 从字符串解析配置
|
||||||
return formatResponse(JSON.parse(config));
|
return formatResponse(JSON.parse(config));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError('读取IndexedDB配置失败:' + error);
|
return formatError("读取IndexedDB配置失败:" + error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveConfig(key, config) {
|
async saveConfig(key, config) {
|
||||||
try {
|
try {
|
||||||
const classNumber = key.split('/').pop();
|
const classNumber = key.split("/").pop();
|
||||||
if (!classNumber) {
|
if (!classNumber) {
|
||||||
return formatError('请先设置班号', 'CONFIG_ERROR');
|
return formatError("请先设置班号", "CONFIG_ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = await initDB();
|
const db = await initDB();
|
||||||
const storageKey = `config_${classNumber}`;
|
const storageKey = `config_${classNumber}`;
|
||||||
// 将配置序列化为字符串存储
|
// 将配置序列化为字符串存储
|
||||||
await db.put('config', JSON.stringify(config), storageKey);
|
await db.put("config", JSON.stringify(config), storageKey);
|
||||||
return formatResponse(null, '保存成功');
|
return formatResponse(null, "保存成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError('保存IndexedDB配置失败:' + error);
|
return formatError("保存IndexedDB配置失败:" + error);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
loadData: (provider, key, date) => providers[provider]?.loadData(key, date),
|
loadData: (provider, key, date) => providers[provider]?.loadData(key, date),
|
||||||
saveData: (provider, key, data, date) => providers[provider]?.saveData(key, data, date),
|
saveData: (provider, key, data, date) =>
|
||||||
|
providers[provider]?.saveData(key, data, date),
|
||||||
loadConfig: (provider, key) => providers[provider]?.loadConfig(key),
|
loadConfig: (provider, key) => providers[provider]?.loadConfig(key),
|
||||||
saveConfig: (provider, key, config) => providers[provider]?.saveConfig(key, config)
|
saveConfig: (provider, key, config) =>
|
||||||
|
providers[provider]?.saveConfig(key, config),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ErrorCodes = {
|
export const ErrorCodes = {
|
||||||
NOT_FOUND: '数据不存在',
|
NOT_FOUND: "数据不存在",
|
||||||
NETWORK_ERROR: '网络连接失败',
|
NETWORK_ERROR: "网络连接失败",
|
||||||
SERVER_ERROR: '服务器错误',
|
SERVER_ERROR: "服务器错误",
|
||||||
SAVE_ERROR: '保存失败',
|
SAVE_ERROR: "保存失败",
|
||||||
CONFIG_ERROR: '配置错误',
|
CONFIG_ERROR: "配置错误",
|
||||||
UNKNOWN_ERROR: '未知错误'
|
UNKNOWN_ERROR: "未知错误",
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@ const defaultOptions = {
|
|||||||
addToLog: true
|
addToLog: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const STORAGE_KEY = 'homeworkpage_messages';
|
const STORAGE_KEY = 'classworks_messages';
|
||||||
const MAX_MESSAGES = 100; // 最大消息数量
|
const MAX_MESSAGES = 100; // 最大消息数量
|
||||||
const MAX_STORAGE_SIZE = 1024 * 1024; // 1MB 存储限制
|
const MAX_STORAGE_SIZE = 1024 * 1024; // 1MB 存储限制
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// 存储所有设置的localStorage键名
|
// 存储所有设置的localStorage键名
|
||||||
const SETTINGS_STORAGE_KEY = 'homeworkpage_settings';
|
const SETTINGS_STORAGE_KEY = "classworks_settings";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有配置项的定义
|
* 所有配置项的定义
|
||||||
@ -18,115 +18,116 @@ const SETTINGS_STORAGE_KEY = 'homeworkpage_settings';
|
|||||||
*/
|
*/
|
||||||
const settingsDefinitions = {
|
const settingsDefinitions = {
|
||||||
// 显示设置
|
// 显示设置
|
||||||
'display.emptySubjectDisplay': {
|
"display.emptySubjectDisplay": {
|
||||||
type: 'string',
|
type: "string",
|
||||||
default: 'button', // 修改默认值为 'button'
|
default: "button", // 修改默认值为 'button'
|
||||||
validate: value => ['card', 'button'].includes(value),
|
validate: (value) => ["card", "button"].includes(value),
|
||||||
description: '空科目的显示方式:卡片或按钮'
|
description: "空科目的显示方式:卡片或按钮",
|
||||||
},
|
},
|
||||||
'display.dynamicSort': {
|
"display.dynamicSort": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: true,
|
default: true,
|
||||||
description: '是否启用动态排序以优化显示效果'
|
description: "是否启用动态排序以优化显示效果",
|
||||||
},
|
},
|
||||||
'display.showRandomButton': {
|
"display.showRandomButton": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: false,
|
default: false,
|
||||||
description: '是否显示随机按钮'
|
description: "是否显示随机按钮",
|
||||||
},
|
},
|
||||||
|
|
||||||
// 服务器设置(合并了数据提供者设置)
|
// 服务器设置(合并了数据提供者设置)
|
||||||
'server.domain': {
|
"server.domain": {
|
||||||
type: 'string',
|
type: "string",
|
||||||
default: '',
|
default: "",
|
||||||
validate: value => !value || /^https?:\/\//.test(value),
|
validate: (value) => !value || /^https?:\/\//.test(value),
|
||||||
description: '后端服务器域名'
|
description: "后端服务器域名",
|
||||||
},
|
},
|
||||||
'server.classNumber': {
|
"server.classNumber": {
|
||||||
type: 'string',
|
type: "string",
|
||||||
default: '',
|
default: "",
|
||||||
validate: value => /^[A-Za-z0-9]*$/.test(value),
|
validate: (value) => /^[A-Za-z0-9]*$/.test(value),
|
||||||
description: '班级编号(无论使用哪种存储方式都需要设置)'
|
description: "班级编号(无论使用哪种存储方式都需要设置)",
|
||||||
},
|
},
|
||||||
'server.provider': {
|
"server.provider": {
|
||||||
type: 'string',
|
type: "string",
|
||||||
default: 'indexedDB',
|
default: "indexedDB",
|
||||||
validate: value => ['server', 'localStorage', 'indexedDB'].includes(value),
|
validate: (value) =>
|
||||||
description: '数据提供者,用于决定数据存储方式'
|
["server", "localStorage", "indexedDB"].includes(value),
|
||||||
|
description: "数据提供者,用于决定数据存储方式",
|
||||||
},
|
},
|
||||||
|
|
||||||
// 刷新设置
|
// 刷新设置
|
||||||
'refresh.auto': {
|
"refresh.auto": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: false,
|
default: false,
|
||||||
description: '是否启用自动刷新'
|
description: "是否启用自动刷新",
|
||||||
},
|
},
|
||||||
'refresh.interval': {
|
"refresh.interval": {
|
||||||
type: 'number',
|
type: "number",
|
||||||
default: 300,
|
default: 300,
|
||||||
validate: value => value >= 10 && value <= 3600,
|
validate: (value) => value >= 10 && value <= 3600,
|
||||||
description: '自动刷新间隔(秒)'
|
description: "自动刷新间隔(秒)",
|
||||||
},
|
},
|
||||||
|
|
||||||
// 字体设置
|
// 字体设置
|
||||||
'font.size': {
|
"font.size": {
|
||||||
type: 'number',
|
type: "number",
|
||||||
default: 28,
|
default: 28,
|
||||||
validate: value => value >= 16 && value <= 100,
|
validate: (value) => value >= 16 && value <= 100,
|
||||||
description: '字体大小(像素)'
|
description: "字体大小(像素)",
|
||||||
},
|
},
|
||||||
|
|
||||||
// 编辑设置
|
// 编辑设置
|
||||||
'edit.autoSave': {
|
"edit.autoSave": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: true,
|
default: true,
|
||||||
description: '是否启用自动保存'
|
description: "是否启用自动保存",
|
||||||
},
|
},
|
||||||
'edit.refreshBeforeEdit': {
|
"edit.refreshBeforeEdit": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: true,
|
default: true,
|
||||||
description: '编辑前是否自动刷新'
|
description: "编辑前是否自动刷新",
|
||||||
},
|
},
|
||||||
|
|
||||||
// 开发者选项
|
// 开发者选项
|
||||||
'developer.enabled': {
|
"developer.enabled": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: false,
|
default: false,
|
||||||
description: '是否启用开发者选项'
|
description: "是否启用开发者选项",
|
||||||
},
|
},
|
||||||
'developer.showDebugConfig': {
|
"developer.showDebugConfig": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: false,
|
default: false,
|
||||||
description: '是否显示调试配置'
|
description: "是否显示调试配置",
|
||||||
},
|
},
|
||||||
|
|
||||||
// 消息设置
|
// 消息设置
|
||||||
'message.showSidebar': {
|
"message.showSidebar": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: true,
|
default: true,
|
||||||
description: '是否显示消息记录侧栏',
|
description: "是否显示消息记录侧栏",
|
||||||
requireDeveloper: true // 添加标记
|
requireDeveloper: true, // 添加标记
|
||||||
},
|
},
|
||||||
'message.maxActiveMessages': {
|
"message.maxActiveMessages": {
|
||||||
type: 'number',
|
type: "number",
|
||||||
default: 5,
|
default: 5,
|
||||||
validate: value => value >= 1 && value <= 10,
|
validate: (value) => value >= 1 && value <= 10,
|
||||||
description: '同时显示的最大消息数量',
|
description: "同时显示的最大消息数量",
|
||||||
requireDeveloper: true
|
requireDeveloper: true,
|
||||||
},
|
},
|
||||||
'message.timeout': {
|
"message.timeout": {
|
||||||
type: 'number',
|
type: "number",
|
||||||
default: 5000,
|
default: 5000,
|
||||||
validate: value => value >= 1000 && value <= 30000,
|
validate: (value) => value >= 1000 && value <= 30000,
|
||||||
description: '消息自动关闭时间(毫秒)',
|
description: "消息自动关闭时间(毫秒)",
|
||||||
requireDeveloper: true
|
requireDeveloper: true,
|
||||||
},
|
},
|
||||||
'message.saveHistory': {
|
"message.saveHistory": {
|
||||||
type: 'boolean',
|
type: "boolean",
|
||||||
default: true,
|
default: true,
|
||||||
description: '是否保存消息历史记录',
|
description: "是否保存消息历史记录",
|
||||||
requireDeveloper: true
|
requireDeveloper: true,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 内存中缓存的设置值
|
// 内存中缓存的设置值
|
||||||
@ -146,7 +147,7 @@ function loadSettings() {
|
|||||||
settingsCache = migrateFromLegacy();
|
settingsCache = migrateFromLegacy();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载设置失败:', error);
|
console.error("加载设置失败:", error);
|
||||||
settingsCache = {};
|
settingsCache = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,42 +165,38 @@ function loadSettings() {
|
|||||||
* 从旧版本的localStorage迁移数据
|
* 从旧版本的localStorage迁移数据
|
||||||
*/
|
*/
|
||||||
function migrateFromLegacy() {
|
function migrateFromLegacy() {
|
||||||
const settings = {};
|
const LEGACY_SETTINGS_KEY = "homeworkpage_settings";
|
||||||
const legacyKeyMap = {
|
const LEGACY_MESSAGE_KEY = "homeworkpage_messages";
|
||||||
'server.domain': 'backendServerDomain',
|
|
||||||
'server.classNumber': 'classNumber',
|
|
||||||
'refresh.auto': 'autoRefresh',
|
|
||||||
'refresh.interval': 'refreshInterval',
|
|
||||||
'font.size': 'fontSize',
|
|
||||||
'edit.autoSave': 'autoSave',
|
|
||||||
'edit.refreshBeforeEdit': 'refreshBeforeEdit',
|
|
||||||
'display.emptySubjectDisplay': 'emptySubjectDisplay',
|
|
||||||
'display.dynamicSort': 'dynamicSort'
|
|
||||||
};
|
|
||||||
|
|
||||||
// 迁移旧数据
|
// 尝试从旧版本的设置中迁移
|
||||||
for (const [newKey, oldKey] of Object.entries(legacyKeyMap)) {
|
const legacySettings = localStorage.getItem(LEGACY_SETTINGS_KEY);
|
||||||
const oldValue = localStorage.getItem(oldKey);
|
if (legacySettings) {
|
||||||
if (oldValue !== null) {
|
try {
|
||||||
const definition = settingsDefinitions[newKey];
|
const settings = JSON.parse(legacySettings);
|
||||||
switch (definition.type) {
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
|
||||||
case 'boolean':
|
// 可选:删除旧的设置
|
||||||
settings[newKey] = oldValue === 'true';
|
localStorage.removeItem(LEGACY_SETTINGS_KEY);
|
||||||
break;
|
return settings;
|
||||||
case 'number':
|
} catch (error) {
|
||||||
settings[newKey] = Number(oldValue);
|
console.error("迁移旧设置失败:", error);
|
||||||
break;
|
}
|
||||||
default:
|
}
|
||||||
settings[newKey] = oldValue;
|
// 尝试从旧版本的message中迁移
|
||||||
}
|
const legacyMessages = localStorage.getItem(LEGACY_MESSAGE_KEY);
|
||||||
// 可选:删除旧的localStorage项
|
if (legacyMessages) {
|
||||||
// localStorage.removeItem(oldKey);
|
try {
|
||||||
|
const messages = JSON.parse(legacyMessages);
|
||||||
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(messages));
|
||||||
|
// 可选:删除旧的message
|
||||||
|
localStorage.removeItem(LEGACY_MESSAGE_KEY);
|
||||||
|
return messages; // 返回迁移后的消息
|
||||||
|
} catch (error) {
|
||||||
|
console.error("迁移旧消息失败:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存迁移后的数据
|
// 如果没有旧设置或迁移失败,返回空对象
|
||||||
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
|
return {};
|
||||||
return settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -209,7 +206,7 @@ function saveSettings() {
|
|||||||
try {
|
try {
|
||||||
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settingsCache));
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settingsCache));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存设置失败:', error);
|
console.error("保存设置失败:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +227,7 @@ function getSetting(key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加对开发者选项依赖的检查
|
// 添加对开发者选项依赖的检查
|
||||||
if (definition.requireDeveloper && !settingsCache['developer.enabled']) {
|
if (definition.requireDeveloper && !settingsCache["developer.enabled"]) {
|
||||||
return definition.default;
|
return definition.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,11 +237,14 @@ function getSetting(key) {
|
|||||||
|
|
||||||
// 添加设置变更日志函数
|
// 添加设置变更日志函数
|
||||||
function logSettingsChange(key, oldValue, newValue) {
|
function logSettingsChange(key, oldValue, newValue) {
|
||||||
if (settingsCache['developer.enabled'] && settingsCache['developer.showDebugConfig']) {
|
if (
|
||||||
|
settingsCache["developer.enabled"] &&
|
||||||
|
settingsCache["developer.showDebugConfig"]
|
||||||
|
) {
|
||||||
console.log(`[Settings] ${key}:`, {
|
console.log(`[Settings] ${key}:`, {
|
||||||
old: oldValue,
|
old: oldValue,
|
||||||
new: newValue,
|
new: newValue,
|
||||||
time: new Date().toLocaleTimeString()
|
time: new Date().toLocaleTimeString(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,7 +263,7 @@ function setSetting(key, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加对开发者选项依赖的检查
|
// 添加对开发者选项依赖的检查
|
||||||
if (definition.requireDeveloper && !settingsCache['developer.enabled']) {
|
if (definition.requireDeveloper && !settingsCache["developer.enabled"]) {
|
||||||
console.warn(`设置项 ${key} 需要启用开发者选项`);
|
console.warn(`设置项 ${key} 需要启用开发者选项`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -272,8 +272,12 @@ function setSetting(key, value) {
|
|||||||
const oldValue = settingsCache[key];
|
const oldValue = settingsCache[key];
|
||||||
// 类型转换
|
// 类型转换
|
||||||
if (typeof value !== definition.type) {
|
if (typeof value !== definition.type) {
|
||||||
value = definition.type === 'boolean' ? Boolean(value) :
|
value =
|
||||||
definition.type === 'number' ? Number(value) : String(value);
|
definition.type === "boolean"
|
||||||
|
? Boolean(value)
|
||||||
|
: definition.type === "number"
|
||||||
|
? Number(value)
|
||||||
|
: String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证
|
// 验证
|
||||||
@ -346,8 +350,8 @@ function watchSettings(callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('storage', handler);
|
window.addEventListener("storage", handler);
|
||||||
return () => window.removeEventListener('storage', handler);
|
return () => window.removeEventListener("storage", handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化设置
|
// 初始化设置
|
||||||
@ -359,5 +363,5 @@ export {
|
|||||||
setSetting,
|
setSetting,
|
||||||
resetSetting,
|
resetSetting,
|
||||||
resetAllSettings,
|
resetAllSettings,
|
||||||
watchSettings
|
watchSettings,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user