diff --git a/src/api/teacher.js b/src/api/teacher.js
index c2ceff6..db7da83 100644
--- a/src/api/teacher.js
+++ b/src/api/teacher.js
@@ -635,6 +635,12 @@ export function getOwnedTeachingClasses() {
method: "get",
});
}
+export function getAccessibleTeachingClasses() {
+ return request({
+ url: "/api/weight/accessibleTeachingClasses",
+ method: "get",
+ });
+}
export function getTeachingClassWeight(teachingClassId) {
return request({
url: "/api/weight/selectTeachingClassWeight",
@@ -693,6 +699,14 @@ export function getScoreDetail(params) {
params,
});
}
+// 保存班级创建教师对学生的人工评分
+export function saveTeacherScore(params) {
+ return request({
+ url: "/api/weight/saveTeacherScore",
+ method: "POST",
+ params,
+ });
+}
// 更新成绩
export function doRankOne(params) {
return request({
diff --git a/src/views/teacherEnd/score/index.vue b/src/views/teacherEnd/score/index.vue
index 7a61c00..a70a44e 100644
--- a/src/views/teacherEnd/score/index.vue
+++ b/src/views/teacherEnd/score/index.vue
@@ -28,14 +28,18 @@
-
+
- 导出
- 权重设置
- 成绩更新
+ 导出
+
+ 权重设置
+
+
+ 成绩更新
+
@@ -46,6 +50,31 @@
+
+
+
+
+ 保存
+
+
+ {{ formatTeacherScore(row.teacherScore) }}
+ 只读
+
+
+
{{ formatTrainingProgress(row) }}
@@ -128,8 +157,12 @@ import * as indexApi from "@/api/teacher";
const { proxy } = getCurrentInstance();
import useUserStore from "@/store/modules/user";
const userStore = useUserStore();
+const currentUserId = computed(() => String(userStore.userInfo.userId || ""));
const workingCapitalList = ref([]);
const loading = ref(false);
+const savingScoreUserId = ref("");
+const classList = ref([]);
+const teachingClassList = computed(() => classList.value.filter((item) => item.classType === "TEACHING"));
const scoreParams = ref({
classId: "",
index: 1,
@@ -142,6 +175,17 @@ const WeightStart = ref(false);
// 权重
const workingCapitalTotal = ref(0);
const scoreWeightObj = ref({});
+const selectedTeachingClass = computed(() => teachingClassList.value.find(
+ (item) => item.schoolClassId === scoreParams.value.classId
+));
+const canManageSelectedClass = computed(() =>
+ Boolean(selectedTeachingClass.value)
+ && String(selectedTeachingClass.value.createdBy || "") === currentUserId.value
+);
+const classActionHint = computed(() => canManageSelectedClass.value
+ ? ""
+ : "权重设置和成绩更新仅限班级创建老师操作"
+);
const formatTrainingProgress = (row) => {
if (row.trainingProgress === null || row.trainingProgress === undefined) return "--";
const percentage = Number(row.trainingProgress);
@@ -152,6 +196,11 @@ const trainingProgressTitle = (row) => {
if (row.trainingProgress === null || row.trainingProgress === undefined) return "";
return `已完成 ${row.completedTaskCount || 0}/${row.totalTaskCount || 0} 项`;
};
+const formatTeacherScore = (score) => {
+ if (score === null || score === undefined || score === "") return "未评分";
+ const value = Number(score);
+ return Number.isFinite(value) ? value.toFixed(2).replace(/\.00$/, "") : "未评分";
+};
const weightFields = ["foundationWeight", "marketInsightWeight", "planningDesignWeight", "developmentValidationWeight", "launchOperationWeight", "comprehensiveTrainingWeight"];
const rules = Object.fromEntries(weightFields.map((field) => [field, [
{ required: true, message: "请输入权重", trigger: "blur" },
@@ -165,12 +214,21 @@ const buildScoreQuery = () => {
};
};
const getList = () => {
+ if (!scoreParams.value.classId) {
+ workingCapitalList.value = [];
+ workingCapitalTotal.value = 0;
+ return;
+ }
loading.value = true;
indexApi.getScoreList(buildScoreQuery()).then((res) => {
- workingCapitalList.value = res.data.list;
+ workingCapitalList.value = (res.data.list || []).map((row) => ({
+ ...row,
+ teacherScoreDraft: row.teacherScore === null || row.teacherScore === undefined
+ ? null
+ : Number(row.teacherScore),
+ }));
workingCapitalTotal.value = res.data.total;
- loading.value = false;
- });
+ }).finally(() => (loading.value = false));
};
const scoreweight = () => {
if (!scoreParams.value.classId) {
@@ -203,17 +261,32 @@ const workingCapitalWeightHandle = () => {
}
});
};
-const classList = ref([]);
-const teachingClassList = computed(() => classList.value.filter((item) => item.classType === "TEACHING"));
-const getClassList = () => {
- indexApi.getOwnedTeachingClasses().then((res) => {
- classList.value = res.data;
+const getClassList = async () => {
+ try {
+ const res = await indexApi.getAccessibleTeachingClasses();
+ classList.value = res.data || [];
if (scoreParams.value.classId && !teachingClassList.value.some((item) => item.schoolClassId === scoreParams.value.classId)) {
scoreParams.value.classId = "";
}
- });
+ if (!scoreParams.value.classId) {
+ const ownClass = teachingClassList.value.find((item) => String(item.createdBy || "") === currentUserId.value);
+ scoreParams.value.classId = (ownClass || teachingClassList.value[0])?.schoolClassId || "";
+ }
+ getList();
+ } catch (error) {
+ workingCapitalList.value = [];
+ workingCapitalTotal.value = 0;
+ }
+};
+const handleClassChange = () => {
+ scoreParams.value.index = 1;
+ getList();
};
const exportExcel = () => {
+ if (!scoreParams.value.classId) {
+ proxy.$modal.msgWarning("请选择教学班后再导出成绩");
+ return;
+ }
const { index, size, ...query } = buildScoreQuery();
indexApi.exportScoreList(query).then((res) => {
// 打开怎么是空的
@@ -228,7 +301,7 @@ const exportExcel = () => {
};
const getClassScoreDetail = (row) => {
if (!scoreParams.value.classId) {
- proxy.$modal.msgWarning("请选择自己的教学班后再查看成绩详情");
+ proxy.$modal.msgWarning("请选择教学班后再查看成绩详情");
return;
}
indexApi.getScoreDetail({ userId: row.userId, classId: scoreParams.value.classId }).then((res) => {
@@ -236,6 +309,26 @@ const getClassScoreDetail = (row) => {
scoreDetailsStart.value = true;
});
};
+const saveTeacherScore = (row) => {
+ if (row.teacherScoreDraft === null || row.teacherScoreDraft === undefined || row.teacherScoreDraft === "") {
+ proxy.$message.error("请输入老师评分");
+ return;
+ }
+ const score = Number(row.teacherScoreDraft);
+ if (!Number.isFinite(score) || score < 0 || score > 100) {
+ proxy.$message.error("老师评分必须为0至100之间的数值");
+ return;
+ }
+ savingScoreUserId.value = row.userId;
+ indexApi.saveTeacherScore({
+ classId: scoreParams.value.classId,
+ studentUserId: row.userId,
+ teacherScore: score,
+ }).then(() => {
+ row.teacherScore = score;
+ proxy.$message.success("老师评分保存成功");
+ }).finally(() => (savingScoreUserId.value = ""));
+};
// 更新成绩
const updateScore = () => {
if (!scoreParams.value.classId) {
@@ -256,7 +349,6 @@ const updateScore = () => {
};
// 拿到当前路由信息
onMounted(() => {
- getList();
getClassList();
});
@@ -265,4 +357,32 @@ onMounted(() => {
background: #ffffff;
height: calc(100vh - 70px);
}
+.teacher-score-editor {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+
+ :deep(.el-input-number) {
+ width: 104px;
+ }
+}
+.teacher-score-readonly {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+
+ strong {
+ color: #63dcff;
+ font-size: 16px;
+ font-variant-numeric: tabular-nums;
+ }
+
+ small {
+ padding: 2px 7px;
+ color: rgba(190, 218, 231, 0.68);
+ border: 1px solid rgba(96, 172, 207, 0.28);
+ border-radius: 999px;
+ }
+}
diff --git a/tests/score-center-class-access-teacher-score.static.test.cjs b/tests/score-center-class-access-teacher-score.static.test.cjs
new file mode 100644
index 0000000..eb7c868
--- /dev/null
+++ b/tests/score-center-class-access-teacher-score.static.test.cjs
@@ -0,0 +1,21 @@
+const assert = require("node:assert/strict");
+const fs = require("node:fs");
+const path = require("node:path");
+
+const root = path.resolve(__dirname, "..");
+const page = fs.readFileSync(path.join(root, "src/views/teacherEnd/score/index.vue"), "utf8");
+const api = fs.readFileSync(path.join(root, "src/api/teacher.js"), "utf8");
+
+assert.match(page, /label="老师评分"/);
+assert.match(page, /teacherScoreDraft/);
+assert.match(page, /canManageSelectedClass/);
+assert.match(page, /createdBy/);
+assert.match(page, /saveTeacherScore/);
+assert.match(page, /老师评分必须为0至100之间的数值/);
+assert.match(page, /ownClass \|\| teachingClassList\.value\[0\]/);
+assert.match(page, /getAccessibleTeachingClasses/);
+assert.doesNotMatch(page, /onMounted\(\(\) => \{\s*getList\(\);\s*getClassList/);
+assert.match(api, /url: "\/api\/weight\/saveTeacherScore"/);
+assert.match(api, /url: "\/api\/weight\/accessibleTeachingClasses"/);
+
+console.log("score center class access and teacher score contract passed");
diff --git a/tests/teacher-score-scope.static.test.cjs b/tests/teacher-score-scope.static.test.cjs
index e5f4f9b..21b71f7 100644
--- a/tests/teacher-score-scope.static.test.cjs
+++ b/tests/teacher-score-scope.static.test.cjs
@@ -8,7 +8,7 @@ const api = fs.readFileSync('src/api/teacher.js', 'utf8');
assert(api.includes('/api/weight/ownedTeachingClasses'));
assert(api.includes('/api/weight/selectTeachingClassWeight'));
assert(api.includes('/api/weight/updateTeachingClassWeight'));
-assert(page.includes('getOwnedTeachingClasses'));
+assert(page.includes('getAccessibleTeachingClasses'));
assert(page.includes('互联网产品开发基础认知'));
assert(page.includes('市场洞察与需求分析'));
assert(page.includes('产品规划与设计'));