Jelajahi Sumber

活动注册

周睿 1 tahun lalu
induk
melakukan
358e9a7b39

+ 49 - 0
app_business/lib/service/api.dart

@@ -1,8 +1,10 @@
 import 'dart:async';
+import 'dart:core';
 import 'dart:typed_data';
 
 import 'package:app_business/app_config.dart';
 import 'package:app_business/generated/base.pb.dart' as pb;
+import 'package:app_business/generated/google/protobuf/duration.pb.dart' as pb;
 import 'package:app_business/generated/google/protobuf/timestamp.pb.dart' as pb;
 import 'package:app_business/generated/track_offical.pbgrpc.dart' as pb;
 import 'package:app_business/service/app.dart';
@@ -36,6 +38,53 @@ extension DateTimeExt on DateTime? {
   }
 }
 
+extension TSExt on pb.Timestamp {
+  DateTime toModel() {
+    return toDateTime(toLocal: true);
+  }
+}
+
+extension DurationExt on pb.Duration {
+  Duration toModel() {
+    final microseconds = hasNanos() ? nanos / 1000 : 0;
+    return Duration(
+        seconds: seconds.toInt(), microseconds: microseconds.toInt());
+  }
+}
+
+extension PositionExt on pb.Position {
+  Position toModel() {
+    return Position(latitude: latitude, longitude: longitude)
+      ..altitude = altitude;
+  }
+}
+
+extension PBToControlPointExt on pb.ToControlPoint {
+  ControlPoint toModel() {
+    final one = ControlPoint()
+      ..areaId = sn
+      ..intId = id
+      ..isSuccess = isCheckSuccess
+      ..sn = orderNo.toString()
+      ..checkAfterPrev = checkAfterLast.toModel()
+      ..checkAfterStart = checkAfterStart.toModel()
+      ..checkDistanceAfterPrev = disAfterLast.meter
+      ..distanceStraightToPrev = disStraightAfterLast.meter
+      ..paceAfterPrev = Pace.perKm(paceAfterLast.seconds)
+      ..paceAfterStart = Pace.perKm(paceAfterStart.seconds)
+      ..position = ciPosition.toModel();
+
+    if (cType == pb.CType.BeginType) {
+      one.isStart = true;
+    }
+    if (cType == pb.CType.EndType) {
+      one.isFinish = true;
+    }
+
+    return one;
+  }
+}
+
 class ApiService extends IService {
   ClientChannel? channel;
 

+ 60 - 5
app_business/lib/service/map_watch.dart

@@ -1,7 +1,5 @@
 import 'package:app_business/service/api.dart';
-import 'package:fixnum/fixnum.dart';
-import 'package:get/get.dart';
-import 'package:track_common/model/map_info.dart';
+import 'package:track_common/model.dart';
 import 'package:track_common/service/map_watch.dart';
 
 import '../generated/base.pb.dart' as pb;
@@ -13,9 +11,66 @@ class MapWatchImpl extends MapWatch {
   ApiService get _api => Get.find();
   @override
   Future<List<EventOnMap>> getEventList(int mapId) async {
-    // final r = _api.stub
+    final r = await _api.stub
+        .toUserDetailQueryV2(pb.ToUserDetailQueryRequestV2()..mapId = mapId);
+    final eventList = <EventOnMap>[];
 
-    return [];
+    for (var one in r.list) {
+      eventList.add(EventOnMap()
+        ..info.id = one.actId
+        ..userList = one.userList.map((e) => toAppPlayer(e)).toList());
+    }
+    return eventList;
+  }
+
+  PlayerOnMap toAppPlayer(pb.ToOrienteerInGameInfo e) {
+    final save = e.gameSaveInfo;
+    final startAt = save.hasStartAt() ? save.startAt.toModel() : DateTime.now();
+
+    return PlayerOnMap()
+      ..info.id = e.userId
+      ..startAt = startAt
+      ..duration = DateTime.now().difference(startAt)
+      ..distance = e.gpsInfo.distance.meter
+      ..cpListChecked = save.checkedSortedList.isEmpty
+          ? []
+          : save.checkedSortedList
+              .map((e) => ControlPoint()
+                ..isSuccess = e.isCheckSuccess
+                ..intId = e.controlPointId.toInt64())
+              .toList();
+  }
+
+  @override
+  Future<EventInfo> getEventInfo(int id) async {
+    final r = await _api.stub.toActionBasicQuery(IdRequest()..id = Int64(id));
+    final event = EventInfo()
+      ..name = r.actName
+      ..cpAllCount = r.totalControlNum;
+
+    return event;
+  }
+
+  @override
+  Future<PlayerInfo> getPlayerInfo(int eventId, int userId) async {
+    final r = await _api.stub
+        .toUserInActionBasicQuery(pb.ToUserInActionBasicQueryRequest()
+          ..actId = eventId
+          ..userId = userId);
+
+    final player = PlayerInfo()
+      ..id = r.userId
+      ..name = r.baseInfo.name
+      ..routeName = r.courseBaseInfo.courseName
+      ..cpWantList = r.courseBaseInfo.controlPointSortedList
+          .map((e) => e.toModel())
+          .toList();
+
+    for (var (i, cp) in player.cpWantList.indexed) {
+      cp.sn = i.toString();
+    }
+
+    return player;
   }
 }
 

+ 11 - 32
app_business/lib/view/home/field_control.dart

@@ -1,5 +1,4 @@
 import 'package:app_business/service/api.dart';
-import 'package:fixnum/fixnum.dart';
 import 'package:track_common/service/map_watch.dart';
 import 'package:track_common/view/home/field_control/field_control.dart';
 import 'package:track_common/view/home/field_control/field_control_controller.dart';
@@ -14,7 +13,7 @@ class FieldControlPageImpl extends FieldControlPage {
       final mapWatch = controller.mapWatch;
 
       return Container(
-          width: 263,
+          width: 370,
           padding: const EdgeInsets.all(6.4),
           height: double.infinity,
           color: Colors.white,
@@ -27,13 +26,7 @@ class FieldControlPageImpl extends FieldControlPage {
                           ? () => _onTapRegister(mapWatch)
                           : null,
                       child: const Text('注册比赛'))),
-              Expanded(
-                child: ListView(
-                  children: controller.eventList
-                      .map((element) => eventView(element))
-                      .toList(),
-                ),
-              )
+              const Expanded(child: EventInfoView())
             ],
           ));
     });
