环境变量增加序号,详情页面

This commit is contained in:
jyuesong
2022-01-19 14:41:14 +08:00
parent 38a6790c51
commit 6185a92759
4 changed files with 493 additions and 121 deletions

View File

@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:qinglong_app/module/config/config_edit_page.dart';
import 'package:qinglong_app/module/env/add_env_page.dart';
import 'package:qinglong_app/module/env/env_bean.dart';
import 'package:qinglong_app/module/env/env_detail_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/others/dependencies/add_dependency_page.dart';
@@ -21,6 +22,7 @@ class Routes {
static const String routeLogin = "/login";
static const String routeAddTask = "/task/add";
static const String routeTaskDetail = "/task/detail";
static const String routeEnvDetail = "/env/detail";
static const String routeAddDependency = "/task/dependency";
static const String routeAddEnv = "/env/add";
static const String routeConfigEdit = "/config/edit";
@@ -98,6 +100,11 @@ class Routes {
builder: (context) => TaskDetailPage(
settings.arguments as TaskBean,
),
); case routeEnvDetail:
return CupertinoPageRoute(
builder: (context) => EnvDetailPage(
settings.arguments as EnvBean,
),
);
}

334
lib/module/env/env_detail_page.dart vendored Normal file
View File

@@ -0,0 +1,334 @@
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/env/env_bean.dart';
import 'package:qinglong_app/module/env/env_viewmodel.dart';
import 'package:qinglong_app/utils/utils.dart';
class EnvDetailPage extends ConsumerStatefulWidget {
final EnvBean envBean;
const EnvDetailPage(this.envBean, {Key? key}) : super(key: key);
@override
_TaskDetailPageState createState() => _TaskDetailPageState();
}
class _TaskDetailPageState extends ConsumerState<EnvDetailPage> {
List<Widget> actions = [];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
actions.clear();
actions.addAll(
[
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: widget.envBean);
},
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();
enableTask();
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 15,
),
alignment: Alignment.center,
child: Material(
color: Colors.transparent,
child: Text(
widget.envBean.status! == 0 ? "禁用" : "启用",
style: const TextStyle(
color: Colors.red,
fontSize: 16,
),
),
),
),
),
],
);
return Scaffold(
appBar: QlAppBar(
canBack: true,
backCall: () {
Navigator.of(context).pop();
},
title: widget.envBean.name ?? "",
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,
),
child: Center(
child: Icon(
Icons.more_horiz,
color: Colors.white,
size: 26,
),
),
),
)
],
),
body: SingleChildScrollView(
child: Column(
children: [
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: [
EnvDetailCell(
title: "ID",
desc: widget.envBean.sId ?? "",
),
EnvDetailCell(
title: "变量名称",
desc: widget.envBean.name ?? "",
),
EnvDetailCell(
title: "创建时间",
desc: Utils.formatMessageTime(widget.envBean.created ?? 0),
),
EnvDetailCell(
title: "更新时间",
desc: Utils.formatGMTTime(widget.envBean.timestamp ?? ""),
),
EnvDetailCell(
title: "",
desc: widget.envBean.value ?? "",
),
EnvDetailCell(
title: "备注",
desc: widget.envBean.remarks ?? "",
),
EnvDetailCell(
title: "变量状态",
desc: widget.envBean.status == 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,
),
],
),
),
);
}
void enableTask() async {
await ref.read(envProvider).enableEnv(widget.envBean.sId!, widget.envBean.status!);
setState(() {});
}
void delTask(BuildContext context, WidgetRef ref) {
showCupertinoDialog(
context: context,
builder: (context) => CupertinoAlertDialog(
title: const Text("确认删除"),
content: Text("确认删除环境变量 ${widget.envBean.name ?? ""}"),
actions: [
CupertinoDialogAction(
child: const Text("取消"),
onPressed: () {
Navigator.of(context).pop();
},
),
CupertinoDialogAction(
child: const Text("确定"),
onPressed: () async {
Navigator.of(context).pop();
await ref.read(envProvider).delEnv(widget.envBean.sId!);
Navigator.of(context).pop();
},
),
],
),
);
}
}
class EnvDetailCell extends ConsumerWidget {
final String title;
final String? desc;
final Widget? icon;
final bool hideDivide;
final Function? taped;
const EnvDetailCell({
Key? key,
required this.title,
this.desc,
this.icon,
this.hideDivide = false,
this.taped,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(
top: 10,
left: 15,
right: 10,
bottom: 10,
),
child: Row(
children: [
Text(
title,
style: TextStyle(
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 16,
),
),
const SizedBox(
width: 30,
),
desc != null
? Expanded(
child: Align(
alignment: Alignment.centerRight,
child: SelectableText(
desc!,
textAlign: TextAlign.right,
onTap: () {
if (taped != null) {
taped!();
}
},
style: TextStyle(
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 14,
),
),
),
)
: Expanded(
child: Align(alignment: Alignment.centerRight, child: icon!),
),
],
),
),
hideDivide
? const SizedBox.shrink()
: const Divider(
indent: 15,
),
],
);
}
}

