|
|
|
|
@ -6,13 +6,14 @@
|
|
|
|
|
AI助学
|
|
|
|
|
</h3>
|
|
|
|
|
|
|
|
|
|
<p class="ai-instruction">点击参考提示词可自动带入问题,AI 将结合当前实训内容给出建议。</p>
|
|
|
|
|
<div class="ai-output">
|
|
|
|
|
<div class="output-glow"></div>
|
|
|
|
|
<p>{{ displayAssistMessage }}</p>
|
|
|
|
|
<div v-if="referenceText" class="reference-block">
|
|
|
|
|
<button v-if="referenceText" type="button" class="reference-block" @click="useReferencePrompt">
|
|
|
|
|
<strong>{{ referenceTitle }}</strong>
|
|
|
|
|
<span v-html="referenceText"></span>
|
|
|
|
|
</div>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="ai-input-shell">
|
|
|
|
|
@ -29,7 +30,7 @@
|
|
|
|
|
AI助评
|
|
|
|
|
</h3>
|
|
|
|
|
|
|
|
|
|
<div class="ai-output">
|
|
|
|
|
<div class="ai-output ai-output--review">
|
|
|
|
|
<div class="output-glow"></div>
|
|
|
|
|
<p>{{ displayEvalMessage }}</p>
|
|
|
|
|
<div v-if="displayScoreVisible" class="score-badge">
|
|
|
|
|
@ -37,18 +38,17 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="ai-input-shell">
|
|
|
|
|
<textarea v-model="reviewQuestion" placeholder="请求AI助评,智能打分"></textarea>
|
|
|
|
|
<button type="button" class="send-btn" aria-label="请求AI助评" @click="requestEvaluation">
|
|
|
|
|
<el-icon><Top /></el-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<el-button class="assessment-button" :loading="assessmentLoading" :disabled="!currentTaskKey" @click="requestEvaluation">AI智能评分</el-button>
|
|
|
|
|
</section>
|
|
|
|
|
</aside>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { Reading, Star, Top } from "@element-plus/icons-vue";
|
|
|
|
|
import { getAiTrainingEvaluation, requestAiTrainingAssessment, requestAiTrainingHelp } from "@/api/aiTrainingEvaluation";
|
|
|
|
|
import { normalizeEvaluationReports } from "./trainingAiEvaluationReport";
|
|
|
|
|
import { resolveTrainingTaskKey } from "@/views/training/taskKeyMap";
|
|
|
|
|
import { buildReferencePrompt } from "./studentTrainingAiPanel";
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
studyTip: {
|
|
|
|
|
@ -83,6 +83,7 @@ const props = defineProps({
|
|
|
|
|
type: Array,
|
|
|
|
|
default: () => [],
|
|
|
|
|
},
|
|
|
|
|
taskKey: { type: String, default: "" },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(["request-assist", "request-evaluation"]);
|
|
|
|
|
@ -93,27 +94,56 @@ const assistMessage = ref("");
|
|
|
|
|
const internalEvalMessage = ref("");
|
|
|
|
|
const internalScore = ref("--");
|
|
|
|
|
const internalScoreVisible = ref(false);
|
|
|
|
|
const assessmentLoading = ref(false);
|
|
|
|
|
const evaluation = ref({});
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const currentTaskKey = computed(() => resolveTrainingTaskKey(route, props.taskKey));
|
|
|
|
|
const reports = computed(() => normalizeEvaluationReports(evaluation.value));
|
|
|
|
|
|
|
|
|
|
const displayAssistMessage = computed(() => assistMessage.value || props.studyTip);
|
|
|
|
|
const displayScoreVisible = computed(() => props.scoreVisible || internalScoreVisible.value);
|
|
|
|
|
const displayFinalScore = computed(() => (props.scoreVisible ? props.finalScore : internalScore.value));
|
|
|
|
|
const displayScoreVisible = computed(() => props.scoreVisible || internalScoreVisible.value || reports.value.score !== null);
|
|
|
|
|
const displayFinalScore = computed(() => (props.scoreVisible ? props.finalScore : reports.value.score ?? internalScore.value));
|
|
|
|
|
const displayEvalMessage = computed(() => {
|
|
|
|
|
if (props.scoreVisible) return props.evalMessage;
|
|
|
|
|
return internalEvalMessage.value || props.evalMessage;
|
|
|
|
|
return reports.value.assessmentReport || internalEvalMessage.value || props.evalMessage;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function requestAssist() {
|
|
|
|
|
onMounted(loadEvaluation);
|
|
|
|
|
watch(currentTaskKey, loadEvaluation);
|
|
|
|
|
|
|
|
|
|
async function loadEvaluation() {
|
|
|
|
|
if (!currentTaskKey.value) return;
|
|
|
|
|
try { evaluation.value = (await getAiTrainingEvaluation(currentTaskKey.value))?.data || {}; } catch (error) { evaluation.value = {}; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function useReferencePrompt() {
|
|
|
|
|
assistQuestion.value = buildReferencePrompt(props.referenceText);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function requestAssist() {
|
|
|
|
|
emit("request-assist", assistQuestion.value);
|
|
|
|
|
assistMessage.value = assistQuestion.value
|
|
|
|
|
? `围绕“${assistQuestion.value}”,建议先对照任务目标检查信息是否完整,再补充数据依据和分析结论。`
|
|
|
|
|
: props.assistText;
|
|
|
|
|
if (currentTaskKey.value) {
|
|
|
|
|
try {
|
|
|
|
|
await requestAiTrainingHelp(currentTaskKey.value);
|
|
|
|
|
await loadEvaluation();
|
|
|
|
|
assistMessage.value = reports.value.helpReport || props.assistText;
|
|
|
|
|
return;
|
|
|
|
|
} catch (error) {}
|
|
|
|
|
}
|
|
|
|
|
assistMessage.value = assistQuestion.value ? `围绕“${assistQuestion.value}”,建议先对照任务目标检查信息是否完整,再补充数据依据和分析结论。` : props.assistText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function requestEvaluation() {
|
|
|
|
|
async function requestEvaluation() {
|
|
|
|
|
emit("request-evaluation", reviewQuestion.value);
|
|
|
|
|
internalScoreVisible.value = true;
|
|
|
|
|
internalScore.value = 88;
|
|
|
|
|
internalEvalMessage.value = "已完成初步评估:内容结构基本完整,建议继续补充真实数据来源、分析过程和可执行结论。";
|
|
|
|
|
if (!currentTaskKey.value) return;
|
|
|
|
|
assessmentLoading.value = true;
|
|
|
|
|
try {
|
|
|
|
|
await requestAiTrainingAssessment(currentTaskKey.value);
|
|
|
|
|
await loadEvaluation();
|
|
|
|
|
internalScoreVisible.value = reports.value.score !== null;
|
|
|
|
|
internalScore.value = reports.value.score ?? "--";
|
|
|
|
|
internalEvalMessage.value = reports.value.assessmentReport || props.evalMessage;
|
|
|
|
|
} finally { assessmentLoading.value = false; }
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
@ -194,6 +224,10 @@ function requestEvaluation() {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.ai-instruction { margin: -4px 0 12px; color: #9fcbe2; font-size: 13px; line-height: 1.6; }
|
|
|
|
|
.reference-block { width: 100%; border: 0; background: transparent; padding: 14px 0 0; text-align: left; cursor: pointer; }
|
|
|
|
|
.reference-block:hover strong { color: #77eaff; }
|
|
|
|
|
.assessment-button { width: 100%; margin-top: 14px; min-height: 44px; font-weight: 800; }
|
|
|
|
|
|
|
|
|
|
.output-glow {
|
|
|
|
|
position: absolute;
|
|
|
|
|
|