1
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:plan/api/dto/plan_item_dto.dart';
|
||||
import 'package:plan/api/endpoints/plan_api.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
import 'widgets/history_item.dart';
|
||||
import '../../../widgets/ui_kit/popup/popup_action.dart';
|
||||
import 'widgets/loading_box.dart';
|
||||
|
||||
class PlanHistoryPage extends StatefulWidget {
|
||||
const PlanHistoryPage({super.key});
|
||||
@@ -16,12 +19,23 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
|
||||
///是否显示删除
|
||||
bool _isDelete = false;
|
||||
|
||||
///数据
|
||||
List<PlanItemDto> _record = [];
|
||||
bool _isInit = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_onRefresh();
|
||||
}
|
||||
|
||||
///刷新
|
||||
Future<void> _onRefresh() async {
|
||||
//模拟网络请求
|
||||
await Future.delayed(Duration(milliseconds: 1000));
|
||||
//结束刷新
|
||||
return Future.value(true);
|
||||
var list = await getPlanListApi();
|
||||
setState(() {
|
||||
_record = list;
|
||||
_isInit = false;
|
||||
});
|
||||
}
|
||||
|
||||
///popup事件
|
||||
@@ -36,7 +50,14 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
|
||||
}
|
||||
|
||||
///确认删除
|
||||
void _confirmDelete(int id) {}
|
||||
void _confirmDelete(int id) {
|
||||
print(_record.map((e) => e.toJson()));
|
||||
setState(() {
|
||||
_record.removeWhere((element) => element.id == id);
|
||||
print(_record.map((e) => e.toJson()));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -44,19 +65,6 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
|
||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: const Text("计划历史"),
|
||||
trailing: PopupAction(
|
||||
onSelected: _onPopupActionSelected,
|
||||
items: [
|
||||
PopupMenuItem(
|
||||
value: 'edit',
|
||||
child: Text(
|
||||
_isDelete ? "完成" : "编辑",
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: Icon(RemixIcons.more_fill),
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: CustomScrollView(
|
||||
@@ -69,36 +77,28 @@ class _PlanHistoryPageState extends State<PlanHistoryPage> {
|
||||
onRefresh: _onRefresh,
|
||||
),
|
||||
//列表
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: CustomScrollView(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverList.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return HistoryItem(
|
||||
showDelete: _isDelete,
|
||||
onDelete: _confirmDelete,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
);
|
||||
},
|
||||
itemCount: 5,
|
||||
),
|
||||
],
|
||||
),
|
||||
LoadingBox(
|
||||
loading: _isInit,
|
||||
isEmpty: _record.isEmpty,
|
||||
child: ClipRRect(
|
||||
child: CustomScrollView(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverList.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return HistoryItem(
|
||||
item: _record[index],
|
||||
showDelete: _isDelete,
|
||||
onDelete: _confirmDelete,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return SizedBox(height: 15);
|
||||
},
|
||||
itemCount: _record.length,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:plan/api/dto/plan_item_dto.dart';
|
||||
import 'package:plan/api/endpoints/plan_api.dart';
|
||||
import 'package:plan/router/config/route_paths.dart';
|
||||
import 'package:plan/utils/format.dart';
|
||||
import 'package:plan/widgets/business/delete_row_item.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
import '../../widgets/edit_desc_dialog.dart';
|
||||
|
||||
class HistoryItem extends StatefulWidget {
|
||||
final PlanItemDto item;
|
||||
final bool showDelete;
|
||||
final Function(int) onDelete;
|
||||
|
||||
const HistoryItem({
|
||||
super.key,
|
||||
required this.item,
|
||||
this.showDelete = false,
|
||||
required this.onDelete,
|
||||
});
|
||||
@@ -19,73 +27,139 @@ class HistoryItem extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _HistoryItemState extends State<HistoryItem> {
|
||||
late PlanItemDto _data;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_data = widget.item;
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant HistoryItem oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.item != widget.item) {
|
||||
setState(() {
|
||||
_data = widget.item;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
///跳转详情
|
||||
void _goDetail() {
|
||||
context.push(RoutePaths.planDetail(1));
|
||||
context.push(RoutePaths.planDetail(_data.id));
|
||||
}
|
||||
|
||||
///编辑摘要
|
||||
void _handEdit() {
|
||||
context.pop();
|
||||
showEditDescDialog(
|
||||
context,
|
||||
value: _data.summary ?? "",
|
||||
onConfirm: (value) async {
|
||||
setState(() {
|
||||
_data.summary = value;
|
||||
});
|
||||
await editPlanSummaryApi(_data.id!, value);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
///删除计划
|
||||
void _handDelete() async {
|
||||
context.pop();
|
||||
widget.onDelete(_data.id!);
|
||||
await deletePlanApi(_data.id!);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: _goDetail,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.symmetric(vertical: 15),
|
||||
color: Colors.white,
|
||||
child: DeleteRowItem(
|
||||
showDelete: widget.showDelete,
|
||||
onDelete: () {
|
||||
widget.onDelete(0);
|
||||
},
|
||||
builder: (_, __) {
|
||||
return [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 5),
|
||||
child: Text("开始学习软件开发"),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 5),
|
||||
child: Text(
|
||||
"创建于 2025/9/3 9:40:51 教练:W教练",
|
||||
style: Theme.of(context).textTheme.labelSmall,
|
||||
return CupertinoContextMenu(
|
||||
actions: [
|
||||
// 编辑摘要
|
||||
CupertinoContextMenuAction(
|
||||
onPressed: _handEdit,
|
||||
child: _actionItem(
|
||||
"Edit Summary",
|
||||
CupertinoIcons.pencil,
|
||||
),
|
||||
),
|
||||
CupertinoContextMenuAction(
|
||||
isDestructiveAction: true,
|
||||
onPressed: _handDelete,
|
||||
child: _actionItem(
|
||||
"Delete Summary",
|
||||
CupertinoIcons.delete,
|
||||
),
|
||||
),
|
||||
],
|
||||
child: GestureDetector(
|
||||
onTap: _goDetail,
|
||||
child: Container(
|
||||
width: 400,
|
||||
margin: EdgeInsets.symmetric(horizontal: 15),
|
||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 15),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 5),
|
||||
child: Text(_data.summary ?? ""),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Expanded(
|
||||
child: LinearProgressIndicator(
|
||||
value: 0.5,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
child: Text(
|
||||
"${formatDateUS(_data.createdAt!, withTime: true)} · Coach ${_data.agentName ?? ""}",
|
||||
style: Theme.of(context).textTheme.labelSmall, // 小号文字
|
||||
),
|
||||
),
|
||||
Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Expanded(
|
||||
child: LinearProgressIndicator(
|
||||
value: (_data.completedSteps! / _data.totalSteps!),
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"0/7",
|
||||
style: Theme.of(context).textTheme.labelSmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
Text(
|
||||
"${_data.completedSteps}/${_data.totalSteps}",
|
||||
style: Theme.of(context).textTheme.labelSmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
RemixIcons.arrow_right_s_line,
|
||||
size: 30,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
];
|
||||
},
|
||||
Icon(
|
||||
RemixIcons.arrow_right_s_line,
|
||||
size: 30,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _actionItem(String title, IconData icon) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(title),
|
||||
Icon(icon, size: 20), // 右边图标
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
48
lib/page/plan/history/widgets/loading_box.dart
Normal file
48
lib/page/plan/history/widgets/loading_box.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:plan/widgets/ui_kit/empty/index.dart';
|
||||
|
||||
class LoadingBox extends StatelessWidget {
|
||||
final bool loading;
|
||||
final bool isEmpty;
|
||||
final Widget child;
|
||||
|
||||
const LoadingBox({
|
||||
super.key,
|
||||
required this.loading,
|
||||
required this.isEmpty,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
///加载中
|
||||
if (loading) {
|
||||
return SliverFillRemaining(
|
||||
child: Center(
|
||||
child: CupertinoActivityIndicator(
|
||||
radius: 14,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///空状态
|
||||
if (isEmpty) {
|
||||
return SliverFillRemaining(
|
||||
child: Empty(
|
||||
title: "No data",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///正常
|
||||
return SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||
child: Container(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user