add scripts

This commit is contained in:
jyuesong
2022-01-18 13:09:29 +08:00
parent 1a72b9b5d7
commit 8aa41e577b
15 changed files with 506 additions and 154 deletions

View File

@@ -12,7 +12,8 @@ import 'package:qinglong_app/module/task/task_detail/task_detail_bean.dart';
import 'url.dart'; import 'url.dart';
class Api { class Api {
static Future<HttpResponse<LoginBean>> login(String userName, String passWord) async { static Future<HttpResponse<LoginBean>> login(
String userName, String passWord) async {
return await Http.post<LoginBean>( return await Http.post<LoginBean>(
Url.login, Url.login,
{ {
@@ -29,14 +30,16 @@ class Api {
); );
} }
static Future<HttpResponse<NullResponse>> startTasks(List<String> crons) async { static Future<HttpResponse<NullResponse>> startTasks(
List<String> crons) async {
return await Http.put<NullResponse>( return await Http.put<NullResponse>(
Url.runTasks, Url.runTasks,
crons, crons,
); );
} }
static Future<HttpResponse<NullResponse>> stopTasks(List<String> crons) async { static Future<HttpResponse<NullResponse>> stopTasks(
List<String> crons) async {
return await Http.put<NullResponse>( return await Http.put<NullResponse>(
Url.runTasks, Url.runTasks,
crons, crons,
@@ -57,7 +60,9 @@ 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 {
var data = {"name": name, "command": command, "schedule": cron}; var data = {"name": name, "command": command, "schedule": cron};
if (id != null) { if (id != null) {
@@ -122,7 +127,8 @@ class Api {
); );
} }
static Future<HttpResponse<NullResponse>> saveFile(String name, String content) async { static Future<HttpResponse<NullResponse>> saveFile(
String name, String content) async {
return await Http.post<NullResponse>( return await Http.post<NullResponse>(
Url.saveFile, Url.saveFile,
{"content": content, "name": name}, {"content": content, "name": name},
@@ -157,7 +163,9 @@ class Api {
); );
} }
static Future<HttpResponse<NullResponse>> addEnv(String name, String value, String remarks, {String? id}) async { static Future<HttpResponse<NullResponse>> addEnv(
String name, String value, String remarks,
{String? id}) async {
var data = { var data = {
"value": value, "value": value,
"remarks": remarks, "remarks": remarks,
@@ -177,7 +185,8 @@ class Api {
); );
} }
static Future<HttpResponse<NullResponse>> moveEnv(String id, int fromIndex, int toIndex) async { static Future<HttpResponse<NullResponse>> moveEnv(
String id, int fromIndex, int toIndex) async {
return await Http.put<NullResponse>( return await Http.put<NullResponse>(
Url.envMove(id), Url.envMove(id),
{"fromIndex": fromIndex, "toIndex": toIndex}, {"fromIndex": fromIndex, "toIndex": toIndex},
@@ -192,7 +201,8 @@ class Api {
} }
static Future<HttpResponse<List<TaskLogBean>>> taskLog() async { static Future<HttpResponse<List<TaskLogBean>>> taskLog() async {
return await Http.get<List<TaskLogBean>>(Url.taskLog, null, serializationName: "dirs"); return await Http.get<List<TaskLogBean>>(Url.taskLog, null,
serializationName: "dirs");
} }
static Future<HttpResponse<String>> taskLogDetail(String name) async { static Future<HttpResponse<String>> taskLogDetail(String name) async {
@@ -209,7 +219,8 @@ class Api {
); );
} }
static Future<HttpResponse<String>> scriptDetail(String name, String path) async { static Future<HttpResponse<String>> scriptDetail(
String name, String? path) async {
return await Http.get<String>( return await Http.get<String>(
Url.scriptDetail + name, Url.scriptDetail + name,
{ {
@@ -218,7 +229,8 @@ class Api {
); );
} }
static Future<HttpResponse<List<DependencyBean>>> dependencies(String type) async { static Future<HttpResponse<List<DependencyBean>>> dependencies(
String type) async {
return await Http.get<List<DependencyBean>>( return await Http.get<List<DependencyBean>>(
Url.dependencies, Url.dependencies,
{ {
@@ -227,7 +239,8 @@ class Api {
); );
} }
static Future<HttpResponse<NullResponse>> dependencyReinstall(String id) async { static Future<HttpResponse<NullResponse>> dependencyReinstall(
String id) async {
return await Http.put<NullResponse>( return await Http.put<NullResponse>(
Url.dependencies, Url.dependencies,
[id], [id],
@@ -241,7 +254,8 @@ class Api {
); );
} }
static Future<HttpResponse<NullResponse>> addDependency(String name, int type) async { static Future<HttpResponse<NullResponse>> addDependency(
String name, int type) async {
return await Http.post<NullResponse>( return await Http.post<NullResponse>(
Url.dependencies, Url.dependencies,
[ [

View File

@@ -40,7 +40,7 @@ class Http {
static Future<HttpResponse<T>> get<T>( static Future<HttpResponse<T>> get<T>(
String uri, String uri,
Map<String, String>? json, { Map<String, String?>? json, {
bool compute = true, bool compute = true,
String serializationName = "data", String serializationName = "data",
}) async { }) async {
@@ -53,7 +53,10 @@ class Http {
if (e.response?.statusCode == 401) { if (e.response?.statusCode == 401) {
exitLogin(); exitLogin();
} }
return HttpResponse(success: false, message: e.response?.statusMessage ?? e.message, code: 0); return HttpResponse(
success: false,
message: e.response?.statusMessage ?? e.message,
code: 0);
} }
} }
@@ -76,7 +79,10 @@ class Http {
if (e.response?.statusCode == 401) { if (e.response?.statusCode == 401) {
exitLogin(); exitLogin();
} }
return HttpResponse(success: false, message: e.response?.statusMessage ?? e.message, code: 0); return HttpResponse(
success: false,
message: e.response?.statusMessage ?? e.message,
code: 0);
} }
} }
@@ -99,7 +105,10 @@ class Http {
if (e.response?.statusCode == 401) { if (e.response?.statusCode == 401) {
exitLogin(); exitLogin();
} }
return HttpResponse(success: false, message: e.response?.statusMessage ?? e.message, code: 0); return HttpResponse(
success: false,
message: e.response?.statusMessage ?? e.message,
code: 0);
} }
} }
@@ -121,7 +130,10 @@ class Http {
if (e.response?.statusCode == 401) { if (e.response?.statusCode == 401) {
exitLogin(); exitLogin();
} }
return HttpResponse(success: false, message: e.response?.statusMessage ?? e.message, code: 0); return HttpResponse(
success: false,
message: e.response?.statusMessage ?? e.message,
code: 0);
} }
} }
@@ -215,7 +227,8 @@ class HttpResponse<T> {
late int code; late int code;
T? bean; T? bean;
HttpResponse({required this.success, this.message, required this.code, this.bean}); HttpResponse(
{required this.success, this.message, required this.code, this.bean});
} }
class DeserializeAction<T> { class DeserializeAction<T> {

View File

@@ -6,6 +6,8 @@ import 'package:qinglong_app/module/env/env_bean.dart';
import 'package:qinglong_app/module/home/home_page.dart'; import 'package:qinglong_app/module/home/home_page.dart';
import 'package:qinglong_app/module/login/login_page.dart'; import 'package:qinglong_app/module/login/login_page.dart';
import 'package:qinglong_app/module/others/login_log/login_log_page.dart'; import 'package:qinglong_app/module/others/login_log/login_log_page.dart';
import 'package:qinglong_app/module/others/scripts/script_detail_page.dart';
import 'package:qinglong_app/module/others/scripts/script_page.dart';
import 'package:qinglong_app/module/others/task_log/task_log_detail_page.dart'; import 'package:qinglong_app/module/others/task_log/task_log_detail_page.dart';
import 'package:qinglong_app/module/others/task_log/task_log_page.dart'; import 'package:qinglong_app/module/others/task_log/task_log_page.dart';
import 'package:qinglong_app/module/task/add_task_page.dart'; import 'package:qinglong_app/module/task/add_task_page.dart';
@@ -20,6 +22,8 @@ class Routes {
static const String routeLoginLog = "/log/login"; static const String routeLoginLog = "/log/login";
static const String routeTaskLog = "/log/task"; static const String routeTaskLog = "/log/task";
static const String routeTaskLogDetail = "/log/taskDetail"; static const String routeTaskLogDetail = "/log/taskDetail";
static const String routeScript = "/script";
static const String routeScriptDetail = "/script/detail";
static Route<dynamic>? generateRoute(RouteSettings settings) { static Route<dynamic>? generateRoute(RouteSettings settings) {
switch (settings.name) { switch (settings.name) {
@@ -60,11 +64,23 @@ class Routes {
return CupertinoPageRoute( return CupertinoPageRoute(
builder: (context) => const TaskLogPage(), builder: (context) => const TaskLogPage(),
); );
case routeScript:
return CupertinoPageRoute(
builder: (context) => const ScriptPage(),
);
case routeTaskLogDetail: case routeTaskLogDetail:
return CupertinoPageRoute( return CupertinoPageRoute(
builder: (context) => TaskLogDetailPage( builder: (context) => TaskLogDetailPage(
title: settings.arguments as String, title: settings.arguments as String,
)); ),
);
case routeScriptDetail:
return CupertinoPageRoute(
builder: (context) => ScriptDetailPage(
title: (settings.arguments as Map)["title"],
path: (settings.arguments as Map)["path"],
),
);
} }
return null; return null;

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
/// @author NewTab
mixin LazyLoadState<T extends StatefulWidget> on State<T> {
@override
void initState() {
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
var route = ModalRoute.of(context);
void handler(status) {
if (status == AnimationStatus.completed) {
route?.animation?.removeStatusListener(handler);
onLazyLoad();
}
}
if (route == null ||
route.animation == null ||
route.animation!.status == AnimationStatus.completed) {
onLazyLoad();
} else {
route.animation!.addStatusListener(handler);
}
});
}
void onLazyLoad();
}

View File

@@ -10,10 +10,8 @@ import 'package:qinglong_app/module/others/task_log/task_log_bean.dart';
import 'package:qinglong_app/module/task/task_bean.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_detail/task_detail_bean.dart';
class JsonConversion$Json { class JsonConversion$Json {
static M fromJson<M>(dynamic json) {
static M fromJson<M>(dynamic json) {
if (json is List) { if (json is List) {
return _getListChildType<M>(json); return _getListChildType<M>(json);
} else { } else {
@@ -22,85 +20,96 @@ class JsonConversion$Json {
} }
static M _fromJsonSingle<M>(dynamic json) { static M _fromJsonSingle<M>(dynamic json) {
String type = M.toString(); String type = M.toString();
if(type == (ConfigBean).toString()){ if (type == (ConfigBean).toString()) {
return ConfigBean.jsonConversion(json) as M; return ConfigBean.jsonConversion(json) as M;
} }
if(type == (EnvBean).toString()){ if (type == (EnvBean).toString()) {
return EnvBean.jsonConversion(json) as M; return EnvBean.jsonConversion(json) as M;
} }
if(type == (LoginBean).toString()){ if (type == (LoginBean).toString()) {
return LoginBean.jsonConversion(json) as M; return LoginBean.jsonConversion(json) as M;
} }
if(type == (DependencyBean).toString()){ if (type == (DependencyBean).toString()) {
return DependencyBean.jsonConversion(json) as M; return DependencyBean.jsonConversion(json) as M;
} }
if(type == (LoginLogBean).toString()){ if (type == (LoginLogBean).toString()) {
return LoginLogBean.jsonConversion(json) as M; return LoginLogBean.jsonConversion(json) as M;
} }
if(type == (ScriptBean).toString()){ if (type == (ScriptBean).toString()) {
return ScriptBean.jsonConversion(json) as M; return ScriptBean.jsonConversion(json) as M;
} }
if(type == (TaskLogBean).toString()){ if (type == (TaskLogBean).toString()) {
return TaskLogBean.jsonConversion(json) as M; return TaskLogBean.jsonConversion(json) as M;
} }
if(type == (TaskBean).toString()){ if (type == (TaskBean).toString()) {
return TaskBean.jsonConversion(json) as M; return TaskBean.jsonConversion(json) as M;
} }
if(type == (TaskDetailBean).toString()){ if (type == (TaskDetailBean).toString()) {
return TaskDetailBean.jsonConversion(json) as M; return TaskDetailBean.jsonConversion(json) as M;
} }
throw Exception("not found"); throw Exception("not found");
} }
static M _getListChildType<M>(List<dynamic> data) { static M _getListChildType<M>(List<dynamic> data) {
if(<ConfigBean>[] is M){ if (<ConfigBean>[] is M) {
return data.map<ConfigBean>((e) => ConfigBean.jsonConversion(e)).toList() as M; return data.map<ConfigBean>((e) => ConfigBean.jsonConversion(e)).toList()
as M;
} }
if(<EnvBean>[] is M){ if (<EnvBean>[] is M) {
return data.map<EnvBean>((e) => EnvBean.jsonConversion(e)).toList() as M; return data.map<EnvBean>((e) => EnvBean.jsonConversion(e)).toList() as M;
} }
if(<LoginBean>[] is M){ if (<LoginBean>[] is M) {
return data.map<LoginBean>((e) => LoginBean.jsonConversion(e)).toList() as M; return data.map<LoginBean>((e) => LoginBean.jsonConversion(e)).toList()
as M;
} }
if(<DependencyBean>[] is M){ if (<DependencyBean>[] is M) {
return data.map<DependencyBean>((e) => DependencyBean.jsonConversion(e)).toList() as M; return data
.map<DependencyBean>((e) => DependencyBean.jsonConversion(e))
.toList() as M;
} }
if(<LoginLogBean>[] is M){ if (<LoginLogBean>[] is M) {
return data.map<LoginLogBean>((e) => LoginLogBean.jsonConversion(e)).toList() as M; return data
.map<LoginLogBean>((e) => LoginLogBean.jsonConversion(e))
.toList() as M;
} }
if(<ScriptBean>[] is M){ if (<ScriptBean>[] is M) {
return data.map<ScriptBean>((e) => ScriptBean.jsonConversion(e)).toList() as M; return data.map<ScriptBean>((e) => ScriptBean.jsonConversion(e)).toList()
as M;
} }
if(<TaskLogBean>[] is M){ if (<TaskLogBean>[] is M) {
return data.map<TaskLogBean>((e) => TaskLogBean.jsonConversion(e)).toList() as M; return data
.map<TaskLogBean>((e) => TaskLogBean.jsonConversion(e))
.toList() as M;
} }
if(<TaskBean>[] is M){ if (<TaskBean>[] is M) {
return data.map<TaskBean>((e) => TaskBean.jsonConversion(e)).toList() as M; return data.map<TaskBean>((e) => TaskBean.jsonConversion(e)).toList()
as M;
} }
if(<TaskDetailBean>[] is M){ if (<TaskDetailBean>[] is M) {
return data.map<TaskDetailBean>((e) => TaskDetailBean.jsonConversion(e)).toList() as M; return data
.map<TaskDetailBean>((e) => TaskDetailBean.jsonConversion(e))
.toList() as M;
} }
throw Exception("not found"); throw Exception("not found");
} }
} }

View File

@@ -20,7 +20,8 @@ class LoginPage extends ConsumerStatefulWidget {
} }
class _LoginPageState extends ConsumerState<LoginPage> { class _LoginPageState extends ConsumerState<LoginPage> {
final TextEditingController _hostController = TextEditingController(text: getIt<UserInfoViewModel>().host); final TextEditingController _hostController =
TextEditingController(text: getIt<UserInfoViewModel>().host);
final TextEditingController _userNameController = TextEditingController(); final TextEditingController _userNameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController(); final TextEditingController _passwordController = TextEditingController();
@@ -30,13 +31,15 @@ class _LoginPageState extends ConsumerState<LoginPage> {
void initState() { void initState() {
super.initState(); super.initState();
if (getIt<UserInfoViewModel>().userName != null && getIt<UserInfoViewModel>().userName!.isNotEmpty) { if (getIt<UserInfoViewModel>().userName != null &&
getIt<UserInfoViewModel>().userName!.isNotEmpty) {
_userNameController.text = getIt<UserInfoViewModel>().userName!; _userNameController.text = getIt<UserInfoViewModel>().userName!;
rememberPassword = true; rememberPassword = true;
} else { } else {
rememberPassword = false; rememberPassword = false;
} }
if (getIt<UserInfoViewModel>().passWord != null && getIt<UserInfoViewModel>().passWord!.isNotEmpty) { if (getIt<UserInfoViewModel>().passWord != null &&
getIt<UserInfoViewModel>().passWord!.isNotEmpty) {
_passwordController.text = getIt<UserInfoViewModel>().passWord!; _passwordController.text = getIt<UserInfoViewModel>().passWord!;
} }
getIt<UserInfoViewModel>().updateToken(""); getIt<UserInfoViewModel>().updateToken("");
@@ -196,15 +199,25 @@ class _LoginPageState extends ConsumerState<LoginPage> {
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width - 80, width: MediaQuery.of(context).size.width - 80,
child: IgnorePointer( child: IgnorePointer(
ignoring: _hostController.text.isEmpty || _userNameController.text.isEmpty || _passwordController.text.isEmpty || isLoading, ignoring: _hostController.text.isEmpty ||
_userNameController.text.isEmpty ||
_passwordController.text.isEmpty ||
isLoading,
child: CupertinoButton( child: CupertinoButton(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 5, vertical: 5,
), ),
color: color: (_hostController.text.isNotEmpty &&
(_hostController.text.isNotEmpty && _userNameController.text.isNotEmpty && _passwordController.text.isNotEmpty && !isLoading) _userNameController.text.isNotEmpty &&
? ref.watch(themeProvider).themeColor.buttonBgColor() _passwordController.text.isNotEmpty &&
: Theme.of(context).primaryColor.withOpacity(0.4), !isLoading)
? ref
.watch(themeProvider)
.themeColor
.buttonBgColor()
: Theme.of(context)
.primaryColor
.withOpacity(0.4),
child: isLoading child: isLoading
? const CupertinoActivityIndicator() ? const CupertinoActivityIndicator()
: const Text( : const Text(
@@ -215,13 +228,17 @@ class _LoginPageState extends ConsumerState<LoginPage> {
), ),
onPressed: () { onPressed: () {
if (rememberPassword) { if (rememberPassword) {
getIt<UserInfoViewModel>().updateUserName(_userNameController.text, _passwordController.text); getIt<UserInfoViewModel>().updateUserName(
_userNameController.text,
_passwordController.text);
} }
Http.pushedLoginPage = false; Http.pushedLoginPage = false;
Utils.hideKeyBoard(context); Utils.hideKeyBoard(context);
getIt<UserInfoViewModel>().updateHost(_hostController.text); getIt<UserInfoViewModel>()
login(_userNameController.text, _passwordController.text); .updateHost(_hostController.text);
login(_userNameController.text,
_passwordController.text);
}), }),
), ),
), ),

View File

@@ -14,13 +14,13 @@ class DependencyBean {
DependencyBean( DependencyBean(
{this.sId, {this.sId,
this.created, this.created,
this.status, this.status,
this.type, this.type,
this.timestamp, this.timestamp,
this.name, this.name,
this.log, this.log,
this.remark}); this.remark});
DependencyBean.fromJson(Map<String, dynamic> json) { DependencyBean.fromJson(Map<String, dynamic> json) {
sId = json['_id']; sId = json['_id'];
@@ -45,6 +45,7 @@ class DependencyBean {
data['remark'] = this.remark; data['remark'] = this.remark;
return data; return data;
} }
static DependencyBean jsonConversion(Map<String, dynamic> json) { static DependencyBean jsonConversion(Map<String, dynamic> json) {
return DependencyBean.fromJson(json); return DependencyBean.fromJson(json);
} }

View File

@@ -9,7 +9,8 @@ class LoginLogBean {
String? platform; String? platform;
int? status; //0代表成功,1代表失败 int? status; //0代表成功,1代表失败
LoginLogBean({this.timestamp, this.address, this.ip, this.platform, this.status}); LoginLogBean(
{this.timestamp, this.address, this.ip, this.platform, this.status});
LoginLogBean.fromJson(Map<String, dynamic> json) { LoginLogBean.fromJson(Map<String, dynamic> json) {
timestamp = json['timestamp']; timestamp = json['timestamp'];

View File

@@ -38,28 +38,39 @@ class _OtherPageState extends ConsumerState<OtherPage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( GestureDetector(
padding: const EdgeInsets.only( behavior: HitTestBehavior.opaque,
top: 12, onTap: () {
bottom: 8, Navigator.of(context).pushNamed(
left: 15, Routes.routeScript,
right: 15, );
), },
child: Row( child: Padding(
children: [ padding: const EdgeInsets.only(
Text( top: 12,
"脚本管理", bottom: 8,
style: TextStyle( left: 15,
color: ref.watch(themeProvider).themeColor.taskTitleColor(), right: 15,
fontSize: 16, ),
child: Row(
children: [
Text(
"脚本管理",
style: TextStyle(
color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16,
),
), ),
), const Spacer(),
const Spacer(), const Icon(
const Icon( CupertinoIcons.right_chevron,
CupertinoIcons.right_chevron, size: 16,
size: 16, ),
), ],
], ),
), ),
), ),
const Divider( const Divider(
@@ -75,7 +86,10 @@ class _OtherPageState extends ConsumerState<OtherPage> {
Text( Text(
"依赖管理", "依赖管理",
style: TextStyle( style: TextStyle(
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16, fontSize: 16,
), ),
), ),
@@ -107,7 +121,10 @@ class _OtherPageState extends ConsumerState<OtherPage> {
Text( Text(
"任务日志", "任务日志",
style: TextStyle( style: TextStyle(
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16, fontSize: 16,
), ),
), ),
@@ -141,7 +158,10 @@ class _OtherPageState extends ConsumerState<OtherPage> {
Text( Text(
"登录日志", "登录日志",
style: TextStyle( style: TextStyle(
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16, fontSize: 16,
), ),
), ),
@@ -186,7 +206,10 @@ class _OtherPageState extends ConsumerState<OtherPage> {
Text( Text(
"夜间模式", "夜间模式",
style: TextStyle( style: TextStyle(
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16, fontSize: 16,
), ),
), ),
@@ -218,7 +241,8 @@ class _OtherPageState extends ConsumerState<OtherPage> {
), ),
onPressed: () { onPressed: () {
getIt<UserInfoViewModel>().updateToken(""); getIt<UserInfoViewModel>().updateToken("");
Navigator.of(context).pushReplacementNamed(Routes.routeLogin); Navigator.of(context)
.pushReplacementNamed(Routes.routeLogin);
}), }),
), ),
), ),

View File

@@ -12,11 +12,11 @@ class ScriptBean {
ScriptBean( ScriptBean(
{this.title, {this.title,
this.value, this.value,
this.key, this.key,
this.mtime, this.mtime,
this.disabled, this.disabled,
this.children}); this.children});
ScriptBean.fromJson(Map<String, dynamic> json) { ScriptBean.fromJson(Map<String, dynamic> json) {
title = json['title']; title = json['title'];
@@ -44,10 +44,10 @@ class ScriptBean {
} }
return data; return data;
} }
static ScriptBean jsonConversion(Map<String, dynamic> json) { static ScriptBean jsonConversion(Map<String, dynamic> json) {
return ScriptBean.fromJson(json); return ScriptBean.fromJson(json);
} }
} }
class ScriptChildren { class ScriptChildren {

View File

@@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
import 'package:flutter_highlight/flutter_highlight.dart';
import 'package:flutter_riverpod/flutter_riverpod.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/base/theme.dart';
import 'package:qinglong_app/base/ui/lazy_load_state.dart';
import 'package:qinglong_app/module/others/task_log/task_log_bean.dart';
import 'package:qinglong_app/utils/extension.dart';
/// @author NewTab
class ScriptDetailPage extends ConsumerStatefulWidget {
final String title;
final String? path;
const ScriptDetailPage({
Key? key,
required this.title,
this.path,
}) : super(key: key);
@override
_ScriptDetailPageState createState() => _ScriptDetailPageState();
}
class _ScriptDetailPageState extends ConsumerState<ScriptDetailPage>
with LazyLoadState<ScriptDetailPage> {
String? content;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: QlAppBar(
canBack: true,
backCall: () {
Navigator.of(context).pop();
},
title: "脚本详情",
),
body: SingleChildScrollView(
child: HighlightView(
content ?? "",
language: getLanguageType(widget.title),
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
theme: ref.watch(themeProvider).themeColor.codeEditorTheme(),
tabSize: 14,
),
),
);
}
Future<void> loadData() async {
HttpResponse<String> response = await Api.scriptDetail(
widget.title,
widget.path,
);
if (response.success) {
content = response.bean;
setState(() {});
} else {
response.message?.toast();
}
}
getLanguageType(String title) {
if (title.endsWith(".js")) {
return "js";
}
if (title.endsWith(".sh")) {
return "sh";
}
if (title.endsWith(".py")) {
return "py";
}
if (title.endsWith(".json")) {
return "json";
}
if (title.endsWith(".yaml")) {
return "yaml";
}
return "html";
}
@override
void onLazyLoad() {
loadData();
}
}

View File

@@ -1,15 +1,30 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.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/base/ql_app_bar.dart';
import 'package:qinglong_app/base/routes.dart';
import 'package:qinglong_app/base/theme.dart';
import 'package:qinglong_app/module/others/scripts/script_bean.dart';
import 'package:qinglong_app/utils/extension.dart';
/// @author NewTab /// @author NewTab
class ScriptPage extends StatefulWidget { class ScriptPage extends ConsumerStatefulWidget {
const ScriptPage({Key? key}) : super(key: key); const ScriptPage({Key? key}) : super(key: key);
@override @override
_ScriptPageState createState() => _ScriptPageState(); _ScriptPageState createState() => _ScriptPageState();
} }
class _ScriptPageState extends State<ScriptPage> { class _ScriptPageState extends ConsumerState<ScriptPage> {
List<ScriptBean> list = [];
@override
void initState() {
super.initState();
loadData();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -20,7 +35,94 @@ class _ScriptPageState extends State<ScriptPage> {
}, },
title: "脚本管理", title: "脚本管理",
), ),
body: Container(), body: ListView.builder(
itemBuilder: (context, index) {
ScriptBean item = list[index];
return ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: (item.children != null && item.children!.isNotEmpty)
? ExpansionTile(
title: Text(
item.title ?? "",
style: TextStyle(
color: (item.disabled ?? false)
? ref.watch(themeProvider).themeColor.descColor()
: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16,
),
),
children: item.children!
.map((e) => ListTile(
onTap: () {
Navigator.of(context).pushNamed(
Routes.routeScriptDetail,
arguments: {
"title": e.title,
"path": e.parent,
},
);
},
title: Text(
e.title ?? "",
style: TextStyle(
color: (item.disabled ?? false)
? ref
.watch(themeProvider)
.themeColor
.descColor()
: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 14,
),
),
))
.toList(),
)
: ListTile(
onTap: () {
Navigator.of(context).pushNamed(
Routes.routeScriptDetail,
arguments: {
"title": item.title,
"path": "",
},
);
},
title: Text(
item.title ?? "",
style: TextStyle(
color: (item.disabled ?? false)
? ref.watch(themeProvider).themeColor.descColor()
: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16,
),
),
),
);
},
itemCount: list.length,
),
); );
} }
Future<void> loadData() async {
HttpResponse<List<ScriptBean>> response = await Api.scripts();
if (response.success) {
list.clear();
list.addAll(response.bean ?? []);
setState(() {});
} else {
response.message?.toast();
}
}
} }

View File

@@ -44,7 +44,7 @@ class _TaskLogDetailPageState extends ConsumerState<TaskLogDetailPage> {
horizontal: 15, horizontal: 15,
), ),
child: SelectableText( child: SelectableText(
(content == null || content!.isEmpty)?"暂无数据":content!, (content == null || content!.isEmpty) ? "暂无数据" : content!,
), ),
), ),
); );

View File

@@ -46,19 +46,27 @@ class _TaskLogPageState extends ConsumerState<TaskLogPage> {
title: Text( title: Text(
item.name ?? "", item.name ?? "",
style: TextStyle( style: TextStyle(
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16, fontSize: 16,
), ),
), ),
children: item.files! children: item.files!
.map((e) => ListTile( .map((e) => ListTile(
onTap: () { onTap: () {
Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: e); Navigator.of(context).pushNamed(
Routes.routeTaskLogDetail,
arguments: e);
}, },
title: Text( title: Text(
e ?? "", e,
style: TextStyle( style: TextStyle(
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 14, fontSize: 14,
), ),
), ),
@@ -67,12 +75,16 @@ class _TaskLogPageState extends ConsumerState<TaskLogPage> {
) )
: ListTile( : ListTile(
onTap: () { onTap: () {
Navigator.of(context).pushNamed(Routes.routeTaskLogDetail, arguments: item.name); Navigator.of(context).pushNamed(Routes.routeTaskLogDetail,
arguments: item.name);
}, },
title: Text( title: Text(
item.name ?? "", item.name ?? "",
style: TextStyle( style: TextStyle(
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 16, fontSize: 16,
), ),
), ),

View File

@@ -104,7 +104,8 @@ class _TaskPageState extends State<TaskPage> {
if (_searchController.text.isEmpty || if (_searchController.text.isEmpty ||
(item.name?.contains(_searchController.text) ?? false) || (item.name?.contains(_searchController.text) ?? false) ||
(item.command?.contains(_searchController.text) ?? false) || (item.command?.contains(_searchController.text) ?? false) ||
(item.schedule?.contains(_searchController.text) ?? false)) { (item.schedule?.contains(_searchController.text) ??
false)) {
return TaskItemCell(item, ref); return TaskItemCell(item, ref);
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -174,7 +175,9 @@ class TaskItemCell extends StatelessWidget {
child: Text( child: Text(
bean.status! == 1 ? "运行" : "停止运行", bean.status! == 1 ? "运行" : "停止运行",
), ),
trailingIcon: bean.status! == 1 ? CupertinoIcons.memories : CupertinoIcons.stop_circle, trailingIcon: bean.status! == 1
? CupertinoIcons.memories
: CupertinoIcons.stop_circle,
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
startCron(context, ref); startCron(context, ref);
@@ -192,7 +195,8 @@ class TaskItemCell extends StatelessWidget {
child: const Text("编辑"), child: const Text("编辑"),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pushNamed(Routes.routeAddTask, arguments: bean); Navigator.of(context)
.pushNamed(Routes.routeAddTask, arguments: bean);
}, },
trailingIcon: CupertinoIcons.pencil_outline, trailingIcon: CupertinoIcons.pencil_outline,
), ),
@@ -202,7 +206,9 @@ class TaskItemCell extends StatelessWidget {
Navigator.of(context).pop(); Navigator.of(context).pop();
pinTask(); pinTask();
}, },
trailingIcon: bean.isPinned! == 0 ? CupertinoIcons.pin : CupertinoIcons.pin_slash, trailingIcon: bean.isPinned! == 0
? CupertinoIcons.pin
: CupertinoIcons.pin_slash,
), ),
QLCupertinoContextMenuAction( QLCupertinoContextMenuAction(
child: Text(bean.isDisabled! == 0 ? "禁用" : "启用"), child: Text(bean.isDisabled! == 0 ? "禁用" : "启用"),
@@ -211,7 +217,9 @@ class TaskItemCell extends StatelessWidget {
enableTask(); enableTask();
}, },
isDestructiveAction: true, isDestructiveAction: true,
trailingIcon: bean.isDisabled! == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp, trailingIcon: bean.isDisabled! == 0
? Icons.dnd_forwardslash
: Icons.check_circle_outline_sharp,
), ),
QLCupertinoContextMenuAction( QLCupertinoContextMenuAction(
child: const Text("删除"), child: const Text("删除"),
@@ -235,7 +243,8 @@ class TaskItemCell extends StatelessWidget {
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color:
ref.watch(themeProvider).themeColor.taskTitleColor(),
fontSize: 18, fontSize: 18,
), ),
), ),
@@ -245,10 +254,10 @@ class TaskItemCell extends StatelessWidget {
), ),
bean.isDisabled == 1 bean.isDisabled == 1
? const Icon( ? const Icon(
Icons.dnd_forwardslash, Icons.dnd_forwardslash,
size: 16, size: 16,
color: Colors.red, color: Colors.red,
) )
: const SizedBox.shrink(), : const SizedBox.shrink(),
], ],
), ),
@@ -259,7 +268,9 @@ class TaskItemCell extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
color: bean.isPinned == 1 ? ref.watch(themeProvider).themeColor.pinColor() : Colors.transparent, color: bean.isPinned == 1
? ref.watch(themeProvider).themeColor.pinColor()
: Colors.transparent,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 15, horizontal: 15,
vertical: 8, vertical: 8,
@@ -279,7 +290,10 @@ class TaskItemCell extends StatelessWidget {
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.taskTitleColor(), color: ref
.watch(themeProvider)
.themeColor
.taskTitleColor(),
fontSize: 18, fontSize: 18,
), ),
), ),
@@ -300,11 +314,16 @@ class TaskItemCell extends StatelessWidget {
Material( Material(
color: Colors.transparent, color: Colors.transparent,
child: Text( child: Text(
(bean.lastExecutionTime == null || bean.lastExecutionTime == 0) ? "-" : Utils.formatMessageTime(bean.lastExecutionTime!), (bean.lastExecutionTime == null ||
bean.lastExecutionTime == 0)
? "-"
: Utils.formatMessageTime(
bean.lastExecutionTime!),
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(), color:
ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12, fontSize: 12,
), ),
), ),
@@ -323,7 +342,8 @@ class TaskItemCell extends StatelessWidget {
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(), color:
ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12, fontSize: 12,
), ),
), ),