diff --git a/src/components/settings/StudentListCard.vue b/src/components/settings/StudentListCard.vue
index 0485afc..8bd4797 100644
--- a/src/components/settings/StudentListCard.vue
+++ b/src/components/settings/StudentListCard.vue
@@ -142,7 +142,7 @@
class="text-body-1 flex-grow-1"
@click="handleClick(index, student)"
>
- {{ student }}
+ {{ student.name }}
@@ -194,7 +194,7 @@
size="large"
:loading="loading"
:disabled="loading"
- @click="$emit('save')"
+ @click="saveStudents"
>
保存名单
@@ -205,7 +205,7 @@
size="large"
:loading="loading"
:disabled="loading"
- @click="$emit('reload')"
+ @click="loadStudents"
>
重载名单
@@ -219,6 +219,8 @@
import UnsavedWarning from "../common/UnsavedWarning.vue";
import "@/styles/warnings.scss";
import { pinyin } from "pinyin-pro";
+import dataProvider from "@/utils/dataProvider";
+import { getSetting } from "@/utils/settings";
export default {
name: "StudentListCard",
@@ -226,19 +228,7 @@ export default {
UnsavedWarning,
},
props: {
- modelValue: {
- type: Object,
- required: true,
- default: () => ({
- list: [],
- text: "",
- advanced: false,
- }),
- },
- loading: Boolean,
- error: String,
isMobile: Boolean,
- unsavedChanges: Boolean,
},
data() {
@@ -248,101 +238,200 @@ export default {
index: -1,
name: "",
},
+ modelValue: {
+ list: [],
+ text: "",
+ advanced: false,
+ },
+ loading: false,
+ error: null,
+ lastSavedData: null,
+ unsavedChanges: false,
};
},
- emits: ["update:modelValue", "save", "reload"],
-
- computed: {
- text: {
- get() {
- return this.modelValue.text;
- },
- set(value) {
- this.handleTextInput(value);
+ watch: {
+ modelValue: {
+ handler(newData) {
+ if (this.lastSavedData) {
+ this.unsavedChanges = JSON.stringify(newData.list) !== JSON.stringify(this.lastSavedData);
+ }
+ if (!this.modelValue.advanced) {
+ this.modelValue.text = newData.list
+ .slice()
+ .sort((a, b) => a.id - b.id)
+ .map(s => s.name)
+ .join("\n");
+ }
},
+ deep: true,
},
},
+ mounted() {
+ this.loadStudents();
+ },
+
methods: {
- // UI 相关方法
+ async loadStudents() {
+ this.error = null;
+ try {
+ this.loading = true;
+ const classNum = getSetting("server.classNumber");
+
+ if (!classNum) {
+ throw new Error("请先设置班号");
+ }
+
+ try {
+ const response = await dataProvider.loadData("classworks-list-main");
+
+ if (response.success != false && Array.isArray(response)) {
+ this.modelValue.list = response.map((item, index) => {
+ if (typeof item === 'string') {
+ return { id: index + 1, name: item };
+ }
+ return {
+ id: item.id || index + 1,
+ name: item.name || item.toString()
+ };
+ });
+
+ this.modelValue.list.sort((a, b) => a.id - b.id);
+ this.modelValue.text = this.modelValue.list.map(s => s.name).join("\n");
+ this.lastSavedData = JSON.parse(JSON.stringify(this.modelValue.list));
+ this.unsavedChanges = false;
+ return;
+ }
+ } catch (error) {
+ console.warn(
+ "Failed to load student list from dedicated key, falling back to config",
+ error
+ );
+ }
+ } catch (error) {
+ console.error("加载学生列表失败:", error);
+ this.error = error.message || "加载失败,请检查设置";
+ this.$message?.error("加载失败", this.error);
+ } finally {
+ this.loading = false;
+ }
+ },
+
+ async saveStudents() {
+ try {
+ const classNum = getSetting("server.classNumber");
+
+ if (!classNum) {
+ throw new Error("请先设置班号");
+ }
+
+ const formattedList = this.modelValue.list
+ .slice()
+ .sort((a, b) => a.id - b.id)
+ .map((student, index) => ({
+ id: index + 1,
+ name: student.name
+ }));
+
+ const response = await dataProvider.saveData(
+ "classworks-list-main",
+ formattedList
+ );
+
+ if (response.success === false) {
+ throw new Error(response.error?.message || "保存失败");
+ }
+
+ this.modelValue.list = formattedList;
+ this.lastSavedData = JSON.parse(JSON.stringify(formattedList));
+ this.unsavedChanges = false;
+ this.$message?.success("保存成功", "学生列表已更新");
+ } catch (error) {
+ console.error("保存学生列表失败:", error);
+ this.$message?.error("保存失败", error.message || "请重试");
+ }
+ },
+
toggleAdvanced() {
- const advanced = !this.modelValue.advanced;
- this.updateModelValue({
- advanced,
- text: advanced ? this.modelValue.list.join("\n") : this.modelValue.text,
- list: this.modelValue.list,
- });
+ this.modelValue.advanced = !this.modelValue.advanced;
},
- updateModelValue(newData) {
- this.$emit("update:modelValue", {
- ...this.modelValue,
- ...newData,
+ handleTextInput(text) {
+ if (!this.modelValue.advanced) return;
+
+ // Split the text into lines and filter out empty lines
+ const lines = text.split("\n").filter((line) => line.trim());
+
+ // Create a map of existing student names to their IDs
+ const currentIds = new Map(this.modelValue.list.map(s => [s.name, s.id]));
+ let maxId = Math.max(0, ...this.modelValue.list.map(s => s.id));
+
+ // Create new list preserving IDs for existing names and generating new IDs for new names
+ const newList = lines.map(name => {
+ name = name.trim();
+ if (currentIds.has(name)) {
+ return { id: currentIds.get(name), name };
+ }
+ return { id: ++maxId, name };
});
+
+ // Update the list
+ this.modelValue.list = newList;
},
- // 基础编辑操作
addStudent() {
const name = this.newStudentName.trim();
- if (!name || this.modelValue.list.includes(name)) return;
-
- const newList = [...this.modelValue.list, name];
- this.updateModelValue({
- list: newList,
- text: newList.join("\n"),
- });
- this.newStudentName = "";
- },
-
- removeStudent(index) {
- const newList = this.modelValue.list.filter((_, i) => i !== index);
- this.updateModelValue({
- list: newList,
- text: newList.join("\n"),
- });
- },
-
- moveStudent(index, direction) {
- const newList = [...this.modelValue.list];
- let targetIndex;
-
- if (direction === "top") {
- targetIndex = 0;
- } else if (direction === "up") {
- targetIndex = index - 1;
- } else {
- targetIndex = index + 1;
- }
-
- if (targetIndex >= 0 && targetIndex < newList.length) {
- const [student] = newList.splice(index, 1);
- newList.splice(targetIndex, 0, student);
-
- this.updateModelValue({
- list: newList,
- text: newList.join("\n"),
- });
+ if (name && !this.modelValue.list.some(s => s.name === name)) {
+ const maxId = Math.max(0, ...this.modelValue.list.map(s => s.id));
+ this.modelValue.list.push({ id: maxId + 1, name });
+ this.newStudentName = "";
}
},
- // 文本编辑操作
- startEdit(index, name) {
- this.editState = { index, name };
+ startEdit(index, student) {
+ this.editState.index = index;
+ this.editState.name = student.name;
},
saveEdit() {
- const { index, name } = this.editState;
- if (index === -1 || !name.trim()) return;
+ if (this.editState.index !== -1) {
+ const newName = this.editState.name.trim();
+ if (newName && newName !== this.modelValue.list[this.editState.index].name) {
+ this.modelValue.list[this.editState.index].name = newName;
+ }
+ this.editState.index = -1;
+ this.editState.name = "";
+ }
+ },
- const newList = [...this.modelValue.list];
- newList[index] = name.trim();
+ removeStudent(index) {
+ if (index !== undefined) {
+ this.modelValue.list.splice(index, 1);
+ }
+ },
- this.updateModelValue({
- list: newList,
- text: newList.join("\n"),
- });
- this.editState = { index: -1, name: "" };
+ moveStudent(index, direction) {
+ if (direction === "top") {
+ if (index > 0) {
+ const student = this.modelValue.list[index];
+ this.modelValue.list.splice(index, 1);
+ this.modelValue.list.unshift(student);
+ this.modelValue.list.forEach((s, i) => s.id = i + 1);
+ }
+ } else {
+ const newIndex = direction === "up" ? index - 1 : index + 1;
+ if (newIndex >= 0 && newIndex < this.modelValue.list.length) {
+ [this.modelValue.list[index], this.modelValue.list[newIndex]] = [
+ this.modelValue.list[newIndex],
+ this.modelValue.list[index],
+ ];
+ [this.modelValue.list[index].id, this.modelValue.list[newIndex].id] = [
+ this.modelValue.list[newIndex].id,
+ this.modelValue.list[index].id,
+ ];
+ }
+ }
},
handleClick(index, student) {
@@ -351,35 +440,20 @@ export default {
}
},
- handleTextInput(value) {
- const list = value
- .split("\n")
- .map((s) => s.trim())
- .filter((s) => s);
-
- this.updateModelValue({
- text: value,
- list,
- });
- },
-
sortStudentsByPinyin() {
- const newList = [...this.modelValue.list].sort((a, b) => {
- const pinyinA = pinyin(a, { toneType: "none" ,mode: 'surname'});
- const pinyinB = pinyin(b, { toneType: "none",mode: 'surname' });
+ const sorted = [...this.modelValue.list].sort((a, b) => {
+ const pinyinA = pinyin(a.name, { toneType: "none" });
+ const pinyinB = pinyin(b.name, { toneType: "none" });
return pinyinA.localeCompare(pinyinB);
});
-
- this.updateModelValue({
- list: newList,
- text: newList.join("\n"),
- });
+ sorted.forEach((s, i) => s.id = i + 1);
+ this.modelValue.list = sorted;
},
},
};
-
diff --git a/src/pages/settings.vue b/src/pages/settings.vue
index 8ba2f6e..f2303cb 100644
--- a/src/pages/settings.vue
+++ b/src/pages/settings.vue
@@ -34,12 +34,13 @@
direction="vertical"
>
-
+
- Classworks
是开源免费的软件,官方没有提供任何形式的付费支持服务,源代码仓库地址在
-
+
{
this.loadAllSettings();
});
- this.loadStudents();
},
beforeUnmount() {
@@ -435,9 +429,7 @@ export default {
});
},
- // 添加统一的设置处理方法
handleSettingsChange(newSettings) {
- // 使用防抖来避免过多更新
if (this.settingsChangeTimeout) {
clearTimeout(this.settingsChangeTimeout);
}
@@ -453,13 +445,12 @@ export default {
this.showMessage("设置已更新", `${settingKey} 已保存`);
} else {
this.showError("保存失败", `${settingKey} 设置失败`);
- // 回滚到原值
this.settings[section][key] = currentValue;
}
}
});
});
- }, 100); // 添加100ms延迟
+ }, 100);
},
showMessage(title, content = "", type = "success") {
@@ -470,89 +461,6 @@ export default {
this.$message.error(title, content);
},
- async loadStudents() {
- this.studentsError = null;
- try {
- this.loading.students = true;
- const classNum = getSetting("server.classNumber");
-
- if (!classNum) {
- throw new Error("请先设置班号");
- }
-
- try {
- // Try to get student list from the dedicated key
- const response = await dataProvider.loadData("classworks-list-main");
-
- if (response.success != false && Array.isArray(response)) {
- // Transform the data into a simple list of names
- this.studentData.list = response.map((student) => student.name);
- this.studentData.text = this.studentData.list.join("\n");
- this.lastSavedData = [...this.studentData.list];
- this.hasUnsavedChanges = false;
- return;
- }
- } catch (error) {
- console.warn(
- "Failed to load student list from dedicated key, falling back to config",
- error
- );
- }
- } catch (error) {
- console.error("加载学生列表失败:", error);
- this.studentsError = error.message || "加载失败,请检查设置";
- this.showError("加载失败", this.studentsError);
- } finally {
- this.loading.students = false;
- }
- },
-
- async saveStudents() {
- try {
- const classNum = getSetting("server.classNumber");
-
- if (!classNum) {
- throw new Error("请先设置班号");
- }
-
- // Convert the list of names to the new format with IDs
- const formattedStudentList = this.studentData.list.map(
- (name, index) => ({
- id: index + 1,
- name,
- })
- );
-
- // Save the student list to the dedicated key
- const response = await dataProvider.saveData(
- "classworks-list-main",
- formattedStudentList
- );
-
- if (response.success == false) {
- throw new Error(response.error?.message || "保存失败");
- }
-
- // 更新保存状态
- this.lastSavedData = [...this.studentData.list];
- this.hasUnsavedChanges = false;
- this.showMessage("保存成功", "学生列表已更新");
- } catch (error) {
- console.error("保存学生列表失败:", error);
- this.showError("保存失败", error.message || "请重试");
- }
- },
-
- handleStudentDataChange(newData) {
- // 仅在列表实际发生变化时更新
- if (
- JSON.stringify(newData.list) !== JSON.stringify(this.studentData.list)
- ) {
- this.studentData = { ...newData };
- this.hasUnsavedChanges = true;
- }
- },
-
saveEdit() {
if (this.editingIndex !== -1) {
const newName = this.editingName.trim();
@@ -587,12 +495,6 @@ export default {
}
},
- setStudentNumber(index) {
- this.studentToMove = index;
- this.newPosition = String(index + 1);
- this.numberDialog = true;
- },
-
applyNewPosition() {
const newPos = parseInt(this.newPosition) - 1;
if (
@@ -680,11 +582,9 @@ export default {
onSettingsSaved() {
this.showMessage("设置已更新", "您的设置已成功保存");
- // 如果需要,可以在这里重新加载相关数据
},
onSettingUpdate(key, value) {
- // 处理设置更新
this.showMessage("设置已更新", `${key} 已保存为 ${value}`);
},
},