View File

@@ -29,13 +29,15 @@ class _EnvPageState extends State<EnvPage> {
builder: (ref, model, child) {
List<EnvItemCell> list = [];
for (var value in model.list) {
for (int i = 0; i < model.list.length; i++) {
EnvBean value = model.list[i];
if (_searchController.text.isEmpty ||
(value.name?.contains(_searchController.text) ?? false) ||
(value.value?.contains(_searchController.text) ?? false) ||
(value.remarks?.contains(_searchController.text) ?? false)) {
list.add(EnvItemCell(
value,
i + 1,
ref,
key: ValueKey(value.sId),
));
@@ -124,120 +126,164 @@ class _EnvPageState extends State<EnvPage> {
class EnvItemCell extends StatelessWidget {
final EnvBean bean;
final int index;
final WidgetRef ref;
const EnvItemCell(this.bean, this.ref, {Key? key}) : super(key: key);
const EnvItemCell(this.bean, this.index, this.ref, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: Slidable(
key: ValueKey(bean.sId),
endActionPane: ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.45,
children: [
SlidableAction(
backgroundColor: Colors.grey,
flex: 1,
onPressed: (_) {
Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: bean);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.pencil,
),
SlidableAction(
backgroundColor: Colors.orange,
flex: 1,
onPressed: (_) {
enableEnv();
},
foregroundColor: Colors.white,
icon: bean.status == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
),
SlidableAction(
backgroundColor: Colors.red,
flex: 1,
onPressed: (_) {
delEnv(context, ref);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
),
],
),
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
return GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(Routes.routeEnvDetail, arguments: bean);
},
child: ColoredBox(
color: ref.watch(themeProvider).themeColor.settingBgColor(),
child: Slidable(
key: ValueKey(bean.sId),
endActionPane: ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.45,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Row(
children: [
Material(
SlidableAction(
backgroundColor: Colors.grey,
flex: 1,
onPressed: (_) {
Navigator.of(context).pushNamed(Routes.routeAddEnv, arguments: bean);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.pencil,
),
SlidableAction(
backgroundColor: Colors.orange,
flex: 1,
onPressed: (_) {
enableEnv();
},
foregroundColor: Colors.white,
icon: bean.status == 0 ? Icons.dnd_forwardslash : Icons.check_circle_outline_sharp,
),
SlidableAction(
backgroundColor: Colors.red,
flex: 1,
onPressed: (_) {
delEnv(context, ref);
},
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
),
],
),
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Row(
children: [
Material(
color: Colors.transparent,
child: Text(
bean.name ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 18,
),
),
),
const SizedBox(
width: 5,
),
bean.status == 1
? const Icon(
Icons.dnd_forwardslash,
size: 16,
color: Colors.red,
)
: const SizedBox.shrink(),
const Spacer(),
],
),
),
const SizedBox(
width: 5,
),
Material(
color: Colors.transparent,
child: Text(
Utils.formatGMTTime(bean.timestamp ?? ""),
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: primaryColor, width: 1),
),
child: Text(
"$index",
style: TextStyle(color: primaryColor, fontSize: 12),
),
),
const SizedBox(
width: 5,
),
Expanded(
child: Material(
color: Colors.transparent,
child: Text(
bean.name ?? "",
bean.remarks ?? "-",
maxLines: 1,
style: TextStyle(
height: 1,
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.titleColor(),
fontSize: 18,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
const SizedBox(
width: 5,
),
bean.status == 1
? const Icon(
Icons.dnd_forwardslash,
size: 16,
color: Colors.red,
)
: const SizedBox.shrink(),
const Spacer(),
],
),
),
const SizedBox(
width: 5,
),
Material(
color: Colors.transparent,
child: Text(
Utils.formatGMTTime(bean.timestamp ?? ""),
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
],
),
],
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Material(
),
const SizedBox(
height: 8,
),
Material(
color: Colors.transparent,
child: Text(
bean.remarks ?? "-",
bean.value ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
@@ -246,30 +292,15 @@ class EnvItemCell extends StatelessWidget {
),
),
),
),
const SizedBox(
height: 8,
),
Material(
color: Colors.transparent,
child: Text(
bean.value ?? "",
maxLines: 1,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: ref.watch(themeProvider).themeColor.descColor(),
fontSize: 12,
),
),
),
],
],
),
),
),
const Divider(
height: 1,
indent: 15,
),
],
const Divider(
height: 1,
indent: 15,
),
],
),
),
),
),

View File

@@ -48,7 +48,7 @@ class EnvViewModel extends BaseViewModel {
notifyListeners();
}
void enableEnv(String sId, int status) async {
Future<void> enableEnv(String sId, int status) async {
if (status == 1) {
HttpResponse<NullResponse> response = await Api.enableEnv(sId);