This commit is contained in:
zhutao
2025-09-05 18:00:26 +08:00
parent 70aa3e6ab6
commit 193d29b0ce
23 changed files with 1071 additions and 338 deletions

View File

@@ -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,
),
],
),
),
),

View File

@@ -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), // 右边图标
],
);
}
}

View 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,
),
),
);
}
}