registration.dart 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. import 'package:eitc_erm_app/select_department.dart';
  2. import 'package:eitc_erm_app/utils/Component.dart';
  3. import 'package:eitc_erm_app/utils/Constants.dart';
  4. import 'package:eitc_erm_app/utils/DateUtils.dart';
  5. import 'package:eitc_erm_app/utils/logger.dart';
  6. import 'package:eitc_erm_app/widget/loading.dart';
  7. import 'package:eitc_erm_app/widget/user_header.dart';
  8. import 'package:flutter/cupertino.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:http/http.dart' as http;
  11. import 'bean/doctor_list.dart' as dcl;
  12. import 'bean/user_list.dart';
  13. import 'confirm_registration.dart';
  14. import 'doctor_detail.dart';
  15. // void main() => runApp(Registration());
  16. UserListEntity mUserListEntity = new UserListEntity();
  17. int mWhichPatient = 0;
  18. class Registration extends StatefulWidget {
  19. Registration(
  20. {required Key key, required userListEntity, required whichPatient})
  21. : super(key: key) {
  22. mUserListEntity = userListEntity;
  23. mWhichPatient = whichPatient;
  24. }
  25. @override
  26. State<StatefulWidget> createState() => RegistrationState();
  27. }
  28. class RegistrationState extends State<Registration> {
  29. DateTime now = DateTime.now();
  30. ValueNotifier<dynamic> result = ValueNotifier(null);
  31. late Future<dcl.DoctorListEntity?>? _future = null;
  32. String searchDeptName = "";
  33. int selectItem = -1;
  34. String selectDateStr = "";
  35. String halfHourLater = "";
  36. @override
  37. void initState() {
  38. super.initState();
  39. _future = fetchData();
  40. }
  41. @override
  42. Widget build(BuildContext context) {
  43. return Scaffold(
  44. appBar: AppBar(
  45. title: const Text('预约挂号',
  46. style: TextStyle(
  47. color: Colors.white,
  48. )),
  49. centerTitle: true,
  50. elevation: 0.5,
  51. backgroundColor: Global.StatusBarColor,
  52. leading: IconButton(
  53. tooltip: '返回上一页',
  54. icon: const Icon(
  55. Icons.arrow_back_ios,
  56. color: Colors.white,
  57. ),
  58. onPressed: () {
  59. Navigator.of(context).pop();
  60. //_nextPage(-1);
  61. },
  62. ),
  63. ),
  64. body: Column(children: [
  65. Row(children: [
  66. GestureDetector(
  67. onTap: () {
  68. _showDatePicker(0);
  69. },
  70. child: Container(
  71. alignment: Alignment.center,
  72. height: 50.0,
  73. width: 50,
  74. color: Global.StatusBarColor,
  75. child: const Column(
  76. mainAxisSize: MainAxisSize.min,
  77. children: <Widget>[
  78. Icon(
  79. Icons.calendar_month_outlined,
  80. size: 15,
  81. color: Colors.white,
  82. ),
  83. Text(
  84. '全部',
  85. style: TextStyle(fontSize: 12, color: Colors.white),
  86. ),
  87. ],
  88. ),
  89. )),
  90. Expanded(
  91. child: Container(
  92. height: 50.0,
  93. width: 350,
  94. color: Global.StatusBarColor,
  95. child: ListView(
  96. scrollDirection: Axis.horizontal,
  97. children: <Widget>[
  98. GestureDetector(
  99. onTap: () {
  100. setState(() {
  101. selectItem = 0;
  102. _showDatePicker(0);
  103. });
  104. },
  105. child: Container(
  106. alignment: Alignment.center,
  107. margin: const EdgeInsets.all(3),
  108. padding: const EdgeInsets.only(right: 5.0, left: 5.0),
  109. decoration: selectItem == 0
  110. ? const BoxDecoration(
  111. borderRadius:
  112. BorderRadius.all(Radius.circular(10.0)),
  113. color: Colors.white)
  114. : null,
  115. child: Text(
  116. "今天\n ${LocalDateUtils.getMMDD(now, "-")} ",
  117. textAlign: TextAlign.center,
  118. style: TextStyle(
  119. fontSize: 10,
  120. color: (selectItem == 0)
  121. ? Global.StatusBarColor
  122. : Colors.white,
  123. ),
  124. ),
  125. ),
  126. ),
  127. GestureDetector(
  128. onTap: () {
  129. setState(() {
  130. _showDatePicker(1);
  131. selectItem = 1;
  132. });
  133. },
  134. child: Container(
  135. alignment: Alignment.center,
  136. margin: const EdgeInsets.all(3),
  137. padding: const EdgeInsets.only(right: 5.0, left: 5.0),
  138. decoration: selectItem == 1
  139. ? const BoxDecoration(
  140. borderRadius:
  141. BorderRadius.all(Radius.circular(10.0)),
  142. color: Colors.white)
  143. : null,
  144. child: Text(
  145. "${LocalDateUtils.getWeekday(now.add(const Duration(days: 1)))}\n ${LocalDateUtils.getMMDD(now.add(const Duration(days: 1)), "-")} ",
  146. style: TextStyle(
  147. fontSize: 10,
  148. color: (selectItem == 1)
  149. ? Global.StatusBarColor
  150. : Colors.white,
  151. ),
  152. ),
  153. ),
  154. ),
  155. GestureDetector(
  156. onTap: () {
  157. setState(() {
  158. _showDatePicker(2);
  159. selectItem = 2;
  160. });
  161. },
  162. child: Container(
  163. alignment: Alignment.center,
  164. margin: const EdgeInsets.all(3),
  165. padding: const EdgeInsets.only(right: 5.0, left: 5.0),
  166. decoration: selectItem == 2
  167. ? const BoxDecoration(
  168. borderRadius:
  169. BorderRadius.all(Radius.circular(10.0)),
  170. color: Colors.white)
  171. : null,
  172. child: Text(
  173. "${LocalDateUtils.getWeekday(now.add(const Duration(days: 2)))}\n ${LocalDateUtils.getMMDD(now.add(const Duration(days: 2)), "-")} ",
  174. style: TextStyle(
  175. fontSize: 10,
  176. color: (selectItem == 2)
  177. ? Global.StatusBarColor
  178. : Colors.white,
  179. ),
  180. ),
  181. ),
  182. ),
  183. GestureDetector(
  184. onTap: () {
  185. setState(() {
  186. _showDatePicker(3);
  187. selectItem = 3;
  188. });
  189. },
  190. child: Container(
  191. alignment: Alignment.center,
  192. margin: const EdgeInsets.all(3),
  193. padding: const EdgeInsets.only(right: 5.0, left: 5.0),
  194. decoration: selectItem == 3
  195. ? const BoxDecoration(
  196. borderRadius:
  197. BorderRadius.all(Radius.circular(10.0)),
  198. color: Colors.white)
  199. : null,
  200. child: Text(
  201. "${LocalDateUtils.getWeekday(now.add(const Duration(days: 3)))}\n ${LocalDateUtils.getMMDD(now.add(const Duration(days: 3)), "-")} ",
  202. style: TextStyle(
  203. fontSize: 10,
  204. color: (selectItem == 3)
  205. ? Global.StatusBarColor
  206. : Colors.white,
  207. ),
  208. ),
  209. ),
  210. ),
  211. GestureDetector(
  212. onTap: () {
  213. setState(() {
  214. _showDatePicker(4);
  215. selectItem = 4;
  216. });
  217. },
  218. child: Container(
  219. alignment: Alignment.center,
  220. margin: const EdgeInsets.all(3),
  221. padding: const EdgeInsets.only(right: 5.0, left: 5.0),
  222. decoration: selectItem == 4
  223. ? const BoxDecoration(
  224. borderRadius:
  225. BorderRadius.all(Radius.circular(10.0)),
  226. color: Colors.white)
  227. : null,
  228. child: Text(
  229. "${LocalDateUtils.getWeekday(now.add(const Duration(days: 4)))}\n ${LocalDateUtils.getMMDD(now.add(const Duration(days: 4)), "-")} ",
  230. style: TextStyle(
  231. fontSize: 10,
  232. color: (selectItem == 4)
  233. ? Global.StatusBarColor
  234. : Colors.white,
  235. ),
  236. ),
  237. ),
  238. ),
  239. GestureDetector(
  240. onTap: () {
  241. setState(() {
  242. _showDatePicker(5);
  243. selectItem = 5;
  244. });
  245. },
  246. child: Container(
  247. alignment: Alignment.center,
  248. margin: const EdgeInsets.all(3),
  249. padding: const EdgeInsets.only(right: 5.0, left: 5.0),
  250. decoration: selectItem == 5
  251. ? const BoxDecoration(
  252. borderRadius:
  253. BorderRadius.all(Radius.circular(10.0)),
  254. color: Colors.white)
  255. : null,
  256. child: Text(
  257. "${LocalDateUtils.getWeekday(now.add(const Duration(days: 5)))}\n ${LocalDateUtils.getMMDD(now.add(const Duration(days: 5)), "-")} ",
  258. style: TextStyle(
  259. fontSize: 10,
  260. color: (selectItem == 5)
  261. ? Global.StatusBarColor
  262. : Colors.white,
  263. ),
  264. ),
  265. ),
  266. ),
  267. GestureDetector(
  268. onTap: () {
  269. setState(() {
  270. _showDatePicker(6);
  271. selectItem = 6;
  272. });
  273. },
  274. child: Container(
  275. alignment: Alignment.center,
  276. margin: const EdgeInsets.all(3),
  277. padding: const EdgeInsets.only(right: 5.0, left: 5.0),
  278. decoration: selectItem == 6
  279. ? const BoxDecoration(
  280. borderRadius:
  281. BorderRadius.all(Radius.circular(10.0)),
  282. color: Colors.white)
  283. : null,
  284. child: Text(
  285. "${LocalDateUtils.getWeekday(now.add(const Duration(days: 6)))}\n ${LocalDateUtils.getMMDD(now.add(const Duration(days: 6)), "-")} ",
  286. style: TextStyle(
  287. fontSize: 10,
  288. color: (selectItem == 6)
  289. ? Global.StatusBarColor
  290. : Colors.white,
  291. ),
  292. ),
  293. ),
  294. ),
  295. // 更多的子Widget根据需要添加
  296. ],
  297. ),
  298. ),
  299. ),
  300. ]),
  301. InkWell(
  302. onTap: () async {
  303. final result = await Navigator.push(
  304. context,
  305. MaterialPageRoute(builder: (context) => SelectDepartment()),
  306. );
  307. setState(() {
  308. searchDeptName = result;
  309. _future = fetchData();
  310. });
  311. },
  312. child: Container(
  313. width: double.infinity,
  314. alignment: Alignment.center,
  315. padding: const EdgeInsets.symmetric(vertical: 15),
  316. child: const Text(
  317. "点击查找科室",
  318. style: TextStyle(fontSize: 18, color: Colors.blue),
  319. ),
  320. ),
  321. ),
  322. const Divider(
  323. indent: 5,
  324. endIndent: 5,
  325. height: 0,
  326. ),
  327. const SizedBox(
  328. height: 5,
  329. ),
  330. Align(
  331. alignment: Alignment.centerLeft,
  332. child: Padding(
  333. padding: const EdgeInsets.only(left: 5),
  334. child: Text(
  335. "坐诊医生",
  336. style: Theme.of(context).textTheme.titleMedium,
  337. ),
  338. ),
  339. ),
  340. const SizedBox(
  341. height: 5,
  342. ),
  343. Expanded(
  344. child: FutureBuilder<dynamic>(
  345. future: _future,
  346. builder: (context, snapshot) {
  347. if (snapshot.hasData) {
  348. dcl.DoctorListEntity data = snapshot.data;
  349. return ListView.builder(
  350. itemCount: data.data!.length,
  351. itemBuilder: (context, index) {
  352. return _getListItem(
  353. context, index, data, data.data?[index]);
  354. },
  355. );
  356. } else if (snapshot.hasError) {
  357. return Text('Error: ${snapshot.error}');
  358. }
  359. return const ColorLoader();
  360. },
  361. ),
  362. ),
  363. ]),
  364. );
  365. }
  366. Widget _getListItem(BuildContext context, int index,
  367. dcl.DoctorListEntity listEntity, dcl.Data? data) {
  368. if (data == null) {
  369. return const SizedBox();
  370. }
  371. return Container(
  372. color: Colors.white,
  373. margin: const EdgeInsets.all(5.0),
  374. child: Container(
  375. padding: const EdgeInsets.all(10.0),
  376. child: Column(
  377. mainAxisSize: MainAxisSize.min,
  378. children: [
  379. Row(
  380. crossAxisAlignment: CrossAxisAlignment.start,
  381. children: [
  382. UserHeader(url: "${Global.ImageUrl}${data.avatar}"),
  383. const SizedBox(
  384. width: 5,
  385. ),
  386. Expanded(
  387. child: Column(
  388. crossAxisAlignment: CrossAxisAlignment.start,
  389. children: [
  390. Row(children: [
  391. Expanded(
  392. child: Text.rich(
  393. TextSpan(children: [
  394. TextSpan(
  395. text: data.nickName,
  396. style:
  397. Theme.of(context).textTheme.titleSmall),
  398. TextSpan(
  399. text: " ${data.deptName}",
  400. style: Theme.of(context).textTheme.bodySmall),
  401. ]),
  402. overflow: TextOverflow.ellipsis,
  403. ),
  404. ),
  405. OutlinedButton(
  406. style: ButtonStyle(
  407. padding: const WidgetStatePropertyAll(
  408. EdgeInsets.fromLTRB(10, 3, 10, 3)),
  409. minimumSize:
  410. const WidgetStatePropertyAll(Size.zero),
  411. side: const WidgetStatePropertyAll(
  412. BorderSide(color: Colors.blue)),
  413. tapTargetSize: MaterialTapTargetSize.shrinkWrap,
  414. shape: WidgetStatePropertyAll(
  415. RoundedRectangleBorder(
  416. borderRadius: BorderRadius.circular(5)))),
  417. child: const Text(
  418. "查看详情",
  419. style: TextStyle(fontSize: 12, color: Colors.blue),
  420. ),
  421. onPressed: () {
  422. Navigator.push(
  423. context,
  424. MaterialPageRoute(
  425. builder: (context) => DoctorDetail(
  426. doctorListEntity: listEntity,
  427. key: const Key(''),
  428. which: index)),
  429. );
  430. },
  431. ),
  432. ]),
  433. data.doctorBlurb == null
  434. ? const SizedBox()
  435. : Text(data.doctorBlurb!,
  436. style: Theme.of(context)
  437. .textTheme
  438. .bodySmall
  439. ?.copyWith(color: Colors.black54)),
  440. ],
  441. ),
  442. ),
  443. ],
  444. ),
  445. Column(
  446. crossAxisAlignment: CrossAxisAlignment.end,
  447. mainAxisSize: MainAxisSize.min,
  448. children: [
  449. const Divider(),
  450. ElevatedButton(
  451. style: ButtonStyle(
  452. padding: const WidgetStatePropertyAll(
  453. EdgeInsets.fromLTRB(10, 3, 10, 3)),
  454. minimumSize: const WidgetStatePropertyAll(Size.zero),
  455. backgroundColor:
  456. const WidgetStatePropertyAll(Colors.blue),
  457. tapTargetSize: MaterialTapTargetSize.shrinkWrap,
  458. shape: WidgetStatePropertyAll(RoundedRectangleBorder(
  459. borderRadius: BorderRadius.circular(5)))),
  460. onPressed: () {
  461. logd(selectDateStr);
  462. if (selectDateStr.isEmpty) {
  463. Component.toast("请选择预约时间", 0);
  464. return;
  465. }
  466. Navigator.push(
  467. context,
  468. MaterialPageRoute(
  469. builder: (context) => ConfirmRegistration(
  470. visitTime: selectDateStr,
  471. visitTimeEnd: halfHourLater,
  472. userListEntity: mUserListEntity,
  473. whichPatient: mWhichPatient,
  474. doctorListEntity: listEntity,
  475. key: const Key(''),
  476. which: index)));
  477. },
  478. child: const Text("挂号",
  479. style: TextStyle(color: Colors.white, fontSize: 12)),
  480. ),
  481. ],
  482. )
  483. ],
  484. ),
  485. ),
  486. );
  487. }
  488. void _showDatePicker(int addDay) async {
  489. /*DateTime now = DateTime.now();
  490. DateTime late = now.add(const Duration(days: 365));
  491. showBoardDateTimePicker(
  492. context: context,
  493. pickerType: DateTimePickerType.datetime,
  494. options: const BoardDateTimeOptions(
  495. languages: BoardPickerLanguages(
  496. today: "今天", tomorrow: "明天", now: "现在", locale: "zh")));
  497. return;*/
  498. DateTime dateTime = DateTime(
  499. DateTime.now().year,
  500. DateTime.now().month,
  501. DateTime.now().day + addDay,
  502. DateTime.now().minute > 30
  503. ? DateTime.now().hour + 1
  504. : DateTime.now().hour,
  505. DateTime.now().minute > 30 ? 0 : 30);
  506. // 默认时间
  507. selectDateStr = dateTime.toString().replaceAll(":00.000", "");
  508. halfHourLater = dateTime
  509. .add(const Duration(minutes: 30))
  510. .toString()
  511. .replaceAll(":00.000", "");
  512. // 显示对话框
  513. await showCupertinoModalPopup<void>(
  514. context: context,
  515. builder: (BuildContext context) {
  516. return Column(
  517. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  518. children: <Widget>[
  519. SizedBox(height: 500),
  520. Expanded(
  521. child: Container(
  522. alignment: Alignment.center,
  523. decoration: BoxDecoration(
  524. borderRadius: BorderRadius.only(
  525. topLeft: Radius.circular(10),
  526. topRight: Radius.circular(10)),
  527. color: Colors.white),
  528. child: Column(
  529. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  530. children: <Widget>[
  531. Padding(
  532. padding: const EdgeInsets.fromLTRB(30, 10, 30, 0),
  533. child: Row(
  534. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  535. children: [
  536. Material(
  537. color: Colors.grey,
  538. borderRadius: BorderRadius.circular(5),
  539. child: InkWell(
  540. onTap: () {
  541. selectDateStr = "";
  542. Navigator.of(context).pop();
  543. },
  544. child: Container(
  545. height: 30,
  546. width: 50,
  547. alignment: Alignment.center,
  548. child: Text(
  549. "取消",
  550. style: TextStyle(
  551. color: Colors.white,
  552. ),
  553. )),
  554. ),
  555. ),
  556. Material(
  557. color: Colors.green,
  558. borderRadius: BorderRadius.circular(5),
  559. child: InkWell(
  560. onTap: () {
  561. _future = fetchData();
  562. Navigator.of(context).pop();
  563. },
  564. child: Container(
  565. height: 30,
  566. width: 50,
  567. alignment: Alignment.center,
  568. child: const Text(
  569. "确定",
  570. style: TextStyle(
  571. color: Colors.white,
  572. ),
  573. )),
  574. ),
  575. ),
  576. ],
  577. ),
  578. ),
  579. Expanded(
  580. child: CupertinoDatePicker(
  581. mode: CupertinoDatePickerMode.dateAndTime,
  582. // 日期选择器模式 `time`,`date`,`dateAndTime`, 默认`dateAndTime`
  583. initialDateTime: DateTime(
  584. DateTime.now().year,
  585. DateTime.now().month,
  586. DateTime.now().day + addDay,
  587. DateTime.now().minute > 30
  588. ? DateTime.now().hour + 1
  589. : DateTime.now().hour,
  590. DateTime.now().minute > 30 ? 0 : 30),
  591. // 初始化日期
  592. minimumDate: DateTime(2024, 07, 09),
  593. // 最小可选日期
  594. maximumDate: DateTime(2025, 07, 22),
  595. // 最大可选日期
  596. minimumYear: 2024,
  597. // 最小年份
  598. maximumYear: 2025,
  599. // 最大年份
  600. minuteInterval: 30,
  601. // 分钟间隔 initialDateTime.minute 必须可以整除 minuteInterval 必须是 60 的整数因子
  602. use24hFormat: true,
  603. // 是否使用24小时制
  604. dateOrder: DatePickerDateOrder.dmy,
  605. // 日期选择器排序方式 默认年/月/日
  606. backgroundColor: Colors.white,
  607. // 选中日期变化回调
  608. onDateTimeChanged: (dateTime) {
  609. logd(dateTime);
  610. selectDateStr =
  611. dateTime.toString().replaceAll(":00.000", "");
  612. halfHourLater = dateTime
  613. .add(const Duration(minutes: 30))
  614. .toString()
  615. .replaceAll(":00.000", "");
  616. // _chooseDateTime = dateTime;
  617. },
  618. ),
  619. ),
  620. ]),
  621. ),
  622. ),
  623. ]);
  624. },
  625. );
  626. }
  627. Future<dcl.DoctorListEntity?> fetchData() async {
  628. Map<String, String> headers = {
  629. 'token': Global.token,
  630. };
  631. const timeout = Duration(seconds: 30);
  632. final response = await http
  633. .get(
  634. Uri.parse(
  635. '${Global.BaseUrl}doctor/list?deptName=$searchDeptName&selectDateStr=$selectDateStr'),
  636. headers: jsonHeaders(withToken: true))
  637. .timeout(timeout);
  638. logd(
  639. '${Global.BaseUrl}doctor/list?deptName=$searchDeptName&selectDateStr=$selectDateStr');
  640. if (response.statusCode == 200) {
  641. final json = decodeBodyToJson(response.bodyBytes);
  642. logd("医生列表=$json");
  643. dcl.DoctorListEntity mDoctorListEntity =
  644. dcl.DoctorListEntity.fromJson(json);
  645. return mDoctorListEntity;
  646. } else {
  647. Component.toast("出错了,请稍后再试!", 0);
  648. }
  649. }
  650. }