field_control.dart 11 KB

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