😋 初始化仓库
This commit is contained in:
2
lib/models/.gitkeep
Normal file
2
lib/models/.gitkeep
Normal file
@@ -0,0 +1,2 @@
|
||||
# Models directory
|
||||
# This directory contains data models for the application
|
||||
111
lib/models/concurrent_task.dart
Normal file
111
lib/models/concurrent_task.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'course.dart';
|
||||
|
||||
/// Concurrent evaluation task status
|
||||
enum TaskStatus {
|
||||
waiting, // 等待开始
|
||||
preparing, // 准备评教(访问页面、解析问卷)
|
||||
countdown, // 倒计时等待
|
||||
submitting, // 提交中
|
||||
verifying, // 验证中
|
||||
completed, // 完成
|
||||
failed, // 失败
|
||||
}
|
||||
|
||||
/// Concurrent evaluation task
|
||||
class ConcurrentTask {
|
||||
final int taskId;
|
||||
final Course course;
|
||||
TaskStatus status;
|
||||
String? statusMessage;
|
||||
int countdownRemaining;
|
||||
int countdownTotal;
|
||||
String? errorMessage;
|
||||
DateTime? startTime;
|
||||
DateTime? endTime;
|
||||
|
||||
ConcurrentTask({
|
||||
required this.taskId,
|
||||
required this.course,
|
||||
this.status = TaskStatus.waiting,
|
||||
this.statusMessage,
|
||||
this.countdownRemaining = 0,
|
||||
this.countdownTotal = 0,
|
||||
this.errorMessage,
|
||||
this.startTime,
|
||||
this.endTime,
|
||||
});
|
||||
|
||||
/// Get progress (0.0 to 1.0)
|
||||
double get progress {
|
||||
switch (status) {
|
||||
case TaskStatus.waiting:
|
||||
return 0.0;
|
||||
case TaskStatus.preparing:
|
||||
return 0.1;
|
||||
case TaskStatus.countdown:
|
||||
if (countdownTotal > 0) {
|
||||
return 0.1 +
|
||||
0.7 * (countdownTotal - countdownRemaining) / countdownTotal;
|
||||
}
|
||||
return 0.1;
|
||||
case TaskStatus.submitting:
|
||||
return 0.85;
|
||||
case TaskStatus.verifying:
|
||||
return 0.95;
|
||||
case TaskStatus.completed:
|
||||
case TaskStatus.failed:
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get status display text
|
||||
String get statusText {
|
||||
if (statusMessage != null) return statusMessage!;
|
||||
|
||||
switch (status) {
|
||||
case TaskStatus.waiting:
|
||||
return '等待开始';
|
||||
case TaskStatus.preparing:
|
||||
return '准备评教';
|
||||
case TaskStatus.countdown:
|
||||
return '等待提交 (${countdownRemaining}s)';
|
||||
case TaskStatus.submitting:
|
||||
return '提交中';
|
||||
case TaskStatus.verifying:
|
||||
return '验证中';
|
||||
case TaskStatus.completed:
|
||||
return '完成';
|
||||
case TaskStatus.failed:
|
||||
return '失败';
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if task is finished
|
||||
bool get isFinished =>
|
||||
status == TaskStatus.completed || status == TaskStatus.failed;
|
||||
|
||||
/// Check if task is successful
|
||||
bool get isSuccess => status == TaskStatus.completed;
|
||||
|
||||
ConcurrentTask copyWith({
|
||||
TaskStatus? status,
|
||||
String? statusMessage,
|
||||
int? countdownRemaining,
|
||||
int? countdownTotal,
|
||||
String? errorMessage,
|
||||
DateTime? startTime,
|
||||
DateTime? endTime,
|
||||
}) {
|
||||
return ConcurrentTask(
|
||||
taskId: taskId,
|
||||
course: course,
|
||||
status: status ?? this.status,
|
||||
statusMessage: statusMessage ?? this.statusMessage,
|
||||
countdownRemaining: countdownRemaining ?? this.countdownRemaining,
|
||||
countdownTotal: countdownTotal ?? this.countdownTotal,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
startTime: startTime ?? this.startTime,
|
||||
endTime: endTime ?? this.endTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
101
lib/models/course.dart
Normal file
101
lib/models/course.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
/// Course data model representing a course that needs evaluation
|
||||
class Course {
|
||||
final String id;
|
||||
final String name;
|
||||
final String teacher;
|
||||
final String evaluatedPeople;
|
||||
final String evaluatedPeopleNumber;
|
||||
final String coureSequenceNumber;
|
||||
final String evaluationContentNumber;
|
||||
final String questionnaireCode;
|
||||
final String questionnaireName;
|
||||
final bool isEvaluated;
|
||||
|
||||
Course({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.teacher,
|
||||
required this.evaluatedPeople,
|
||||
required this.evaluatedPeopleNumber,
|
||||
required this.coureSequenceNumber,
|
||||
required this.evaluationContentNumber,
|
||||
required this.questionnaireCode,
|
||||
required this.questionnaireName,
|
||||
this.isEvaluated = false,
|
||||
});
|
||||
|
||||
/// Create Course from JSON
|
||||
factory Course.fromJson(Map<String, dynamic> json) {
|
||||
return Course(
|
||||
id: json['id'] as String? ?? '',
|
||||
name: json['name'] as String? ?? '',
|
||||
teacher: json['teacher'] as String? ?? '',
|
||||
evaluatedPeople: json['evaluatedPeople'] as String? ?? '',
|
||||
evaluatedPeopleNumber: json['evaluatedPeopleNumber'] as String? ?? '',
|
||||
coureSequenceNumber: json['coureSequenceNumber'] as String? ?? '',
|
||||
evaluationContentNumber: json['evaluationContentNumber'] as String? ?? '',
|
||||
questionnaireCode: json['questionnaireCode'] as String? ?? '',
|
||||
questionnaireName: json['questionnaireName'] as String? ?? '',
|
||||
isEvaluated: json['isEvaluated'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert Course to JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'teacher': teacher,
|
||||
'evaluatedPeople': evaluatedPeople,
|
||||
'evaluatedPeopleNumber': evaluatedPeopleNumber,
|
||||
'coureSequenceNumber': coureSequenceNumber,
|
||||
'evaluationContentNumber': evaluationContentNumber,
|
||||
'questionnaireCode': questionnaireCode,
|
||||
'questionnaireName': questionnaireName,
|
||||
'isEvaluated': isEvaluated,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a copy of Course with updated fields
|
||||
Course copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
String? teacher,
|
||||
String? evaluatedPeople,
|
||||
String? evaluatedPeopleNumber,
|
||||
String? coureSequenceNumber,
|
||||
String? evaluationContentNumber,
|
||||
String? questionnaireCode,
|
||||
String? questionnaireName,
|
||||
bool? isEvaluated,
|
||||
}) {
|
||||
return Course(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
teacher: teacher ?? this.teacher,
|
||||
evaluatedPeople: evaluatedPeople ?? this.evaluatedPeople,
|
||||
evaluatedPeopleNumber:
|
||||
evaluatedPeopleNumber ?? this.evaluatedPeopleNumber,
|
||||
coureSequenceNumber: coureSequenceNumber ?? this.coureSequenceNumber,
|
||||
evaluationContentNumber:
|
||||
evaluationContentNumber ?? this.evaluationContentNumber,
|
||||
questionnaireCode: questionnaireCode ?? this.questionnaireCode,
|
||||
questionnaireName: questionnaireName ?? this.questionnaireName,
|
||||
isEvaluated: isEvaluated ?? this.isEvaluated,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Course(id: $id, name: $name, teacher: $teacher, isEvaluated: $isEvaluated)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is Course && other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
}
|
||||
54
lib/models/evaluation_history.dart
Normal file
54
lib/models/evaluation_history.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'course.dart';
|
||||
|
||||
/// Evaluation history record
|
||||
class EvaluationHistory {
|
||||
final String id;
|
||||
final Course course;
|
||||
final DateTime timestamp;
|
||||
final bool success;
|
||||
final String? errorMessage;
|
||||
|
||||
EvaluationHistory({
|
||||
required this.id,
|
||||
required this.course,
|
||||
required this.timestamp,
|
||||
required this.success,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
factory EvaluationHistory.fromJson(Map<String, dynamic> json) {
|
||||
return EvaluationHistory(
|
||||
id: json['id'] as String? ?? '',
|
||||
course: Course.fromJson(json['course'] as Map<String, dynamic>),
|
||||
timestamp: json['timestamp'] != null
|
||||
? DateTime.parse(json['timestamp'] as String)
|
||||
: DateTime.now(),
|
||||
success: json['success'] as bool? ?? false,
|
||||
errorMessage: json['errorMessage'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'course': course.toJson(),
|
||||
'timestamp': timestamp.toIso8601String(),
|
||||
'success': success,
|
||||
'errorMessage': errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'EvaluationHistory(id: $id, course: ${course.name}, success: $success, timestamp: $timestamp)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is EvaluationHistory && other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
}
|
||||
89
lib/models/evaluation_result.dart
Normal file
89
lib/models/evaluation_result.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'course.dart';
|
||||
|
||||
/// Result of a single course evaluation
|
||||
class EvaluationResult {
|
||||
final Course course;
|
||||
final bool success;
|
||||
final String? errorMessage;
|
||||
final DateTime timestamp;
|
||||
|
||||
EvaluationResult({
|
||||
required this.course,
|
||||
required this.success,
|
||||
this.errorMessage,
|
||||
DateTime? timestamp,
|
||||
}) : timestamp = timestamp ?? DateTime.now();
|
||||
|
||||
factory EvaluationResult.fromJson(Map<String, dynamic> json) {
|
||||
return EvaluationResult(
|
||||
course: Course.fromJson(json['course'] as Map<String, dynamic>),
|
||||
success: json['success'] as bool? ?? false,
|
||||
errorMessage: json['errorMessage'] as String?,
|
||||
timestamp: json['timestamp'] != null
|
||||
? DateTime.parse(json['timestamp'] as String)
|
||||
: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'course': course.toJson(),
|
||||
'success': success,
|
||||
'errorMessage': errorMessage,
|
||||
'timestamp': timestamp.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'EvaluationResult(course: ${course.name}, success: $success, errorMessage: $errorMessage)';
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of batch evaluation
|
||||
class BatchEvaluationResult {
|
||||
final int total;
|
||||
final int success;
|
||||
final int failed;
|
||||
final List<EvaluationResult> results;
|
||||
final Duration duration;
|
||||
|
||||
BatchEvaluationResult({
|
||||
required this.total,
|
||||
required this.success,
|
||||
required this.failed,
|
||||
required this.results,
|
||||
required this.duration,
|
||||
});
|
||||
|
||||
factory BatchEvaluationResult.fromJson(Map<String, dynamic> json) {
|
||||
return BatchEvaluationResult(
|
||||
total: json['total'] as int? ?? 0,
|
||||
success: json['success'] as int? ?? 0,
|
||||
failed: json['failed'] as int? ?? 0,
|
||||
results:
|
||||
(json['results'] as List<dynamic>?)
|
||||
?.map((e) => EvaluationResult.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
duration: Duration(milliseconds: json['durationMs'] as int? ?? 0),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'total': total,
|
||||
'success': success,
|
||||
'failed': failed,
|
||||
'results': results.map((e) => e.toJson()).toList(),
|
||||
'durationMs': duration.inMilliseconds,
|
||||
};
|
||||
}
|
||||
|
||||
double get successRate => total > 0 ? success / total : 0.0;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'BatchEvaluationResult(total: $total, success: $success, failed: $failed, duration: ${duration.inSeconds}s)';
|
||||
}
|
||||
}
|
||||
85
lib/models/login_status.dart
Normal file
85
lib/models/login_status.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
/// EC登录状态
|
||||
class ECLoginStatus {
|
||||
final bool success;
|
||||
final bool failNotFoundTwfid;
|
||||
final bool failNotFoundRsaKey;
|
||||
final bool failNotFoundRsaExp;
|
||||
final bool failNotFoundCsrfCode;
|
||||
final bool failInvalidCredentials;
|
||||
final bool failMaybeAttacked;
|
||||
final bool failNetworkError;
|
||||
final bool failUnknownError;
|
||||
|
||||
ECLoginStatus({
|
||||
this.success = false,
|
||||
this.failNotFoundTwfid = false,
|
||||
this.failNotFoundRsaKey = false,
|
||||
this.failNotFoundRsaExp = false,
|
||||
this.failNotFoundCsrfCode = false,
|
||||
this.failInvalidCredentials = false,
|
||||
this.failMaybeAttacked = false,
|
||||
this.failNetworkError = false,
|
||||
this.failUnknownError = false,
|
||||
});
|
||||
|
||||
bool get isSuccess => success;
|
||||
bool get isFailed => !success;
|
||||
|
||||
String get errorMessage {
|
||||
if (failNotFoundTwfid) return '未找到TwfID';
|
||||
if (failNotFoundRsaKey) return '未找到RSA密钥';
|
||||
if (failNotFoundRsaExp) return '未找到RSA指数';
|
||||
if (failNotFoundCsrfCode) return '未找到CSRF代码';
|
||||
if (failInvalidCredentials) return '用户名或密码错误';
|
||||
if (failMaybeAttacked) return '可能受到攻击或需要验证码';
|
||||
if (failNetworkError) return '网络连接错误';
|
||||
if (failUnknownError) return '未知错误';
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// UAAP登录状态
|
||||
class UAAPLoginStatus {
|
||||
final bool success;
|
||||
final bool failNotFoundLt;
|
||||
final bool failNotFoundExecution;
|
||||
final bool failInvalidCredentials;
|
||||
final bool failNetworkError;
|
||||
final bool failUnknownError;
|
||||
|
||||
UAAPLoginStatus({
|
||||
this.success = false,
|
||||
this.failNotFoundLt = false,
|
||||
this.failNotFoundExecution = false,
|
||||
this.failInvalidCredentials = false,
|
||||
this.failNetworkError = false,
|
||||
this.failUnknownError = false,
|
||||
});
|
||||
|
||||
bool get isSuccess => success;
|
||||
bool get isFailed => !success;
|
||||
|
||||
String get errorMessage {
|
||||
if (failNotFoundLt) return '未找到lt参数';
|
||||
if (failNotFoundExecution) return '未找到execution参数';
|
||||
if (failInvalidCredentials) return '用户名或密码错误';
|
||||
if (failNetworkError) return '网络连接错误';
|
||||
if (failUnknownError) return '未知错误';
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// EC检查状态
|
||||
class ECCheckStatus {
|
||||
final bool loggedIn;
|
||||
final bool failNetworkError;
|
||||
final bool failUnknownError;
|
||||
|
||||
ECCheckStatus({
|
||||
this.loggedIn = false,
|
||||
this.failNetworkError = false,
|
||||
this.failUnknownError = false,
|
||||
});
|
||||
|
||||
bool get isLoggedIn => loggedIn;
|
||||
}
|
||||
6
lib/models/models.dart
Normal file
6
lib/models/models.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
/// Export all data models
|
||||
export 'course.dart';
|
||||
export 'questionnaire.dart';
|
||||
export 'user_credentials.dart';
|
||||
export 'evaluation_result.dart';
|
||||
export 'evaluation_history.dart';
|
||||
224
lib/models/questionnaire.dart
Normal file
224
lib/models/questionnaire.dart
Normal file
@@ -0,0 +1,224 @@
|
||||
/// Question type enum for text questions
|
||||
enum QuestionType {
|
||||
inspiration, // 启发类(包含"启发"关键词)
|
||||
suggestion, // 建议类(包含"建议"、"意见"关键词)
|
||||
overall, // 总体评价(zgpj)
|
||||
general, // 通用类型
|
||||
}
|
||||
|
||||
/// Metadata for questionnaire
|
||||
class QuestionnaireMetadata {
|
||||
final String title;
|
||||
final String evaluatedPerson;
|
||||
final String evaluationContent;
|
||||
final String tokenValue;
|
||||
final String questionnaireCode;
|
||||
final String evaluatedPeopleNumber;
|
||||
|
||||
QuestionnaireMetadata({
|
||||
required this.title,
|
||||
required this.evaluatedPerson,
|
||||
required this.evaluationContent,
|
||||
required this.tokenValue,
|
||||
required this.questionnaireCode,
|
||||
required this.evaluatedPeopleNumber,
|
||||
});
|
||||
|
||||
factory QuestionnaireMetadata.fromJson(Map<String, dynamic> json) {
|
||||
return QuestionnaireMetadata(
|
||||
title: json['title'] as String? ?? '',
|
||||
evaluatedPerson: json['evaluatedPerson'] as String? ?? '',
|
||||
evaluationContent: json['evaluationContent'] as String? ?? '',
|
||||
tokenValue: json['tokenValue'] as String? ?? '',
|
||||
questionnaireCode: json['questionnaireCode'] as String? ?? '',
|
||||
evaluatedPeopleNumber: json['evaluatedPeopleNumber'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'title': title,
|
||||
'evaluatedPerson': evaluatedPerson,
|
||||
'evaluationContent': evaluationContent,
|
||||
'tokenValue': tokenValue,
|
||||
'questionnaireCode': questionnaireCode,
|
||||
'evaluatedPeopleNumber': evaluatedPeopleNumber,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Radio option for single-choice questions
|
||||
class RadioOption {
|
||||
final String label; // 如"(A) 非常满意"
|
||||
final String value; // 如"5_1"(5分×100%)
|
||||
final double score; // 解析后的分数
|
||||
final double weight; // 解析后的权重
|
||||
|
||||
RadioOption({
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.score,
|
||||
required this.weight,
|
||||
});
|
||||
|
||||
factory RadioOption.fromJson(Map<String, dynamic> json) {
|
||||
return RadioOption(
|
||||
label: json['label'] as String? ?? '',
|
||||
value: json['value'] as String? ?? '',
|
||||
score: (json['score'] as num?)?.toDouble() ?? 0.0,
|
||||
weight: (json['weight'] as num?)?.toDouble() ?? 0.0,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'label': label, 'value': value, 'score': score, 'weight': weight};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RadioOption(label: $label, value: $value, score: $score, weight: $weight)';
|
||||
}
|
||||
}
|
||||
|
||||
/// Radio question (single-choice question)
|
||||
class RadioQuestion {
|
||||
final String key; // 动态key,如"0000000401"
|
||||
final String questionText; // 题目文本
|
||||
final List<RadioOption> options;
|
||||
final String category; // 如"师德师风"、"教学内容"
|
||||
|
||||
RadioQuestion({
|
||||
required this.key,
|
||||
required this.questionText,
|
||||
required this.options,
|
||||
this.category = '',
|
||||
});
|
||||
|
||||
factory RadioQuestion.fromJson(Map<String, dynamic> json) {
|
||||
return RadioQuestion(
|
||||
key: json['key'] as String? ?? '',
|
||||
questionText: json['questionText'] as String? ?? '',
|
||||
options:
|
||||
(json['options'] as List<dynamic>?)
|
||||
?.map((e) => RadioOption.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
category: json['category'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'key': key,
|
||||
'questionText': questionText,
|
||||
'options': options.map((e) => e.toJson()).toList(),
|
||||
'category': category,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RadioQuestion(key: $key, questionText: $questionText, category: $category, options: ${options.length})';
|
||||
}
|
||||
}
|
||||
|
||||
/// Text question (open-ended question)
|
||||
class TextQuestion {
|
||||
final String key; // 动态key或"zgpj"
|
||||
final String questionText; // 题目文本
|
||||
final QuestionType type; // 通过关键词识别的类型
|
||||
final bool isRequired; // 是否必填
|
||||
|
||||
TextQuestion({
|
||||
required this.key,
|
||||
required this.questionText,
|
||||
required this.type,
|
||||
this.isRequired = false,
|
||||
});
|
||||
|
||||
factory TextQuestion.fromJson(Map<String, dynamic> json) {
|
||||
return TextQuestion(
|
||||
key: json['key'] as String? ?? '',
|
||||
questionText: json['questionText'] as String? ?? '',
|
||||
type: QuestionType.values.firstWhere(
|
||||
(e) => e.toString() == 'QuestionType.${json['type']}',
|
||||
orElse: () => QuestionType.general,
|
||||
),
|
||||
isRequired: json['isRequired'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'key': key,
|
||||
'questionText': questionText,
|
||||
'type': type.toString().split('.').last,
|
||||
'isRequired': isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TextQuestion(key: $key, questionText: $questionText, type: $type, isRequired: $isRequired)';
|
||||
}
|
||||
}
|
||||
|
||||
/// Complete questionnaire structure
|
||||
class Questionnaire {
|
||||
final QuestionnaireMetadata metadata;
|
||||
final List<RadioQuestion> radioQuestions;
|
||||
final List<TextQuestion> textQuestions;
|
||||
final String tokenValue;
|
||||
final String questionnaireCode;
|
||||
final String evaluationContent;
|
||||
final String evaluatedPeopleNumber;
|
||||
|
||||
Questionnaire({
|
||||
required this.metadata,
|
||||
required this.radioQuestions,
|
||||
required this.textQuestions,
|
||||
required this.tokenValue,
|
||||
required this.questionnaireCode,
|
||||
required this.evaluationContent,
|
||||
required this.evaluatedPeopleNumber,
|
||||
});
|
||||
|
||||
factory Questionnaire.fromJson(Map<String, dynamic> json) {
|
||||
return Questionnaire(
|
||||
metadata: QuestionnaireMetadata.fromJson(
|
||||
json['metadata'] as Map<String, dynamic>? ?? {},
|
||||
),
|
||||
radioQuestions:
|
||||
(json['radioQuestions'] as List<dynamic>?)
|
||||
?.map((e) => RadioQuestion.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
textQuestions:
|
||||
(json['textQuestions'] as List<dynamic>?)
|
||||
?.map((e) => TextQuestion.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
tokenValue: json['tokenValue'] as String? ?? '',
|
||||
questionnaireCode: json['questionnaireCode'] as String? ?? '',
|
||||
evaluationContent: json['evaluationContent'] as String? ?? '',
|
||||
evaluatedPeopleNumber: json['evaluatedPeopleNumber'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'metadata': metadata.toJson(),
|
||||
'radioQuestions': radioQuestions.map((e) => e.toJson()).toList(),
|
||||
'textQuestions': textQuestions.map((e) => e.toJson()).toList(),
|
||||
'tokenValue': tokenValue,
|
||||
'questionnaireCode': questionnaireCode,
|
||||
'evaluationContent': evaluationContent,
|
||||
'evaluatedPeopleNumber': evaluatedPeopleNumber,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Questionnaire(radioQuestions: ${radioQuestions.length}, textQuestions: ${textQuestions.length})';
|
||||
}
|
||||
}
|
||||
78
lib/models/user_credentials.dart
Normal file
78
lib/models/user_credentials.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
/// User credentials for authentication
|
||||
class UserCredentials {
|
||||
final String userId;
|
||||
final String ecPassword;
|
||||
final String password;
|
||||
|
||||
UserCredentials({
|
||||
required this.userId,
|
||||
required this.ecPassword,
|
||||
required this.password,
|
||||
});
|
||||
|
||||
factory UserCredentials.fromJson(Map<String, dynamic> json) {
|
||||
return UserCredentials(
|
||||
userId: json['userId'] as String? ?? '',
|
||||
ecPassword: json['ecPassword'] as String? ?? '',
|
||||
password: json['password'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'userId': userId, 'ecPassword': ecPassword, 'password': password};
|
||||
}
|
||||
|
||||
/// Save credentials securely using flutter_secure_storage
|
||||
Future<void> saveSecurely() async {
|
||||
const storage = FlutterSecureStorage();
|
||||
await storage.write(key: 'user_id', value: userId);
|
||||
await storage.write(key: 'ec_password', value: ecPassword);
|
||||
await storage.write(key: 'password', value: password);
|
||||
}
|
||||
|
||||
/// Load credentials from secure storage
|
||||
static Future<UserCredentials?> loadSecurely() async {
|
||||
const storage = FlutterSecureStorage();
|
||||
|
||||
final userId = await storage.read(key: 'user_id');
|
||||
final ecPassword = await storage.read(key: 'ec_password');
|
||||
final password = await storage.read(key: 'password');
|
||||
|
||||
if (userId == null || ecPassword == null || password == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return UserCredentials(
|
||||
userId: userId,
|
||||
ecPassword: ecPassword,
|
||||
password: password,
|
||||
);
|
||||
}
|
||||
|
||||
/// Clear credentials from secure storage
|
||||
static Future<void> clearSecurely() async {
|
||||
const storage = FlutterSecureStorage();
|
||||
await storage.delete(key: 'user_id');
|
||||
await storage.delete(key: 'ec_password');
|
||||
await storage.delete(key: 'password');
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserCredentials(userId: $userId)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is UserCredentials &&
|
||||
other.userId == userId &&
|
||||
other.ecPassword == ecPassword &&
|
||||
other.password == password;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(userId, ecPassword, password);
|
||||
}
|
||||
Reference in New Issue
Block a user