diff --git a/lib/base/base_state_widget.dart b/lib/base/base_state_widget.dart index 519edc2..5dbd81f 100644 --- a/lib/base/base_state_widget.dart +++ b/lib/base/base_state_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:qinglong_app/base/common_dialog.dart'; import 'base_viewmodel.dart'; class BaseStateWidget extends ConsumerStatefulWidget { @@ -36,6 +37,12 @@ class _BaseStateWidgetState extends ConsumerState(widget.model); + if (viewModel.failReason != null) { + WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { + failDialog(context, viewModel.failReason!); + viewModel.clearToast(); + }); + } if (viewModel.currentState == PageState.CONTENT) { return widget.builder(ref, viewModel, widget.child); } @@ -50,7 +57,7 @@ class _BaseStateWidgetState extends ConsumerState> addTask(String name, String command, String cron, {String? id}) async { - return await Http.put(Url.ADD_TASK, {"name": name, "command": command, "schedule": cron, "_id": id}); + var data = {"name": name, "command": command, "schedule": cron}; + + if (id != null) { + data["_id"] = id; + return await Http.put(Url.ADD_TASK, data); + } + return await Http.post(Url.ADD_TASK, data); + } + + static Future> delTask(String cron) async { + return await Http.delete(Url.ADD_TASK, [cron]); } } diff --git a/lib/base/http/http.dart b/lib/base/http/http.dart index baf1be9..1f5488f 100644 --- a/lib/base/http/http.dart +++ b/lib/base/http/http.dart @@ -36,31 +36,46 @@ class Http { } static Future> get(String uri, Map? json, {bool compute = true}) async { - _init(); - var response = await _dio!.get(uri, queryParameters: json); + try { + _init(); + var response = await _dio!.get(uri, queryParameters: json); - return decodeResponse(response, compute); + return decodeResponse(response, compute); + } on DioError catch (e) { + return HttpResponse(success: false, message: e.message, code: 0); + } } static Future> post(String uri, dynamic json, {bool compute = true}) async { - _init(); - var response = await _dio!.post(uri, data: json); + try { + _init(); + var response = await _dio!.post(uri, data: json); - return decodeResponse(response, compute); + return decodeResponse(response, compute); + } on DioError catch (e) { + return HttpResponse(success: false, message: e.message, code: 0); + } } static Future> delete(String uri, dynamic json, {bool compute = true}) async { - _init(); - var response = await _dio!.delete(uri, data: json); + try { + _init(); + var response = await _dio!.delete(uri, data: json); - return decodeResponse(response, compute); + return decodeResponse(response, compute); + } on DioError catch (e) { + return HttpResponse(success: false, message: e.message, code: 0); + } } static Future> put(String uri, dynamic json, {bool compute = true}) async { - _init(); - var response = await _dio!.put(uri, data: json); - - return decodeResponse(response, compute); + try { + _init(); + var response = await _dio!.put(uri, data: json); + return decodeResponse(response, compute); + } on DioError catch (e) { + return HttpResponse(success: false, message: e.message, code: 0); + } } static HttpResponse decodeResponse( @@ -173,4 +188,4 @@ void decode() async { compute(DeserializeAction.invokeJson, DeserializeAction({})); } -class NullResponse{} \ No newline at end of file +class NullResponse {} diff --git a/lib/base/http/token_interceptor.dart b/lib/base/http/token_interceptor.dart index f384c98..9fa3922 100644 --- a/lib/base/http/token_interceptor.dart +++ b/lib/base/http/token_interceptor.dart @@ -7,7 +7,7 @@ class TokenInterceptor extends Interceptor { if (userInfoViewModel.token != null) { options.headers["Authorization"] = "Bearer " + userInfoViewModel.token!; } - options.queryParameters["t"] = DateTime.now().millisecondsSinceEpoch; + options.queryParameters["t"] = (DateTime.now().millisecondsSinceEpoch~/1000).toString(); return handler.next(options); } } diff --git a/lib/base/routes.dart b/lib/base/routes.dart index c00a993..60f8c3e 100644 --- a/lib/base/routes.dart +++ b/lib/base/routes.dart @@ -18,6 +18,8 @@ class Routes { builder: (context) => AddTaskPage( taskBean: settings.arguments as TaskBean, )); + } else { + return CupertinoPageRoute(builder: (context) => AddTaskPage()); } } diff --git a/lib/module/home/home_page.dart b/lib/module/home/home_page.dart index aa9fcc7..5462210 100644 --- a/lib/module/home/home_page.dart +++ b/lib/module/home/home_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:qinglong_app/base/ql_app_bar.dart'; +import 'package:qinglong_app/base/routes.dart'; import 'package:qinglong_app/base/theme.dart'; import 'package:qinglong_app/module/config/config_page.dart'; import 'package:qinglong_app/module/env/env_page.dart'; @@ -30,20 +31,44 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { + List actions = []; + + if (_index == 0) { + actions.add(InkWell( + onTap: () { + Navigator.of(context).pushNamed( + Routes.route_AddTask, + ); + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 15, + ), + child: Center( + child: Icon( + CupertinoIcons.add, + size: 20, + ), + ), + ), + )); + } + + actions.add( + Consumer(builder: (context, ref, child) { + return InkWell( + onTap: () { + ref.read(themeProvider).changeTheme(); + }, + child: const Center(child: Text("改变主题")), + ); + }), + ); return Scaffold( appBar: QlAppBar( canBack: false, title: _title, - actions: [ - Consumer(builder: (context, ref, child) { - return InkWell( - onTap: () { - ref.read(themeProvider).changeTheme(); - }, - child: const Center(child: Text("改变主题")), - ); - }), - ], + actions: actions, ), body: IndexedStack( index: _index, diff --git a/lib/module/task/add_task_page.dart b/lib/module/task/add_task_page.dart index 3eb1273..d255f40 100644 --- a/lib/module/task/add_task_page.dart +++ b/lib/module/task/add_task_page.dart @@ -79,7 +79,7 @@ class _AddTaskPageState extends State { height: 10, ), const Text( - "任务名称:", + "名称:", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, @@ -92,7 +92,7 @@ class _AddTaskPageState extends State { controller: _nameController, decoration: const InputDecoration( contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), - hintText: "请输入任务名称", + hintText: "请输入名称", ), autofocus: false, ), diff --git a/lib/module/task/task_bean.dart b/lib/module/task/task_bean.dart index 0fafd98..d320e50 100644 --- a/lib/module/task/task_bean.dart +++ b/lib/module/task/task_bean.dart @@ -9,7 +9,7 @@ class TaskBean { String? schedule; bool? saved; String? sId; - num? created; + int? created; int? status; String? timestamp; int? isSystem; diff --git a/lib/module/task/task_page.dart b/lib/module/task/task_page.dart index bb83d72..d34285d 100644 --- a/lib/module/task/task_page.dart +++ b/lib/module/task/task_page.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -31,6 +33,7 @@ class _TaskPageState extends State { Widget build(BuildContext context) { return BaseStateWidget( builder: (ref, model, child) { + return RefreshIndicator( onRefresh: () async { return model.loadData(false); @@ -335,6 +338,7 @@ class _TaskItemCellState extends ConsumerState { child: const Text('删除'), onPressed: () { Navigator.pop(context); + delTask(context, ref); }, ), CupertinoActionSheetAction( @@ -347,4 +351,29 @@ class _TaskItemCellState extends ConsumerState { ), ); } + + void delTask(BuildContext context, WidgetRef ref) { + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: const Text("确认删除"), + content: Text("确认删除定时任务 ${bean.name ?? ""} 吗"), + actions: [ + CupertinoDialogAction( + child: const Text("取消"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + CupertinoDialogAction( + child: const Text("确定"), + onPressed: () { + Navigator.of(context).pop(); + ref.read(taskProvider).delCron(bean.sId!); + }, + ), + ], + ), + ); + } } diff --git a/lib/module/task/task_viewmodel.dart b/lib/module/task/task_viewmodel.dart index e3ca657..fb72c11 100644 --- a/lib/module/task/task_viewmodel.dart +++ b/lib/module/task/task_viewmodel.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; +import 'dart:math'; + import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:qinglong_app/base/base_viewmodel.dart'; import 'package:qinglong_app/base/http/api.dart'; @@ -9,6 +12,8 @@ var taskProvider = ChangeNotifierProvider((ref) => TaskViewModel()); class TaskViewModel extends BaseViewModel { List list = []; + String temp = "sadad"; + Future loadData([isLoading = true]) async { if (isLoading) { loading(notify: true); @@ -19,7 +24,6 @@ class TaskViewModel extends BaseViewModel { if (result.success && result.bean != null) { list.clear(); list.addAll(result.bean!); - sortList(); success(); } else { @@ -30,11 +34,14 @@ class TaskViewModel extends BaseViewModel { void sortList() { list.sort((a, b) { - return a.isDisabled! - b.isDisabled!; + return b.created!.compareTo(a.created!); + }); + list.sort((a, b) { + return a.isDisabled!.compareTo(b.isDisabled!); }); list.sort((a, b) { - return a.status! - b.status!; + return a.status!.compareTo(b.status!); }); } @@ -43,6 +50,8 @@ class TaskViewModel extends BaseViewModel { if (result.success) { list.firstWhere((element) => element.sId == cron).status = 0; notifyListeners(); + } else { + failed(result.message, notify: true); } } @@ -51,6 +60,18 @@ class TaskViewModel extends BaseViewModel { if (result.success) { list.firstWhere((element) => element.sId == cron).status = 1; notifyListeners(); + } else { + failed(result.message, notify: true); + } + } + + Future delCron(String id) async { + HttpResponse result = await Api.delTask(id); + if (result.success) { + list.removeWhere((element) => element.sId == id); + notifyListeners(); + } else { + failed(result.message, notify: true); } } }