doctor_detail.dart 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. import 'dart:io';
  2. import 'package:eitc_erm_app/select_patient.dart';
  3. import 'package:eitc_erm_app/utils/Component.dart';
  4. import 'package:eitc_erm_app/utils/Constants.dart';
  5. import 'package:eitc_erm_app/utils/logger.dart';
  6. import 'package:eitc_erm_app/widget/line.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';
  12. import 'bean/favourite_doctor_list.dart';
  13. import 'bean/normal_response.dart';
  14. import 'confirm_registration.dart';
  15. import 'online_consultation.dart';
  16. /*void main() {
  17. WidgetsFlutterBinding.ensureInitialized();
  18. runApp(DoctorDetail());
  19. }*/
  20. late DoctorListEntity mDoctorListEntity = new DoctorListEntity();
  21. int mWhich = 0;
  22. String selectDateStr = "";
  23. String halfHourLater = "";
  24. FavouriteDoctorListEntity mFavouriteDoctorListEntity =
  25. new FavouriteDoctorListEntity();
  26. class DoctorDetail extends StatefulWidget {
  27. DoctorDetail({required Key key, required doctorListEntity, which})
  28. : super(key: key) {
  29. mDoctorListEntity = doctorListEntity;
  30. mWhich = which;
  31. logd(mDoctorListEntity.data![mWhich].userId.toString() +
  32. " =====================");
  33. }
  34. @override
  35. State<StatefulWidget> createState() => DoctorDetailState();
  36. }
  37. class DoctorDetailState extends State<DoctorDetail> {
  38. List<Widget> widgetList = [];
  39. @override
  40. void initState() {
  41. super.initState();
  42. fetchData();
  43. String? doctorProficient = mDoctorListEntity.data?[mWhich].doctorProficient;
  44. List<String>? doctorProficientList = doctorProficient?.split(',');
  45. if (doctorProficientList != null) {
  46. for (var i = 0; i < doctorProficientList.length; i++) {
  47. widgetList.add(
  48. Container(
  49. padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0),
  50. decoration: BoxDecoration(
  51. color: Colors.lightBlueAccent,
  52. borderRadius: BorderRadius.circular(30)),
  53. child: Text(
  54. ' ${doctorProficientList[i]} ',
  55. style: const TextStyle(
  56. fontSize: 10,
  57. color: Colors.white,
  58. ),
  59. textAlign: TextAlign.center,
  60. ),
  61. ),
  62. );
  63. }
  64. }
  65. }
  66. @override
  67. Widget build(BuildContext context) {
  68. return Scaffold(
  69. appBar: AppBar(
  70. title: const Text('医生详情',
  71. style: TextStyle(
  72. color: Colors.white,
  73. )),
  74. centerTitle: true,
  75. elevation: 0.5,
  76. backgroundColor: Global.StatusBarColor,
  77. leading: IconButton(
  78. tooltip: '返回上一页',
  79. icon: const Icon(
  80. Icons.arrow_back_ios,
  81. color: Colors.white,
  82. ),
  83. onPressed: () {
  84. Navigator.of(context).pop();
  85. //_nextPage(-1);
  86. },
  87. ),
  88. ),
  89. body: Container(
  90. padding: const EdgeInsets.all(10),
  91. child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
  92. Row(mainAxisSize: MainAxisSize.max, children: [
  93. Padding(
  94. padding: const EdgeInsets.only(left: 10, top: 10, right: 10),
  95. child: SizedBox.fromSize(
  96. size: const Size.square(60),
  97. child: UserHeader(
  98. url:
  99. "${Global.ImageUrl}${mDoctorListEntity.data?[mWhich].avatar}",
  100. ),
  101. ),
  102. ),
  103. const SizedBox(
  104. width: 5,
  105. ),
  106. Expanded(
  107. child: Column(
  108. mainAxisAlignment: MainAxisAlignment.start,
  109. mainAxisSize: MainAxisSize.max,
  110. children: [
  111. Row(
  112. mainAxisAlignment: MainAxisAlignment.spaceAround,
  113. children: [
  114. Row(
  115. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  116. children: [
  117. Text(
  118. '${mDoctorListEntity.data?[mWhich].nickName}',
  119. style: const TextStyle(fontSize: 18),
  120. ),
  121. const SizedBox(
  122. width: 10,
  123. ),
  124. Text(
  125. mDoctorListEntity.data?[mWhich].postNames ??
  126. "",
  127. style: const TextStyle(
  128. fontSize: 15, color: Colors.brown),
  129. ),
  130. ]),
  131. const Spacer(),
  132. if (mDoctorListEntity.data?[mWhich].isCollection == 0)
  133. GestureDetector(
  134. child: const Icon(
  135. Icons.favorite_border,
  136. color: Colors.grey,
  137. ),
  138. onTap: () {
  139. collectDoctor();
  140. }),
  141. if (mDoctorListEntity.data?[mWhich].isCollection == 1)
  142. GestureDetector(
  143. child: const Icon(
  144. Icons.favorite,
  145. color: Colors.red,
  146. ),
  147. onTap: () {
  148. cancelCollectDoctor();
  149. }),
  150. ]),
  151. Container(
  152. padding: const EdgeInsets.only(top: 5),
  153. alignment: Alignment.centerLeft,
  154. width: double.infinity,
  155. child: Text(
  156. '服务人数:${mDoctorListEntity.data?[mWhich].receivePatientNum}人',
  157. style:
  158. const TextStyle(fontSize: 15, color: Colors.grey),
  159. ),
  160. ),
  161. ]),
  162. ),
  163. ]),
  164. Padding(
  165. padding: const EdgeInsets.all(10),
  166. child: Text(
  167. mDoctorListEntity.data?[mWhich].doctorBlurb ?? "简介:暂无。",
  168. style: const TextStyle(color: Colors.grey),
  169. ),
  170. ),
  171. Padding(
  172. padding: const EdgeInsets.all(10),
  173. child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
  174. const Text(
  175. '擅长:',
  176. style: TextStyle(color: Colors.grey),
  177. ),
  178. widgetList.isEmpty
  179. ? const Text(
  180. "暂无。",
  181. style: TextStyle(color: Colors.grey),
  182. )
  183. : Expanded(
  184. child: Wrap(
  185. direction: Axis.horizontal,
  186. spacing: 5.0,
  187. runSpacing: 5.0,
  188. children: widgetList,
  189. )),
  190. ]),
  191. ),
  192. Line(),
  193. const Padding(
  194. padding: EdgeInsets.all(10),
  195. child: Text(
  196. '服务项目',
  197. style: TextStyle(fontSize: 18, color: Colors.black),
  198. ),
  199. ),
  200. Padding(
  201. padding: const EdgeInsets.all(10),
  202. child: Row(
  203. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  204. children: <Widget>[
  205. const Row(
  206. mainAxisSize: MainAxisSize.min,
  207. children: <Widget>[
  208. Icon(
  209. Icons.collections_bookmark,
  210. color: Colors.blue,
  211. size: 35,
  212. ),
  213. SizedBox(width: 10),
  214. Text('图文咨询',
  215. style:
  216. TextStyle(color: Colors.deepPurple, fontSize: 20)),
  217. ],
  218. ),
  219. ElevatedButton(
  220. style: ButtonStyle(
  221. backgroundColor:
  222. WidgetStateProperty.resolveWith<Color>((states) {
  223. return Colors.orange; // Regular color
  224. }),
  225. ),
  226. onPressed: () {
  227. if (Global.selectPatient != -1) {
  228. Navigator.push(
  229. context,
  230. MaterialPageRoute(
  231. builder: (context) => OnlineConsultation()),
  232. );
  233. } else {
  234. Component.toast("请先选择就诊人", 1);
  235. Navigator.push(
  236. context,
  237. MaterialPageRoute(
  238. builder: (context) =>
  239. SelectPatient("fromDoctorDetail")),
  240. );
  241. }
  242. },
  243. child: const Text("问诊",
  244. style: TextStyle(color: Colors.white, fontSize: 15)),
  245. ),
  246. ],
  247. ),
  248. ),
  249. Padding(
  250. padding: const EdgeInsets.all(10),
  251. child: Row(
  252. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  253. children: <Widget>[
  254. const Row(
  255. mainAxisSize: MainAxisSize.min,
  256. children: <Widget>[
  257. Icon(
  258. Icons.reddit_outlined,
  259. color: Colors.blue,
  260. size: 35,
  261. ),
  262. SizedBox(width: 10),
  263. Text('挂号预约',
  264. style:
  265. TextStyle(color: Colors.deepPurple, fontSize: 20)),
  266. ],
  267. ),
  268. ElevatedButton(
  269. style: ButtonStyle(
  270. backgroundColor:
  271. WidgetStateProperty.resolveWith<Color>((states) {
  272. return Colors.blue; // Regular color
  273. }),
  274. ),
  275. onPressed: () async {
  276. if (Global.selectPatient != -1) {
  277. if (selectDateStr.isEmpty) {
  278. Component.toast("请选择预约时间", 0);
  279. _showDatePicker(0);
  280. return;
  281. }
  282. Navigator.push(
  283. context,
  284. MaterialPageRoute(
  285. builder: (context) => ConfirmRegistration(
  286. visitTime: selectDateStr,
  287. visitTimeEnd: halfHourLater,
  288. userListEntity: Global.patient,
  289. whichPatient: Global.selectPatient,
  290. doctorListEntity: mDoctorListEntity,
  291. key: const Key(''),
  292. which: mWhich)));
  293. } else {
  294. Component.toast("请先选择就诊人", 1);
  295. Navigator.push(
  296. context,
  297. MaterialPageRoute(
  298. builder: (context) =>
  299. SelectPatient("fromDoctorDetail")),
  300. );
  301. }
  302. },
  303. child: const Text("挂号",
  304. style: TextStyle(color: Colors.white, fontSize: 15)),
  305. ),
  306. ],
  307. ),
  308. ),
  309. ]),
  310. ),
  311. );
  312. }
  313. Future<void> collectDoctor() async {
  314. var params = {
  315. "avatar": mDoctorListEntity.data?[mWhich].avatar,
  316. "briefIntroduction": mDoctorListEntity.data?[mWhich].doctorBlurb,
  317. "doctorId": mDoctorListEntity.data?[mWhich].userId,
  318. "doctorName": mDoctorListEntity.data?[mWhich].nickName,
  319. "label": "",
  320. "postName": mDoctorListEntity.data?[mWhich].postNames
  321. };
  322. var response = await http.post(
  323. Uri.parse(
  324. '${Global.BaseUrl}collection-doctor/collect-doctor'),
  325. body: encodeBody(params),
  326. headers: jsonHeaders(withToken: true));
  327. logd(response.body.toString());
  328. if (response.statusCode == 200) {
  329. final json = decodeBodyToJson(response.bodyBytes);
  330. logd("收藏医生结果=$json");
  331. NormalResponse mNormalResponse = new NormalResponse.fromJson(json);
  332. if (mNormalResponse.code == Global.responseSuccessCode) {
  333. Component.toast("收藏成功!", 2);
  334. setState(() {
  335. mDoctorListEntity.data?[mWhich].isCollection = 1;
  336. });
  337. } else {
  338. Component.toast(mNormalResponse.msg.toString(), 0);
  339. }
  340. } else {
  341. Component.toast("出错了,请稍后再试!", 0);
  342. return null;
  343. }
  344. }
  345. Future<FavouriteDoctorListEntity?> fetchData() async {
  346. Map<String, String> headers = {
  347. 'token': Global.token,
  348. };
  349. final response = await http.get(
  350. Uri.parse('${Global.BaseUrl}collection-doctor/list'),
  351. headers: headers);
  352. if (response.statusCode == 200) {
  353. final json = decodeBodyToJson(response.bodyBytes);
  354. logd("收藏的医生列表=$json");
  355. mFavouriteDoctorListEntity = FavouriteDoctorListEntity.fromJson(json);
  356. if (mFavouriteDoctorListEntity.code == Global.responseSuccessCode) {
  357. return mFavouriteDoctorListEntity;
  358. } else {
  359. Component.toast(mFavouriteDoctorListEntity.msg.toString(), 0);
  360. }
  361. return null;
  362. } else {
  363. Component.toast("出错了,请稍后再试!", 0);
  364. return null;
  365. }
  366. }
  367. Future<void> cancelCollectDoctor() async {
  368. var params = {
  369. "avatar": mDoctorListEntity.data?[mWhich].avatar,
  370. "briefIntroduction": mDoctorListEntity.data?[mWhich].doctorBlurb,
  371. "doctorId": mDoctorListEntity.data?[mWhich].userId,
  372. "doctorName": mDoctorListEntity.data?[mWhich].nickName,
  373. "label": "",
  374. "postName": mDoctorListEntity.data?[mWhich].postNames
  375. };
  376. var response = await http.post(
  377. Uri.parse(
  378. '${Global.BaseUrl}collection-doctor/cancel-collect-doctor'),
  379. body: encodeBody(params),
  380. headers: jsonHeaders(withToken: true));
  381. if (response.statusCode == 200) {
  382. final json = decodeBodyToJson(response.bodyBytes);
  383. logd("取消收藏医生结果=$json");
  384. NormalResponse mNormalResponse = NormalResponse.fromJson(json);
  385. if (mNormalResponse.code == Global.responseSuccessCode) {
  386. Component.toast("取消成功!", 2);
  387. setState(() {
  388. mDoctorListEntity.data?[mWhich].isCollection = 0;
  389. });
  390. } else {
  391. Component.toast(mNormalResponse.msg.toString(), 0);
  392. }
  393. } else {
  394. Component.toast("出错了,请稍后再试!", 0);
  395. return null;
  396. }
  397. }
  398. void _showDatePicker(int addDay) async {
  399. DateTime dateTime = DateTime(
  400. DateTime.now().year,
  401. DateTime.now().month,
  402. DateTime.now().day + addDay,
  403. DateTime.now().minute > 30
  404. ? DateTime.now().hour + 1
  405. : DateTime.now().hour,
  406. DateTime.now().minute > 30 ? 0 : 30);
  407. // 默认时间
  408. selectDateStr = dateTime.toString().replaceAll(":00.000", "");
  409. halfHourLater = dateTime
  410. .add(const Duration(minutes: 30))
  411. .toString()
  412. .replaceAll(":00.000", "");
  413. // 显示对话框
  414. await showCupertinoModalPopup<void>(
  415. context: context,
  416. builder: (BuildContext context) {
  417. return Column(
  418. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  419. children: <Widget>[
  420. SizedBox(height: 500),
  421. Expanded(
  422. child: Container(
  423. alignment: Alignment.center,
  424. decoration: BoxDecoration(
  425. borderRadius: BorderRadius.only(
  426. topLeft: Radius.circular(10),
  427. topRight: Radius.circular(10)),
  428. color: Colors.white),
  429. child: Column(
  430. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  431. children: <Widget>[
  432. Padding(
  433. padding: const EdgeInsets.fromLTRB(30, 10, 30, 0),
  434. child: Row(
  435. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  436. children: [
  437. Material(
  438. color: Colors.grey,
  439. borderRadius: BorderRadius.circular(5),
  440. child: InkWell(
  441. onTap: () {
  442. selectDateStr = "";
  443. Navigator.of(context).pop();
  444. },
  445. child: Container(
  446. height: 30,
  447. width: 50,
  448. alignment: Alignment.center,
  449. child: Text(
  450. "取消",
  451. style: TextStyle(
  452. color: Colors.white,
  453. ),
  454. )),
  455. ),
  456. ),
  457. Material(
  458. color: Colors.green,
  459. borderRadius: BorderRadius.circular(5),
  460. child: InkWell(
  461. onTap: () {
  462. Navigator.of(context).pop();
  463. },
  464. child: Container(
  465. height: 30,
  466. width: 50,
  467. alignment: Alignment.center,
  468. child: Text(
  469. "确定",
  470. style: TextStyle(
  471. color: Colors.white,
  472. ),
  473. )),
  474. ),
  475. ),
  476. ],
  477. ),
  478. ),
  479. Expanded(
  480. child: CupertinoDatePicker(
  481. mode: CupertinoDatePickerMode.dateAndTime,
  482. // 日期选择器模式 `time`,`date`,`dateAndTime`, 默认`dateAndTime`
  483. initialDateTime: DateTime(
  484. DateTime.now().year,
  485. DateTime.now().month,
  486. DateTime.now().day + addDay,
  487. DateTime.now().minute > 30
  488. ? DateTime.now().hour + 1
  489. : DateTime.now().hour,
  490. DateTime.now().minute > 30 ? 0 : 30),
  491. // 初始化日期
  492. minimumDate: DateTime(2024, 07, 09),
  493. // 最小可选日期
  494. maximumDate: DateTime(2025, 07, 22),
  495. // 最大可选日期
  496. minimumYear: 2024,
  497. // 最小年份
  498. maximumYear: 2025,
  499. // 最大年份
  500. minuteInterval: 30,
  501. // 分钟间隔 initialDateTime.minute 必须可以整除 minuteInterval 必须是 60 的整数因子
  502. use24hFormat: true,
  503. // 是否使用24小时制
  504. dateOrder: DatePickerDateOrder.dmy,
  505. // 日期选择器排序方式 默认年/月/日
  506. backgroundColor: Colors.white,
  507. // 选中日期变化回调
  508. onDateTimeChanged: (dateTime) {
  509. logd(dateTime);
  510. selectDateStr =
  511. dateTime.toString().replaceAll(":00.000", "");
  512. halfHourLater = dateTime
  513. .add(const Duration(minutes: 30))
  514. .toString()
  515. .replaceAll(":00.000", "");
  516. // _chooseDateTime = dateTime;
  517. },
  518. ),
  519. ),
  520. ]),
  521. ),
  522. ),
  523. ]);
  524. },
  525. );
  526. }
  527. }