mirror of
https://github.com/qinglong-app/qinglong_app.git
synced 2025-10-09 16:48:19 +08:00
add task
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:qinglong_app/base/common_dialog.dart';
|
||||||
import 'base_viewmodel.dart';
|
import 'base_viewmodel.dart';
|
||||||
|
|
||||||
class BaseStateWidget<T extends BaseViewModel> extends ConsumerStatefulWidget {
|
class BaseStateWidget<T extends BaseViewModel> extends ConsumerStatefulWidget {
|
||||||
@@ -36,6 +37,12 @@ class _BaseStateWidgetState<T extends BaseViewModel> extends ConsumerState<BaseS
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var viewModel = ref.watch<T>(widget.model);
|
var viewModel = ref.watch<T>(widget.model);
|
||||||
|
if (viewModel.failReason != null) {
|
||||||
|
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
|
||||||
|
failDialog(context, viewModel.failReason!);
|
||||||
|
viewModel.clearToast();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (viewModel.currentState == PageState.CONTENT) {
|
if (viewModel.currentState == PageState.CONTENT) {
|
||||||
return widget.builder(ref, viewModel, widget.child);
|
return widget.builder(ref, viewModel, widget.child);
|
||||||
}
|
}
|
||||||
@@ -50,7 +57,7 @@ class _BaseStateWidgetState<T extends BaseViewModel> extends ConsumerState<BaseS
|
|||||||
if (viewModel.currentState == PageState.FAILED) {
|
if (viewModel.currentState == PageState.FAILED) {
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(viewModel.failReason ??""),
|
child: Text(viewModel.failReason ?? ""),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class BaseViewModel extends ViewModel {
|
|||||||
String? failReason;
|
String? failReason;
|
||||||
|
|
||||||
void loading({bool notify = false}) {
|
void loading({bool notify = false}) {
|
||||||
|
failReason = null;
|
||||||
currentState = PageState.LOADING;
|
currentState = PageState.LOADING;
|
||||||
if (notify) {
|
if (notify) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@@ -14,6 +15,7 @@ class BaseViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void success({bool notify = true}) {
|
void success({bool notify = true}) {
|
||||||
|
failReason = null;
|
||||||
currentState = PageState.CONTENT;
|
currentState = PageState.CONTENT;
|
||||||
if (notify) {
|
if (notify) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@@ -27,8 +29,20 @@ class BaseViewModel extends ViewModel {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void failToast(String? reason, {bool notify = false}) {
|
||||||
|
currentState = PageState.CONTENT;
|
||||||
|
failReason = reason;
|
||||||
|
if (notify) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearToast(){
|
||||||
|
failReason = null;
|
||||||
|
}
|
||||||
|
|
||||||
void empty({bool notify = false}) {
|
void empty({bool notify = false}) {
|
||||||
|
failReason = null;
|
||||||
currentState = PageState.EMPTY;
|
currentState = PageState.EMPTY;
|
||||||
if (notify) {
|
if (notify) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|||||||
@@ -39,6 +39,16 @@ class Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<HttpResponse<TaskDetailBean>> addTask(String name, String command, String cron, {String? id}) async {
|
static Future<HttpResponse<TaskDetailBean>> addTask(String name, String command, String cron, {String? id}) async {
|
||||||
return await Http.put<TaskDetailBean>(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<TaskDetailBean>(Url.ADD_TASK, data);
|
||||||
|
}
|
||||||
|
return await Http.post<TaskDetailBean>(Url.ADD_TASK, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<HttpResponse<NullResponse>> delTask(String cron) async {
|
||||||
|
return await Http.delete<NullResponse>(Url.ADD_TASK, [cron]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,31 +36,46 @@ class Http {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<HttpResponse<T>> get<T>(String uri, Map<String, String>? json, {bool compute = true}) async {
|
static Future<HttpResponse<T>> get<T>(String uri, Map<String, String>? json, {bool compute = true}) async {
|
||||||
|
try {
|
||||||
_init();
|
_init();
|
||||||
var response = await _dio!.get(uri, queryParameters: json);
|
var response = await _dio!.get(uri, queryParameters: json);
|
||||||
|
|
||||||
return decodeResponse<T>(response, compute);
|
return decodeResponse<T>(response, compute);
|
||||||
|
} on DioError catch (e) {
|
||||||
|
return HttpResponse(success: false, message: e.message, code: 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<HttpResponse<T>> post<T>(String uri, dynamic json, {bool compute = true}) async {
|
static Future<HttpResponse<T>> post<T>(String uri, dynamic json, {bool compute = true}) async {
|
||||||
|
try {
|
||||||
_init();
|
_init();
|
||||||
var response = await _dio!.post(uri, data: json);
|
var response = await _dio!.post(uri, data: json);
|
||||||
|
|
||||||
return decodeResponse<T>(response, compute);
|
return decodeResponse<T>(response, compute);
|
||||||
|
} on DioError catch (e) {
|
||||||
|
return HttpResponse(success: false, message: e.message, code: 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<HttpResponse<T>> delete<T>(String uri, dynamic json, {bool compute = true}) async {
|
static Future<HttpResponse<T>> delete<T>(String uri, dynamic json, {bool compute = true}) async {
|
||||||
|
try {
|
||||||
_init();
|
_init();
|
||||||
var response = await _dio!.delete(uri, data: json);
|
var response = await _dio!.delete(uri, data: json);
|
||||||
|
|
||||||
return decodeResponse<T>(response, compute);
|
return decodeResponse<T>(response, compute);
|
||||||
|
} on DioError catch (e) {
|
||||||
|
return HttpResponse(success: false, message: e.message, code: 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<HttpResponse<T>> put<T>(String uri, dynamic json, {bool compute = true}) async {
|
static Future<HttpResponse<T>> put<T>(String uri, dynamic json, {bool compute = true}) async {
|
||||||
|
try {
|
||||||
_init();
|
_init();
|
||||||
var response = await _dio!.put(uri, data: json);
|
var response = await _dio!.put(uri, data: json);
|
||||||
|
|
||||||
return decodeResponse<T>(response, compute);
|
return decodeResponse<T>(response, compute);
|
||||||
|
} on DioError catch (e) {
|
||||||
|
return HttpResponse(success: false, message: e.message, code: 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HttpResponse<T> decodeResponse<T>(
|
static HttpResponse<T> decodeResponse<T>(
|
||||||
@@ -173,4 +188,4 @@ void decode<T>() async {
|
|||||||
compute(DeserializeAction.invokeJson, DeserializeAction<T>({}));
|
compute(DeserializeAction.invokeJson, DeserializeAction<T>({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
class NullResponse{}
|
class NullResponse {}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class TokenInterceptor extends Interceptor {
|
|||||||
if (userInfoViewModel.token != null) {
|
if (userInfoViewModel.token != null) {
|
||||||
options.headers["Authorization"] = "Bearer " + userInfoViewModel.token!;
|
options.headers["Authorization"] = "Bearer " + userInfoViewModel.token!;
|
||||||
}
|
}
|
||||||
options.queryParameters["t"] = DateTime.now().millisecondsSinceEpoch;
|
options.queryParameters["t"] = (DateTime.now().millisecondsSinceEpoch~/1000).toString();
|
||||||
return handler.next(options);
|
return handler.next(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ class Routes {
|
|||||||
builder: (context) => AddTaskPage(
|
builder: (context) => AddTaskPage(
|
||||||
taskBean: settings.arguments as TaskBean,
|
taskBean: settings.arguments as TaskBean,
|
||||||
));
|
));
|
||||||
|
} else {
|
||||||
|
return CupertinoPageRoute(builder: (context) => AddTaskPage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:qinglong_app/base/ql_app_bar.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/base/theme.dart';
|
||||||
import 'package:qinglong_app/module/config/config_page.dart';
|
import 'package:qinglong_app/module/config/config_page.dart';
|
||||||
import 'package:qinglong_app/module/env/env_page.dart';
|
import 'package:qinglong_app/module/env/env_page.dart';
|
||||||
@@ -30,11 +31,30 @@ class _HomePageState extends State<HomePage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
List<Widget> actions = [];
|
||||||
appBar: QlAppBar(
|
|
||||||
canBack: false,
|
if (_index == 0) {
|
||||||
title: _title,
|
actions.add(InkWell(
|
||||||
actions: [
|
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) {
|
Consumer(builder: (context, ref, child) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -43,7 +63,12 @@ class _HomePageState extends State<HomePage> {
|
|||||||
child: const Center(child: Text("改变主题")),
|
child: const Center(child: Text("改变主题")),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: QlAppBar(
|
||||||
|
canBack: false,
|
||||||
|
title: _title,
|
||||||
|
actions: actions,
|
||||||
),
|
),
|
||||||
body: IndexedStack(
|
body: IndexedStack(
|
||||||
index: _index,
|
index: _index,
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class _AddTaskPageState extends State<AddTaskPage> {
|
|||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
const Text(
|
const Text(
|
||||||
"任务名称:",
|
"名称:",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@@ -92,7 +92,7 @@ class _AddTaskPageState extends State<AddTaskPage> {
|
|||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
|
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
|
||||||
hintText: "请输入任务名称",
|
hintText: "请输入名称",
|
||||||
),
|
),
|
||||||
autofocus: false,
|
autofocus: false,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class TaskBean {
|
|||||||
String? schedule;
|
String? schedule;
|
||||||
bool? saved;
|
bool? saved;
|
||||||
String? sId;
|
String? sId;
|
||||||
num? created;
|
int? created;
|
||||||
int? status;
|
int? status;
|
||||||
String? timestamp;
|
String? timestamp;
|
||||||
int? isSystem;
|
int? isSystem;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -31,6 +33,7 @@ class _TaskPageState extends State<TaskPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BaseStateWidget<TaskViewModel>(
|
return BaseStateWidget<TaskViewModel>(
|
||||||
builder: (ref, model, child) {
|
builder: (ref, model, child) {
|
||||||
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
return model.loadData(false);
|
return model.loadData(false);
|
||||||
@@ -335,6 +338,7 @@ class _TaskItemCellState extends ConsumerState<TaskItemCell> {
|
|||||||
child: const Text('删除'),
|
child: const Text('删除'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
delTask(context, ref);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
CupertinoActionSheetAction(
|
CupertinoActionSheetAction(
|
||||||
@@ -347,4 +351,29 @@ class _TaskItemCellState extends ConsumerState<TaskItemCell> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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!);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:qinglong_app/base/base_viewmodel.dart';
|
import 'package:qinglong_app/base/base_viewmodel.dart';
|
||||||
import 'package:qinglong_app/base/http/api.dart';
|
import 'package:qinglong_app/base/http/api.dart';
|
||||||
@@ -9,6 +12,8 @@ var taskProvider = ChangeNotifierProvider((ref) => TaskViewModel());
|
|||||||
class TaskViewModel extends BaseViewModel {
|
class TaskViewModel extends BaseViewModel {
|
||||||
List<TaskBean> list = [];
|
List<TaskBean> list = [];
|
||||||
|
|
||||||
|
String temp = "sadad";
|
||||||
|
|
||||||
Future<void> loadData([isLoading = true]) async {
|
Future<void> loadData([isLoading = true]) async {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
loading(notify: true);
|
loading(notify: true);
|
||||||
@@ -19,7 +24,6 @@ class TaskViewModel extends BaseViewModel {
|
|||||||
if (result.success && result.bean != null) {
|
if (result.success && result.bean != null) {
|
||||||
list.clear();
|
list.clear();
|
||||||
list.addAll(result.bean!);
|
list.addAll(result.bean!);
|
||||||
|
|
||||||
sortList();
|
sortList();
|
||||||
success();
|
success();
|
||||||
} else {
|
} else {
|
||||||
@@ -30,11 +34,14 @@ class TaskViewModel extends BaseViewModel {
|
|||||||
|
|
||||||
void sortList() {
|
void sortList() {
|
||||||
list.sort((a, b) {
|
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) {
|
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) {
|
if (result.success) {
|
||||||
list.firstWhere((element) => element.sId == cron).status = 0;
|
list.firstWhere((element) => element.sId == cron).status = 0;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
} else {
|
||||||
|
failed(result.message, notify: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +60,18 @@ class TaskViewModel extends BaseViewModel {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
list.firstWhere((element) => element.sId == cron).status = 1;
|
list.firstWhere((element) => element.sId == cron).status = 1;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
} else {
|
||||||
|
failed(result.message, notify: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> delCron(String id) async {
|
||||||
|
HttpResponse<NullResponse> result = await Api.delTask(id);
|
||||||
|
if (result.success) {
|
||||||
|
list.removeWhere((element) => element.sId == id);
|
||||||
|
notifyListeners();
|
||||||
|
} else {
|
||||||
|
failed(result.message, notify: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user