dialog_event_register.dart 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. import 'package:track_common/widget/prelude.dart';
  2. import '../../service/api.dart';
  3. import 'field_control.dart';
  4. class _ArgCreate {
  5. int mapId = 0;
  6. Iterable<EventInfo> eventList = [];
  7. }
  8. class _ArgEdit {
  9. int mapId = 0;
  10. EventRegisterInfo old = EventRegisterInfo();
  11. }
  12. extension DateTimeExt on DateTime {
  13. (DateTime, TimeOfDay) split() {
  14. return (DateTime(year, month, day), TimeOfDay.fromDateTime(this));
  15. }
  16. }
  17. Future<EventRegisterInfo?> showEventRegisterDialog(
  18. int mapId, Iterable<EventInfo> eventList) async {
  19. return await Get.dialog(const RegisterDialog(),
  20. arguments: _ArgCreate()
  21. ..mapId = mapId
  22. ..eventList = eventList);
  23. }
  24. Future<EventRegisterInfo?> showEventEditDialog(
  25. int mapId, EventRegisterInfo old) async {
  26. return await Get.dialog(const RegisterDialog(),
  27. arguments: _ArgEdit()
  28. ..mapId = mapId
  29. ..old = old);
  30. }
  31. class RegisterDialogController extends GetxController {
  32. var registerName = '';
  33. final selected = Rx<EventInfo?>(null);
  34. final hasPasswordQuery = false.obs;
  35. final hasPasswordEvent = false.obs;
  36. var passwordQuery = '';
  37. var passwordEvent = '';
  38. late final int mapId;
  39. late final Iterable<EventInfo>? eventList;
  40. late final Object _args;
  41. Rx<DateTime?> eventDate = Rx(null);
  42. TimeOfDay? eventStartAt;
  43. TimeOfDay? eventEndAt;
  44. Rx<DateTime?> showDateStart = Rx(null);
  45. TimeOfDay? showStartAt;
  46. Rx<DateTime?> showDateEnd = Rx(null);
  47. TimeOfDay? showEndAt;
  48. @override
  49. void onInit() {
  50. final args = Get.arguments;
  51. _args = args;
  52. if (args is _ArgCreate) {
  53. mapId = args.mapId;
  54. eventList = args.eventList;
  55. }
  56. if (args is _ArgEdit) {
  57. eventList = null;
  58. mapId = args.mapId;
  59. registerName = args.old.name;
  60. {
  61. final (date, time) = args.old.eventStartAt.split();
  62. eventDate.value = date;
  63. eventStartAt = time;
  64. eventEndAt = TimeOfDay.fromDateTime(args.old.eventStopAt);
  65. }
  66. {
  67. final (date, time) = args.old.showStartAt.split();
  68. showDateStart.value = date;
  69. showStartAt = time;
  70. }
  71. {
  72. final (date, time) = args.old.showStopAt.split();
  73. showDateEnd.value = date;
  74. showEndAt = time;
  75. }
  76. passwordQuery = args.old.passwordQuery ?? '';
  77. hasPasswordQuery.value = args.old.passwordQuery != null;
  78. passwordEvent = args.old.passwordEvent ?? '';
  79. hasPasswordEvent.value = args.old.passwordEvent != null;
  80. }
  81. super.onInit();
  82. }
  83. void updateShowTime(DateTime? dateStart, TimeOfDay? startAt,
  84. DateTime? dateEnd, TimeOfDay? endAt) {
  85. if (dateStart != null) {
  86. showDateStart.value = dateStart;
  87. }
  88. if (startAt != null) {
  89. showStartAt = startAt;
  90. }
  91. if (endAt != null) {
  92. showEndAt = endAt;
  93. }
  94. if (dateEnd != null) {
  95. showDateEnd.value = dateEnd;
  96. }
  97. }
  98. void updateEventTime(DateTime? date, TimeOfDay? startAt, TimeOfDay? endAt) {
  99. if (date != null) {
  100. eventDate.value = date;
  101. }
  102. if (startAt != null) {
  103. eventStartAt = startAt;
  104. }
  105. if (endAt != null) {
  106. eventEndAt = endAt;
  107. }
  108. }
  109. }
  110. const double dialogWidth = 400.0;
  111. class RegisterDialog extends GetView<RegisterDialogController> {
  112. const RegisterDialog({super.key});
  113. @override
  114. Widget build(BuildContext context) {
  115. return GetBuilder(
  116. init: RegisterDialogController(),
  117. builder: (c) {
  118. final children = <Widget>[];
  119. final eventList = controller.eventList;
  120. if (eventList != null) {
  121. children.addAll([
  122. SizedBox(
  123. child: DropdownMenu<EventInfo>(
  124. key: GlobalKey(),
  125. width: dialogWidth,
  126. hintText: '请选择活动',
  127. onSelected: (one) {
  128. controller.selected.value = one;
  129. },
  130. inputDecorationTheme: InputDecorationTheme(
  131. border: textBorder,
  132. isDense: true,
  133. ),
  134. dropdownMenuEntries: eventList
  135. .map((e) => DropdownMenuEntry<EventInfo>(
  136. value: e, label: e.name))
  137. .toList())),
  138. const SizedBox(height: 21.34),
  139. ]);
  140. }
  141. children.addAll([
  142. _TextField(
  143. hint: '请输入名称',
  144. onChanged: (v) {
  145. c.registerName = v;
  146. },
  147. initText: controller.registerName.isEmpty
  148. ? null
  149. : controller.registerName,
  150. ),
  151. const SizedBox(height: 21.34),
  152. Obx(() => _EventTimeSelect(
  153. date: c.eventDate.value,
  154. startAt: c.eventStartAt,
  155. endAt: c.eventEndAt,
  156. onChanged: c.updateEventTime)),
  157. const SizedBox(height: 12),
  158. Obx(() => _ShowTimeSelect(
  159. dateStart: c.showDateStart.value,
  160. startAt: c.showStartAt,
  161. dateEnd: c.showDateEnd.value,
  162. endAt: c.showEndAt,
  163. onChanged: c.updateShowTime)),
  164. password('查询密码', c.hasPasswordQuery, (v) {
  165. c.passwordQuery = v;
  166. }),
  167. // password('赛事密码', c.hasPasswordEvent, (v) {
  168. // c.passwordEvent = v;
  169. // }),
  170. const SizedBox(height: 21.34),
  171. SizedBox(
  172. width: double.infinity,
  173. child: DarkButton(
  174. onPressed: _onRegister,
  175. child: Text(eventList != null ? '注 册' : '确 定')))
  176. ]);
  177. return AlertDialog(
  178. title: Center(
  179. child: Text(
  180. eventList != null ? '注册比赛' : '编辑比赛',
  181. style: const TextStyle(fontSize: 17),
  182. )),
  183. backgroundColor: Colors.white,
  184. shape: RoundedRectangleBorder(
  185. borderRadius: BorderRadius.circular(17.78)),
  186. content: SizedBox(
  187. width: dialogWidth,
  188. child: ListView(shrinkWrap: true, children: children)),
  189. );
  190. });
  191. }
  192. Widget password(
  193. String title,
  194. Rx<bool> hasPassword,
  195. void Function(String) onChanged,
  196. ) {
  197. return SizedBox(
  198. height: 80,
  199. child: Row(mainAxisSize: MainAxisSize.min, children: [
  200. Obx(() => Switch(
  201. value: hasPassword.value,
  202. onChanged: (v) {
  203. hasPassword.value = v;
  204. })),
  205. Text(title),
  206. const SizedBox(width: 12),
  207. Obx(() => Expanded(
  208. child: Visibility(
  209. visible: hasPassword.value,
  210. child: _TextField(hint: '请输入密码', onChanged: onChanged))))
  211. ]));
  212. }
  213. void _onRegister() {
  214. final showDateStart = controller.showDateStart.value;
  215. final showDateEnd = controller.showDateEnd.value;
  216. final showTimeStartAt = controller.showStartAt;
  217. final showTimeStopAt = controller.showEndAt;
  218. final evenDate = controller.eventDate;
  219. final eventTimeStartAt = controller.eventStartAt;
  220. final eventTimeStopAt = controller.eventEndAt;
  221. final selected = controller.selected.value;
  222. final args = controller._args;
  223. var selectedId = -1;
  224. if (args is _ArgCreate) {
  225. if (selected == null) {
  226. Get.snackbar('错误', '请选择一个活动');
  227. return;
  228. }
  229. selectedId = selected.id;
  230. }
  231. if (args is _ArgEdit) {
  232. selectedId = args.old.id;
  233. }
  234. if (controller.registerName.isEmpty) {
  235. Get.snackbar('错误', '输入名称');
  236. return;
  237. }
  238. if (showDateStart == null) {
  239. Get.snackbar('错误', '请选择显示开始日期');
  240. return;
  241. }
  242. if (showDateEnd == null) {
  243. Get.snackbar('错误', '请选择显示结束日期');
  244. return;
  245. }
  246. if (showTimeStartAt == null) {
  247. Get.snackbar('错误', '请选择开始时间');
  248. return;
  249. }
  250. if (showTimeStopAt == null) {
  251. Get.snackbar('错误', '请选择结束时间');
  252. return;
  253. }
  254. if (evenDate.value == null) {
  255. Get.snackbar('错误', '请选择日期');
  256. return;
  257. }
  258. if (eventTimeStartAt == null) {
  259. Get.snackbar('错误', '请选择开始时间');
  260. return;
  261. }
  262. if (eventTimeStopAt == null) {
  263. Get.snackbar('错误', '请选择结束时间');
  264. return;
  265. }
  266. final eventStartAt = evenDate.value!
  267. .copyWith(hour: eventTimeStartAt.hour, minute: eventTimeStartAt.minute);
  268. final eventStopAt = evenDate.value!
  269. .copyWith(hour: eventTimeStopAt.hour, minute: eventTimeStopAt.minute);
  270. if (eventStartAt.isAfter(eventStopAt)) {
  271. Get.snackbar('错误', '结束时间应晚于开始时间');
  272. return;
  273. }
  274. final showStartAt = showDateStart.copyWith(
  275. hour: showTimeStartAt.hour, minute: showTimeStartAt.minute);
  276. final showStopAt = showDateEnd.copyWith(
  277. hour: showTimeStopAt.hour, minute: showTimeStopAt.minute);
  278. if (showStartAt.isAfter(showStopAt)) {
  279. Get.snackbar('错误', '结束时间应晚于开始时间');
  280. return;
  281. }
  282. Get.back(
  283. result: EventRegisterInfo()
  284. ..id = selectedId
  285. ..name = controller.registerName
  286. ..showStartAt = showStartAt
  287. ..showStopAt = showStopAt
  288. ..eventStartAt = eventStartAt
  289. ..eventStopAt = eventStopAt
  290. ..passwordQuery = controller.hasPasswordQuery.value
  291. ? controller.passwordQuery
  292. : null
  293. ..passwordEvent = controller.hasPasswordEvent.value
  294. ? controller.passwordEvent
  295. : null);
  296. }
  297. }
  298. Future<TimeOfDay?> _showTimePicker(
  299. BuildContext context, TimeOfDay? init) async {
  300. final TimeOfDay? time = await showTimePicker(
  301. context: context,
  302. initialTime: init ?? TimeOfDay.now(),
  303. );
  304. return time;
  305. }
  306. Future<DateTime?> _showDatePicker(BuildContext context, DateTime? init) async {
  307. final DateTime? time = await showDatePicker(
  308. context: context,
  309. initialDate: init ?? DateTime.now(),
  310. firstDate: DateTime.now(),
  311. lastDate: DateTime.now().add(365.days),
  312. );
  313. return time;
  314. }
  315. final textBorder = OutlineInputBorder(
  316. borderSide: const BorderSide(width: 0.71, color: Color(0xff818181)),
  317. borderRadius: BorderRadius.circular(2.13),
  318. );
  319. class _TextField extends StatelessWidget {
  320. const _TextField(
  321. {required this.hint,
  322. this.onChanged,
  323. this.readOnly = false,
  324. this.onTap,
  325. this.initText});
  326. final String hint;
  327. final void Function(String)? onChanged;
  328. final bool readOnly;
  329. final void Function()? onTap;
  330. final String? initText;
  331. @override
  332. Widget build(BuildContext context) {
  333. return SizedBox(
  334. child: TextFormField(
  335. key: GlobalKey(),
  336. initialValue: initText,
  337. maxLines: 1,
  338. onChanged: onChanged,
  339. onTap: onTap,
  340. readOnly: readOnly,
  341. decoration: InputDecoration(
  342. hintText: hint,
  343. border: textBorder,
  344. isDense: true,
  345. // contentPadding: const EdgeInsets.all(8.53)
  346. )),
  347. );
  348. }
  349. }
  350. const timeColor = Color(0xff6e6e6e);
  351. class _TimeSelect extends StatelessWidget {
  352. const _TimeSelect({required this.children, required this.title});
  353. final String title;
  354. final List<Widget> children;
  355. @override
  356. Widget build(BuildContext context) {
  357. return Column(
  358. mainAxisSize: MainAxisSize.min,
  359. crossAxisAlignment: CrossAxisAlignment.start,
  360. children: [
  361. Text(
  362. title,
  363. style: const TextStyle(color: Colors.black),
  364. ),
  365. Container(
  366. height: 54,
  367. width: double.infinity,
  368. decoration: BoxDecoration(
  369. borderRadius: BorderRadius.circular(2.5),
  370. border: Border.all(color: timeColor, width: 1)),
  371. child: DefaultTextStyle(
  372. style: const TextStyle(color: timeColor),
  373. child: Row(
  374. children: children,
  375. )))
  376. ],
  377. );
  378. }
  379. }
  380. class _TimeButton extends StatelessWidget {
  381. const _TimeButton(
  382. {required this.onPressed, required this.hint, required this.value});
  383. final VoidCallback onPressed;
  384. final String hint;
  385. final String? value;
  386. @override
  387. Widget build(BuildContext context) {
  388. return TextButton(
  389. onPressed: onPressed,
  390. child: Text(value ?? hint, style: const TextStyle(color: timeColor)));
  391. }
  392. }
  393. class _EventTimeSelect extends StatefulWidget {
  394. const _EventTimeSelect(
  395. {this.date, this.startAt, this.endAt, required this.onChanged});
  396. final DateTime? date;
  397. final TimeOfDay? startAt;
  398. final TimeOfDay? endAt;
  399. final void Function(DateTime? date, TimeOfDay? startAt, TimeOfDay? endAt)
  400. onChanged;
  401. @override
  402. State<StatefulWidget> createState() {
  403. return _EventTimeSelectState();
  404. }
  405. }
  406. class _EventTimeSelectState extends State<_EventTimeSelect> {
  407. DateTime? date;
  408. TimeOfDay? startAt;
  409. TimeOfDay? endAt;
  410. @override
  411. void initState() {
  412. date = widget.date;
  413. startAt = widget.startAt;
  414. endAt = widget.endAt;
  415. super.initState();
  416. }
  417. @override
  418. Widget build(BuildContext context) {
  419. return _TimeSelect(
  420. title: '比赛时间',
  421. children: [
  422. Expanded(
  423. child: _TimeButton(
  424. onPressed: () async {
  425. date = await _showDatePicker(context, date);
  426. setState(() {});
  427. widget.onChanged(date, null, null);
  428. },
  429. hint: '比赛日期',
  430. value: dateString(date))),
  431. const Text('-'),
  432. Expanded(
  433. child: _TimeButton(
  434. onPressed: () async {
  435. startAt = await _showTimePicker(context, startAt);
  436. setState(() {});
  437. widget.onChanged(null, startAt, null);
  438. },
  439. hint: '开始时间',
  440. value: startAt?.format(context))),
  441. const Text("-"),
  442. Expanded(
  443. child: _TimeButton(
  444. onPressed: () async {
  445. endAt = await _showTimePicker(context, endAt);
  446. setState(() {});
  447. widget.onChanged(null, null, endAt);
  448. },
  449. hint: '结束时间',
  450. value: endAt?.format(context))),
  451. const Text(' '),
  452. Expanded(child: TextButton(onPressed: () {}, child: const SizedBox()))
  453. ],
  454. );
  455. }
  456. }
  457. class _ShowTimeSelect extends StatefulWidget {
  458. const _ShowTimeSelect(
  459. {this.dateStart,
  460. this.dateEnd,
  461. this.startAt,
  462. this.endAt,
  463. required this.onChanged});
  464. final DateTime? dateStart;
  465. final DateTime? dateEnd;
  466. final TimeOfDay? startAt;
  467. final TimeOfDay? endAt;
  468. final void Function(DateTime? dateStart, TimeOfDay? startAt,
  469. DateTime? dateEnd, TimeOfDay? endAt) onChanged;
  470. @override
  471. State<StatefulWidget> createState() {
  472. return _ShowTimeSelectState();
  473. }
  474. }
  475. class _ShowTimeSelectState extends State<_ShowTimeSelect> {
  476. DateTime? dateStart;
  477. DateTime? dateEnd;
  478. TimeOfDay? startAt;
  479. TimeOfDay? endAt;
  480. @override
  481. void initState() {
  482. dateStart = widget.dateStart;
  483. dateEnd = widget.dateEnd;
  484. startAt = widget.startAt;
  485. endAt = widget.endAt;
  486. super.initState();
  487. }
  488. @override
  489. Widget build(BuildContext context) {
  490. return _TimeSelect(
  491. title: '显示时间',
  492. children: [
  493. Expanded(
  494. child: _TimeButton(
  495. onPressed: () async {
  496. dateStart = await _showDatePicker(context, dateStart);
  497. setState(() {});
  498. widget.onChanged(dateStart, null, null, null);
  499. },
  500. hint: '开始日期',
  501. value: dateString(dateStart))),
  502. const Text('-'),
  503. Expanded(
  504. child: _TimeButton(
  505. onPressed: () async {
  506. startAt = await _showTimePicker(context, startAt);
  507. setState(() {});
  508. widget.onChanged(null, startAt, null, null);
  509. },
  510. hint: '开始时间',
  511. value: startAt?.format(context))),
  512. const Text('至'),
  513. Expanded(
  514. child: _TimeButton(
  515. onPressed: () async {
  516. dateEnd = await _showDatePicker(context, dateEnd);
  517. setState(() {});
  518. widget.onChanged(null, null, dateEnd, null);
  519. },
  520. hint: '结束日期',
  521. value: dateString(dateEnd))),
  522. const Text("-"),
  523. Expanded(
  524. child: _TimeButton(
  525. onPressed: () async {
  526. endAt = await _showTimePicker(context, endAt);
  527. setState(() {});
  528. widget.onChanged(null, null, null, endAt);
  529. },
  530. hint: '结束时间',
  531. value: endAt?.format(context))),
  532. ],
  533. );
  534. }
  535. }
  536. String? dateString(DateTime? d) {
  537. if (d != null) {
  538. return '${d.month}/${d.day}';
  539. }
  540. return null;
  541. }
  542. class _DateTimeSelect extends StatefulWidget {
  543. const _DateTimeSelect(
  544. {required this.title,
  545. this.date,
  546. this.startAt,
  547. this.endAt,
  548. required this.onChanged});
  549. final String title;
  550. final DateTime? date;
  551. final TimeOfDay? startAt;
  552. final TimeOfDay? endAt;
  553. final void Function(DateTime? date, TimeOfDay? startAt, TimeOfDay? endAt)
  554. onChanged;
  555. @override
  556. State<StatefulWidget> createState() {
  557. return _DateTimeSelectState();
  558. }
  559. }
  560. class _DateTimeSelectState extends State<_DateTimeSelect> {
  561. DateTime? date;
  562. TimeOfDay? startAt;
  563. TimeOfDay? endAt;
  564. @override
  565. void initState() {
  566. date = widget.date;
  567. startAt = widget.startAt;
  568. endAt = widget.endAt;
  569. super.initState();
  570. }
  571. String? dateString(DateTime? d) {
  572. if (d != null) {
  573. return '${d.month}/${d.day}';
  574. }
  575. return null;
  576. }
  577. @override
  578. Widget build(BuildContext context) {
  579. return Column(
  580. mainAxisSize: MainAxisSize.min,
  581. crossAxisAlignment: CrossAxisAlignment.start,
  582. children: [
  583. Text(widget.title),
  584. Row(children: [
  585. Expanded(
  586. child: _TextField(
  587. hint: '日期',
  588. readOnly: true,
  589. initText: dateString(date),
  590. onTap: () async {
  591. date = await _showDatePicker(context, date);
  592. setState(() {});
  593. widget.onChanged(date, null, null);
  594. })),
  595. const SizedBox(width: 15.64),
  596. Expanded(
  597. child: _TextField(
  598. hint: '开始时间',
  599. readOnly: true,
  600. initText: startAt?.format(context),
  601. onTap: () async {
  602. startAt = await _showTimePicker(context, startAt);
  603. setState(() {});
  604. widget.onChanged(null, startAt, null);
  605. })),
  606. const SizedBox(width: 15.64),
  607. Expanded(
  608. child: _TextField(
  609. hint: '结束时间',
  610. readOnly: true,
  611. initText: endAt?.format(context),
  612. onTap: () async {
  613. endAt = await _showTimePicker(context, endAt);
  614. setState(() {});
  615. widget.onChanged(null, null, endAt);
  616. })),
  617. ]),
  618. ],
  619. );
  620. }
  621. }