mirror of
https://github.com/qinglong-app/qinglong_app.git
synced 2025-10-09 16:48:19 +08:00
add config
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
|
|
||||||
import 'package:qinglong_app/base/http/http.dart';
|
import 'package:qinglong_app/base/http/http.dart';
|
||||||
|
import 'package:qinglong_app/module/config/config_bean.dart';
|
||||||
import 'package:qinglong_app/module/login/login_bean.dart';
|
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_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';
|
||||||
@@ -67,4 +68,15 @@ class Api {
|
|||||||
static Future<HttpResponse<NullResponse>> disableTask(String cron) async {
|
static Future<HttpResponse<NullResponse>> disableTask(String cron) async {
|
||||||
return await Http.put<NullResponse>(Url.DISABLE_TASK, [cron]);
|
return await Http.put<NullResponse>(Url.DISABLE_TASK, [cron]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<HttpResponse<List<ConfigBean>>> files() async {
|
||||||
|
return await Http.get<List<ConfigBean>>(Url.FILES, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<HttpResponse<String>> content(String name) async {
|
||||||
|
return await Http.get<String>(Url.CONFIG_CONTENT+name, null);
|
||||||
|
}
|
||||||
|
static Future<HttpResponse<NullResponse>> saveFile(String name,String content) async {
|
||||||
|
return await Http.post<NullResponse>(Url.SAVE_FILE, {"content":content,"name": name});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ class Url {
|
|||||||
static const UNPIN_TASK = "/api/crons/unpin";
|
static const UNPIN_TASK = "/api/crons/unpin";
|
||||||
static const ENABLE_TASK = "/api/crons/enable";
|
static const ENABLE_TASK = "/api/crons/enable";
|
||||||
static const DISABLE_TASK = "/api/crons/disable";
|
static const DISABLE_TASK = "/api/crons/disable";
|
||||||
|
static const FILES = "/api/configs/files";
|
||||||
|
static const CONFIG_CONTENT = "/api/configs/";
|
||||||
|
static const SAVE_FILE = "/api/configs/save";
|
||||||
|
|
||||||
static INTIME_LOG(String cronId) {
|
static INTIME_LOG(String cronId) {
|
||||||
return "/api/crons/$cronId/log";
|
return "/api/crons/$cronId/log";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qinglong_app/module/config/config_edit_page.dart';
|
||||||
import 'package:qinglong_app/module/home/home_page.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/add_task_page.dart';
|
||||||
import 'package:qinglong_app/module/task/task_bean.dart';
|
import 'package:qinglong_app/module/task/task_bean.dart';
|
||||||
@@ -7,6 +8,7 @@ import 'package:qinglong_app/module/task/task_bean.dart';
|
|||||||
class Routes {
|
class Routes {
|
||||||
static const String route_HomePage = "/home/homepage";
|
static const String route_HomePage = "/home/homepage";
|
||||||
static const String route_AddTask = "/task/add";
|
static const String route_AddTask = "/task/add";
|
||||||
|
static const String route_ConfigEdit = "/config/edit";
|
||||||
|
|
||||||
static Route<dynamic>? generateRoute(RouteSettings settings) {
|
static Route<dynamic>? generateRoute(RouteSettings settings) {
|
||||||
switch (settings.name) {
|
switch (settings.name) {
|
||||||
@@ -19,8 +21,15 @@ class Routes {
|
|||||||
taskBean: settings.arguments as TaskBean,
|
taskBean: settings.arguments as TaskBean,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
return CupertinoPageRoute(builder: (context) => AddTaskPage());
|
return CupertinoPageRoute(builder: (context) => const AddTaskPage());
|
||||||
}
|
}
|
||||||
|
case route_ConfigEdit:
|
||||||
|
return CupertinoPageRoute(
|
||||||
|
builder: (context) => ConfigEditPage(
|
||||||
|
(settings.arguments as Map)["title"],
|
||||||
|
(settings.arguments as Map)["content"],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
import 'package:qinglong_app/module/config/config_bean.dart';
|
||||||
import 'package:qinglong_app/module/login/login_bean.dart';
|
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_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';
|
||||||
@@ -19,6 +20,10 @@ class JsonConversion$Json {
|
|||||||
|
|
||||||
String type = M.toString();
|
String type = M.toString();
|
||||||
|
|
||||||
|
if(type == (ConfigBean).toString()){
|
||||||
|
return ConfigBean.jsonConversion(json) as M;
|
||||||
|
}
|
||||||
|
|
||||||
if(type == (LoginBean).toString()){
|
if(type == (LoginBean).toString()){
|
||||||
return LoginBean.jsonConversion(json) as M;
|
return LoginBean.jsonConversion(json) as M;
|
||||||
}
|
}
|
||||||
@@ -35,7 +40,11 @@ class JsonConversion$Json {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static M _getListChildType<M>(List<dynamic> data) {
|
static M _getListChildType<M>(List<dynamic> data) {
|
||||||
if(<LoginBean>[] is M){
|
if(<ConfigBean>[] is M){
|
||||||
|
return data.map<ConfigBean>((e) => ConfigBean.jsonConversion(e)).toList() as 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
lib/module/config/config_bean.dart
Normal file
25
lib/module/config/config_bean.dart
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:json_conversion_annotation/json_conversion_annotation.dart';
|
||||||
|
|
||||||
|
@JsonConversion()
|
||||||
|
class ConfigBean {
|
||||||
|
|
||||||
|
String? title;
|
||||||
|
String? value;
|
||||||
|
|
||||||
|
ConfigBean({this.title, this.value});
|
||||||
|
|
||||||
|
ConfigBean.fromJson(Map<String, dynamic> json) {
|
||||||
|
title = json['title'];
|
||||||
|
value = json['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['title'] = this.title;
|
||||||
|
data['value'] = this.value;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
static ConfigBean jsonConversion(Map<String, dynamic> json) {
|
||||||
|
return ConfigBean.fromJson(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
83
lib/module/config/config_edit_page.dart
Normal file
83
lib/module/config/config_edit_page.dart
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import 'package:code_editor/code_editor.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.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/config/config_viewmodel.dart';
|
||||||
|
|
||||||
|
class ConfigEditPage extends ConsumerStatefulWidget {
|
||||||
|
final String content;
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
const ConfigEditPage(this.title, this.content, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ConfigEditPageState createState() => _ConfigEditPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConfigEditPageState extends ConsumerState<ConfigEditPage> {
|
||||||
|
String? value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<FileEditor> files = [
|
||||||
|
FileEditor(
|
||||||
|
name: widget.title,
|
||||||
|
language: "sh",
|
||||||
|
code: widget.content, // [code] needs a string
|
||||||
|
),
|
||||||
|
];
|
||||||
|
EditorModel editMode = EditorModel(
|
||||||
|
files: files,
|
||||||
|
styleOptions: EditorModelStyleOptions(
|
||||||
|
fontSize: 13,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: QlAppBar(
|
||||||
|
canBack: true,
|
||||||
|
backCall: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
title: '编辑文件',
|
||||||
|
actions: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
if (value == null) {
|
||||||
|
failDialog(context, "请先点击保存");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HttpResponse<NullResponse> response = await Api.saveFile(widget.title, value!);
|
||||||
|
if (response.success) {
|
||||||
|
ref.read(configProvider).loadContent(widget.title);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
} else {
|
||||||
|
failDialog(context, response.message ?? "");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 15,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text("提交"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: CodeEditor(
|
||||||
|
model: editMode,
|
||||||
|
edit: true,
|
||||||
|
onSubmit: (title, v) {
|
||||||
|
value = v;
|
||||||
|
},
|
||||||
|
disableNavigationbar: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,11 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qinglong_app/base/base_state_widget.dart';
|
||||||
|
import 'package:code_editor/code_editor.dart';
|
||||||
|
import 'package:qinglong_app/base/routes.dart';
|
||||||
|
import 'package:qinglong_app/base/theme.dart';
|
||||||
|
|
||||||
|
import 'config_viewmodel.dart';
|
||||||
|
|
||||||
class ConfigPage extends StatefulWidget {
|
class ConfigPage extends StatefulWidget {
|
||||||
const ConfigPage({Key? key}) : super(key: key);
|
const ConfigPage({Key? key}) : super(key: key);
|
||||||
@@ -8,8 +15,72 @@ class ConfigPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ConfigPageState extends State<ConfigPage> {
|
class _ConfigPageState extends State<ConfigPage> {
|
||||||
|
final myController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold();
|
return BaseStateWidget<ConfigViewModel>(
|
||||||
|
builder: (ref, model, child) {
|
||||||
|
List<FileEditor> files = [
|
||||||
|
FileEditor(
|
||||||
|
name: model.title,
|
||||||
|
language: "sh",
|
||||||
|
code: model.content, // [code] needs a string
|
||||||
|
),
|
||||||
|
];
|
||||||
|
EditorModel editMode = EditorModel(
|
||||||
|
files: files,
|
||||||
|
styleOptions: EditorModelStyleOptions(
|
||||||
|
fontSize: 13,
|
||||||
|
heightOfContainer: MediaQuery.of(context).size.height - kToolbarHeight - kBottomNavigationBarHeight - 150,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
myController.text = model.content;
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
DropdownButton<String>(
|
||||||
|
value: model.title,
|
||||||
|
items: model.list
|
||||||
|
.map(
|
||||||
|
(e) => DropdownMenuItem<String>(
|
||||||
|
value: e.value ?? "",
|
||||||
|
child: Text(e.value ?? ""),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
onChanged: (value) {
|
||||||
|
model.loadContent(value!);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
CupertinoButton(
|
||||||
|
child: const Text("编辑"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pushNamed(Routes.route_ConfigEdit, arguments: {
|
||||||
|
"title": model.title,
|
||||||
|
"content": model.content,
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CodeEditor(
|
||||||
|
model: editMode,
|
||||||
|
edit: false,
|
||||||
|
textEditingController: myController,
|
||||||
|
disableNavigationbar: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
model: configProvider,
|
||||||
|
onReady: (viewModel) {
|
||||||
|
viewModel.loadData();
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
lib/module/config/config_viewmodel.dart
Normal file
46
lib/module/config/config_viewmodel.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
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/config/config_bean.dart';
|
||||||
|
|
||||||
|
var configProvider = ChangeNotifierProvider((ref) => ConfigViewModel());
|
||||||
|
|
||||||
|
class ConfigViewModel extends BaseViewModel {
|
||||||
|
List<ConfigBean> list = [];
|
||||||
|
|
||||||
|
String content = "";
|
||||||
|
String title = "";
|
||||||
|
|
||||||
|
Future<void> loadData([isLoading = true]) async {
|
||||||
|
if (isLoading) {
|
||||||
|
loading(notify: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse<List<ConfigBean>> result = await Api.files();
|
||||||
|
|
||||||
|
if (result.success && result.bean != null) {
|
||||||
|
list.clear();
|
||||||
|
list.addAll(result.bean!);
|
||||||
|
title = list[0].value!;
|
||||||
|
success();
|
||||||
|
loadContent(list[0].value!);
|
||||||
|
} else {
|
||||||
|
list.clear();
|
||||||
|
failed(result.message, notify: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadContent(String name) async {
|
||||||
|
title = name;
|
||||||
|
notifyListeners();
|
||||||
|
HttpResponse<String> result = await Api.content(name);
|
||||||
|
|
||||||
|
if (result.success && result.bean != null) {
|
||||||
|
content = result.bean!;
|
||||||
|
success();
|
||||||
|
} else {
|
||||||
|
failToast(result.message, notify: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
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';
|
||||||
@@ -9,7 +7,6 @@ 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/task/intime_log/intime_log_page.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_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/module/task/task_viewmodel.dart';
|
||||||
import 'package:qinglong_app/utils/utils.dart';
|
import 'package:qinglong_app/utils/utils.dart';
|
||||||
|
|
||||||
@@ -21,8 +18,8 @@ class TaskPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TaskPageState extends State<TaskPage> {
|
class _TaskPageState extends State<TaskPage> {
|
||||||
String? _searchKey = null;
|
String? _searchKey;
|
||||||
TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|||||||
28
pubspec.lock
28
pubspec.lock
@@ -141,6 +141,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.1.0"
|
||||||
|
code_editor:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: code_editor
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -223,6 +230,13 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_highlight:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_highlight
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@@ -254,6 +268,13 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
font_awesome_flutter:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: font_awesome_flutter
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "9.2.0"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -275,6 +296,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
highlight:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: highlight
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.0"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ dependencies:
|
|||||||
json_conversion_annotation: ^0.0.4
|
json_conversion_annotation: ^0.0.4
|
||||||
logger: ^1.1.0
|
logger: ^1.1.0
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
|
code_editor: ^1.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.0.0
|
build_runner: ^2.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user