@@ -53,22 +46,6 @@ class FieldControlPageImpl extends FieldControlPage {
         ..queryPasswd = r.password ?? '');
     }
   }
-
-  Widget eventView(EventOnMap event) {
-    return Card(
-      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(3.56)),
-      child: Row(
-        children: [
-          Text(event.name),
-          Text('(${event.userList.length} 人)'),
-          const Spacer(),
-          IconButton(
-              onPressed: () {},
-              icon: const Icon(Icons.arrow_drop_down_outlined))
-        ],
-      ),
-    );
-  }
 }
 
 class EventInfo {
@@ -95,6 +72,8 @@ class RegisterDialogController extends GetxController {
   final eventList = <EventInfo>[].obs;
   final hasPassword = false.obs;
   var password = '';
+  late final int mapId;
+  final api = Get.find<ApiService>();
 
   String? get dateString {
     final d = date.value;
@@ -106,15 +85,15 @@ class RegisterDialogController extends GetxController {
 
   @override
   void onInit() {
-    super.onInit();
-    final mapId = Get.arguments as int;
-    final api = Get.find<ApiService>();
-
+    mapId = Get.arguments as int;
     api.stub.toActivitySelectList(IdRequest()..id = Int64(mapId)).then((r) {
-      eventList.addAll(r.list.map((e) => EventInfo()
-        ..id = e.actId
-        ..name = e.actName));
+      eventList.value = r.list
+          .map((e) => EventInfo()
+            ..id = e.actId
+            ..name = e.actName)
+          .toList();
     });
+    super.onInit();
   }
 }
 

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

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

+ 124 - 14
libs/track_common/lib/service/map_watch.dart

@@ -29,30 +29,33 @@ class Flag {
   static List<Flag> get values => [red, yellow, blue];
 }
 
-class UserOnMap {
-  var info = UserInfo();
+class PlayerInfo {
+  var id = 0;
+  var name = '';
+  var routeName = '';
+  var cpWantList = <ControlPoint>[];
+}
 
+class PlayerOnMap extends AppGameState {
+  var info = PlayerInfo();
   int get id => info.id;
-
   String get name => info.name;
-  var startAt = DateTime.now();
-  var cpList = <ControlPoint>[];
+  List<ControlPoint> get cpList => cpListChecked;
   final isHide = false.obs;
   var trace = <TracePoint>[].obs;
   var flag = Flag.red.obs;
-  String routeName = '';
+  String get routeName => info.routeName;
   int heartRatePercent = 0;
   Pace pace = Pace.perKm(99.hours);
   var distance = 0.km;
-  List<HeartRate> hrInfo = [];
-  List<Position> positionList = [];
+  List<HeartRate> get hrInfo => hrHistory;
+  List<Position> get positionList => positionHistory;
 
+  @override
   Duration get duration => DateTime.now().difference(startAt);
 
-  ControlPoint? nextWant;
-
   Distance get nextDistance {
-    final one = nextWant;
+    final one = cpNextWant;
     if (one != null) {
       final p1 = one.position;
       final p22 = positionList.lastOrNull;
@@ -64,13 +67,13 @@ class UserOnMap {
   }
 
   String get nextCPSN {
-    return nextWant?.snString ?? '';
+    return cpNextWant?.snString ?? '';
   }
 }
 
 class EventOnMap {
   var info = EventInfo();
-  var userList = <UserOnMap>[];
+  var userList = <PlayerOnMap>[];
 
   int get id => info.id;
 
@@ -78,6 +81,16 @@ class EventOnMap {
 
   int get cpAllCount => info.cpAllCount;
   final isHide = false.obs;
+
+  PlayerOnMap? getUserById(int id) {
+    for (final one in userList) {
+      if (one.id == id) {
+        return one;
+      }
+    }
+
+    return null;
+  }
 }
 
 abstract class MapWatchService extends GetxService {
@@ -101,7 +114,7 @@ abstract class MapWatch extends PlugController {
   Future<void> workFlushData() async {
     while (isActive) {
       try {
-        // await flushData();
+        await flushData();
       } catch (e) {
         error(e);
       }
@@ -125,6 +138,103 @@ abstract class MapWatch extends PlugController {
   final plugMap = PlugMap();
   final eventList = <EventOnMap>[].obs;
 
+  Future<void> flushData() async {
+    final list = await getEventList(id);
+
+    final newList = <EventOnMap>[];
+
+    for (final one in list) {
+      late EventOnMap event;
+      final old = getEventById(one.id);
+      if (old != null) {
+        event = old;
+        await updateEvent(event, one);
+      } else {
+        event = await initEvent(one);
+      }
+      newList.add(event);
+    }
+
+    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);
+    }
+    return event;
+  }
+
+  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;
+    return player;
+  }
+
+  Future<void> updateEvent(EventOnMap old, EventOnMap newOne) async {
+    final newUserList = <PlayerOnMap>[];
+
+    for (final nUser in newOne.userList) {
+      late PlayerOnMap user;
+      final oUser = old.getUserById(nUser.id);
+      if (oUser != null) {
+        user = oUser;
+        await updatePlayer(user, nUser);
+      } else {
+        user = await initPlayer(old, nUser);
+      }
+      user.updateState();
+      await playerUpdateMap(user);
+      newUserList.add(user);
+    }
+    old.userList = newUserList;
+  }
+
+  Future<void> playerUpdateMap(PlayerOnMap info) async {
+    for (var one in info.cpList) {
+      one.onMap = await plugMap.gameMap.worldToPixel(one.position);
+    }
+  }
+
+  Future<void> updatePlayer(PlayerOnMap old, PlayerOnMap newUser) async {
+    final indexMap = <int, TracePoint>{};
+
+    for (final one in old.trace) {
+      indexMap[one.ts.inMilliseconds] = one;
+    }
+
+    for (final one in newUser.positionList) {
+      final t = one.timestamp;
+      final startAt = old.startAt;
+      final ts = t.difference(startAt);
+      if (ts.inMilliseconds > 0 && !indexMap.containsKey(ts.inMilliseconds)) {
+        final pos = one;
+        final oneTrace = TracePoint()
+          ..ts = ts
+          ..position = pos;
+        if (plugMap.isInitFinish) {
+          oneTrace.onMap =
+              await plugMap.gameMap.worldToPixel(oneTrace.position);
+        }
+
+        old.trace.add(oneTrace);
+      }
+    }
+  }
+
   @protected
   Future<List<EventOnMap>> getEventList(int mapId);
+
+  @protected
+  Future<EventInfo> getEventInfo(int id);
+
+  @protected
+  Future<PlayerInfo> getPlayerInfo(int eventId, int userId);
 }

+ 8 - 6
libs/track_common/lib/view/home/field_control/field_control.dart

@@ -168,11 +168,13 @@ class _ViewTrace extends GetView<FieldControlController> {
   }
 }
 
-class _ActiveInfoView extends GetView<FieldControlController> {
+class EventInfoView extends GetView<FieldControlController> {
+  const EventInfoView({super.key});
+
   @override
   Widget build(BuildContext context) {
     return Obx(() => Container(
-          width: 370,
+          width: double.infinity,
           height: double.infinity,
           color: Colors.white,
           child: ListView(
@@ -214,7 +216,8 @@ class _ActiveInfoView extends GetView<FieldControlController> {
             children: [
               const Text('广播'),
               const Spacer(),
-              Image.asset(Assets.imagesIcCp, height: 20, width: 20),
+              Image.asset(Assets.imagesIcCp,
+                  height: 20, width: 20, package: package),
               Text(' ${info.cpAllCount}'),
               const Spacer(),
               const Text('全部隐藏'),
@@ -230,7 +233,6 @@ class _ActiveInfoView extends GetView<FieldControlController> {
       decoration: BoxDecoration(
           color: const Color(0xffe0e0e0),
           borderRadius: BorderRadius.circular(5)),
-      margin: const EdgeInsets.fromLTRB(9, 12, 9, 12),
       padding: const EdgeInsets.all(9),
       child: Column(
         children: children,
@@ -242,7 +244,7 @@ class _ActiveInfoView extends GetView<FieldControlController> {
 class _UserInfoView extends GetView<FieldControlController> {
   const _UserInfoView({required this.data});
 
-  final UserOnMap data;
+  final PlayerOnMap data;
 
   @override
   Widget build(BuildContext context) {
@@ -343,7 +345,7 @@ class _UserInfoView extends GetView<FieldControlController> {
   }
 
   String get cpInfo {
-    final next = data.nextWant;
+    final next = data.cpNextWant;
     return next != null ? '${data.nextCPSN}点(${next.areaId})' : '--';
   }
 

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

@@ -35,7 +35,7 @@ class FieldControlController extends GetxController {
   final eventList = <EventOnMap>[].obs;
   final Rx<int?> focusUserId = Rx(null);
 
-  UserOnMap? findFocusUser(List<EventOnMap> list) {
+  PlayerOnMap? findFocusUser(List<EventOnMap> list) {
     if (focusUserId.value == null) {
       return null;
     }
@@ -50,7 +50,7 @@ class FieldControlController extends GetxController {
     return null;
   }
 
-  UserOnMap? get focusUser {
+  PlayerOnMap? get focusUser {
     return findFocusUser(eventList);
   }
 }