周睿 před 2 roky
rodič
revize
7b5dee3bdb

+ 34 - 17
app_business/lib/service/map_watch.dart

@@ -10,28 +10,36 @@ class MapWatchImpl extends MapWatch {
 
   ApiService get _api => Get.find();
   @override
-  Future<List<EventOnMap>> getEventList(int mapId) async {
+  Future<List<EventInfo>> getEventList(int mapId) async {
     final r = await _api.stub
         .toUserDetailQueryV2(pb.ToUserDetailQueryRequestV2()..mapId = mapId);
-    final eventList = <EventOnMap>[];
+    final eventList = <EventInfo>[];
 
     for (var one in r.list) {
-      eventList.add(EventOnMap()
-        ..info.id = one.actId
-        ..userList = one.userList.map((e) => toAppPlayer(e)).toList());
+      eventList.add(EventInfo()
+        ..id = one.actId
+        ..players = one.userList.map((e) => toAppPlayer(e)).toList());
     }
     return eventList;
   }
 
-  PlayerOnMap toAppPlayer(pb.ToOrienteerInGameInfo e) {
+  PlayerInfo toAppPlayer(pb.ToOrienteerInGameInfo e) {
     final save = e.gameSaveInfo;
     final startAt = save.hasStartAt() ? save.startAt.toModel() : DateTime.now();
-
-    return PlayerOnMap()
-      ..info.id = e.userId
+    final out = PlayerInfo()
+      ..id = e.userId
       ..startAt = startAt
-      ..duration = DateTime.now().difference(startAt)
       ..distance = e.gpsInfo.distance.meter
+      ..duration = Duration.zero
+      ..positionHistory = e.gpsInfo.gameGpsInfos
+          .map((e) => Position()
+            ..latitude = e.latitude
+            ..longitude = e.longitude
+            ..altitude = e.altitude
+            ..timestamp = e.gpsTime.toModel())
+          .toList()
+      ..heartRatePercent = e.otherInfo.heartRatePercent
+      ..stepCount = e.otherInfo.stepNum
       ..cpListChecked = save.checkedSortedList.isEmpty
           ? []
           : save.checkedSortedList
@@ -39,12 +47,22 @@ class MapWatchImpl extends MapWatch {
                 ..isSuccess = e.isCheckSuccess
                 ..intId = e.controlPointId.toInt64())
               .toList();
+
+    if (save.hasStartAt()) {
+      out.hrHistory = e.hrInfo.hrInfo
+          .map((e) => HeartRate(
+              startAt.add(Duration(milliseconds: e.timeStampMs.toInt())), e.hr))
+          .toList();
+      out.duration = DateTime.now().difference(startAt);
+    }
+
+    return out;
   }
 
   @override
-  Future<EventInfo> getEventInfo(int id) async {
+  Future<EventInfoExt> getEventInfoExt(int id) async {
     final r = await _api.stub.toActionBasicQuery(IdRequest()..id = Int64(id));
-    final event = EventInfo()
+    final event = EventInfoExt()
       ..name = r.actName
       ..cpAllCount = r.totalControlNum;
 
@@ -52,21 +70,20 @@ class MapWatchImpl extends MapWatch {
   }
 
   @override
-  Future<PlayerInfo> getPlayerInfo(int eventId, int userId) async {
+  Future<PlayerInfoExt> getPlayerInfoExt(int eventId, int userId) async {
     final r = await _api.stub
         .toUserInActionBasicQuery(pb.ToUserInActionBasicQueryRequest()
           ..actId = eventId
           ..userId = userId);
 
-    final player = PlayerInfo()
-      ..id = r.userId
+    final player = PlayerInfoExt()
       ..name = r.baseInfo.name
       ..routeName = r.courseBaseInfo.courseName
-      ..cpWantList = r.courseBaseInfo.controlPointSortedList
+      ..cpListWant = r.courseBaseInfo.controlPointSortedList
           .map((e) => e.toModel())
           .toList();
 
-    for (var (i, cp) in player.cpWantList.indexed) {
+    for (var (i, cp) in player.cpListWant.indexed) {
       cp.sn = i.toString();
     }
 

+ 1 - 1
app_business/lib/view/home/dialog_event_register.dart

@@ -1,7 +1,7 @@
-import 'package:track_common/model.dart';
 import 'package:track_common/widget/prelude.dart';
 
 import '../../service/api.dart';
+import 'field_control.dart';
 
 class _ArgCreate {
   int mapId = 0;

+ 12 - 14
app_business/lib/view/home/event_manage/event_manage.dart

@@ -11,20 +11,18 @@ class EventManage extends GetView<EventManagerController> {
 
   @override
   Widget build(BuildContext context) {
-    return GetBuilder(
-        init: EventManagerController(),
-        builder: (c) {
-          return Level2View(
-              level1: level1(),
-              level2: level2(),
-              level1Title: '赛事列表',
-              level1Action: wDate(context),
-              level2Title: '用户列表',
-              level2SubTitle: Obx(() => Text(
-                    c.selected?.name != null ? '(${c.selected!.name})' : '',
-                    style: const TextStyle(color: Colors.grey, fontSize: 14.22),
-                  )));
-        });
+    return Level2View(
+        level1: level1(),
+        level2: level2(),
+        level1Title: '赛事列表',
+        level1Action: wDate(context),
+        level2Title: '用户列表',
+        level2SubTitle: Obx(() => Text(
+              controller.selected?.name != null
+                  ? '(${controller.selected!.name})'
+                  : '',
+              style: const TextStyle(color: Colors.grey, fontSize: 14.22),
+            )));
   }
 
   Widget wDate(BuildContext context) {

+ 15 - 2
app_business/lib/view/home/field_control.dart

@@ -1,5 +1,6 @@
 import 'package:app_business/service/api.dart';
 import 'package:track_common/service/map_watch.dart';
+import 'package:track_common/track_common.dart';
 import 'package:track_common/view/home/field_control/field_control.dart';
 import 'package:track_common/view/home/field_control/field_control_controller.dart';
 import 'package:track_common/widget/prelude.dart';
@@ -11,7 +12,7 @@ class FieldControlPageImpl extends FieldControlPage {
   Widget get rightColumn {
     return Obx(() {
       final mapWatch = controller.mapWatch;
-
+      debug('${identityHashCode(controller)}');
       return Container(
           width: 370,
           padding: const EdgeInsets.all(6.4),
@@ -61,7 +62,19 @@ class RegisterInfo {
   String? password;
 }
 
-class FieldControlControllerImpl extends FieldControlController {}
+class FieldControlControllerImpl extends FieldControlController {
+  @override
+  void onInit() {
+    debug('init');
+    super.onInit();
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    debug('close');
+  }
+}
 
 class RegisterDialogController extends GetxController {
   var registerName = '';

+ 57 - 9
app_business/lib/view/home/home.dart

@@ -1,3 +1,5 @@
+import 'package:app_business/view/home/event_manage/event_manage_controller.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:get/get.dart';
 import 'package:track_common/view.dart';
 import 'package:track_common/view/home/field_control/field_control_controller.dart';
@@ -15,18 +17,64 @@ class HomeControllerImpl extends HomeController {
   List<HomeTab> get tabs => [
         HomeTab(
             '地图',
-            () => GetBuilder<MapPageController>(
-                init: MapPageControllerImpl(),
+            () => _TabBuilder<MapPageController>(
+                init: () => MapPageControllerImpl(),
                 builder: (c) {
                   return const MapPage();
                 })),
+        HomeTab('场控', () {
+          return _TabBuilder<FieldControlController>(
+              init: () => FieldControlControllerImpl(),
+              builder: (c) {
+                return const FieldControlPageImpl();
+              });
+        }),
         HomeTab(
-            '场控',
-            () => GetBuilder<FieldControlController>(
-                init: FieldControlControllerImpl(),
-                builder: (c) {
-                  return const FieldControlPageImpl();
-                })),
-        HomeTab('赛事管理', () => const EventManage()),
+            '赛事管理',
+            () => _TabBuilder<EventManagerController>(
+                  init: () => EventManagerController(),
+                  builder: (c) {
+                    return EventManage();
+                  },
+                )),
       ];
 }
+
+class _TabBuilder<T> extends StatefulWidget {
+  const _TabBuilder({required this.init, required this.builder});
+
+  final T Function() init;
+  final Widget Function(BuildContext contest) builder;
+
+  @override
+  State<StatefulWidget> createState() {
+    return _TabBuilderState<T>();
+  }
+}
+
+class _TabBuilderState<T> extends State<_TabBuilder> {
+  @override
+  void dispose() {
+    super.dispose();
+    Get.delete<T>();
+  }
+
+  @override
+  void initState() {
+    final c = widget.init();
+    tag = '${identityHashCode(c)}';
+    Get.put<T>(widget.init());
+    super.initState();
+    setState(() {
+      ok = true;
+    });
+  }
+
+  late final String tag;
+  var ok = false;
+
+  @override
+  Widget build(BuildContext context) {
+    return ok ? widget.builder(context) : const Center();
+  }
+}

+ 1 - 1
libs/common_pub

@@ -1 +1 @@
-Subproject commit 4e2b200cfedb869a52074e541fed11e1b71de6d3
+Subproject commit e8f4bfab5527ea8bf24d5f284987bfc9982df8fb

+ 0 - 1
libs/track_common/lib/model.dart

@@ -1,6 +1,5 @@
 export 'package:common_pub/model.dart';
 
-export 'model/event.dart';
 export 'model/game.dart';
 export 'model/map_info.dart';
 export 'model/route.dart';

+ 0 - 8
libs/track_common/lib/model/event.dart

@@ -1,8 +0,0 @@
-export 'package:common_pub/model.dart';
-
-/// 活动信息
-class EventInfo {
-  var id = 0;
-  var name = '';
-  var cpAllCount = 0;
-}

+ 77 - 44
libs/track_common/lib/service/map_watch.dart

@@ -29,33 +29,53 @@ class Flag {
   static List<Flag> get values => [red, yellow, blue];
 }
 
-class PlayerInfo {
+class PlayerInfo extends AppGameState {
   var id = 0;
+  int heartRatePercent = 0;
+}
+
+class PlayerInfoExt {
   var name = '';
   var routeName = '';
-  var cpWantList = <ControlPoint>[];
+  var cpListWant = <ControlPoint>[];
+}
+
+class EventInfo {
+  var id = 0;
+  var players = <PlayerInfo>[];
 }
 
-class PlayerOnMap extends AppGameState {
+class EventInfoExt {
+  var name = '';
+  var cpAllCount = 0;
+}
+
+class PlayerOnMap {
   var info = PlayerInfo();
+  var _ext = PlayerInfoExt();
+  set ext(PlayerInfoExt v) {
+    _ext = v;
+    info.cpListWant = v.cpListWant;
+  }
+
   int get id => info.id;
-  String get name => info.name;
-  List<ControlPoint> get cpList => cpListChecked;
+  String get name => _ext.name;
+  List<ControlPoint> get cpList => info.cpListWant;
   final isHide = false.obs;
   var trace = <TracePoint>[].obs;
   var flag = Flag.red.obs;
-  String get routeName => info.routeName;
-  int heartRatePercent = 0;
-  Pace pace = Pace.perKm(99.hours);
-  var distance = 0.km;
-  List<HeartRate> get hrInfo => hrHistory;
-  List<Position> get positionList => positionHistory;
-
-  @override
-  Duration get duration => DateTime.now().difference(startAt);
+  String get routeName => _ext.routeName;
+  Distance get distance => info.distance;
+  List<HeartRate> get hrInfo => info.hrHistory;
+  List<Position> get positionList => info.positionHistory;
+  DateTime watchAt = DateTime.now();
+  int get heartRatePercent => info.heartRatePercent;
+  Pace get pace => info.pace;
+  Duration get duration => info.duration;
+  ControlPoint? get cpNextWant => info.cpNextWant;
 
   Distance get nextDistance {
-    final one = cpNextWant;
+    final one = info.cpNextWant;
     if (one != null) {
       final p1 = one.position;
       final p22 = positionList.lastOrNull;
@@ -67,19 +87,20 @@ class PlayerOnMap extends AppGameState {
   }
 
   String get nextCPSN {
-    return cpNextWant?.snString ?? '';
+    return info.cpNextWant?.snString ?? '';
   }
 }
 
 class EventOnMap {
   var info = EventInfo();
+  var ext = EventInfoExt();
   var userList = <PlayerOnMap>[];
 
   int get id => info.id;
 
-  String get name => info.name;
+  String get name => ext.name;
 
-  int get cpAllCount => info.cpAllCount;
+  int get cpAllCount => ext.cpAllCount;
   final isHide = false.obs;
 
   PlayerOnMap? getUserById(int id) {
@@ -104,6 +125,7 @@ abstract class MapWatchService extends GetxService {
   Future<void> setMap(MapInfo mapInfo) async {
     final thisInstance = await newInstanceByMap(mapInfo);
     thisInstance.addPlugs([thisInstance.plugMap]);
+    _instance.value?.close();
     _instance.value = thisInstance;
     thisInstance.init();
     thisInstance.workFlushData();
@@ -158,39 +180,36 @@ abstract class MapWatch extends PlugController {
     eventList.value = newList;
   }
 
-  Future<EventOnMap> initEvent(EventOnMap event) async {
-    final id = event.id;
-    final info = await getEventInfo(id);
-    event.info = info;
-    event.info.id = id;
-    for (var p in event.userList) {
-      await initPlayer(event, p);
+  Future<EventOnMap> initEvent(EventInfo info) async {
+    final ext = await getEventInfoExt(info.id);
+    final one = EventOnMap()
+      ..info = info
+      ..ext = ext;
+    for (var p in info.players) {
+      one.userList.add(await initPlayer(info, p));
     }
-    return event;
+    return one;
   }
 
-  Future<PlayerOnMap> initPlayer(EventOnMap event, PlayerOnMap player) async {
-    final userId = player.id;
-    final info = await getPlayerInfo(event.id, userId);
-    player.info = info;
-    player.info.id = userId;
-    player.cpListWant = info.cpWantList;
+  Future<PlayerOnMap> initPlayer(EventInfo event, PlayerInfo playerInfo) async {
+    final userId = playerInfo.id;
+    final ext = await getPlayerInfoExt(event.id, userId);
+    final player = PlayerOnMap()..info = playerInfo;
+    player.ext = ext;
     return player;
   }
 
-  Future<void> updateEvent(EventOnMap old, EventOnMap newOne) async {
+  Future<void> updateEvent(EventOnMap old, EventInfo newOne) async {
     final newUserList = <PlayerOnMap>[];
 
-    for (final nUser in newOne.userList) {
+    for (final nUser in newOne.players) {
       late PlayerOnMap user;
       final oUser = old.getUserById(nUser.id);
       if (oUser != null) {
-        user = oUser;
-        await updatePlayer(user, nUser);
+        user = await updatePlayer(oUser, nUser);
       } else {
-        user = await initPlayer(old, nUser);
+        user = await initPlayer(old.info, nUser);
       }
-      user.updateState();
       await playerUpdateMap(user);
       newUserList.add(user);
     }
@@ -203,16 +222,18 @@ abstract class MapWatch extends PlugController {
     }
   }
 
-  Future<void> updatePlayer(PlayerOnMap old, PlayerOnMap newUser) async {
+  Future<PlayerOnMap> updatePlayer(PlayerOnMap old, PlayerInfo newUser) async {
     final indexMap = <int, TracePoint>{};
+    old.info = newUser;
+    old.ext = old._ext;
 
     for (final one in old.trace) {
       indexMap[one.ts.inMilliseconds] = one;
     }
 
-    for (final one in newUser.positionList) {
+    for (final one in newUser.positionHistory) {
       final t = one.timestamp;
-      final startAt = old.startAt;
+      final startAt = old.watchAt;
       final ts = t.difference(startAt);
       if (ts.inMilliseconds > 0 && !indexMap.containsKey(ts.inMilliseconds)) {
         final pos = one;
@@ -225,16 +246,28 @@ abstract class MapWatch extends PlugController {
         }
 
         old.trace.add(oneTrace);
+      } else if (old.trace.isEmpty) {
+        final oneTrace = TracePoint()
+          ..ts = Duration.zero
+          ..position = one;
+        if (plugMap.isInitFinish) {
+          oneTrace.onMap =
+              await plugMap.gameMap.worldToPixel(oneTrace.position);
+
+          old.trace.add(oneTrace);
+        }
       }
     }
+
+    return old;
   }
 
   @protected
-  Future<List<EventOnMap>> getEventList(int mapId);
+  Future<List<EventInfo>> getEventList(int mapId);
 
   @protected
-  Future<EventInfo> getEventInfo(int id);
+  Future<EventInfoExt> getEventInfoExt(int id);
 
   @protected
-  Future<PlayerInfo> getPlayerInfo(int eventId, int userId);
+  Future<PlayerInfoExt> getPlayerInfoExt(int eventId, int userId);
 }

+ 1 - 1
libs/track_common/lib/view/home/field_control/field_control.dart

@@ -140,7 +140,7 @@ class _ViewTrace extends GetView<FieldControlController> {
           }
           final trace = user.trace.lastOrNull;
           final traceTailOnMap = <Offset>[];
-          final st = user.startAt;
+          final st = user.watchAt;
           for (final one in user.trace) {
             if (DateTime.now().difference(st.add(one.ts)) < traceDuration) {
               traceTailOnMap.add(one.onMap);

+ 2 - 1
libs/track_common/lib/view/home/field_control/field_control_controller.dart

@@ -9,9 +9,9 @@ class FieldControlController extends GetxController {
 
   @override
   void onInit() {
-    super.onInit();
     final map = _mapWatch.instance;
     if (map != null) {
+      eventList.clear();
       eventList.bindStream(map.eventList.stream);
     }
 
@@ -21,6 +21,7 @@ class FieldControlController extends GetxController {
         viewCpController.setCPList(user.cpList);
       }
     });
+    super.onInit();
   }
 
   @override

+ 0 - 10
libs/track_common/lib/view/home/home_view.dart

@@ -36,16 +36,6 @@ class HomeView extends GetView<HomeController> {
   }
 }
 
-// final _tabElems = [
-// _TabElem(title: '设置', child: const SizedBox()),
-// _TabElem(title: '地图', child: const MapPage()),
-// _TabElem(title: '场控', child: const FieldControlPage()),
-// _TabElem(title: '用户管理', child: const UserManagePage()),
-// _TabElem(title: '个人排名', child: PersonalRankPage()),
-// _TabElem(title: '分组排名', child: const SizedBox()),
-// _TabElem(title: '数据详情', child: const DataDetailPage()),
-// ];
-
 class CustomTabIndicator extends Decoration {
   @override
   BoxPainter createBoxPainter([VoidCallback? onChanged]) {