field_control.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. import 'package:app_business/service/api.dart';
  2. import 'package:track_common/service/map_watch.dart';
  3. import 'package:track_common/track_common.dart';
  4. import 'package:track_common/view/home/field_control/field_control.dart';
  5. import 'package:track_common/view/home/field_control/field_control_controller.dart';
  6. import 'package:track_common/widget/prelude.dart';
  7. class FieldControlPageImpl extends FieldControlPage {
  8. const FieldControlPageImpl({super.key});
  9. @override
  10. Widget get rightColumn {
  11. return Obx(() {
  12. final mapWatch = controller.mapWatch;
  13. debug('${identityHashCode(controller)}');
  14. return Container(
  15. width: 370,
  16. padding: const EdgeInsets.all(6.4),
  17. height: double.infinity,
  18. color: Colors.white,
  19. child: Column(
  20. children: [
  21. SizedBox(
  22. width: double.infinity,
  23. child: DarkButton(
  24. onPressed: mapWatch != null
  25. ? () => _onTapRegister(mapWatch)
  26. : null,
  27. child: const Text('注册比赛'))),
  28. const Expanded(child: EventInfoView())
  29. ],
  30. ));
  31. });
  32. }
  33. Future<void> _onTapRegister(MapWatch mapWatch) async {
  34. final r = await Get.dialog(const RegisterDialog(), arguments: mapWatch.id)
  35. as RegisterInfo?;
  36. if (r != null) {
  37. Get.find<ApiService>().stub.toMatchRegusterAdd(ToMatchRegusterAddRequest()
  38. ..actId = r.id
  39. ..regName = r.name
  40. ..startAt = r.startAt.toPb()
  41. ..stopAt = r.stopAt.toPb()
  42. ..isQueryPwd = r.password != null
  43. ..queryPasswd = r.password ?? '');
  44. }
  45. }
  46. }
  47. class EventInfo {
  48. int id = 0;
  49. String name = '';
  50. }
  51. class RegisterInfo {
  52. var id = 0;
  53. var name = '';
  54. var startAt = DateTime.now();
  55. var stopAt = DateTime.now();
  56. String? password;
  57. }
  58. class FieldControlControllerImpl extends FieldControlController {
  59. @override
  60. void onInit() {
  61. debug('init');
  62. super.onInit();
  63. }
  64. @override
  65. void onClose() {
  66. super.onClose();
  67. debug('close');
  68. }
  69. }
  70. class RegisterDialogController extends GetxController {
  71. var registerName = '';
  72. final date = Rx<DateTime?>(null);
  73. final registerStartAt = Rx<TimeOfDay?>(null);
  74. final registerStopAt = Rx<TimeOfDay?>(null);
  75. final selected = Rx<EventInfo?>(null);
  76. final eventList = <EventInfo>[].obs;
  77. final hasPassword = false.obs;
  78. var password = '';
  79. late final int mapId;
  80. final api = Get.find<ApiService>();
  81. String? get dateString {
  82. final d = date.value;
  83. if (d != null) {
  84. return '${d.month}/${d.day}';
  85. }
  86. return null;
  87. }
  88. @override
  89. void onInit() {
  90. mapId = Get.arguments as int;
  91. api.stub.toActivitySelectList(IdRequest()..id = Int64(mapId)).then((r) {
  92. eventList.value = r.list
  93. .map((e) => EventInfo()
  94. ..id = e.actId
  95. ..name = e.actName)
  96. .toList();
  97. });
  98. super.onInit();
  99. }
  100. }
  101. class RegisterDialog extends GetView<RegisterDialogController> {
  102. const RegisterDialog({super.key});
  103. @override
  104. Widget build(BuildContext context) {
  105. return GetBuilder(
  106. init: RegisterDialogController(),
  107. builder: (c) {
  108. return AlertDialog(
  109. title: const Center(
  110. child: Text(
  111. '注册比赛',
  112. style: TextStyle(fontSize: 17),
  113. )),
  114. backgroundColor: Colors.white,
  115. shape: RoundedRectangleBorder(
  116. borderRadius: BorderRadius.circular(17.78)),
  117. content: SizedBox(
  118. width: 320,
  119. child: ListView(
  120. shrinkWrap: true,
  121. children: [
  122. Obx(() => SizedBox(
  123. child: DropdownMenu<EventInfo>(
  124. key: GlobalKey(),
  125. width: 320,
  126. hintText: '请选择活动',
  127. onSelected: (one) {
  128. controller.selected.value = one;
  129. },
  130. inputDecorationTheme: InputDecorationTheme(
  131. border: textBorder,
  132. isDense: true,
  133. ),
  134. dropdownMenuEntries: controller.eventList
  135. .map((e) => DropdownMenuEntry<EventInfo>(
  136. value: e, label: e.name))
  137. .toList()))),
  138. const SizedBox(height: 21.34),
  139. _TextField(
  140. hint: '请输入名称',
  141. onChanged: (v) {
  142. c.registerName = v;
  143. }),
  144. const SizedBox(height: 21.34),
  145. Row(children: [
  146. Expanded(
  147. child: Obx(() => _TextField(
  148. hint: '日期',
  149. readOnly: true,
  150. initText: c.dateString,
  151. onTap: () async {
  152. c.date.value = await _showDatePicker(
  153. context, c.date.value);
  154. }))),
  155. const SizedBox(width: 15.64),
  156. Expanded(
  157. child: Obx(() => _TextField(
  158. hint: '开始时间',
  159. readOnly: true,
  160. initText:
  161. c.registerStartAt.value?.format(context),
  162. onTap: () async {
  163. c.registerStartAt.value = await _showTimePicker(
  164. context, c.registerStartAt.value);
  165. }))),
  166. const SizedBox(width: 15.64),
  167. Expanded(
  168. child: Obx(() => _TextField(
  169. hint: '结束时间',
  170. readOnly: true,
  171. initText: c.registerStopAt.value?.format(context),
  172. onTap: () async {
  173. c.registerStopAt.value = await _showTimePicker(
  174. context, c.registerStopAt.value);
  175. }))),
  176. ]),
  177. const SizedBox(height: 21.34),
  178. Row(
  179. mainAxisSize: MainAxisSize.min,
  180. children: [
  181. Obx(() => Switch(
  182. value: c.hasPassword.value,
  183. onChanged: (v) {
  184. c.hasPassword.value = v;
  185. })),
  186. const Text('查询密码'),
  187. const SizedBox(width: 12),
  188. Obx(() => Expanded(
  189. child: Visibility(
  190. visible: c.hasPassword.value,
  191. child: _TextField(
  192. hint: '请输入密码',
  193. onChanged: (v) {
  194. c.password = v;
  195. })))),
  196. ],
  197. ),
  198. const SizedBox(height: 21.34),
  199. SizedBox(
  200. width: double.infinity,
  201. child: DarkButton(
  202. onPressed: _onRegister, child: const Text('注 册')))
  203. ],
  204. )),
  205. );
  206. });
  207. }
  208. void _onRegister() {
  209. final date = controller.date.value;
  210. final timeStartAt = controller.registerStartAt.value;
  211. final timeStopAt = controller.registerStopAt.value;
  212. final selected = controller.selected.value;
  213. if (selected == null) {
  214. Get.snackbar('错误', '请选择一个活动');
  215. return;
  216. }
  217. if (controller.registerName.isEmpty) {
  218. Get.snackbar('错误', '输入名称');
  219. return;
  220. }
  221. if (date == null) {
  222. Get.snackbar('错误', '请选择日期');
  223. return;
  224. }
  225. if (timeStartAt == null) {
  226. Get.snackbar('错误', '请选择开始时间');
  227. return;
  228. }
  229. if (timeStopAt == null) {
  230. Get.snackbar('错误', '请选择结束时间');
  231. return;
  232. }
  233. final startAt =
  234. date.copyWith(hour: timeStartAt.hour, minute: timeStartAt.minute);
  235. final stopAt =
  236. date.copyWith(hour: timeStopAt.hour, minute: timeStopAt.minute);
  237. if (startAt.isAfter(stopAt)) {
  238. Get.snackbar('错误', '结束时间应晚于开始时间');
  239. return;
  240. }
  241. Get.back(
  242. result: RegisterInfo()
  243. ..id = selected.id
  244. ..name = controller.registerName
  245. ..startAt = startAt
  246. ..stopAt = stopAt
  247. ..password =
  248. controller.hasPassword.value ? controller.password : null);
  249. }
  250. Future<TimeOfDay?> _showTimePicker(
  251. BuildContext context, TimeOfDay? init) async {
  252. final TimeOfDay? time = await showTimePicker(
  253. context: context,
  254. initialTime: init ?? TimeOfDay.now(),
  255. );
  256. return time;
  257. }
  258. Future<DateTime?> _showDatePicker(
  259. BuildContext context, DateTime? init) async {
  260. final DateTime? time = await showDatePicker(
  261. context: context,
  262. initialDate: init ?? DateTime.now(),
  263. firstDate: DateTime.now(),
  264. lastDate: DateTime.now().add(365.days),
  265. );
  266. return time;
  267. }
  268. }
  269. final textBorder = OutlineInputBorder(
  270. borderSide: const BorderSide(width: 0.71, color: Color(0xff818181)),
  271. borderRadius: BorderRadius.circular(2.13),
  272. );
  273. class _TextField extends StatelessWidget {
  274. const _TextField(
  275. {required this.hint,
  276. this.onChanged,
  277. this.readOnly = false,
  278. this.onTap,
  279. this.initText});
  280. final String hint;
  281. final void Function(String)? onChanged;
  282. final bool readOnly;
  283. final void Function()? onTap;
  284. final String? initText;
  285. @override
  286. Widget build(BuildContext context) {
  287. return SizedBox(
  288. child: TextFormField(
  289. key: GlobalKey(),
  290. initialValue: initText,
  291. maxLines: 1,
  292. onChanged: onChanged,
  293. onTap: onTap,
  294. readOnly: readOnly,
  295. decoration: InputDecoration(
  296. hintText: hint,
  297. border: textBorder,
  298. isDense: true,
  299. // contentPadding: const EdgeInsets.all(8.53)
  300. )),
  301. );
  302. }
  303. }