Files
xianyan/lib/features/task/task_core.dart
Developer 83720002e6 feat: 新增工作台模式、系统托盘,修复多平台兼容性问题
1. 新增工作台三栏布局模式,适配宽屏设备
2. 添加跨平台系统托盘支持,新增托盘图标资源
3. 修复工作台模式下导航返回异常问题
4. 统一JSON类型安全解析,替换硬类型转换
5. 增加macOS深度链接支持,统一渠道分发信息
6. 优化部分页面生命周期和状态加载逻辑
7. 移除废弃的nearby_connections依赖
2026-06-19 06:43:55 +08:00

262 lines
7.5 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// @name 每日任务核心模块
/// @date 2026-06-12
/// @desc 合并自 task_service.dart + task_provider.dart包含API服务与状态管理
/// @update 2026-06-19 类型安全修复(int vs num): DailyTask/TaskSummary.fromJson 使用 SafeJson.parseInt
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:xianyan/core/utils/safe_json.dart';
import '../../core/network/api_client.dart';
// ============================================================
// API 服务层
// ============================================================
/// 每日任务API服务提供者
final taskServiceProvider = Provider<TaskService>((ref) => TaskService());
/// 每日任务API服务
class TaskService {
static final ApiClient _api = ApiClient.instance;
/// 获取今日任务列表
Future<Map<String, dynamic>> getTodayTasks() async {
final response = await _api.get<Map<String, dynamic>>('/api/task/today');
return response.data!;
}
/// 上报任务进度
Future<Map<String, dynamic>> reportProgress(int taskId, {int increment = 1}) async {
final response = await _api.post<Map<String, dynamic>>('/api/task/reportProgress', data: {
'task_id': taskId,
'increment': increment,
});
return response.data!;
}
/// 领取任务奖励
Future<Map<String, dynamic>> claimReward(int taskId) async {
final response = await _api.post<Map<String, dynamic>>('/api/task/claim', data: {
'task_id': taskId,
});
return response.data!;
}
/// 领取完美日奖励
Future<Map<String, dynamic>> claimPerfectDay() async {
final response = await _api.post<Map<String, dynamic>>('/api/task/claimPerfect', data: <String, dynamic>{});
return response.data!;
}
/// 注册自定义任务
Future<Map<String, dynamic>> registerCustomTask({
required String name,
String icon = '🎯',
String? customUrl,
String? customPage,
int target = 1,
int expReward = 5,
int scoreReward = 2,
}) async {
final data = <String, dynamic>{
'name': name,
'icon': icon,
'target': target,
'exp_reward': expReward,
'score_reward': scoreReward,
};
if (customUrl != null) data['custom_url'] = customUrl;
if (customPage != null) data['custom_page'] = customPage;
final response = await _api.post<Map<String, dynamic>>('/api/task/registerCustom', data: data);
return response.data!;
}
}
// ============================================================
// 数据模型层
// ============================================================
/// 每日任务数据模型
class DailyTask {
final int id;
final String name;
final String icon;
final String type;
final int target;
final String action;
final String customUrl;
final String customPage;
final int expReward;
final int scoreReward;
final int isRandom;
int progress;
bool completed;
bool claimed;
int percent;
DailyTask({
required this.id,
required this.name,
required this.icon,
required this.type,
required this.target,
required this.action,
required this.customUrl,
required this.customPage,
required this.expReward,
required this.scoreReward,
required this.isRandom,
required this.progress,
required this.completed,
required this.claimed,
required this.percent,
});
factory DailyTask.fromJson(Map<String, dynamic> json) {
return DailyTask(
id: SafeJson.parseInt(json['id']),
name: (json['name'] ?? '') as String,
icon: (json['icon'] ?? '📋') as String,
type: (json['type'] ?? '') as String,
target: SafeJson.parseInt(json['target'], 1),
action: (json['action'] ?? '') as String,
customUrl: (json['custom_url'] ?? '') as String,
customPage: (json['custom_page'] ?? '') as String,
expReward: SafeJson.parseInt(json['exp_reward']),
scoreReward: SafeJson.parseInt(json['score_reward']),
isRandom: SafeJson.parseInt(json['is_random']),
progress: SafeJson.parseInt(json['progress']),
completed: json['completed'] == 1 || json['completed'] == true,
claimed: json['claimed'] == 1 || json['claimed'] == true,
percent: SafeJson.parseInt(json['percent']),
);
}
}
/// 任务汇总数据模型
class TaskSummary {
final int total;
final int completed;
final int claimed;
final bool isPerfectDay;
final bool perfectClaimed;
final String date;
TaskSummary({
required this.total,
required this.completed,
required this.claimed,
required this.isPerfectDay,
required this.perfectClaimed,
required this.date,
});
factory TaskSummary.fromJson(Map<String, dynamic> json) {
return TaskSummary(
total: SafeJson.parseInt(json['total']),
completed: SafeJson.parseInt(json['completed']),
claimed: SafeJson.parseInt(json['claimed']),
isPerfectDay:
json['is_perfect_day'] == true || json['is_perfect_day'] == 1,
perfectClaimed:
json['perfect_claimed'] == true || json['perfect_claimed'] == 1,
date: (json['date'] ?? '') as String,
);
}
}
// ============================================================
// 状态管理层
// ============================================================
/// 任务状态
class TaskState {
final List<DailyTask> tasks;
final TaskSummary? summary;
final bool isLoading;
final String? error;
const TaskState({
this.tasks = const [],
this.summary,
this.isLoading = false,
this.error,
});
TaskState copyWith({
List<DailyTask>? tasks,
TaskSummary? summary,
bool? isLoading,
String? error,
}) {
return TaskState(
tasks: tasks ?? this.tasks,
summary: summary ?? this.summary,
isLoading: isLoading ?? this.isLoading,
error: error,
);
}
}
/// 任务状态管理器
class TaskNotifier extends Notifier<TaskState> {
@override
TaskState build() => const TaskState();
TaskService get _taskService => ref.read(taskServiceProvider);
/// 加载今日任务
Future<void> loadTodayTasks() async {
state = state.copyWith(isLoading: true);
try {
final response = await _taskService.getTodayTasks();
final data = (response['data'] ?? response) as Map<String, dynamic>;
final List<dynamic> taskList = data['tasks'] as List<dynamic>? ?? [];
final tasks = taskList
.map((e) => DailyTask.fromJson(e as Map<String, dynamic>))
.toList();
final summary = TaskSummary.fromJson(data);
state = state.copyWith(tasks: tasks, summary: summary, isLoading: false);
} catch (e) {
state = state.copyWith(isLoading: false, error: e.toString());
}
}
/// 上报任务进度
Future<bool> reportProgress(int taskId, {int increment = 1}) async {
try {
await _taskService.reportProgress(taskId, increment: increment);
await loadTodayTasks();
return true;
} catch (e) {
return false;
}
}
/// 领取任务奖励
Future<Map<String, dynamic>?> claimReward(int taskId) async {
try {
final response = await _taskService.claimReward(taskId);
await loadTodayTasks();
return (response['data'] ?? response) as Map<String, dynamic>?;
} catch (e) {
return null;
}
}
/// 领取完美日奖励
Future<Map<String, dynamic>?> claimPerfectDay() async {
try {
final response = await _taskService.claimPerfectDay();
await loadTodayTasks();
return (response['data'] ?? response) as Map<String, dynamic>?;
} catch (e) {
return null;
}
}
}
/// 任务状态提供者
final taskProvider = NotifierProvider<TaskNotifier, TaskState>(
TaskNotifier.new,
);