|
|
@@ -0,0 +1,293 @@
|
|
|
+import 'package:common_pub/ui/history_detail/trace_bar.dart';
|
|
|
+import 'package:common_pub/ui/map_view/map_view.dart';
|
|
|
+import 'package:common_pub/ui/map_view/view_map_cp.dart';
|
|
|
+import 'package:common_pub/ui/map_view/view_map_image.dart';
|
|
|
+import 'package:common_pub/ui/map_view/view_map_touch.dart';
|
|
|
+import 'package:common_pub/ui/map_view/view_map_trace.dart';
|
|
|
+import 'package:common_pub/ui/map_view/view_plug_loading.dart';
|
|
|
+import 'package:track_common/service/map_watch.dart';
|
|
|
+import 'package:track_common/widget/prelude.dart';
|
|
|
+
|
|
|
+import 'data_detail_bar_charts.dart';
|
|
|
+import 'data_detail_controller.dart';
|
|
|
+import 'data_detail_cp.dart';
|
|
|
+
|
|
|
+class DataDetailPage extends GetView<DataDetailController> {
|
|
|
+ const DataDetailPage({super.key});
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final mapWatch = controller.mapWatch;
|
|
|
+
|
|
|
+ return Container(
|
|
|
+ height: double.infinity,
|
|
|
+ width: double.infinity,
|
|
|
+ color: const Color(0xffc9c0c0),
|
|
|
+ alignment: Alignment.center,
|
|
|
+ child: mapWatch != null ? content(context, mapWatch) : noData());
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget noData() {
|
|
|
+ return Center(
|
|
|
+ child: Column(
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
+ children: [
|
|
|
+ Image.asset(Assets.imagesIcNoData, height: 64, package: package),
|
|
|
+ const SizedBox(height: 25),
|
|
|
+ const Text('没有数据, 请选择地图',
|
|
|
+ style: TextStyle(color: Color(0xff707070), fontSize: 18.5)),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ static const cpColor = Color(0xffcc00ff);
|
|
|
+
|
|
|
+ Widget content(BuildContext context, MapWatch map) {
|
|
|
+ return Obx(() {
|
|
|
+ return Row(children: [
|
|
|
+ Expanded(
|
|
|
+ child: Column(
|
|
|
+ children: [
|
|
|
+ Expanded(
|
|
|
+ child: ViewMapStack(
|
|
|
+ plug: map.plugMap,
|
|
|
+ children: [SizedBox.expand(child: _MapContent())])),
|
|
|
+ _traceBarView()
|
|
|
+ ],
|
|
|
+ )),
|
|
|
+ _UserListView()
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _traceBarView() {
|
|
|
+ final detail = controller.selectedDetail.value;
|
|
|
+ final children = <Widget>[];
|
|
|
+
|
|
|
+ if (detail != null) {
|
|
|
+ final data =
|
|
|
+ detail.traceList.map((e) => TraceBarData(e.pace)..ts = e.ts).toList();
|
|
|
+
|
|
|
+ children.addAll([
|
|
|
+ const SizedBox(height: 8),
|
|
|
+ const Text('配速(按时间)'),
|
|
|
+ TraceBar(
|
|
|
+ data,
|
|
|
+ controller: controller.traceBarController,
|
|
|
+ direction: Axis.horizontal,
|
|
|
+ trackWidth: 10,
|
|
|
+ paddingStart: 100,
|
|
|
+ paddingEnd: 100,
|
|
|
+ mask: true,
|
|
|
+ isShowCp: true,
|
|
|
+ cpList: detail.controlPoints,
|
|
|
+ ),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return Container(
|
|
|
+ decoration: const BoxDecoration(color: Colors.white),
|
|
|
+ height: 73,
|
|
|
+ width: double.infinity,
|
|
|
+ child: Column(children: children),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _MapContent extends GetView<DataDetailController> {
|
|
|
+ static const cpColor = Color(0xffcc00ff);
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return Obx(() {
|
|
|
+ final map = controller.mapWatch!;
|
|
|
+
|
|
|
+ final children = <Widget>[
|
|
|
+ ViewPlugLoading(map.plugMap),
|
|
|
+ ViewMapImage(map.plugMap),
|
|
|
+ ];
|
|
|
+ final data = controller.selectedDetail.value;
|
|
|
+ if (data != null) {
|
|
|
+ children.add(
|
|
|
+ Container(
|
|
|
+ color: Colors.white.withAlpha(120),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+
|
|
|
+ if (controller.selectedLoading.value) {
|
|
|
+ children.add(const Center(child: CircularProgressIndicator()));
|
|
|
+ } else {
|
|
|
+ children.add(ViewMapCP(
|
|
|
+ key: UniqueKey(),
|
|
|
+ map.plugMap,
|
|
|
+ cpWantAndHistoryList: data.controlPoints,
|
|
|
+ isHideRouteBeforeStart: false,
|
|
|
+ isShowPath: false,
|
|
|
+ cpTheme: ViewMapCPTheme()
|
|
|
+ ..cpJumpColor = cpColor
|
|
|
+ ..cpPunchedColor = cpColor,
|
|
|
+ ));
|
|
|
+
|
|
|
+ children.add(ViewMapTrace(
|
|
|
+ key: UniqueKey(),
|
|
|
+ map.plugMap,
|
|
|
+ data.traceList,
|
|
|
+ controller: controller.viewMapTraceController));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ children.add(ViewMapTouch(map.plugMap));
|
|
|
+
|
|
|
+ return Stack(alignment: Alignment.topLeft, children: children);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _UserListView extends GetView<DataDetailController> {
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return Obx(() {
|
|
|
+ return Container(
|
|
|
+ width: 263,
|
|
|
+ height: double.infinity,
|
|
|
+ decoration: const BoxDecoration(color: Colors.white, boxShadow: [
|
|
|
+ BoxShadow(color: Color(0x33000000), blurRadius: 4.3)
|
|
|
+ ]),
|
|
|
+ padding: const EdgeInsets.all(20),
|
|
|
+ child: Column(
|
|
|
+ children: [
|
|
|
+ Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
+ children: [
|
|
|
+ const Text('用户列表'),
|
|
|
+ IconButton(
|
|
|
+ onPressed: controller.selectedDetail.value != null
|
|
|
+ ? () => controller.showDetail.value =
|
|
|
+ !controller.showDetail.value
|
|
|
+ : null,
|
|
|
+ icon: const Icon(Icons.more_horiz)),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ Expanded(
|
|
|
+ child: ListView(
|
|
|
+ children: controller.showDetail.value
|
|
|
+ ? _detailView()
|
|
|
+ : controller.userList
|
|
|
+ .map((element) => _userElem(element))
|
|
|
+ .toList(),
|
|
|
+ ))
|
|
|
+ ],
|
|
|
+ ));
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Widget> _detailView() {
|
|
|
+ final detail = controller.selectedDetail.value!;
|
|
|
+
|
|
|
+ return <Widget>[
|
|
|
+ DataDetailCP(cpList: detail.controlPoints),
|
|
|
+ const SizedBox(height: 8),
|
|
|
+ const DataDetailBarCharts(),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _userElem(UserInfo data) {
|
|
|
+ return Obx(() {
|
|
|
+ final children = <Widget>[
|
|
|
+ Container(
|
|
|
+ width: double.infinity,
|
|
|
+ height: 42,
|
|
|
+ margin: const EdgeInsets.only(top: 8),
|
|
|
+ padding: const EdgeInsets.only(left: 4),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Colors.white,
|
|
|
+ boxShadow: const [
|
|
|
+ BoxShadow(color: Color(0x29000000), blurRadius: 3)
|
|
|
+ ],
|
|
|
+ borderRadius: BorderRadius.circular(3.56)),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ Container(
|
|
|
+ height: double.infinity,
|
|
|
+ width: 3.56,
|
|
|
+ margin: const EdgeInsets.only(top: 8, bottom: 8, right: 3.55),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: data.data.id == controller.selectedUserId.value
|
|
|
+ ? Colors.orange
|
|
|
+ : Colors.transparent,
|
|
|
+ borderRadius: BorderRadius.circular(2.1)),
|
|
|
+ ),
|
|
|
+ Text(data.data.name),
|
|
|
+ const Spacer(),
|
|
|
+ IconButton(
|
|
|
+ onPressed: () {
|
|
|
+ data.isExpand.value = !data.isExpand.value;
|
|
|
+ },
|
|
|
+ icon: Icon(data.isExpand.value
|
|
|
+ ? Icons.arrow_drop_up
|
|
|
+ : Icons.arrow_drop_down))
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ ];
|
|
|
+ if (data.isExpand.value) {
|
|
|
+ children.add(Column(
|
|
|
+ children: data.data.history
|
|
|
+ .map((element) => GestureDetector(
|
|
|
+ onTap: () => controller.selectDetail(element, data),
|
|
|
+ child: detailElem(element)))
|
|
|
+ .toList(),
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ return Column(
|
|
|
+ children: children,
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget detailElem(UserHistorySimple detail) {
|
|
|
+ return Container(
|
|
|
+ margin: const EdgeInsets.only(left: 12, top: 2, bottom: 4),
|
|
|
+ width: double.infinity,
|
|
|
+ height: 58,
|
|
|
+ padding: const EdgeInsets.fromLTRB(4, 6, 4, 6),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Colors.white,
|
|
|
+ borderRadius: BorderRadius.circular(3.5),
|
|
|
+ boxShadow: const [
|
|
|
+ BoxShadow(color: Color(0x33000000), blurRadius: 1.3)
|
|
|
+ ]),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ Container(
|
|
|
+ height: double.infinity,
|
|
|
+ width: 3.56,
|
|
|
+ margin: const EdgeInsets.only(right: 3.55),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: detail.gameId ==
|
|
|
+ controller.selectedDetailSimple.value.gameId
|
|
|
+ ? Colors.orange
|
|
|
+ : Colors.transparent,
|
|
|
+ borderRadius: BorderRadius.circular(2.1)),
|
|
|
+ ),
|
|
|
+ Expanded(
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Text(detail.routeName,
|
|
|
+ maxLines: 1, overflow: TextOverflow.ellipsis),
|
|
|
+ Text(
|
|
|
+ detail.eventName,
|
|
|
+ maxLines: 1,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ )),
|
|
|
+ const SizedBox(width: 12),
|
|
|
+ Text(detail.isComplete ? '完赛' : '未完赛')
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|