diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 8910ae0..701ab09 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.2.10\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.2.1\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.3.0\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2024-08-21 11:28:19.723327","version":"3.24.0","swift_package_manager_enabled":false} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.2.10\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.2.1\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.3.0\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2024-08-23 17:31:42.127712","version":"3.24.0","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/lib/controllers/plumController.dart b/lib/controllers/plumController.dart new file mode 100644 index 0000000..72a53e4 --- /dev/null +++ b/lib/controllers/plumController.dart @@ -0,0 +1,60 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:roslibdart/roslibdart.dart'; + +class PlumDataController extends GetxController { + var isGenerate = false.obs; //是否生成 + var angle = 0.0.obs; //方向弧度 + var isDirect = false.obs; //是否为方向设置 + var checkValue = "".obs; //checkPile -桩点坐标,checkDirection-方向设置 + var checkName = "".obs; + var centerXY = Offset.zero.obs; //中心点 + var space = 5.0.obs; //间距 m + var pileWidth = 400.0.obs; //打桩宽度 m + var genLenth = 0.obs; //半径 + var isPileId = false.obs; + var direction = 0.0.obs; //角度 + var isSave = false.obs; //是否保存 + var centerOffset = Offset.zero.obs; + var linePointOffset = Offset.zero.obs; + var linePointXY = Offset.zero.obs; + var isUp = false.obs; + var plumList = [Offset.zero]; + // var shouldPaint = true.obs; + var isMap = false.obs; + late Service service; + late Ros ros; + var canvasSize = Size.zero; + + @override + void onInit() async { + super.onInit(); + // plumList.value = []; + // centerXY.value = const Offset(3790620.0588630675, 577014.4059290753); + + // for (int i = -2; i <= 2; i++) { + // for (int j = -2; j <= 2; j++) { + // plumList.add(Offset(centerXY.value.dx + i, centerXY.value.dy + j)); + // } + // } + + // ros = BaseService().getRos(); + // ros.connect(); + // service = Service( + // name: '/smash_point_list_service', + // ros: ros, + // type: "nav2_smash_behavior/srv/SmashPointList"); + // var json = {'data': []}; + // service.call(json).then((value) { + // print('ros$value'); + // }); + } + + updateLinePoint(Offset offset) { + linePointOffset.value = offset; + + update(); + } +} diff --git a/lib/main.dart b/lib/main.dart index f708704..2317f45 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,14 +1,16 @@ -import 'package:cpnav/appbar.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:scence_map/controller.dart'; +import 'appbar.dart'; +import 'controllers/plumController.dart'; import 'pages/pass_track/view.dart'; +import 'pages/pile/rightDra/pileGenerate.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); //设置全屏 - + Get.put(PlumDataController()); runApp(const MyApp()); } @@ -68,12 +70,12 @@ class _MyHomePageState extends State { final _currentIndex = 0.obs; final List _pages = [ - PassTrack( - date: '', - ), Container( color: Colors.green, ), + PassTrack( + date: '', + ), Container( color: Colors.blue, ), @@ -86,6 +88,7 @@ class _MyHomePageState extends State { ]; @override Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // @@ -93,6 +96,12 @@ class _MyHomePageState extends State { // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. return Scaffold( + endDrawer: _currentIndex.value == 1 + ? Drawer( + width: size.width * .8, + child: const PileGenerate(), + ) + : null, appBar: PreferredSize( // TRY THIS: Try changing the color here to a specific color (to // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar diff --git a/lib/models/pilePoint/hyrecorditem.dart b/lib/models/pilePoint/hyrecorditem.dart new file mode 100644 index 0000000..37e0044 --- /dev/null +++ b/lib/models/pilePoint/hyrecorditem.dart @@ -0,0 +1,58 @@ +class HyRecordItem { + final int id; + final String startTime; + final String endTime; + final int tid; + final int tpId; + final String name; + final double lat; + final double lng; + final double alt; + final double x; + final double y; + final int times; + final double strongDrop; + final int layer; + final int qualified; + double dx; + double dy; + HyRecordItem({ + this.alt = 0, + this.endTime = "", + required this.id, + this.lat = 0, + this.lng = 0, + this.layer = 1, + this.name = "", + this.qualified = 1, + this.startTime = "", + this.strongDrop = 0, + required this.tid, + this.times = 1, + required this.tpId, + this.x = 0, + this.y = 0, + this.dx = 0, + this.dy = 0, + }); + factory HyRecordItem.fromJson(Map json) { + return HyRecordItem( + alt: json['ALT'].toDouble() ?? 0, + endTime: json['end_time'], + id: json['id'], + lat: json['LAT'].toDouble() ?? 0, + lng: json['LNG'].toDouble() ?? 0, + layer: json['layer'], + name: json['name'] ?? "", + qualified: json['is_qualified'], + startTime: json['start_time'], + strongDrop: json['strong_drop'].toDouble() ?? 0, + tid: json['tid'], + times: json['times'], + tpId: json['tp_id'], + x: json['x'].toDouble() ?? 0, + y: json['y'].toDouble() ?? 0, + dx: 0, + dy: 0); + } +} diff --git a/lib/pages/pass_track/controller.dart b/lib/pages/pass_track/controller.dart index 63081f6..89c0357 100644 --- a/lib/pages/pass_track/controller.dart +++ b/lib/pages/pass_track/controller.dart @@ -41,6 +41,7 @@ class PassTrackController extends GetxController { double minX = double.infinity; double minY = double.infinity; var sideLineData = data as Map; + // var sideLineData = data; sideLineData.forEach((group, items) { for (var item in items) { SideLineItem sideLineItem = SideLineItem.fromJson(item); diff --git a/lib/pages/pile/pileNav/draw_pile.dart b/lib/pages/pile/pileNav/draw_pile.dart new file mode 100644 index 0000000..df11e47 --- /dev/null +++ b/lib/pages/pile/pileNav/draw_pile.dart @@ -0,0 +1,120 @@ +import 'dart:math'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:scence_map/controller.dart'; + +import '../../../controllers/plumController.dart'; + + +ScenceMapController mapController = Get.find(); + +class DrawDirection extends CustomPainter { + PlumDataController controller; + Offset pos; + bool isDarkMode; + bool isInit; + DrawDirection(this.controller, this.pos, this.isDarkMode, this.isInit); + + @override + void paint(Canvas canvas, Size size) { + controller.canvasSize = size; + final paint = Paint(); + Path path = Path(); + + paint + ..strokeWidth = 2 + ..style = PaintingStyle.stroke + ..color = isDarkMode ? Colors.white : Colors.black; + if (controller.linePointOffset.value == Offset.zero || + controller.centerXY.value == Offset.zero) { + return; + } + + Offset linePointOffset = mapController.xy2Screen( + controller.linePointXY.value.dx, controller.linePointXY.value.dy); + Offset centerOffset = controller.centerOffset.value; + Offset centerXY = controller.centerXY.value; + if (isInit) { + linePointOffset = linePointOffset + pos; + centerOffset = controller.centerOffset.value + pos; + } + print("-----矩阵中心$centerOffset,$centerXY"); + + path.moveTo(centerOffset.dx, centerOffset.dy); + path.lineTo(linePointOffset.dx, linePointOffset.dy); + canvas.drawPath(path, paint); + paint.style = PaintingStyle.fill; + canvas.drawCircle(linePointOffset, 10, paint); + // canvas.translate(centerOffset.dx, centerOffset.dy); + // canvas.rotate(controller.angle.value); + // canvas.translate(-centerOffset.dx, -centerOffset.dy); + paint + // ..color = Colors.grey.withOpacity(.4) + .style = PaintingStyle.stroke; + + if (controller.isUp.value && controller.angle.value != 0) { + double unit = + mapController.plottingScale.value / mapController.pixel2MeterRatio; + + // 沿着路径绘制圆圈 + double distance = (linePointOffset - centerOffset).distance; + int horizonalCircles = (distance / unit).floor(); + int verticalCircles = (controller.pileWidth / unit).floor(); + + // controller.plumList.length = 0; + List circlePoints = []; + // List plumList = []; + controller.plumList.length = 0; + for (int i = 0; i <= horizonalCircles; i++) { + double t = i * unit / distance; + Offset point = Offset.lerp(centerOffset, linePointOffset, t)!; + canvas.drawCircle(point, .3 / mapController.pixel2MeterRatio, paint); + circlePoints.add(point); + // Offset xy = mapController.screen2xy(point.dx, point.dy); + // plumList.add(Offset(xy.dx, xy.dy)); + controller.plumList.add(point); + } + + // 在反方向延长线上绘制对称的圆圈 + for (int i = 1; i <= horizonalCircles; i++) { + double t = i * unit / distance; + Offset point = Offset.lerp(centerOffset, linePointOffset, -t)!; + canvas.drawCircle(point, .3 / mapController.pixel2MeterRatio, paint); + circlePoints.add(point); + controller.plumList.add(point); + + //List保存 + } + + // 计算垂直于path的方向向量 + Offset direction = + (linePointOffset - centerOffset).scale(1 / distance, 1 / distance); + Offset perpendicular = Offset(-direction.dy, direction.dx); + + // 绘制上下方的圆圈,形成正方形矩阵 + for (Offset point in circlePoints) { + for (int j = 0; j <= verticalCircles / 2; j++) { + Offset upPoint = point + perpendicular * (j * unit); + Offset downPoint = point - perpendicular * (j * unit); + canvas.drawCircle( + upPoint, .3 / mapController.pixel2MeterRatio, paint); + canvas.drawCircle( + downPoint, .3 / mapController.pixel2MeterRatio, paint); + + // Offset xy = mapController.screen2xy0(upPoint); + // Offset xy1 = mapController.screen2xy0(downPoint); + controller.plumList.add(upPoint); + controller.plumList.add(downPoint); + } + } + + // if (plumList.isNotEmpty) { + // controller.plumList.value = plumList; + // // controller.update(); + // } + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => true; +} diff --git a/lib/pages/pile/pileNav/view.dart b/lib/pages/pile/pileNav/view.dart new file mode 100644 index 0000000..0ec406e --- /dev/null +++ b/lib/pages/pile/pileNav/view.dart @@ -0,0 +1,207 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:scence_map/controller.dart'; +import 'package:scence_map/scence_map.dart'; +import 'package:get/get.dart'; + +import '../../../controllers/plumController.dart'; +import '../../../models/pilePoint/hyrecorditem.dart'; +import 'draw_pile.dart'; + +class RealView extends StatefulWidget { + const RealView({super.key}); + + @override + State createState() => _RealViewState(); +} + +class _RealViewState extends State { + final ScenceMapController scenceMapController = + Get.put(ScenceMapController()); + final controller = Get.find(); + @override + void dispose() { + super.dispose(); + } + + bool isInit = false; + @override + void initState() { + super.initState(); + // scenceMapController.disableMove.value = false; + scenceMapController.update(); + isInit = true; + } + + @override + Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + double diagonal = scenceMapController.diagonal; + double mapWidth = scenceMapController.width; + double mapHeight = scenceMapController.height; + Offset scOffset = + Offset(mapWidth / 2 - diagonal / 2, mapHeight / 2 - diagonal / 2); + onTapDown(TapDownDetails details) { + isInit = false; + if (controller.checkValue.value == "checkPile") { + // controller.centerOffset.value = details.localPosition; + Offset sc2xy = scenceMapController.screen2xy0(details.localPosition); + controller.centerXY.value = sc2xy; + + HyRecordItem? checkPoint = + scenceMapController.pointInfo(controller.centerXY.value); + if (checkPoint != null) { + controller.isPileId.value = true; + controller.checkName.value = checkPoint.tpId.toString(); + } else { + controller.isPileId.value = false; + controller.checkName.value = "未找到"; + } + Scaffold.of(context).openEndDrawer(); + } + } + + onScaleStart(ScaleStartDetails details) { + if (controller.checkValue.value != "checkPile") { + controller.linePointOffset.value = details.localFocalPoint; + } + // controller.shouldPaint.value = true; + } + + onScaleUpdate(ScaleUpdateDetails details) { + controller.isUp.value = false; + // controller.shouldPaint.value = true; + if (controller.checkValue.value != "checkPile") { + if (controller.linePointOffset.value != details.localFocalPoint) { + controller.linePointXY.value = + scenceMapController.screen2xy0(details.localFocalPoint); + + controller.updateLinePoint(details.localFocalPoint); + } + } + controller.isUp.value = true; + } + + onScaleEnd(ScaleEndDetails details) { + double deg = (atan2( + controller.linePointOffset.value.dy - + controller.centerOffset.value.dy, + controller.linePointOffset.value.dx - + controller.centerOffset.value.dx) * + 180 / + pi) + .roundToDouble(); + controller.direction.value = deg + 90; + controller.angle.value = + ((controller.direction.value * pi / 180) * 100).round() / 100; + + controller.isUp.value = true; + } + +// 中间 + var center = Obx(() { + // 桩点生成 + if (!controller.isGenerate.value) { + return const Text(""); + } + + return Positioned( + width: scenceMapController.diagonal, + height: scenceMapController.diagonal, + top: scOffset.dy, + left: scOffset.dx, + child: GestureDetector( + onTapDown: (TapDownDetails details) => onTapDown(details), + onScaleStart: (ScaleStartDetails details) => onScaleStart(details), + onScaleUpdate: (ScaleUpdateDetails details) => + onScaleUpdate(details), + onScaleEnd: (ScaleEndDetails details) => onScaleEnd(details), + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Obx(() { + ////必须写 因为 需要监听 -- 的值发生变化 刷新 + + controller.linePointOffset.value; + controller.isUp.value; + return CustomPaint( + // size: Size(scenceMapController.diagonal, + // scenceMapController.diagonal), + foregroundPainter: + DrawDirection(controller, scOffset, isDarkMode, isInit), + // child: + ); + }), + ), + )); + }); + // 桩点生成时返回按钮 + var back = Obx(() { + // bug :有时候点击的位置不准确 8寸屏的是正常的 + + controller.centerOffset.value = scenceMapController.xy2Screen( + controller.centerXY.value.dx, controller.centerXY.value.dy); + + if (isInit) { + controller.centerOffset.value = scenceMapController.xy2Screen( + controller.centerXY.value.dx, controller.centerXY.value.dy) - + scOffset; + } + print( + "中心${controller.centerOffset.value},${controller.centerXY.value},${scenceMapController.centerXY},$scOffset,$isInit"); + print(scenceMapController.xy2Screen( + controller.centerXY.value.dx, controller.centerXY.value.dy)); + + return Positioned( + left: controller.isGenerate.value + ? controller.centerOffset.value.dx - + 25 + + (mapWidth / 2 - diagonal / 2) + : -50, + top: controller.isGenerate.value + ? controller.centerOffset.value.dy - + 20 + + (mapHeight / 2 - diagonal / 2) + // 20 为高一半 + : -50, + width: 50, + height: 40, + child: ClipOval( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: EdgeInsets.zero, + shape: const CircleBorder(), + ), + child: const Icon(Icons.keyboard_return), + onPressed: () { + Scaffold.of(context).openEndDrawer(); + controller.isDirect.value = false; + }, + ), + )); + }); + return Stack( + children: [ + Obx(() => AbsorbPointer( + absorbing: controller.isGenerate.value + ? true + : false, //设置CenterLayout 内的GestureDetector 不生效 + child: const ScenceMapView( + children: [], + ), + )), + center, + back, + ], + ); + } +} diff --git a/lib/pages/pile/rightDra/pileGenerate.dart b/lib/pages/pile/rightDra/pileGenerate.dart new file mode 100644 index 0000000..871eed9 --- /dev/null +++ b/lib/pages/pile/rightDra/pileGenerate.dart @@ -0,0 +1,226 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:scence_map/controller.dart'; + +import '../../../controllers/plumController.dart'; + +import '../../../service/pile/device_type.dart'; +import '../../../service/pile/input.dart'; +import '../../../service/pile/public_widget.dart'; + +final ScenceMapController mapController = Get.find(); + +class PileGenerate extends GetView { + const PileGenerate({super.key}); + + @override + Widget build(BuildContext context) { + double titleTextWidth = 90; + double inputLength = 120; + FocusNode xFocus = FocusNode(); + FocusNode yFocus = FocusNode(); + FocusNode directionFocus = FocusNode(); + FocusNode pileSpaceFocus = FocusNode(); + FocusNode pileWidthFocus = FocusNode(); + DeviceType deviceType = getDeviceType(context); + double fontSize = 16; + if (deviceType == DeviceType.mobile) { + fontSize = 16; + } else { + fontSize = 20; + } + double centerPointX = controller.centerXY.value.dx; + double centerPointY = controller.centerXY.value.dy; + + final size = MediaQuery.of(context).size; + return Scaffold( + appBar: AppBar( + title: const Text("桩点生成"), + toolbarHeight: 30, + ), + body: SizedBox( + height: size.height, + child: Stack( + children: [ + SingleChildScrollView( + child: AlignWrapWidget( + children: [ + Row( + children: [ + const Text('地图显示:'), + Obx(() => Switch( + value: controller.isMap.value, + onChanged: ((value) { + controller.isMap.value = !controller.isMap.value; + }))), + ], + ), + AlignWrapWidget( + children: [ + ElevatedButton( + child: const Text("夯锤坐标"), + onPressed: () => {controller.isDirect.value = false}, + ), + const SizedBox( + width: 10, + ), + ElevatedButton( + child: const Text("桩点坐标"), + onPressed: () => { + controller.isGenerate.value = true, + controller.checkValue.value = "checkPile", + controller.isDirect.value = false, + Navigator.pop(context) + }), + const SizedBox( + width: 10, + ), + ElevatedButton( + child: const Text("方向设置"), + onPressed: () => { + controller.isGenerate.value = true, + controller.checkValue.value = "checkDirection", + controller.isDirect.value = true, + controller.centerXY.value = + Offset(centerPointX, centerPointY), + Navigator.pop(context) + }), + ], + ), + Row(children: [ + FixedWidthTextWidget(width: titleTextWidth, text: "X:"), + inputText( + inputLength: inputLength, + value: centerPointX.toString(), + fontsize: fontSize, + focusNode: yFocus, + onChanged: (value) => value.isNotEmpty + ? centerPointY = double.parse(value) + : '') + ]), + Row(children: [ + FixedWidthTextWidget(width: titleTextWidth, text: "Y:"), + inputText( + inputLength: inputLength, + value: centerPointY.toString(), + fontsize: fontSize, + focusNode: xFocus, + onChanged: (value) => value.isNotEmpty + ? centerPointX = double.parse(value) + : '') + ]), + Row(children: [ + FixedWidthTextWidget(width: titleTextWidth, text: "方向(°):"), + inputText( + inputLength: inputLength, + value: controller.direction.toString(), + fontsize: fontSize, + focusNode: directionFocus, + keyboardType: 0, + onChanged: (value) { + if (value.isNotEmpty) { + controller.direction.value = double.parse(value); + // bug 值修改后 绘制没有变化 + controller.angle.value = + controller.direction.value * pi / 180; + } + }) + ]), + Row(children: [ + FixedWidthTextWidget( + width: titleTextWidth + 10, text: "夯点间距(m):"), + inputText( + inputLength: inputLength - 10, + fontsize: fontSize, + value: controller.space.toString(), + focusNode: pileSpaceFocus, + onChanged: (value) => { + value.isNotEmpty + ? controller.space.value = double.parse(value) + : '', + }) + ]), + Row(children: [ + FixedWidthTextWidget( + width: titleTextWidth + 10, text: "宽度(m):"), + inputText( + inputLength: inputLength - 10, + fontsize: fontSize, + value: controller.pileWidth.toString(), + focusNode: pileWidthFocus, + onChanged: (value) => { + value.isNotEmpty + ? controller.pileWidth.value = + double.parse(value) + : '', + }) + ]), + Row(children: [ + const Icon( + Icons.tips_and_updates_outlined, + color: Colors.red, + ), + Text( + controller.isPileId.value + ? '选中桩点:${controller.checkName.value}' + : ' 未选中桩点', + style: TextStyle( + color: !controller.isPileId.value + ? Colors.red + : Colors.black), + ) + ]), + ], + )), + Positioned( + bottom: 10, + child: Row( + children: [ + TextButton( + child: const Text('取消'), + onPressed: () { + controller.isGenerate.value = false; + controller.isDirect.value = false; + controller.isSave.value = false; + // 执行取消的逻辑 + Navigator.of(context).pop(); + }, + ), + TextButton( + child: const Text('确定'), + onPressed: () { + // 执行确定的逻辑 + var dx = controller.canvasSize.width / 2; + var dy = controller.canvasSize.height / 2; + for (int i = 0; i < controller.plumList.length; i++) { + Offset item = controller.plumList[i]; + + Offset xy = mapController.ScreenCenter2xy( + item.dx - dx, item.dy - dy); + PilePoint pilePoint = PilePoint( + x: xy.dx, + y: xy.dy, + state: 0, + id: i + 1, + radius: 0.3); + mapController.pilePoints.add(pilePoint); + } + controller.isGenerate.value = false; + controller.isDirect.value = false; + controller.isSave.value = true; + controller.centerXY.value = + Offset(centerPointX, centerPointY); + + Navigator.of(context).pop(); + }, + ), + ], + )) + ], + ), + ), + ); + } +} diff --git a/lib/service/base.dart b/lib/service/base.dart index 5e16114..ed335dd 100644 --- a/lib/service/base.dart +++ b/lib/service/base.dart @@ -9,7 +9,7 @@ class BaseService { //创建client实例 final _client = http.Client(); final String token = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc1IiOjAsInJvbGVJZHMiOlsiMSIsIjI0Il0sInVzZXJuYW1lIjoiYWRtaW4iLCJ1c2VySWQiOjEsIlBWIjo1LCJvcmciOiJhIiwiaWF0IjoxNzIyODY1MTE0LCJleHAiOjE3MjQxNjExMTR9.zuY366ldKkbtd1TTfcYIZfvhrovMlXLzzRk3j65Ua7o"; + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc1IiOjAsInJvbGVJZHMiOlsiODMiXSwidXNlcm5hbWUiOiJseWNzIiwidXNlcklkIjozNTYsIlBWIjoyLCJvcmciOiJhIiwiaWF0IjoxNzI0MDI5MzcwLCJleHAiOjE3MjUzMjUzNzB9.w24n7SSTXz3vnRNqKmt2zht_xbXR-iQ1EnreBIWqYNU"; // String baseUrl = "http://192.168.1.189:8001";//本地 String baseUrl = "http://1.82.251.83:8001"; //线上 @@ -80,8 +80,14 @@ class GetServices { // 设备绑定 --- 获取设备 Future getDeviceBind() async { Map res = await service.getClient( + // '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode'); + // if (res['code'] == 1000) { + // return res['data']; + // } else { + // return []; + // } '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode'); - if (res['code'] == 1000) { + if (res != null && res['code'] == 1000) { return res['data']; } else { return []; diff --git a/lib/service/pile/device_type.dart b/lib/service/pile/device_type.dart new file mode 100644 index 0000000..9c85a22 --- /dev/null +++ b/lib/service/pile/device_type.dart @@ -0,0 +1,34 @@ +import 'package:flutter/widgets.dart'; + +enum DeviceType { + mobile, + tablet, + desktop, +} + +DeviceType getDeviceType(BuildContext context) { + final screenSize = MediaQuery.of(context).size; + const minWidth = 500; // 设定判断平板的最小宽度 + const maxWidth = 1024; // 设定判断电脑的最大宽度 + final orientation = MediaQuery.of(context).orientation; + + if (orientation == Orientation.portrait) { + // 竖屏时按照宽度判断设备类型 + if (screenSize.width < minWidth) { + return DeviceType.mobile; // 宽度小于最小宽度,判断为手机 + } else if (screenSize.width <= maxWidth) { + return DeviceType.tablet; // 宽度在最小宽度和最大宽度之间,判断为平板 + } else { + return DeviceType.desktop; // 宽度大于最大宽度,判断为电脑 + } + } else { + // 横屏时按照高度判断设备类型 + if (screenSize.height < minWidth) { + return DeviceType.mobile; // 高度小于最小宽度,判断为手机 + } else if (screenSize.height <= maxWidth) { + return DeviceType.tablet; // 高度在最小宽度和最大宽度之间,判断为平板 + } else { + return DeviceType.desktop; // 高度大于最大宽度,判断为电脑 + } + } +} \ No newline at end of file diff --git a/lib/service/pile/input.dart b/lib/service/pile/input.dart new file mode 100644 index 0000000..5da8c94 --- /dev/null +++ b/lib/service/pile/input.dart @@ -0,0 +1,168 @@ +// ignore_for_file: must_be_immutable + +import 'package:flutter/material.dart'; +import 'device_type.dart'; + +// ignore: camel_case_types, +class inputText extends StatefulWidget { + //内容 + String value; + //跟在后面的单位,默认为空 + String? endValue; + //控制焦点 + FocusNode? focusNode; + //控制长度 + double inputLength; + //控制键盘类型,默认为数字0,其他参数都是字符串 + int keyboardType; + //回调数据变化后返回新值 + double fontsize; + double inputHeight; + final ValueChanged? onChanged; + final Function()? onTap; + inputText( + {super.key, + required this.value, + required this.focusNode, + required this.onChanged, + this.endValue = "", + this.inputLength = 200, + this.keyboardType = 0, + this.fontsize = 20, + this.inputHeight = 40, + this.onTap}); + + @override + State createState() => _inputTextState(); +} + +// ignore: camel_case_types +class _inputTextState extends State { + //控制默认文本 + TextEditingController? _controller; + //传入的值,作为显示的初始值 + String _inputTextContext = ""; + //字体 + late double _fontSize; + // late double _inputHeight; + Color _fontcolor = Colors.black; + @override + void initState() { + super.initState(); + _inputTextContext = widget.value; + _controller = TextEditingController(text: _inputTextContext); + _fontSize = widget.fontsize; + // _inputHeight = widget.inputHeight; + } + + @override + Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + _fontcolor = isDarkMode ? Colors.white : Colors.black; + final deviceType = getDeviceType(context); + double dynamicWidth = deviceType == DeviceType.mobile ? 0 : 50; + return Row( + children: [ + Container( + margin: const EdgeInsets.only(bottom: 5), + width: widget.endValue != "" + ? widget.inputLength + dynamicWidth - 5 + : widget.inputLength + dynamicWidth, + height: widget.inputHeight, + child: TextField( + keyboardType: widget.keyboardType == 0 + ? TextInputType.number + : TextInputType.text, + clipBehavior: Clip.hardEdge, + focusNode: widget.focusNode, + controller: _controller, + style: TextStyle(fontSize: _fontSize, color: _fontcolor), + onChanged: (value) { + setState(() { + _inputTextContext = value; + }); + // 调用回调函数,通知外部数据变化 + if (widget.onChanged != null) { + widget.onChanged!(value); + } + }, + decoration: InputDecoration( + contentPadding: const EdgeInsets.only(left: 10), + hintText: _inputTextContext, + border: const OutlineInputBorder( + borderSide: BorderSide(width: 1, color: Colors.black))), + onTap: widget.onTap, + ), + ), + Container( + padding: const EdgeInsets.only(left: 10), + child: Transform.translate( + offset: const Offset(-35.0, 0.0), + child: Text( + "${widget.endValue}", + style: TextStyle(fontSize: _fontSize, color: _fontcolor), + ), + ), + ) + ], + ); + } +} + +class DropDown extends StatefulWidget { + List optionList = []; + double listLength; + double fontSize; + double listHeight; + final void Function(String?) onValueChanged; + DropDown( + {super.key, + required this.optionList, + this.listLength = 200, + this.fontSize = 20, + this.listHeight = 50, + required this.onValueChanged}); + + @override + State createState() => _DropDownState(); +} + +class _DropDownState extends State { + List optionList = []; + String? dropdownValue; + @override + void initState() { + super.initState(); + optionList = widget.optionList; + // dropdownValue = widget.optionList.isNotEmpty ? widget.optionList[0] : null; + dropdownValue = optionList[0]; + + // widget.onValueChanged(optionList[0]); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + widget.onValueChanged(dropdownValue); + }); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + height: widget.listHeight, + width: widget.listLength, + child: DropdownButton( + value: dropdownValue, + style: TextStyle(fontSize: widget.fontSize, color: Colors.black), + onChanged: (String? newValue) { + setState(() { + dropdownValue = newValue!; + }); + widget.onValueChanged(newValue); + }, + items: optionList.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + )); + } +} diff --git a/lib/service/pile/public_widget.dart b/lib/service/pile/public_widget.dart new file mode 100644 index 0000000..256b353 --- /dev/null +++ b/lib/service/pile/public_widget.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; + +import 'device_type.dart'; + + + +class InlineRowWidget extends StatelessWidget { + final List children; + + const InlineRowWidget({super.key, required this.children}); + + @override + Widget build(BuildContext context) { + return IntrinsicWidth( + child: Row( + children: children, + ), + ); + } +} + +class AlignWrapWidget extends StatelessWidget { + final List children; + + const AlignWrapWidget({super.key, required this.children}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Align( + alignment: Alignment.centerLeft, + child: Wrap( + children: children, + ), + ), + ); + } +} + +// ignore: must_be_immutable +class FixedWidthTextWidget extends StatelessWidget { + final String text; + final double width; + final TextStyle? style; + + FixedWidthTextWidget({ + super.key, + required this.text, + this.width = 80, + this.style, + }); + TextStyle? textStyle; + @override + Widget build(BuildContext context) { + final deviceType = getDeviceType(context); + double dynamicWidth = deviceType == DeviceType.mobile ? 0 : 50; + + if (style != null) { + textStyle = + style!.copyWith(fontSize: deviceType == DeviceType.mobile ? 16 : 20); + } else { + textStyle = + TextStyle(fontSize: deviceType == DeviceType.mobile ? 16 : 20); + } + return Container( + margin: const EdgeInsets.symmetric(horizontal: 3), + width: width + dynamicWidth, + child: Text( + text, + style: textStyle, + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index a56f94c..0b24b90 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -307,6 +307,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + roslibdart: + dependency: "direct main" + description: + name: roslibdart + sha256: "7473a39947f3f5ee32b032f8bab5285a465449e5cd234ae486e5ea11bd6c9e3b" + url: "https://pub.dev" + source: hosted + version: "0.0.1-dev+4" scence_map: dependency: "direct main" description: @@ -439,6 +447,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a3614d8..5c15f7d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: google_fonts: ^6.2.1 syncfusion_flutter_sliders: ^26.2.9 bottom_picker: ^2.8.0 + roslibdart: ^0.0.1-dev+4 dev_dependencies: flutter_test: