936 lines
27 KiB
Dart
936 lines
27 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter/foundation.dart';
|
|
import '../models/course.dart';
|
|
import '../models/evaluation_result.dart';
|
|
import '../models/evaluation_history.dart';
|
|
import '../models/concurrent_task.dart';
|
|
import '../services/evaluation_service.dart';
|
|
import '../services/notification_service.dart';
|
|
import '../services/storage_service.dart';
|
|
import '../services/questionnaire_parser.dart';
|
|
import '../utils/text_generator.dart';
|
|
|
|
/// Evaluation state enum
|
|
enum EvaluationState { idle, loading, evaluating, completed, error }
|
|
|
|
/// Provider for managing course evaluation state and operations
|
|
///
|
|
/// Handles loading courses, batch evaluation, progress tracking,
|
|
/// and notification management
|
|
///
|
|
/// Usage example:
|
|
/// ```dart
|
|
/// final evaluationProvider = Provider.of<EvaluationProvider>(context);
|
|
///
|
|
/// // Load courses
|
|
/// await evaluationProvider.loadCourses();
|
|
///
|
|
/// // Start batch evaluation
|
|
/// await evaluationProvider.startBatchEvaluation();
|
|
///
|
|
/// // Retry failed courses
|
|
/// await evaluationProvider.retryFailed();
|
|
/// ```
|
|
class EvaluationProvider extends ChangeNotifier {
|
|
EvaluationService? _service;
|
|
final NotificationService _notificationService;
|
|
final StorageService _storageService;
|
|
|
|
List<Course> _courses = [];
|
|
EvaluationState _state = EvaluationState.idle;
|
|
BatchEvaluationResult? _lastResult;
|
|
String? _errorMessage;
|
|
List<EvaluationHistory> _evaluationHistory = [];
|
|
|
|
// Progress tracking
|
|
int _currentProgress = 0;
|
|
int _totalProgress = 0;
|
|
Course? _currentCourse;
|
|
String? _currentStatus;
|
|
final List<String> _logs = [];
|
|
|
|
// Countdown tracking
|
|
int _countdownRemaining = 0;
|
|
int _countdownTotal = 0;
|
|
|
|
// Concurrent evaluation tracking
|
|
final List<ConcurrentTask> _concurrentTasks = [];
|
|
bool _isConcurrentMode = false;
|
|
|
|
EvaluationProvider({
|
|
EvaluationService? service,
|
|
required NotificationService notificationService,
|
|
StorageService? storageService,
|
|
}) : _service = service,
|
|
_notificationService = notificationService,
|
|
_storageService = storageService ?? StorageService() {
|
|
_loadEvaluationHistory();
|
|
}
|
|
|
|
dynamic _connection;
|
|
|
|
/// Set the connection to use for fetching courses and create evaluation service
|
|
void setConnection(dynamic connection) {
|
|
_connection = connection;
|
|
if (connection != null) {
|
|
_service = EvaluationService(
|
|
connection: connection,
|
|
parser: QuestionnaireParser(),
|
|
textGenerator: TextGenerator(),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Get current evaluation state
|
|
EvaluationState get state => _state;
|
|
|
|
/// Get list of courses
|
|
List<Course> get courses => _courses;
|
|
|
|
/// Get last batch evaluation result
|
|
BatchEvaluationResult? get lastResult => _lastResult;
|
|
|
|
/// Get current error message (if any)
|
|
String? get errorMessage => _errorMessage;
|
|
|
|
/// Get current progress (0.0 to 1.0)
|
|
double get progress =>
|
|
_totalProgress > 0 ? _currentProgress / _totalProgress : 0.0;
|
|
|
|
/// Get current progress count
|
|
int get currentProgress => _currentProgress;
|
|
|
|
/// Get total progress count
|
|
int get totalProgress => _totalProgress;
|
|
|
|
/// Get current course being evaluated
|
|
Course? get currentCourse => _currentCourse;
|
|
|
|
/// Get current status message
|
|
String? get currentStatus => _currentStatus;
|
|
|
|
/// Get evaluation logs
|
|
List<String> get logs => List.unmodifiable(_logs);
|
|
|
|
/// Get countdown remaining seconds
|
|
int get countdownRemaining => _countdownRemaining;
|
|
|
|
/// Get countdown total seconds
|
|
int get countdownTotal => _countdownTotal;
|
|
|
|
/// Get countdown progress (0.0 to 1.0)
|
|
double get countdownProgress => _countdownTotal > 0
|
|
? (_countdownTotal - _countdownRemaining) / _countdownTotal
|
|
: 0.0;
|
|
|
|
/// Get concurrent tasks
|
|
List<ConcurrentTask> get concurrentTasks =>
|
|
List.unmodifiable(_concurrentTasks);
|
|
|
|
/// Check if in concurrent mode
|
|
bool get isConcurrentMode => _isConcurrentMode;
|
|
|
|
/// Add a log entry
|
|
void _addLog(String message, {bool updateLast = false}) {
|
|
final timestamp = DateTime.now().toString().substring(11, 19);
|
|
final logEntry = '[$timestamp] $message';
|
|
|
|
if (updateLast && _logs.isNotEmpty) {
|
|
// Update the last log entry
|
|
_logs[_logs.length - 1] = logEntry;
|
|
} else {
|
|
// Add new log entry
|
|
_logs.add(logEntry);
|
|
// Keep only last 100 logs
|
|
if (_logs.length > 100) {
|
|
_logs.removeAt(0);
|
|
}
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Clear logs
|
|
void clearLogs() {
|
|
_logs.clear();
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Get pending courses (not yet evaluated)
|
|
List<Course> get pendingCourses =>
|
|
_courses.where((c) => !c.isEvaluated).toList();
|
|
|
|
/// Get evaluated courses
|
|
List<Course> get evaluatedCourses =>
|
|
_courses.where((c) => c.isEvaluated).toList();
|
|
|
|
/// Get failed courses from last batch evaluation
|
|
List<Course> get failedCourses {
|
|
if (_lastResult == null) return [];
|
|
return _lastResult!.results
|
|
.where((r) => !r.success)
|
|
.map((r) => r.course)
|
|
.toList();
|
|
}
|
|
|
|
/// Get evaluation history
|
|
List<EvaluationHistory> get evaluationHistory => _evaluationHistory;
|
|
|
|
/// Load evaluation history from storage
|
|
Future<void> _loadEvaluationHistory() async {
|
|
try {
|
|
_evaluationHistory = await _storageService.loadEvaluationHistory();
|
|
notifyListeners();
|
|
} catch (e) {
|
|
debugPrint('Failed to load evaluation history: $e');
|
|
}
|
|
}
|
|
|
|
/// Refresh evaluation history from storage
|
|
Future<void> refreshEvaluationHistory() async {
|
|
await _loadEvaluationHistory();
|
|
}
|
|
|
|
/// Clear evaluation history
|
|
Future<void> clearEvaluationHistory() async {
|
|
try {
|
|
await _storageService.clearEvaluationHistory();
|
|
_evaluationHistory = [];
|
|
notifyListeners();
|
|
} catch (e) {
|
|
debugPrint('Failed to clear evaluation history: $e');
|
|
}
|
|
}
|
|
|
|
/// Save evaluation results to history
|
|
Future<void> _saveEvaluationResults(List<EvaluationResult> results) async {
|
|
try {
|
|
final histories = results.map((result) {
|
|
return EvaluationHistory(
|
|
id: '${result.course.id}_${result.timestamp.millisecondsSinceEpoch}',
|
|
course: result.course,
|
|
timestamp: result.timestamp,
|
|
success: result.success,
|
|
errorMessage: result.errorMessage,
|
|
);
|
|
}).toList();
|
|
|
|
await _storageService.saveEvaluationHistories(histories);
|
|
await _loadEvaluationHistory();
|
|
} catch (e) {
|
|
debugPrint('Failed to save evaluation results: $e');
|
|
}
|
|
}
|
|
|
|
/// Load courses from the server
|
|
///
|
|
/// Fetches the list of courses that need evaluation
|
|
/// Updates state and notifies listeners
|
|
///
|
|
/// Returns true if successful, false otherwise
|
|
Future<bool> loadCourses() async {
|
|
print('📚 loadCourses called');
|
|
print('📚 _connection: $_connection');
|
|
|
|
if (_connection == null) {
|
|
_errorMessage = '未设置连接';
|
|
_setState(EvaluationState.error);
|
|
print('❌ No connection set');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
print('📚 Setting state to loading...');
|
|
_setState(EvaluationState.loading);
|
|
_errorMessage = null;
|
|
|
|
print('📚 Calling _connection.fetchCourseList()...');
|
|
final courses = await _connection.fetchCourseList();
|
|
print('📚 Received ${courses.length} courses');
|
|
|
|
_courses = courses;
|
|
_setState(EvaluationState.idle);
|
|
|
|
return true;
|
|
} catch (e, stackTrace) {
|
|
_errorMessage = '加载课程列表失败: $e';
|
|
_setState(EvaluationState.error);
|
|
print('❌ Error loading courses: $e');
|
|
print('❌ Stack trace: $stackTrace');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Start batch evaluation of all pending courses
|
|
///
|
|
/// Evaluates all courses that haven't been evaluated yet
|
|
/// Shows notifications for progress and completion
|
|
/// Updates state and progress in real-time
|
|
///
|
|
/// Returns the batch evaluation result
|
|
Future<BatchEvaluationResult?> startBatchEvaluation() async {
|
|
if (_service == null) {
|
|
_errorMessage = '评教服务未初始化';
|
|
_setState(EvaluationState.error);
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
_setState(EvaluationState.evaluating);
|
|
_errorMessage = null;
|
|
|
|
// Get pending courses
|
|
final pending = pendingCourses;
|
|
if (pending.isEmpty) {
|
|
_errorMessage = '没有待评课程';
|
|
_setState(EvaluationState.idle);
|
|
return null;
|
|
}
|
|
|
|
// Initialize progress
|
|
_currentProgress = 0;
|
|
_totalProgress = pending.length;
|
|
_currentCourse = null;
|
|
_currentStatus = null;
|
|
notifyListeners();
|
|
|
|
// Show start notification
|
|
await _notificationService.showBatchStartNotification(_totalProgress);
|
|
|
|
// Clear previous logs
|
|
_logs.clear();
|
|
_addLog('开始批量评教,共 $_totalProgress 门课程');
|
|
|
|
// Start batch evaluation with custom logic
|
|
final results = <EvaluationResult>[];
|
|
final startTime = DateTime.now();
|
|
|
|
for (int i = 0; i < pending.length; i++) {
|
|
final course = pending[i];
|
|
|
|
_currentProgress = i;
|
|
_currentCourse = course;
|
|
_currentStatus = '准备评教';
|
|
notifyListeners();
|
|
|
|
_addLog(
|
|
'❤ Created By LoveACE Team, 🌧 Powered By Sibuxiangx & Flutter',
|
|
);
|
|
_addLog('开始评教: ${course.name} (${course.teacher})');
|
|
|
|
// 1. Prepare evaluation
|
|
_currentStatus = '访问评价页面';
|
|
notifyListeners();
|
|
_addLog('📝 ${course.name}: 访问评价页面');
|
|
|
|
final formData = await _service!.prepareEvaluation(
|
|
course,
|
|
totalCourses: _totalProgress,
|
|
);
|
|
|
|
if (formData == null) {
|
|
final result = EvaluationResult(
|
|
course: course,
|
|
success: false,
|
|
errorMessage: '无法访问评价页面',
|
|
);
|
|
results.add(result);
|
|
_addLog('❌ ${course.name}: 访问失败,任务中断');
|
|
|
|
// Stop on error
|
|
_currentProgress = i + 1;
|
|
break;
|
|
}
|
|
|
|
_currentStatus = '解析问卷';
|
|
_addLog('📝 ${course.name}: 解析问卷');
|
|
|
|
_currentStatus = '生成答案';
|
|
_addLog('📝 ${course.name}: 生成答案');
|
|
|
|
// 2. Countdown (140 seconds)
|
|
_currentStatus = '等待提交';
|
|
_countdownTotal = 140;
|
|
|
|
for (int countdown = 140; countdown > 0; countdown--) {
|
|
_countdownRemaining = countdown;
|
|
notifyListeners();
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
}
|
|
|
|
_countdownRemaining = 0;
|
|
_countdownTotal = 0;
|
|
|
|
// 3. Submit evaluation
|
|
_currentStatus = '提交评价';
|
|
notifyListeners();
|
|
_addLog('📝 ${course.name}: 提交评价');
|
|
|
|
final result = await _service!.submitEvaluation(course, formData);
|
|
results.add(result);
|
|
|
|
if (!result.success) {
|
|
_addLog('❌ ${course.name}: 评教失败,任务中断');
|
|
_currentProgress = i + 1;
|
|
break;
|
|
}
|
|
|
|
// 4. Verify evaluation
|
|
_currentStatus = '验证结果';
|
|
_addLog('📝 ${course.name}: 验证结果');
|
|
|
|
final updatedCourses = await _connection!.fetchCourseList();
|
|
final updatedCourse = updatedCourses.firstWhere(
|
|
(c) => c.id == course.id,
|
|
orElse: () => course,
|
|
);
|
|
|
|
if (!updatedCourse.isEvaluated) {
|
|
results[results.length - 1] = EvaluationResult(
|
|
course: course,
|
|
success: false,
|
|
errorMessage: '评教未生效,服务器未确认',
|
|
);
|
|
_addLog('❌ ${course.name}: 评教未生效,任务中断');
|
|
_currentProgress = i + 1;
|
|
break;
|
|
}
|
|
|
|
_addLog('✅ ${course.name}: 评教完成');
|
|
_currentProgress = i + 1;
|
|
_currentStatus = '评教完成';
|
|
notifyListeners();
|
|
|
|
// Small delay between courses
|
|
if (i < pending.length - 1) {
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
}
|
|
}
|
|
|
|
// Calculate statistics
|
|
final successCount = results.where((r) => r.success).length;
|
|
final failedCount = results.where((r) => !r.success).length;
|
|
final duration = DateTime.now().difference(startTime);
|
|
|
|
final result = BatchEvaluationResult(
|
|
total: results.length,
|
|
success: successCount,
|
|
failed: failedCount,
|
|
results: results,
|
|
duration: duration,
|
|
);
|
|
|
|
// Save result
|
|
_lastResult = result;
|
|
|
|
// Save evaluation results to history
|
|
await _saveEvaluationResults(result.results);
|
|
|
|
// Add completion log
|
|
if (result.failed > 0) {
|
|
_addLog(
|
|
'❌ 批量评教中断: 成功 ${result.success}/${result.total},失败 ${result.failed}',
|
|
);
|
|
} else {
|
|
_addLog('✅ 批量评教完成: 全部 ${result.total} 门课程评教成功');
|
|
}
|
|
|
|
// Show completion notification
|
|
await _notificationService.showCompletionNotification(
|
|
success: result.success,
|
|
failed: result.failed,
|
|
total: result.total,
|
|
);
|
|
|
|
// Reload courses to update evaluation status
|
|
_addLog('刷新课程列表...');
|
|
await loadCourses();
|
|
_addLog('课程列表已更新');
|
|
|
|
_setState(EvaluationState.completed);
|
|
return result;
|
|
} catch (e) {
|
|
_errorMessage = '批量评教失败: $e';
|
|
_setState(EvaluationState.error);
|
|
|
|
// Show error notification
|
|
await _notificationService.showErrorNotification(_errorMessage!);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Retry evaluation for failed courses
|
|
///
|
|
/// Re-evaluates only the courses that failed in the last batch evaluation
|
|
/// Useful for handling temporary network issues or server errors
|
|
///
|
|
/// Returns the batch evaluation result for retry attempt
|
|
Future<BatchEvaluationResult?> retryFailed() async {
|
|
if (_service == null) {
|
|
_errorMessage = '评教服务未初始化';
|
|
_setState(EvaluationState.error);
|
|
return null;
|
|
}
|
|
|
|
if (_lastResult == null || failedCourses.isEmpty) {
|
|
_errorMessage = '没有失败的课程需要重试';
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
_setState(EvaluationState.evaluating);
|
|
_errorMessage = null;
|
|
|
|
final failedList = failedCourses;
|
|
|
|
// Initialize progress
|
|
_currentProgress = 0;
|
|
_totalProgress = failedList.length;
|
|
_currentCourse = null;
|
|
_currentStatus = null;
|
|
notifyListeners();
|
|
|
|
// Show start notification
|
|
await _notificationService.showBatchStartNotification(_totalProgress);
|
|
|
|
// Evaluate each failed course
|
|
final results = <EvaluationResult>[];
|
|
final startTime = DateTime.now();
|
|
|
|
for (int i = 0; i < failedList.length; i++) {
|
|
final course = failedList[i];
|
|
|
|
// Update progress
|
|
_currentProgress = i + 1;
|
|
_currentCourse = course;
|
|
_currentStatus = '正在重试...';
|
|
notifyListeners();
|
|
|
|
// Update notification
|
|
await _notificationService.updateProgressNotification(
|
|
current: i + 1,
|
|
total: _totalProgress,
|
|
courseName: course.name,
|
|
);
|
|
|
|
// Evaluate course
|
|
final result = await _service!.evaluateCourse(
|
|
course,
|
|
onStatusChange: (status) {
|
|
_currentStatus = status;
|
|
notifyListeners();
|
|
},
|
|
);
|
|
results.add(result);
|
|
|
|
// Small delay between evaluations
|
|
if (i < failedList.length - 1) {
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
}
|
|
}
|
|
|
|
// Calculate statistics
|
|
final successCount = results.where((r) => r.success).length;
|
|
final failedCount = results.where((r) => !r.success).length;
|
|
final duration = DateTime.now().difference(startTime);
|
|
|
|
final retryResult = BatchEvaluationResult(
|
|
total: failedList.length,
|
|
success: successCount,
|
|
failed: failedCount,
|
|
results: results,
|
|
duration: duration,
|
|
);
|
|
|
|
// Update last result
|
|
_lastResult = retryResult;
|
|
|
|
// Save retry results to history
|
|
await _saveEvaluationResults(results);
|
|
|
|
// Show completion notification
|
|
await _notificationService.showCompletionNotification(
|
|
success: successCount,
|
|
failed: failedCount,
|
|
total: failedList.length,
|
|
);
|
|
|
|
// Reload courses
|
|
await loadCourses();
|
|
|
|
_setState(EvaluationState.completed);
|
|
return retryResult;
|
|
} catch (e) {
|
|
_errorMessage = '重试失败: $e';
|
|
_setState(EvaluationState.error);
|
|
|
|
// Show error notification
|
|
await _notificationService.showErrorNotification(_errorMessage!);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Evaluate a single course
|
|
///
|
|
/// [course] - The course to evaluate
|
|
///
|
|
/// Returns the evaluation result
|
|
Future<EvaluationResult?> evaluateSingleCourse(Course course) async {
|
|
if (_service == null) {
|
|
_errorMessage = '评教服务未初始化';
|
|
_setState(EvaluationState.error);
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
_setState(EvaluationState.evaluating);
|
|
_errorMessage = null;
|
|
|
|
_currentProgress = 0;
|
|
_totalProgress = 1;
|
|
_currentCourse = course;
|
|
_currentStatus = '正在评教...';
|
|
notifyListeners();
|
|
|
|
final result = await _service!.evaluateCourse(
|
|
course,
|
|
onStatusChange: (status) {
|
|
_currentStatus = status;
|
|
notifyListeners();
|
|
},
|
|
);
|
|
|
|
// Save single evaluation result to history
|
|
await _saveEvaluationResults([result]);
|
|
|
|
if (result.success) {
|
|
// Reload courses to update status
|
|
await loadCourses();
|
|
}
|
|
|
|
_setState(EvaluationState.completed);
|
|
return result;
|
|
} catch (e) {
|
|
_errorMessage = '评教失败: $e';
|
|
_setState(EvaluationState.error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Clear last evaluation result
|
|
void clearLastResult() {
|
|
_lastResult = null;
|
|
_currentProgress = 0;
|
|
_totalProgress = 0;
|
|
_currentCourse = null;
|
|
_currentStatus = null;
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Reset provider state
|
|
void reset() {
|
|
_courses = [];
|
|
_state = EvaluationState.idle;
|
|
_lastResult = null;
|
|
_errorMessage = null;
|
|
_currentProgress = 0;
|
|
_totalProgress = 0;
|
|
_currentCourse = null;
|
|
_currentStatus = null;
|
|
_logs.clear();
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Update evaluation state and notify listeners
|
|
void _setState(EvaluationState newState) {
|
|
_state = newState;
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Start concurrent batch evaluation
|
|
///
|
|
/// Evaluates all pending courses concurrently with 6-second intervals
|
|
/// Each task runs independently with its own 140-second countdown
|
|
///
|
|
/// Returns the batch evaluation result
|
|
Future<BatchEvaluationResult?> startConcurrentBatchEvaluation() async {
|
|
if (_service == null) {
|
|
_errorMessage = '评教服务未初始化';
|
|
_setState(EvaluationState.error);
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
_setState(EvaluationState.evaluating);
|
|
_errorMessage = null;
|
|
_isConcurrentMode = true;
|
|
|
|
// Get pending courses
|
|
final pending = pendingCourses;
|
|
if (pending.isEmpty) {
|
|
_errorMessage = '没有待评课程';
|
|
_setState(EvaluationState.idle);
|
|
_isConcurrentMode = false;
|
|
return null;
|
|
}
|
|
|
|
// Initialize
|
|
_currentProgress = 0;
|
|
_totalProgress = pending.length;
|
|
_concurrentTasks.clear();
|
|
_logs.clear();
|
|
notifyListeners();
|
|
|
|
// Show start notification
|
|
await _notificationService.showBatchStartNotification(_totalProgress);
|
|
_addLog('开始并发批量评教,共 $_totalProgress 门课程');
|
|
|
|
// Create tasks
|
|
for (int i = 0; i < pending.length; i++) {
|
|
_concurrentTasks.add(
|
|
ConcurrentTask(
|
|
taskId: i + 1,
|
|
course: pending[i],
|
|
status: TaskStatus.waiting,
|
|
),
|
|
);
|
|
}
|
|
notifyListeners();
|
|
|
|
// Start tasks with 6-second intervals
|
|
final taskFutures = <Future<EvaluationResult>>[];
|
|
final startTime = DateTime.now();
|
|
|
|
for (int i = 0; i < _concurrentTasks.length; i++) {
|
|
final task = _concurrentTasks[i];
|
|
|
|
// Wait 6 seconds before starting next task (except first one)
|
|
if (i > 0) {
|
|
_addLog('等待 6 秒后启动下一个任务... (${i + 1}/$_totalProgress)');
|
|
await Future.delayed(const Duration(seconds: 6));
|
|
}
|
|
|
|
// Start task
|
|
_addLog('启动任务 ${task.taskId}: ${task.course.name}');
|
|
taskFutures.add(_executeConcurrentTask(task));
|
|
}
|
|
|
|
// Wait for all tasks to complete
|
|
_addLog('所有任务已启动,等待完成...');
|
|
final results = await Future.wait(taskFutures);
|
|
|
|
// Calculate statistics
|
|
final successCount = results.where((r) => r.success).length;
|
|
final failedCount = results.where((r) => !r.success).length;
|
|
final duration = DateTime.now().difference(startTime);
|
|
|
|
final result = BatchEvaluationResult(
|
|
total: results.length,
|
|
success: successCount,
|
|
failed: failedCount,
|
|
results: results,
|
|
duration: duration,
|
|
);
|
|
|
|
// Save result
|
|
_lastResult = result;
|
|
_currentProgress = _totalProgress;
|
|
|
|
// Save evaluation results to history
|
|
await _saveEvaluationResults(result.results);
|
|
|
|
// Add completion log
|
|
if (result.failed > 0) {
|
|
_addLog(
|
|
'⚠️ 并发评教完成: 成功 ${result.success}/${result.total},失败 ${result.failed}',
|
|
);
|
|
} else {
|
|
_addLog('✅ 并发评教完成: 全部 ${result.total} 门课程评教成功');
|
|
}
|
|
|
|
// Show completion notification
|
|
await _notificationService.showCompletionNotification(
|
|
success: result.success,
|
|
failed: result.failed,
|
|
total: result.total,
|
|
);
|
|
|
|
// Reload courses to update evaluation status
|
|
_addLog('刷新课程列表...');
|
|
await loadCourses();
|
|
_addLog('课程列表已更新');
|
|
|
|
_setState(EvaluationState.completed);
|
|
_isConcurrentMode = false;
|
|
return result;
|
|
} catch (e) {
|
|
_errorMessage = '并发评教失败: $e';
|
|
_setState(EvaluationState.error);
|
|
_isConcurrentMode = false;
|
|
|
|
// Show error notification
|
|
await _notificationService.showErrorNotification(_errorMessage!);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// Execute a single concurrent task
|
|
Future<EvaluationResult> _executeConcurrentTask(ConcurrentTask task) async {
|
|
try {
|
|
// Update task status
|
|
_updateTaskStatus(
|
|
task.taskId,
|
|
TaskStatus.preparing,
|
|
'❤ Created By LoveACE Team, 🌧 Powered By Sibuxiangx & Flutter',
|
|
);
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 开始评教');
|
|
|
|
task.startTime = DateTime.now();
|
|
|
|
// 1. Prepare evaluation
|
|
_updateTaskStatus(task.taskId, TaskStatus.preparing, '访问评价页面');
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 访问评价页面');
|
|
|
|
final formData = await _service!.prepareEvaluation(
|
|
task.course,
|
|
totalCourses: _totalProgress,
|
|
);
|
|
|
|
if (formData == null) {
|
|
_updateTaskStatus(
|
|
task.taskId,
|
|
TaskStatus.failed,
|
|
'访问失败',
|
|
errorMessage: '无法访问评价页面',
|
|
);
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: ❌ 访问失败');
|
|
return EvaluationResult(
|
|
course: task.course,
|
|
success: false,
|
|
errorMessage: '无法访问评价页面',
|
|
);
|
|
}
|
|
|
|
_updateTaskStatus(task.taskId, TaskStatus.preparing, '解析问卷');
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 解析问卷');
|
|
|
|
_updateTaskStatus(task.taskId, TaskStatus.preparing, '生成答案');
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 生成答案');
|
|
|
|
// 2. Countdown (140 seconds) - independent for each task
|
|
_updateTaskStatus(
|
|
task.taskId,
|
|
TaskStatus.countdown,
|
|
'等待提交',
|
|
countdownTotal: 140,
|
|
);
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 开始独立等待 140 秒');
|
|
|
|
for (int countdown = 140; countdown > 0; countdown--) {
|
|
_updateTaskCountdown(task.taskId, countdown, 140);
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
}
|
|
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 等待完成');
|
|
|
|
// 3. Submit evaluation
|
|
_updateTaskStatus(task.taskId, TaskStatus.submitting, '提交评价');
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 提交评价');
|
|
|
|
final result = await _service!.submitEvaluation(task.course, formData);
|
|
|
|
if (!result.success) {
|
|
_updateTaskStatus(
|
|
task.taskId,
|
|
TaskStatus.failed,
|
|
'提交失败',
|
|
errorMessage: result.errorMessage,
|
|
);
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: ❌ 提交失败');
|
|
return result;
|
|
}
|
|
|
|
// 4. Verify evaluation
|
|
_updateTaskStatus(task.taskId, TaskStatus.verifying, '验证结果');
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: 验证结果');
|
|
|
|
final updatedCourses = await _connection!.fetchCourseList();
|
|
final updatedCourse = updatedCourses.firstWhere(
|
|
(c) => c.id == task.course.id,
|
|
orElse: () => task.course,
|
|
);
|
|
|
|
if (!updatedCourse.isEvaluated) {
|
|
_updateTaskStatus(
|
|
task.taskId,
|
|
TaskStatus.failed,
|
|
'验证失败',
|
|
errorMessage: '评教未生效,服务器未确认',
|
|
);
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: ❌ 评教未生效');
|
|
return EvaluationResult(
|
|
course: task.course,
|
|
success: false,
|
|
errorMessage: '评教未生效,服务器未确认',
|
|
);
|
|
}
|
|
|
|
// Success
|
|
_updateTaskStatus(task.taskId, TaskStatus.completed, '完成');
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: ✅ 评教完成');
|
|
_currentProgress++;
|
|
notifyListeners();
|
|
|
|
task.endTime = DateTime.now();
|
|
return EvaluationResult(course: task.course, success: true);
|
|
} catch (e) {
|
|
_updateTaskStatus(
|
|
task.taskId,
|
|
TaskStatus.failed,
|
|
'异常',
|
|
errorMessage: e.toString(),
|
|
);
|
|
_addLog('任务 ${task.taskId} [${task.course.name}]: ❌ 异常: $e');
|
|
return EvaluationResult(
|
|
course: task.course,
|
|
success: false,
|
|
errorMessage: '评教过程出错: $e',
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Update task status
|
|
void _updateTaskStatus(
|
|
int taskId,
|
|
TaskStatus status,
|
|
String? statusMessage, {
|
|
String? errorMessage,
|
|
int? countdownTotal,
|
|
}) {
|
|
final index = _concurrentTasks.indexWhere((t) => t.taskId == taskId);
|
|
if (index != -1) {
|
|
_concurrentTasks[index] = _concurrentTasks[index].copyWith(
|
|
status: status,
|
|
statusMessage: statusMessage,
|
|
errorMessage: errorMessage,
|
|
countdownTotal: countdownTotal,
|
|
);
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
/// Update task countdown
|
|
void _updateTaskCountdown(int taskId, int remaining, int total) {
|
|
final index = _concurrentTasks.indexWhere((t) => t.taskId == taskId);
|
|
if (index != -1) {
|
|
_concurrentTasks[index] = _concurrentTasks[index].copyWith(
|
|
countdownRemaining: remaining,
|
|
countdownTotal: total,
|
|
);
|
|
notifyListeners();
|
|
}
|
|
}
|
|
}
|