From 38a6790c5104f517aa455d6c347a98407875224f Mon Sep 17 00:00:00 2001 From: jyuesong <425698907@qq.com> Date: Wed, 19 Jan 2022 14:13:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=BB=E5=8A=A1=E8=AF=A6?= =?UTF-8?q?=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/module/task/add_task_page.dart | 206 +++++---- .../task/task_detail/task_detail_page.dart | 395 +++++++++++++++--- lib/module/task/task_page.dart | 8 +- lib/module/task/task_viewmodel.dart | 9 +- 4 files changed, 445 insertions(+), 173 deletions(-) diff --git a/lib/module/task/add_task_page.dart b/lib/module/task/add_task_page.dart index 3fc6f24..3d240c5 100644 --- a/lib/module/task/add_task_page.dart +++ b/lib/module/task/add_task_page.dart @@ -71,115 +71,113 @@ class _AddTaskPageState extends ConsumerState { ) ], ), - 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.w600, - ), - ), - const SizedBox( - height: 10, - ), - TextField( - controller: _nameController, - decoration: const InputDecoration( - contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), - hintText: "请输入名称", - ), - autofocus: false, - ), - ], - ), + body: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 15, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 10, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 10, + ), + const Text( + "名称:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, ), - const Text( - "命令:", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), + ), + const SizedBox( + height: 10, + ), + TextField( + controller: _nameController, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入名称", ), - const SizedBox( - height: 10, - ), - TextField( - controller: _commandController, - maxLines: 4, - minLines: 1, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(scheduleCron)), - ], - decoration: const InputDecoration( - contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), - hintText: "请输入命令", - ), - autofocus: false, - ), - ], - ), + 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.w600, - ), - ), - const SizedBox( - height: 10, - ), - TextField( - controller: _cronController, - 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.w600, + ), + ), + const SizedBox( + height: 10, + ), + TextField( + controller: _commandController, + maxLines: 4, + minLines: 1, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(scheduleCron)), + ], + 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.w600, + ), + ), + const SizedBox( + height: 10, + ), + TextField( + controller: _cronController, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入定时", + ), + autofocus: false, + ), + ], + ), + ), + ], ), ); } diff --git a/lib/module/task/task_detail/task_detail_page.dart b/lib/module/task/task_detail/task_detail_page.dart index 1b146b7..3303bd0 100644 --- a/lib/module/task/task_detail/task_detail_page.dart +++ b/lib/module/task/task_detail/task_detail_page.dart @@ -2,11 +2,14 @@ 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/task/intime_log/intime_log_page.dart'; import 'package:qinglong_app/module/task/task_bean.dart'; import 'package:qinglong_app/utils/utils.dart'; +import '../task_viewmodel.dart'; + class TaskDetailPage extends ConsumerStatefulWidget { final TaskBean taskBean; @@ -17,8 +20,132 @@ class TaskDetailPage extends ConsumerStatefulWidget { } class _TaskDetailPageState extends ConsumerState { + List actions = []; + + @override + void initState() { + super.initState(); + } + @override Widget build(BuildContext context) { + actions.clear(); + actions.addAll( + [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pop(); + startCron(context, ref); + }, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + alignment: Alignment.center, + child: Material( + color: Colors.transparent, + child: Text( + widget.taskBean.status! == 1 ? "运行" : "停止运行", + style: const TextStyle( + fontSize: 16, + ), + ), + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pop(); + showLog(); + }, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + alignment: Alignment.center, + child: const Material( + color: Colors.transparent, + child: Text( + "查看日志", + style: TextStyle( + fontSize: 16, + ), + ), + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pop(); + Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: widget.taskBean); + }, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + alignment: Alignment.center, + child: const Material( + color: Colors.transparent, + child: Text( + "编辑", + style: TextStyle( + fontSize: 16, + ), + ), + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pop(); + pinTask(); + }, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + color: Colors.transparent, + alignment: Alignment.center, + child: Material( + color: Colors.transparent, + child: Text( + widget.taskBean.isPinned! == 0 ? "置顶" : "取消置顶", + style: const TextStyle( + fontSize: 16, + ), + ), + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pop(); + enableTask(); + }, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + alignment: Alignment.center, + child: Material( + color: Colors.transparent, + child: Text( + widget.taskBean.isDisabled! == 0 ? "禁用" : "启用", + style: const TextStyle( + color: Colors.red, + fontSize: 16, + ), + ), + ), + ), + ), + ], + ); return Scaffold( appBar: QlAppBar( canBack: true, @@ -26,78 +153,221 @@ class _TaskDetailPageState extends ConsumerState { Navigator.of(context).pop(); }, title: widget.taskBean.name ?? "", - ), - body: SingleChildScrollView( - child: Container( - margin: const EdgeInsets.symmetric( - horizontal: 15, - vertical: 10, - ), - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - ), - decoration: BoxDecoration( - color: ref.watch(themeProvider).themeColor.settingBgColor(), - borderRadius: BorderRadius.circular(15), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TaskDetailCell( - title: "ID", - desc: widget.taskBean.sId ?? "", + actions: [ + InkWell( + onTap: () { + showCupertinoModalPopup( + context: context, + builder: (context) { + return CupertinoActionSheet( + title: Container( + alignment: Alignment.center, + child: const Material( + color: Colors.transparent, + child: Text( + "更多操作", + style: TextStyle( + fontSize: 16, + ), + ), + ), + ), + actions: actions, + cancelButton: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.pop(context); + }, + child: Container( + alignment: Alignment.center, + padding: const EdgeInsets.symmetric( + vertical: 10, + ), + child: const Material( + color: Colors.transparent, + child: Text( + "取消", + style: TextStyle( + color: Colors.red, + fontSize: 16, + ), + ), + ), + ), + ), + ); + }); + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 15, ), - TaskDetailCell( - title: "任务", - desc: widget.taskBean.command ?? "", - ), - TaskDetailCell( - title: "创建时间", - desc: Utils.formatMessageTime(widget.taskBean.created ?? 0), - ), - TaskDetailCell( - title: "任务定时", - desc: widget.taskBean.schedule ?? "", - ), - TaskDetailCell( - title: "最后运行时间", - desc: Utils.formatMessageTime(widget.taskBean.lastExecutionTime ?? 0), - ), - TaskDetailCell( - title: "最后运行时长", - desc: widget.taskBean.lastRunningTime == null ? "-" : "${widget.taskBean.lastRunningTime ?? "-"}秒", - ), - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - showLog(); - }, - child: TaskDetailCell( - title: "日志路径", - desc: widget.taskBean.logPath ?? "-", - taped: () { - showLog(); - }, + child: Center( + child: Icon( + Icons.more_horiz, + color: Colors.white, + size: 26, ), ), - TaskDetailCell( - title: "运行状态", - desc: widget.taskBean.status == 0 ? "正在运行" : "空闲", + ), + ) + ], + ), + body: SingleChildScrollView( + child: Column( + children: [ + Container( + margin: const EdgeInsets.symmetric( + horizontal: 15, + vertical: 10, ), - TaskDetailCell( - title: "脚本状态", - desc: widget.taskBean.isDisabled == 1 ? "已禁用" : "正常", - hideDivide: true, + padding: const EdgeInsets.only( + top: 10, + bottom: 10, ), - ], - ), + decoration: BoxDecoration( + color: ref.watch(themeProvider).themeColor.settingBgColor(), + borderRadius: BorderRadius.circular(15), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TaskDetailCell( + title: "ID", + desc: widget.taskBean.sId ?? "", + ), + TaskDetailCell( + title: "任务", + desc: widget.taskBean.command ?? "", + ), + TaskDetailCell( + title: "创建时间", + desc: Utils.formatMessageTime(widget.taskBean.created ?? 0), + ), + TaskDetailCell( + title: "更新时间", + desc: Utils.formatGMTTime(widget.taskBean.timestamp ?? ""), + ), + TaskDetailCell( + title: "任务定时", + desc: widget.taskBean.schedule ?? "", + ), + TaskDetailCell( + title: "最后运行时间", + desc: Utils.formatMessageTime(widget.taskBean.lastExecutionTime ?? 0), + ), + TaskDetailCell( + title: "最后运行时长", + desc: widget.taskBean.lastRunningTime == null ? "-" : "${widget.taskBean.lastRunningTime ?? "-"}秒", + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + showLog(); + }, + child: TaskDetailCell( + title: "日志路径", + desc: widget.taskBean.logPath ?? "-", + taped: () { + showLog(); + }, + ), + ), + TaskDetailCell( + title: "运行状态", + desc: widget.taskBean.status == 0 ? "正在运行" : "空闲", + ), + TaskDetailCell( + title: "脚本状态", + desc: widget.taskBean.isDisabled == 1 ? "已禁用" : "已启用", + ), + TaskDetailCell( + title: "是否置顶", + desc: widget.taskBean.isPinned == 1 ? "已置顶" : "未置顶", + hideDivide: true, + ), + ], + ), + ), + const SizedBox( + height: 30, + ), + SizedBox( + width: MediaQuery.of(context).size.width - 80, + child: CupertinoButton( + padding: const EdgeInsets.symmetric( + vertical: 5, + ), + color: Colors.red, + child: const Text( + "删 除", + style: TextStyle( + fontSize: 16, + ), + ), + onPressed: () { + delTask(context, ref); + }), + ), + const SizedBox( + height: 30, + ), + ], ), ), ); } + startCron(BuildContext context, WidgetRef ref) async { + await ref.read(taskProvider).runCrons(widget.taskBean.sId!); + setState(() {}); + WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { + showLog(); + }); + } + + stopCron(BuildContext context, WidgetRef ref) async { + await ref.read(taskProvider).stopCrons(widget.taskBean.sId!); + setState(() {}); + } + + void enableTask() async { + await ref.read(taskProvider).enableTask(widget.taskBean.sId!, widget.taskBean.isDisabled!); + setState(() {}); + } + + void pinTask() async { + await ref.read(taskProvider).pinTask(widget.taskBean.sId!, widget.taskBean.isPinned!); + setState(() {}); + } + + void delTask(BuildContext context, WidgetRef ref) { + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: const Text("确认删除"), + content: Text("确认删除定时任务 ${widget.taskBean.name ?? ""} 吗"), + actions: [ + CupertinoDialogAction( + child: const Text("取消"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + CupertinoDialogAction( + child: const Text("确定"), + onPressed: () async { + Navigator.of(context).pop(); + await ref.read(taskProvider).delCron(widget.taskBean.sId!); + Navigator.of(context).pop(); + }, + ), + ], + ), + ); + } + void showLog() { showCupertinoDialog( builder: (BuildContext context) { @@ -116,6 +386,7 @@ class _TaskDetailPageState extends ConsumerState { ), onPressed: () { Navigator.of(context).pop(); + ref.read(taskProvider).loadData(false); }, ), ], diff --git a/lib/module/task/task_page.dart b/lib/module/task/task_page.dart index 7b587fb..07b5723 100644 --- a/lib/module/task/task_page.dart +++ b/lib/module/task/task_page.dart @@ -354,8 +354,11 @@ class TaskItemCell extends StatelessWidget { ); } - startCron(BuildContext context, WidgetRef ref) { - ref.read(taskProvider).runCrons(bean.sId!); + startCron(BuildContext context, WidgetRef ref) async { + await ref.read(taskProvider).runCrons(bean.sId!); + WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { + logCron(context, ref); + }); } stopCron(BuildContext context, WidgetRef ref) { @@ -381,6 +384,7 @@ class TaskItemCell extends StatelessWidget { ), onPressed: () { Navigator.of(context).pop(); + ref.read(taskProvider).loadData(false); }, ), ], diff --git a/lib/module/task/task_viewmodel.dart b/lib/module/task/task_viewmodel.dart index 1338c11..ce01bf5 100644 --- a/lib/module/task/task_viewmodel.dart +++ b/lib/module/task/task_viewmodel.dart @@ -3,6 +3,7 @@ import 'package:qinglong_app/base/base_viewmodel.dart'; import 'package:qinglong_app/base/http/api.dart'; import 'package:qinglong_app/base/http/http.dart'; import 'package:qinglong_app/module/task/task_bean.dart'; +import 'package:qinglong_app/utils/extension.dart'; var taskProvider = ChangeNotifierProvider((ref) => TaskViewModel()); @@ -30,7 +31,6 @@ class TaskViewModel extends BaseViewModel { } void sortList() { - for (int i = 0; i < list.length; i++) { if (list[i].isPinned == 1) { final TaskBean item = list.removeAt(i); @@ -68,6 +68,7 @@ class TaskViewModel extends BaseViewModel { HttpResponse result = await Api.delTask(id); if (result.success) { list.removeWhere((element) => element.sId == id); + "删除成功".toast(); notifyListeners(); } else { failToast(result.message, notify: true); @@ -86,12 +87,11 @@ class TaskViewModel extends BaseViewModel { notifyListeners(); } - void pinTask(String sId, int isPinned) async { + Future pinTask(String sId, int isPinned) async { if (isPinned == 1) { HttpResponse response = await Api.unpinTask(sId); if (response.success) { - list.firstWhere((element) => element.sId == sId).isPinned = 0; sortList(); success(); } else { @@ -101,7 +101,6 @@ class TaskViewModel extends BaseViewModel { HttpResponse response = await Api.pinTask(sId); if (response.success) { - list.firstWhere((element) => element.sId == sId).isPinned = 1; sortList(); success(); } else { @@ -110,7 +109,7 @@ class TaskViewModel extends BaseViewModel { } } - void enableTask(String sId, int isDisabled) async { + Future enableTask(String sId, int isDisabled) async { if (isDisabled == 0) { HttpResponse response = await Api.disableTask(sId);