From d29c9e73f739598390f19f92ab92a1be231adee0 Mon Sep 17 00:00:00 2001 From: jyuesong <425698907@qq.com> Date: Thu, 13 Jan 2022 14:52:44 +0800 Subject: [PATCH] add task --- lib/base/common_dialog.dart | 23 +- lib/base/http/api.dart | 7 +- lib/base/http/url.dart | 1 + lib/base/routes.dart | 10 + lib/json.jc.dart | 9 + lib/module/task/add_task_page.dart | 201 ++++++++++++++++++ .../task/task_detail/task_detail_bean.dart | 4 + lib/module/task/task_page.dart | 28 ++- 8 files changed, 277 insertions(+), 6 deletions(-) create mode 100644 lib/module/task/add_task_page.dart diff --git a/lib/base/common_dialog.dart b/lib/base/common_dialog.dart index 2bcd3d3..6294661 100644 --- a/lib/base/common_dialog.dart +++ b/lib/base/common_dialog.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:back_button_interceptor/back_button_interceptor.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; /// @author newtab on 2021/7/16 @@ -13,6 +14,22 @@ class CommonDialog extends StatelessWidget { @override Widget build(BuildContext context) { + Widget loading; + + if (commonDialogState == CommonDialogState.FAILED) { + loading = const Icon( + CupertinoIcons.clear_circled, + size: 50, + ); + } else if (commonDialogState == CommonDialogState.SUCCESS) { + loading = const Icon( + CupertinoIcons.checkmark_alt, + size: 50, + ); + } else { + loading = LoadingIcon(); + } + Widget result = Material( color: Colors.transparent, child: Align( @@ -36,7 +53,7 @@ class CommonDialog extends StatelessWidget { color: Colors.white, size: 40.0, ), - child: LoadingIcon()), + child: loading), ), const SizedBox( height: 15, @@ -132,7 +149,7 @@ HideCallback showCommonDialog( }, zIndex: backButtonIndex, name: backButtonName); backButtonIndex++; - if (overlay != null) { + if (overlay != null && overlay!.mounted) { overlay?.remove(); overlay = null; } @@ -146,11 +163,13 @@ HideCallback showCommonDialog( }, child: CommonDialog( text: text, + commonDialogState: commonDialogState, ), ), ); result.complete(() { overlay?.remove(); + overlay = null; BackButtonInterceptor.removeByName(backButtonName); }); if (overlay != null) { diff --git a/lib/base/http/api.dart b/lib/base/http/api.dart index 14e1e95..0332ccc 100644 --- a/lib/base/http/api.dart +++ b/lib/base/http/api.dart @@ -34,8 +34,11 @@ class Api { return await Http.get(Url.INTIME_LOG(cron), null); } - static Future> taskDetail(String cron) async { - return await Http.get(Url.TASK_DETAIL+cron, null); + return await Http.get(Url.TASK_DETAIL + cron, null); + } + + static Future> 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}); } } diff --git a/lib/base/http/url.dart b/lib/base/http/url.dart index 04b767d..4fb7ceb 100644 --- a/lib/base/http/url.dart +++ b/lib/base/http/url.dart @@ -4,6 +4,7 @@ class Url { static const RUN_TASKS = "/api/crons/run"; static const STOP_TASKS = "/api/crons/stop"; static const TASK_DETAIL = "/api/crons/"; + static const ADD_TASK = "/api/crons"; static INTIME_LOG(String cronId) { return "/api/crons/$cronId/log"; diff --git a/lib/base/routes.dart b/lib/base/routes.dart index e021026..c00a993 100644 --- a/lib/base/routes.dart +++ b/lib/base/routes.dart @@ -1,14 +1,24 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:qinglong_app/module/home/home_page.dart'; +import 'package:qinglong_app/module/task/add_task_page.dart'; +import 'package:qinglong_app/module/task/task_bean.dart'; class Routes { static const String route_HomePage = "/home/homepage"; + static const String route_AddTask = "/task/add"; static Route? generateRoute(RouteSettings settings) { switch (settings.name) { case route_HomePage: return MaterialPageRoute(builder: (context) => const HomePage()); + case route_AddTask: + if (settings.arguments != null) { + return CupertinoPageRoute( + builder: (context) => AddTaskPage( + taskBean: settings.arguments as TaskBean, + )); + } } return null; diff --git a/lib/json.jc.dart b/lib/json.jc.dart index 55696da..d35bd35 100644 --- a/lib/json.jc.dart +++ b/lib/json.jc.dart @@ -2,6 +2,7 @@ import 'package:qinglong_app/module/login/login_bean.dart'; import 'package:qinglong_app/module/task/task_bean.dart'; +import 'package:qinglong_app/module/task/task_detail/task_detail_bean.dart'; class JsonConversion$Json { @@ -26,6 +27,10 @@ class JsonConversion$Json { return TaskBean.jsonConversion(json) as M; } + if(type == (TaskDetailBean).toString()){ + return TaskDetailBean.jsonConversion(json) as M; + } + throw Exception("not found"); } @@ -38,6 +43,10 @@ class JsonConversion$Json { return data.map((e) => TaskBean.jsonConversion(e)).toList() as M; } + if([] is M){ + return data.map((e) => TaskDetailBean.jsonConversion(e)).toList() as M; + } + throw Exception("not found"); } } diff --git a/lib/module/task/add_task_page.dart b/lib/module/task/add_task_page.dart new file mode 100644 index 0000000..3eb1273 --- /dev/null +++ b/lib/module/task/add_task_page.dart @@ -0,0 +1,201 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:qinglong_app/base/common_dialog.dart'; +import 'package:qinglong_app/base/http/api.dart'; +import 'package:qinglong_app/base/http/http.dart'; +import 'package:qinglong_app/base/ql_app_bar.dart'; +import 'package:qinglong_app/module/task/task_bean.dart'; +import 'package:qinglong_app/module/task/task_detail/task_detail_bean.dart'; + +class AddTaskPage extends StatefulWidget { + final TaskBean? taskBean; + + const AddTaskPage({Key? key, this.taskBean}) : super(key: key); + + @override + State createState() => _AddTaskPageState(); +} + +class _AddTaskPageState extends State { + late TaskBean taskBean; + + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _commandController = TextEditingController(); + final TextEditingController _cronController = TextEditingController(); + + @override + void initState() { + super.initState(); + if (widget.taskBean != null) { + taskBean = widget.taskBean!; + _nameController.text = taskBean.name ?? ""; + _commandController.text = taskBean.command ?? ""; + _cronController.text = taskBean.schedule ?? ""; + } else { + taskBean = TaskBean(); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: QlAppBar( + canBack: true, + backCall: () { + Navigator.of(context).pop(); + }, + title: taskBean.name == null ? "新增任务" : "编辑任务", + actions: [ + InkWell( + onTap: () { + submit(); + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 15, + ), + child: Center( + child: Text("提交"), + ), + ), + ) + ], + ), + body: Container( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 10, + ), + const Text( + "任务名称:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox( + height: 10, + ), + TextField( + controller: _nameController, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入任务名称", + ), + autofocus: false, + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 10, + ), + const Text( + "命令:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox( + height: 10, + ), + TextField( + controller: _commandController, + maxLines: 4, + minLines: 1, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入命令", + ), + autofocus: false, + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 10, + ), + const Text( + "定时:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox( + height: 10, + ), + TextField( + controller: _cronController, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入定时", + ), + autofocus: false, + ), + ], + ), + ), + ], + ), + ), + ); + } + + void submit() async { + if (_nameController.text.isEmpty) { + failDialog(context, "任务名称不能为空"); + return; + } + if (_commandController.text.isEmpty) { + failDialog(context, "命令不能为空"); + return; + } + if (_cronController.text.isEmpty) { + failDialog(context, "定时不能为空"); + return; + } + + taskBean.name = _nameController.text; + taskBean.command = _commandController.text; + taskBean.schedule = _cronController.text; + HttpResponse response = await Api.addTask(_nameController.text, _commandController.text, _cronController.text, id: taskBean.sId); + + if (response.success) { + successDialog(context, "操作成功").then((value) { + Navigator.of(context).pop(response.bean); + }); + } else { + failDialog(context, response.message ??""); + } + } +} diff --git a/lib/module/task/task_detail/task_detail_bean.dart b/lib/module/task/task_detail/task_detail_bean.dart index 2c33020..fa7d5a7 100644 --- a/lib/module/task/task_detail/task_detail_bean.dart +++ b/lib/module/task/task_detail/task_detail_bean.dart @@ -60,4 +60,8 @@ class TaskDetailBean { data['isPinned'] = this.isPinned; return data; } + + static TaskDetailBean jsonConversion(Map json) { + return TaskDetailBean.fromJson(json); + } } diff --git a/lib/module/task/task_page.dart b/lib/module/task/task_page.dart index 3b2b07b..bb83d72 100644 --- a/lib/module/task/task_page.dart +++ b/lib/module/task/task_page.dart @@ -3,9 +3,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:qinglong_app/base/base_state_widget.dart'; +import 'package:qinglong_app/base/routes.dart'; import 'package:qinglong_app/base/theme.dart'; import 'package:qinglong_app/module/task/intime_log/intime_log_page.dart'; import 'package:qinglong_app/module/task/task_bean.dart'; +import 'package:qinglong_app/module/task/task_detail/task_detail_bean.dart'; import 'package:qinglong_app/module/task/task_viewmodel.dart'; import 'package:qinglong_app/utils/utils.dart'; @@ -97,13 +99,26 @@ class _TaskPageState extends State { } } -class TaskItemCell extends ConsumerWidget { +class TaskItemCell extends ConsumerStatefulWidget { final TaskBean bean; const TaskItemCell(this.bean, {Key? key}) : super(key: key); @override - Widget build(BuildContext context, WidgetRef ref) { + _TaskItemCellState createState() => _TaskItemCellState(); +} + +class _TaskItemCellState extends ConsumerState { + late TaskBean bean; + + @override + void initState() { + bean = widget.bean; + super.initState(); + } + + @override + Widget build(BuildContext context) { return Slidable( key: const ValueKey(0), startActionPane: ActionPane( @@ -299,6 +314,15 @@ class TaskItemCell extends ConsumerWidget { child: const Text('编辑'), onPressed: () { Navigator.pop(context); + Navigator.of(context).pushNamed(Routes.route_AddTask, arguments: bean).then((value) { + if (value != null) { + var result = value as TaskDetailBean; + bean.name = result.name; + bean.schedule = result.schedule; + bean.command = result.command; + setState(() {}); + } + }); }, ), CupertinoActionSheetAction(