|
|
@@ -3,11 +3,12 @@
|
|
|
<div class="rating-component">
|
|
|
<span>评分: </span>
|
|
|
<input type="number" class="score-input" :min="1" :max="100" placeholder="暂无分数" title="请输入0~100间的数字"
|
|
|
- v-model="correction.score" :disabled="isStudent" />
|
|
|
+ v-model="correction.score" :disabled="isStudent" @input="validateScore" />
|
|
|
+ <span v-if="scoreError" class="error-message">{{ scoreError }}</span>
|
|
|
</div>
|
|
|
|
|
|
<div class="textarea-container">
|
|
|
- <textarea v-model="correction.remark" placeholder="暂无评语" :readonly="isStudent"></textarea>
|
|
|
+ <textarea v-model="correction.remark" placeholder="请输入评语" :readonly="isStudent"></textarea>
|
|
|
</div>
|
|
|
|
|
|
<div class="correction-actions">
|
|
|
@@ -49,16 +50,55 @@
|
|
|
</div>
|
|
|
|
|
|
<div class="right-buttons">
|
|
|
+ <!-- 新增:评语模板 -->
|
|
|
+ <el-button color="#597D3B" @click="showTemplateDialog" v-if="!isStudent">评语模板</el-button>
|
|
|
<el-button color="#597D3B" @click="goBack">返回</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 添加评语模板弹窗 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="templateDialogVisible"
|
|
|
+ title="评语模板"
|
|
|
+ width="50%"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ class="template-dialog"
|
|
|
+ >
|
|
|
+ <div class="template-list">
|
|
|
+ <div
|
|
|
+ v-for="(template, index) in remarkTemplates"
|
|
|
+ :key="index"
|
|
|
+ class="template-item"
|
|
|
+ @click="selectTemplate(template)"
|
|
|
+ >
|
|
|
+ <el-tooltip
|
|
|
+ v-if="isTruncatedList[index]"
|
|
|
+ :content="template"
|
|
|
+ placement="top"
|
|
|
+ :show-after="500"
|
|
|
+ effect="light"
|
|
|
+ >
|
|
|
+ <div class="template-content" :ref="el => setTemplateContentRef(el, index)">
|
|
|
+ {{ index + 1 }}. {{ template }}
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ <div
|
|
|
+ v-else
|
|
|
+ class="template-content"
|
|
|
+ :ref="el => setTemplateContentRef(el, index)"
|
|
|
+ >
|
|
|
+ {{ index + 1 }}. {{ template }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts">
|
|
|
-import { defineComponent, ref, onMounted, computed } from 'vue';
|
|
|
+import { defineComponent, ref, onMounted, computed, nextTick, watch } from 'vue';
|
|
|
import useApis from "@/apis";
|
|
|
import { ElMessage } from "element-plus";
|
|
|
import router from '@/router';
|
|
|
@@ -81,6 +121,7 @@ export default defineComponent({
|
|
|
setup(props) {
|
|
|
const isStudent = computed(() => store.user.role === 'STUDENT');
|
|
|
const submitting = ref(false);
|
|
|
+ const scoreError = ref('');
|
|
|
|
|
|
//定义一个correction接收后端传过来的批改信息(如果有)
|
|
|
const correction = ref({
|
|
|
@@ -224,6 +265,60 @@ export default defineComponent({
|
|
|
params: { assignmentId: props.assignmentId }
|
|
|
});
|
|
|
};
|
|
|
+ //新增:验证评分是否在1-100之间
|
|
|
+ const validateScore = () => {
|
|
|
+ const score = Number(correction.value.score);
|
|
|
+ if (isNaN(score) || score < 1 || score > 100) {
|
|
|
+ scoreError.value = '评分必须在1-100之间';
|
|
|
+ } else {
|
|
|
+ scoreError.value = '';
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ //新增:评语模板
|
|
|
+ const templateDialogVisible = ref(false);
|
|
|
+ const remarkTemplates = [
|
|
|
+ 'Great job! Your writing is clear and well-organized.',
|
|
|
+ 'There are some grammar mistakes that affect clarity. Please revise. ',
|
|
|
+ 'Watch out for tense consistency throughout your writing.',
|
|
|
+ 'You used some good vocabulary, but try to expand your word choice.',
|
|
|
+ 'Your argument is clear, but could be strengthened with more supporting details.Use more precise words to convey your ideas more effectively.'
|
|
|
+ ];
|
|
|
+
|
|
|
+ const showTemplateDialog = () => {
|
|
|
+ templateDialogVisible.value = true;
|
|
|
+ };
|
|
|
+
|
|
|
+ const selectTemplate = (template: string) => {
|
|
|
+ correction.value.remark = template;
|
|
|
+ templateDialogVisible.value = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 新增:判断每个选项是否被截断
|
|
|
+ const isTruncatedList = ref<boolean[]>([]);
|
|
|
+ const templateContentRefs = ref<(HTMLElement|null)[]>([]);
|
|
|
+
|
|
|
+ const setTemplateContentRef = (el: any, index: number) => {
|
|
|
+ templateContentRefs.value[index] = el;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 计算截断
|
|
|
+ const checkTruncated = () => {
|
|
|
+ isTruncatedList.value = remarkTemplates.map((_, idx) => {
|
|
|
+ const el = templateContentRefs.value[idx];
|
|
|
+ if (!el || !(el instanceof HTMLElement)) return false;
|
|
|
+ return el.scrollWidth > el.clientWidth;
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ // 弹窗打开后检查
|
|
|
+ watch(templateDialogVisible, (val) => {
|
|
|
+ if (val) {
|
|
|
+ nextTick(() => {
|
|
|
+ checkTruncated();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
return {
|
|
|
correction,
|
|
|
@@ -235,7 +330,15 @@ export default defineComponent({
|
|
|
progressPercentage,
|
|
|
uncorrectedNumber,
|
|
|
isAllCorrected,
|
|
|
- goBack
|
|
|
+ goBack,//返回
|
|
|
+ scoreError,//评分错误
|
|
|
+ validateScore,//验证评分
|
|
|
+ templateDialogVisible,//评语模板弹窗
|
|
|
+ remarkTemplates,//评语模板
|
|
|
+ showTemplateDialog,//显示评语模板弹窗
|
|
|
+ selectTemplate,//选择评语模板
|
|
|
+ isTruncatedList,
|
|
|
+ setTemplateContentRef,
|
|
|
};
|
|
|
}
|
|
|
});
|
|
|
@@ -274,4 +377,61 @@ export default defineComponent({
|
|
|
margin-top: 10px;
|
|
|
}
|
|
|
}
|
|
|
+/* 新增:评分错误 css样式*/
|
|
|
+.rating-component {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 15px;
|
|
|
+
|
|
|
+ .error-message {
|
|
|
+ color: #ff4d4f;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 700;
|
|
|
+ }
|
|
|
+}
|
|
|
+/* 新增:评语模板 css样式*/
|
|
|
+.template-dialog {
|
|
|
+ :deep(.el-dialog__body) {
|
|
|
+ padding: 20px 0; // 上下20px,左右0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.template-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 15px;
|
|
|
+ padding: 0 24px; // 左右留白对称
|
|
|
+
|
|
|
+ .template-item {
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 0 16px;
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ height: 50px;
|
|
|
+ overflow: hidden;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin: 0 auto;
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ border-color: #597D3B;
|
|
|
+ }
|
|
|
+
|
|
|
+ .template-content {
|
|
|
+ width: 100%;
|
|
|
+ text-align: left;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.5;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|