@ -168,6 +168,150 @@
< / template >
< / template >
< / e l - d i a l o g >
< / e l - d i a l o g >
< el -dialog
v - model = "batchAiScoreDialogVisible"
width = "520px"
append - to - body
: show - close = "false"
: close - on - click - modal = "false"
: close - on - press - escape = "false"
class = "score-review-dialog batch-ai-score-dialog"
>
< template # header >
< div class = "dialog-header" >
< div class = "dialog-header-main" >
< span class = "dialog-badge" >
< el -icon > < TrendCharts / > < / e l - i c o n >
批量AI评分
< / span >
< h3 class = "dialog-title" > 已选择 { { selectedStudents . length } } 名学生 < / h3 >
< / div >
< button
v - if = "batchAiScoreProgress.status !== 'running'"
type = "button"
class = "dialog-close"
@ click = "closeBatchAiScoreDialog"
>
< el -icon > < Close / > < / e l - i c o n >
< / button >
< / div >
< / template >
< div class = "batch-ai-score-content" >
<!-- 状态说明 -- >
< div v-if ="batchAiScoreProgress.status === 'idle'" class="batch-ai-info" >
< p class = "batch-ai-info__title" > 准备开始批量AI评分 < / p >
< p class = "batch-ai-info__desc" > AI将自动分析已选中学生的作业内容 , 并生成评分结果 。 此过程可能需要几分钟 , 请耐心等待 。 < / p >
< ul class = "batch-ai-info__list" >
< li > AI会根据任务要求和评分标准进行评估 < / li >
< li > 评分维度包括内容完整性 、 分析深度 、 创新性等 < / li >
< li > 评分完成后可在学生列表中查看AI评分 < / li >
< / ul >
< / div >
<!-- 进度条和状态 -- >
< div v-if ="batchAiScoreProgress.status !== 'idle'" class="batch-ai-progress" >
< div class = "batch-ai-progress__stats" >
< div class = "batch-ai-progress__stat" >
< span class = "batch-ai-progress__label" > 总计 < / span >
< strong class = "batch-ai-progress__value" > { { batchAiScoreProgress . total } } < / strong >
< / div >
< div class = "batch-ai-progress__stat batch-ai-progress__stat--success" >
< span class = "batch-ai-progress__label" > 成功 < / span >
< strong class = "batch-ai-progress__value" > { { batchAiScoreProgress . successCount } } < / strong >
< / div >
< div class = "batch-ai-progress__stat batch-ai-progress__stat--fail" >
< span class = "batch-ai-progress__label" > 失败 < / span >
< strong class = "batch-ai-progress__value" > { { batchAiScoreProgress . failCount } } < / strong >
< / div >
< / div >
< div class = "batch-ai-progress__bar-wrapper" >
< el -progress
: percentage = "Math.floor((batchAiScoreProgress.current / batchAiScoreProgress.total) * 100)"
: status = "batchAiScoreProgress.status === 'completed' ? 'success' : batchAiScoreProgress.status === 'failed' ? 'exception' : undefined"
: stroke - width = "12"
/ >
< p class = "batch-ai-progress__text" >
{ { batchAiScoreProgress . current } } / { { batchAiScoreProgress . total } }
< / p >
< / div >
< p v-if ="batchAiScoreProgress.status === 'running'" class="batch-ai-progress__tip" >
< el -icon class = "is-loading" > < Loading / > < / e l - i c o n >
正在进行AI评分 , 请稍候 ...
< / p >
< p v-if ="batchAiScoreProgress.status === 'completed'" class="batch-ai-progress__tip batch-ai-progress__tip--success" >
< el -icon > < CircleCheck / > < / e l - i c o n >
批量AI评分已完成 !
< / p >
< p v-if ="batchAiScoreProgress.status === 'failed'" class="batch-ai-progress__tip batch-ai-progress__tip--error" >
AI评分过程中出现错误 , 请重试
< / p >
< / div >
< / div >
< template # footer >
< div class = "dialog-footer" >
< button
v - if = "batchAiScoreProgress.status === 'idle'"
type = "button"
class = "dialog-btn dialog-btn--cancel"
@ click = "batchAiScoreDialogVisible = false"
>
取消
< / button >
< button
v - if = "batchAiScoreProgress.status === 'idle'"
type = "button"
class = "dialog-btn dialog-btn--primary"
@ click = "startBatchAiScore"
>
< el -icon > < TrendCharts / > < / e l - i c o n >
开始AI评分
< / button >
< button
v - if = "batchAiScoreProgress.status === 'completed' || batchAiScoreProgress.status === 'failed'"
type = "button"
class = "dialog-btn dialog-btn--primary"
@ click = "closeBatchAiScoreDialog"
>
关闭
< / button >
< / div >
< / template >
< / e l - d i a l o g >
< el -dialog
v - model = "aiAssistEvalDialogVisible"
width = "420px"
append - to - body
: show - close = "false"
: close - on - click - modal = "false"
: close - on - press - escape = "false"
class = "score-review-dialog ai-assist-eval-dialog"
>
< template # header >
< div class = "dialog-header" >
< div class = "dialog-header-main" >
< span class = "dialog-badge" >
< el -icon > < TrendCharts / > < / e l - i c o n >
AI助评
< / span >
< h3 class = "dialog-title" > { { selectedStudent ? . name || selectedStudent ? . username } } < / h3 >
< / div >
< / div >
< / template >
< div class = "ai-assist-eval-content" >
< div class = "ai-assist-eval-loading" >
< el -icon class = "ai-assist-eval-loading__icon" > < Loading / > < / e l - i c o n >
< p class = "ai-assist-eval-loading__text" > AI正在分析学生作业 ... < / p >
< p class = "ai-assist-eval-loading__desc" > 这可能需要15 - 30 秒 , 请稍候 < / p >
< / div >
< / div >
< / e l - d i a l o g >
< el -dialog
< el -dialog
v - model = "aiScoreDetailDialogVisible"
v - model = "aiScoreDetailDialogVisible"
width = "720px"
width = "720px"
@ -282,6 +426,17 @@ const aiScoreDetailData = ref({
dimensions : [ ] ,
dimensions : [ ] ,
improvements : [ ]
improvements : [ ]
} ) ;
} ) ;
const batchAiScoreDialogVisible = ref ( false ) ;
const batchAiScoring = ref ( false ) ;
const batchAiScoreProgress = ref ( {
total : 0 ,
current : 0 ,
successCount : 0 ,
failCount : 0 ,
status : 'idle' / / ' i d l e ' | ' r u n n i n g ' | ' c o m p l e t e d ' | ' f a i l e d '
} ) ;
const aiAssistEvalDialogVisible = ref ( false ) ;
const aiAssistEvaluating = ref ( false ) ;
const canManageClass = computed ( ( ) => {
const canManageClass = computed ( ( ) => {
const currentClass = teachingClasses . value . find ( ( item ) => item . schoolClassId === filters . value . classId ) ;
const currentClass = teachingClasses . value . find ( ( item ) => item . schoolClassId === filters . value . classId ) ;
@ -486,25 +641,128 @@ onBeforeUnmount(() => {
} ) ;
} ) ;
/ / = = = = = = = = = = 新 增 方 法 = = = = = = = = = =
/ / = = = = = = = = = = 新 增 方 法 = = = = = = = = = =
function onBatchAiScore ( ) {
if ( selectedStudents . value . length === 0 ) {
ElMessage . warning ( "请先选择学生" ) ;
return ;
}
ElMessage . info ( "批量AI评分功能开发中..." ) ;
/ / 后 续 接 入 A I 评 分 接 口
}
function onViewReferenceAnswer ( ) {
function onViewReferenceAnswer ( ) {
if ( ! selectedStudent . value ) return ;
if ( ! selectedStudent . value ) return ;
ElMessage . info ( "查看参考答案功能开发中..." ) ;
ElMessage . info ( "查看参考答案功能开发中..." ) ;
/ / 后 续 弹 窗 展 示 参 考 答 案
/ / 后 续 弹 窗 展 示 参 考 答 案
}
}
function onAiAssistEvaluation ( ) {
function onBatchAiScore ( ) {
if ( ! selectedStudents . value || selectedStudents . value . length === 0 ) return ;
batchAiScoreDialogVisible . value = true ;
batchAiScoreProgress . value = {
total : selectedStudents . value . length ,
current : 0 ,
successCount : 0 ,
failCount : 0 ,
status : 'idle'
} ;
}
async function startBatchAiScore ( ) {
batchAiScoring . value = true ;
batchAiScoreProgress . value . status = 'running' ;
batchAiScoreProgress . value . current = 0 ;
batchAiScoreProgress . value . successCount = 0 ;
batchAiScoreProgress . value . failCount = 0 ;
try {
for ( const student of selectedStudents . value ) {
try {
/ / 模 拟 A I 评 分 过 程 , 后 续 替 换 为 真 实 A P I
await new Promise ( resolve => setTimeout ( resolve , 800 + Math . random ( ) * 400 ) ) ;
/ / 调 用 真 实 A P I : a w a i t t e a c h e r A p i . a i S c o r e S t u d e n t ( { . . . } ) ;
batchAiScoreProgress . value . successCount ++ ;
} catch ( error ) {
batchAiScoreProgress . value . failCount ++ ;
}
batchAiScoreProgress . value . current ++ ;
}
batchAiScoreProgress . value . status = 'completed' ;
ElMessage . success (
` AI评分完成! 成功 ${ batchAiScoreProgress . value . successCount } 名学生,失败 ${ batchAiScoreProgress . value . failCount } 名 `
) ;
/ / 延 迟 关 闭 对 话 框
setTimeout ( ( ) => {
batchAiScoreDialogVisible . value = false ;
loadReview ( ) ;
} , 2000 ) ;
} catch ( error ) {
batchAiScoreProgress . value . status = 'failed' ;
ElMessage . error ( '批量AI评分发生错误' ) ;
} finally {
batchAiScoring . value = false ;
}
}
function closeBatchAiScoreDialog ( ) {
if ( batchAiScoreProgress . value . status === 'running' ) {
ElMessage . warning ( '正在进行中,请等待...' ) ;
return ;
}
batchAiScoreDialogVisible . value = false ;
}
async function onAiAssistEvaluation ( ) {
if ( ! selectedStudent . value ) return ;
if ( ! selectedStudent . value ) return ;
ElMessage . info ( "AI助评功能开发中..." ) ;
/ / 后 续 调 用 A I 助 评 接 口 并 展 示 结 果
aiAssistEvalDialogVisible . value = true ;
aiAssistEvaluating . value = true ;
try {
/ / 模 拟 A I 助 评 过 程 , 后 续 替 换 为 真 实 A P I
await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ;
/ / 调 用 真 实 A P I : c o n s t r e s p o n s e = a w a i t t e a c h e r A p i . a i A s s i s t E v a l u a t i o n ( { . . . } ) ;
/ / 模 拟 生 成 A I 评 分 详 情
aiScoreDetailData . value = {
totalScore : Math . floor ( 75 + Math . random ( ) * 25 ) ,
totalFullScore : 100 ,
comment : "学生整体完成质量较好,在用户角度分析和市场反馈分析方面表现出色,技术与合规角度分析基本符合要求,结论总结分析有待提升。" ,
dimensions : [
{
name : "用户角度分析" ,
score : 25 ,
fullScore : 25 ,
analysis : "学生全面分析了产品的用户痛点、需求洞察和用户体验优化方向,能够从用户视角出发提出有价值的改进建议,符合用户为中心的产品设计思维。"
} ,
{
name : "技术与合规角度分析" ,
score : 23 ,
fullScore : 25 ,
analysis : "对产品的技术可行性和合规性进行了基本分析,识别了主要技术风险点,但在法律法规适配性方面的论述深度不够,建议补充更详细的合规性评估。"
} ,
{
name : "商业化及市场反馈角度分析" ,
score : 25 ,
fullScore : 25 ,
analysis : "学生准确把握了市场定位和商业模式,对竞争环境有清晰认知,提出的市场推广策略具有可操作性,商业价值分析完整。"
} ,
{
name : "结论总结分析" ,
score : 19 ,
fullScore : 25 ,
analysis : "总结部分提炼了主要观点,但逻辑性和结构性有待加强,建议按照问题-分析-结论的框架重新组织,增加可操作性建议。"
}
] ,
improvements : [
"补充技术合规性评估的详细内容,包括数据安全、隐私保护等方面的法规适配性分析" ,
"优化结论总结的逻辑结构, 建议采用MECE原则( 相互独立、完全穷尽) 进行归纳" ,
"在商业化分析中增加财务可行性评估, 包括成本收益分析和ROI预测"
]
} ;
aiAssistEvalDialogVisible . value = false ;
aiScoreDetailDialogVisible . value = true ;
} catch ( error ) {
ElMessage . error ( 'AI助评失败, 请重试' ) ;
} finally {
aiAssistEvaluating . value = false ;
}
}
}
async function showAiScoreDetail ( ) {
async function showAiScoreDetail ( ) {
@ -1270,6 +1528,200 @@ async function showAiScoreDetail() {
}
}
}
}
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* 批量AI评分对话框
* === === === === === === === === === === === === === === === === === === === === * /
. batch - ai - score - content {
display : grid ;
gap : 24 px ;
}
. batch - ai - info {
display : grid ;
gap : 12 px ;
}
. batch - ai - info _ _title {
margin : 0 ;
color : # 1 f2937 ;
font - size : 15 px ;
font - weight : 600 ;
}
. batch - ai - info _ _desc {
margin : 0 ;
color : # 6 b7280 ;
font - size : 13 px ;
line - height : 1.6 ;
}
. batch - ai - info _ _list {
margin : 4 px 0 0 ;
padding - left : 20 px ;
list - style : disc ;
li {
margin - bottom : 6 px ;
color : # 6 b7280 ;
font - size : 12 px ;
line - height : 1.5 ;
& : last - child {
margin - bottom : 0 ;
}
}
}
. batch - ai - progress {
display : grid ;
gap : 20 px ;
}
. batch - ai - progress _ _stats {
display : grid ;
grid - template - columns : repeat ( 3 , 1 fr ) ;
gap : 12 px ;
}
. batch - ai - progress _ _stat {
padding : 12 px ;
border : 1 px solid # e5e7eb ;
border - radius : 8 px ;
background : # fafbfc ;
text - align : center ;
& . batch - ai - progress _ _stat -- success {
background : # f0fdf4 ;
border - color : # dcfce7 ;
}
& . batch - ai - progress _ _stat -- fail {
background : # fef2f2 ;
border - color : # fee2e2 ;
}
}
. batch - ai - progress _ _label {
display : block ;
color : # 9 ca3af ;
font - size : 11 px ;
font - weight : 600 ;
text - transform : uppercase ;
margin - bottom : 4 px ;
}
. batch - ai - progress _ _value {
display : block ;
color : # 1 f2937 ;
font - size : 20 px ;
font - weight : 700 ;
font - family : ui - monospace , "SF Mono" , Consolas , monospace ;
. batch - ai - progress _ _stat -- success & {
color : # 16 a34a ;
}
. batch - ai - progress _ _stat -- fail & {
color : # dc2626 ;
}
}
. batch - ai - progress _ _bar - wrapper {
position : relative ;
padding : 12 px 0 8 px ;
: deep ( . el - progress _ _bar ) {
border - radius : 6 px ;
}
}
. batch - ai - progress _ _text {
margin : 0 ;
color : # 6 b7280 ;
font - size : 12 px ;
text - align : center ;
font - weight : 500 ;
}
. batch - ai - progress _ _tip {
margin : 0 ;
padding : 12 px ;
border - radius : 8 px ;
background : # f3f4f6 ;
color : # 6 b7280 ;
font - size : 12 px ;
display : flex ;
align - items : center ;
justify - content : center ;
gap : 8 px ;
border : 1 px solid # e5e7eb ;
. el - icon {
font - size : 14 px ;
& . is - loading {
animation : rotating 2 s linear infinite ;
}
}
& . batch - ai - progress _ _tip -- success {
background : # f0fdf4 ;
border - color : # dcfce7 ;
color : # 16 a34a ;
}
& . batch - ai - progress _ _tip -- error {
background : # fef2f2 ;
border - color : # fee2e2 ;
color : # dc2626 ;
}
}
@ keyframes rotating {
from {
transform : rotate ( 0 deg ) ;
}
to {
transform : rotate ( 360 deg ) ;
}
}
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* AI助评加载对话框
* === === === === === === === === === === === === === === === === === === === === * /
. ai - assist - eval - content {
min - height : 160 px ;
display : flex ;
align - items : center ;
justify - content : center ;
}
. ai - assist - eval - loading {
text - align : center ;
display : grid ;
gap : 12 px ;
}
. ai - assist - eval - loading _ _icon {
font - size : 48 px ;
color : # 3 b82f6 ;
animation : rotating 2 s linear infinite ;
margin : 0 auto ;
}
. ai - assist - eval - loading _ _text {
margin : 0 ;
color : # 1 f2937 ;
font - size : 14 px ;
font - weight : 600 ;
}
. ai - assist - eval - loading _ _desc {
margin : 0 ;
color : # 9 ca3af ;
font - size : 12 px ;
}
@ media ( max - width : 1180 px ) {
@ media ( max - width : 1180 px ) {
. task - review {
. task - review {
grid - template - columns : 1 fr ;
grid - template - columns : 1 fr ;