online_consultation.dart 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:dio/dio.dart';
  4. import 'package:eitc_erm_app/chat/chat_home.dart';
  5. import 'package:eitc_erm_app/utils/Component.dart';
  6. import 'package:eitc_erm_app/utils/Constants.dart';
  7. import 'package:file_picker/file_picker.dart';
  8. import 'package:flutter/cupertino.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:flutter/services.dart';
  11. import 'package:permission_handler/permission_handler.dart';
  12. import 'bean/normal_response.dart';
  13. import 'bean/normal_response2.dart';
  14. import 'package:http/http.dart' as http;
  15. void main() {
  16. WidgetsFlutterBinding.ensureInitialized();
  17. runApp(OnlineConsultation());
  18. }
  19. class OnlineConsultation extends StatefulWidget {
  20. @override
  21. State<StatefulWidget> createState() => OnlineConsultationState();
  22. }
  23. class OnlineConsultationState extends State<OnlineConsultation> {
  24. List<String> uploadImg = ["assets/images/upload_photo.png"];
  25. TextEditingController resourceController = TextEditingController();
  26. String age = "请选择年龄";
  27. String sex = "请选择性别";
  28. List<int> ageList = List.generate(101, (index) => index);
  29. @override
  30. void initState() {
  31. super.initState();
  32. // initPlatformState();
  33. }
  34. Future<void> initPlatformState() async {
  35. //相机权限
  36. if (await requestCameraPermission() == false) {
  37. return;
  38. }
  39. //录音权限
  40. if (await requestMicrophonePermission() == false) {
  41. return;
  42. }
  43. }
  44. Future<bool> requestCameraPermission() async {
  45. var status = await Permission.camera.status;
  46. if (status == PermissionStatus.granted) {
  47. return true;
  48. } else {
  49. status = await Permission.camera.request();
  50. if (status == PermissionStatus.granted) {
  51. return true;
  52. } else {
  53. return false;
  54. }
  55. }
  56. }
  57. Future<bool> requestMicrophonePermission() async {
  58. var status = await Permission.microphone.status;
  59. if (status == PermissionStatus.granted) {
  60. return true;
  61. } else {
  62. status = await Permission.microphone.request();
  63. if (status == PermissionStatus.granted) {
  64. return true;
  65. } else {
  66. return false;
  67. }
  68. }
  69. }
  70. @override
  71. Widget build(BuildContext context) {
  72. return MaterialApp(
  73. home: Scaffold(
  74. resizeToAvoidBottomInset: false,
  75. backgroundColor: Global.BackgroundColor,
  76. appBar: new AppBar(
  77. title: new Text('在线问诊',
  78. style: TextStyle(
  79. color: Colors.white,
  80. )),
  81. centerTitle: true,
  82. elevation: 0.5,
  83. backgroundColor: Global.StatusBarColor,
  84. leading: new IconButton(
  85. tooltip: '返回上一页',
  86. icon: const Icon(
  87. Icons.arrow_back_ios,
  88. color: Colors.white,
  89. ),
  90. onPressed: () {
  91. Navigator.of(context).pop();
  92. //_nextPage(-1);
  93. },
  94. ),
  95. ),
  96. body: SingleChildScrollView(
  97. child: Container(
  98. padding: EdgeInsets.all(10),
  99. child: Column(
  100. mainAxisSize: MainAxisSize.min,
  101. crossAxisAlignment: CrossAxisAlignment.start,
  102. children: <Widget>[
  103. Padding(
  104. padding: EdgeInsets.all(10),
  105. child: Row(
  106. mainAxisAlignment:
  107. MainAxisAlignment.spaceBetween,
  108. children: [
  109. Text(
  110. '问诊资料',
  111. style: TextStyle(
  112. fontSize: 20, color: Colors.black),
  113. ),
  114. ]),
  115. ),
  116. ClipRRect(
  117. borderRadius: BorderRadius.circular(10.0),
  118. child: Container(
  119. color: Colors.white,
  120. padding: const EdgeInsets.all(10),
  121. child: Column(
  122. mainAxisSize: MainAxisSize.min,
  123. crossAxisAlignment: CrossAxisAlignment.start,
  124. children: <Widget>[
  125. /*Padding(
  126. padding: EdgeInsets.all(10),
  127. child: Row(
  128. mainAxisAlignment:
  129. MainAxisAlignment.spaceBetween,
  130. children: [
  131. Text(
  132. '挂号费',
  133. style: TextStyle(
  134. fontSize: 15, color: Colors.grey),
  135. ),
  136. Text(
  137. '¥12.5',
  138. style: TextStyle(fontSize: 15),
  139. ),
  140. ]),
  141. ),*/
  142. Padding(
  143. padding: EdgeInsets.all(10),
  144. child: Row(
  145. mainAxisAlignment:
  146. MainAxisAlignment.spaceBetween,
  147. children: [
  148. Text(
  149. '就诊人',
  150. style: TextStyle(
  151. fontSize: 15,
  152. color: Colors.grey),
  153. ),
  154. Text(
  155. Global
  156. .patient
  157. .data![Global.selectPatient]
  158. .patientName
  159. .toString(),
  160. style: TextStyle(fontSize: 15),
  161. ),
  162. ]),
  163. ),
  164. Padding(
  165. padding: EdgeInsets.all(10),
  166. child: Row(
  167. mainAxisAlignment:
  168. MainAxisAlignment.spaceBetween,
  169. children: [
  170. Text(
  171. '年龄',
  172. style: TextStyle(
  173. fontSize: 15,
  174. color: Colors.grey),
  175. ),
  176. GestureDetector(
  177. onTap: () {
  178. selectItem(ageList, 0);
  179. },
  180. child: Row(children: <Widget>[
  181. Text(
  182. age,
  183. style: TextStyle(
  184. color: Colors.black,
  185. ),
  186. ),
  187. Icon(
  188. Icons.keyboard_arrow_down,
  189. color: Colors.black,
  190. ),
  191. ])),
  192. ]),
  193. ),
  194. Padding(
  195. padding: EdgeInsets.all(10),
  196. child: GestureDetector(
  197. onTap: () {
  198. selectItem(['男', '女'], 1);
  199. },
  200. child: Row(
  201. mainAxisAlignment:
  202. MainAxisAlignment.spaceBetween,
  203. children: [
  204. Text(
  205. '性别',
  206. style: TextStyle(
  207. fontSize: 15,
  208. color: Colors.grey),
  209. ),
  210. Row(children: <Widget>[
  211. Text(
  212. sex,
  213. style: TextStyle(
  214. color: Colors.black,
  215. ),
  216. ),
  217. Icon(
  218. Icons.keyboard_arrow_down,
  219. color: Colors.black,
  220. ),
  221. ])
  222. ]),
  223. ),
  224. ),
  225. Padding(
  226. padding: EdgeInsets.all(10),
  227. child: Row(
  228. mainAxisAlignment:
  229. MainAxisAlignment.spaceBetween,
  230. children: [
  231. Text(
  232. '咨询医生',
  233. style: TextStyle(
  234. fontSize: 15,
  235. color: Colors.grey),
  236. ),
  237. Text(
  238. Global
  239. .doctor
  240. .data![Global.selectDoctor]
  241. .nickName
  242. .toString(),
  243. style: TextStyle(fontSize: 15),
  244. ),
  245. ]),
  246. ),
  247. ]),
  248. ),
  249. ),
  250. SizedBox(height: 8),
  251. Padding(
  252. padding: EdgeInsets.all(10),
  253. child: Row(
  254. mainAxisAlignment:
  255. MainAxisAlignment.spaceBetween,
  256. children: [
  257. Text(
  258. '病情资料',
  259. style: TextStyle(
  260. fontSize: 20, color: Colors.black),
  261. ),
  262. ]),
  263. ),
  264. ClipRRect(
  265. borderRadius: BorderRadius.circular(10.0),
  266. child: Container(
  267. color: Colors.white,
  268. padding: const EdgeInsets.all(10),
  269. child: Column(
  270. mainAxisSize: MainAxisSize.min,
  271. crossAxisAlignment: CrossAxisAlignment.start,
  272. children: <Widget>[
  273. Padding(
  274. padding: EdgeInsets.all(10),
  275. child: Row(
  276. mainAxisAlignment:
  277. MainAxisAlignment.spaceBetween,
  278. children: [
  279. Expanded(
  280. child: TextField(
  281. maxLines: 5,
  282. enabled: true,
  283. controller: resourceController,
  284. decoration: InputDecoration(
  285. border: OutlineInputBorder(),
  286. hintText:
  287. '请简单描述病情,录入:主要症状、发病时间、治疗过程、病情变化、想得到什么样的帮助等',
  288. ),
  289. ),
  290. ),
  291. ]),
  292. ),
  293. ]),
  294. ),
  295. ),
  296. Padding(
  297. padding: EdgeInsets.all(5),
  298. child: Column(
  299. crossAxisAlignment: CrossAxisAlignment.start,
  300. children: [
  301. Text(
  302. '上传患处、病历、检查单等照片',
  303. style: TextStyle(fontSize: 10),
  304. ),
  305. SizedBox(height: 3),
  306. GridView.builder(
  307. padding: const EdgeInsets.all(10),
  308. shrinkWrap: true,
  309. physics: NeverScrollableScrollPhysics(),
  310. gridDelegate:
  311. const SliverGridDelegateWithFixedCrossAxisCount(
  312. //注意此行
  313. crossAxisCount: 3, //每行 widget 数量
  314. crossAxisSpacing: 10, //widget 水平之间的距离
  315. mainAxisSpacing: 10, //widget 垂直之间的距离
  316. ),
  317. itemCount: uploadImg.length,
  318. // itemCount: 2,
  319. itemBuilder: _customWidget,
  320. ),
  321. /*GestureDetector(
  322. onTap: () {
  323. uploadFile();
  324. },
  325. child:
  326. Image(
  327. image: AssetImage('assets/images/upload_photo.png'),
  328. ),),*/
  329. ]),
  330. ),
  331. ElevatedButton(
  332. child: Text("下一步",
  333. style: TextStyle(
  334. color: Colors.white, fontSize: 15)),
  335. style: ButtonStyle(
  336. backgroundColor:
  337. MaterialStateProperty.resolveWith<Color>(
  338. (states) {
  339. return Colors.blue; // Regular color
  340. }),
  341. fixedSize: MaterialStateProperty.all<Size>(
  342. Size(MediaQuery.of(context).size.width - 30,
  343. 30), // 设置宽度和高度
  344. ),
  345. ),
  346. onPressed: () {
  347. editChatDisease();
  348. },
  349. ),
  350. ])))));
  351. }
  352. Widget _customWidget(BuildContext context, int index) {
  353. return GestureDetector(
  354. onTap: () {
  355. if (index == 0) {
  356. uploadFile();
  357. }
  358. },
  359. child: Container(
  360. child: Expanded(
  361. child: Column(
  362. children: [
  363. index == 0
  364. ? Image(
  365. image: AssetImage(
  366. 'assets/images/upload_photo.png',
  367. ),
  368. width: 80,
  369. )
  370. : Image.network(
  371. // 图片地址
  372. uploadImg[index],
  373. width: 80,
  374. fit: BoxFit.cover,
  375. excludeFromSemantics: true,
  376. errorBuilder: (context, error, stackTrace) => Icon(
  377. Icons.image,
  378. size: 80,
  379. color: Colors.grey,
  380. ),
  381. loadingBuilder: (context, child, loadingProgress) {
  382. if (loadingProgress == null) return child;
  383. return Center(
  384. child: CircularProgressIndicator(
  385. value: loadingProgress.expectedTotalBytes != null
  386. ? loadingProgress.cumulativeBytesLoaded /
  387. loadingProgress.expectedTotalBytes!
  388. : null,
  389. ),
  390. );
  391. },
  392. ),
  393. ],
  394. ),
  395. ),
  396. ),
  397. );
  398. }
  399. void uploadFile() async {
  400. FilePickerResult? result = await FilePicker.platform.pickFiles();
  401. if (result != null) {
  402. String fileName = result.files.single.name;
  403. String? filePath = result.files.single.path;
  404. FormData formData = FormData.fromMap({
  405. "file": await MultipartFile.fromFile(filePath!, filename: fileName),
  406. "path": "chat",
  407. });
  408. try {
  409. Map<String, String> headers = {
  410. 'token': '${Global.token}',
  411. };
  412. Response response = await Dio().post(
  413. Global.BaseUrl + 'common/minioUploadImage',
  414. data: formData,
  415. options: Options(headers: headers));
  416. print(response.data);
  417. if (response.statusCode == 200) {
  418. Normal2Response mNormal2Response =
  419. new Normal2Response.fromJson(response.data);
  420. if (mNormal2Response.code == Global.responseSuccessCode) {
  421. // Component.toast("上传成功!", 2);
  422. uploadImg.add(mNormal2Response.msg.toString());
  423. setState(() {});
  424. } else {
  425. Component.toast(mNormal2Response.msg.toString(), 0);
  426. }
  427. } else {
  428. Component.toast("出错了,请稍后再试!", 0);
  429. return null;
  430. }
  431. } catch (e) {
  432. print(e);
  433. }
  434. }
  435. }
  436. Future<void> editChatDisease() async {
  437. if (age == "请选择年龄") {
  438. Component.toast("请选择患者年龄!", 0);
  439. return;
  440. }
  441. if (sex == "请选择性别") {
  442. Component.toast("请选择患者性别!", 0);
  443. return;
  444. }
  445. if (resourceController.text.isEmpty) {
  446. Component.toast("请填写病情资料!", 0);
  447. return;
  448. }
  449. if (uploadImg.length < 1) {
  450. Component.toast("请上传病历图片!", 0);
  451. return;
  452. }
  453. String uploadImgStr = uploadImg
  454. .sublist(1, uploadImg.length)
  455. .toString()
  456. .replaceAll("[", "")
  457. .replaceAll("]", "");
  458. print(uploadImgStr);
  459. int ageInt = int.parse(age);
  460. int sexInt = 0;
  461. if(sex == "女")
  462. sexInt = 1;
  463. var params = {
  464. 'name': Global.patient.data![Global.selectPatient].patientName.toString(),
  465. 'age': ageInt,
  466. 'sex': sexInt,
  467. 'docker': Global.doctor.data![Global.selectDoctor].nickName.toString(),
  468. 'resource': resourceController.text,
  469. 'patientId': Global.patient.data![Global.selectPatient].patientId,
  470. 'url': uploadImgStr,
  471. };
  472. print(params);
  473. Map<String, String> headers = {
  474. HttpHeaders.contentTypeHeader: "application/json; charset=utf-8",
  475. 'token': '${Global.token}',
  476. };
  477. var response = await http.put(
  478. Uri.parse(Global.BaseUrl + 'chat/editChatDisease'),
  479. body: jsonEncode(params),
  480. headers: headers);
  481. print(response.body.toString());
  482. if (response.statusCode == 200) {
  483. final jsonString = utf8.decode(response.bodyBytes);
  484. final jsonResponse = jsonDecode(jsonString);
  485. print(jsonString);
  486. NormalResponse mNormalResponse =
  487. new NormalResponse.fromJson(jsonResponse);
  488. if (mNormalResponse.code == Global.responseSuccessCode) {
  489. Navigator.push(
  490. context,
  491. MaterialPageRoute(builder: (context) => ChatHome("")),
  492. );
  493. /*Navigator.pushAndRemoveUntil(
  494. context,
  495. MaterialPageRoute(builder: (context) => ChatHome()), (route) => false,
  496. );*/
  497. } else {
  498. Component.toast(mNormalResponse.msg.toString(), 0);
  499. }
  500. } else {
  501. Component.toast("出错了,请稍后再试!", 0);
  502. return null;
  503. }
  504. }
  505. selectItem(List list, int item) {
  506. showModalBottomSheet(
  507. context: context,
  508. builder: (BuildContext context) {
  509. return SingleChildScrollView(
  510. child: Container(
  511. width: double.infinity,
  512. height: list.length * 50,
  513. child: Column(
  514. children: List.generate(
  515. list.length,
  516. (index) => GestureDetector(
  517. onTap: () {
  518. setState(() {
  519. switch (item) {
  520. case 0:
  521. age = list[index].toString();
  522. break;
  523. case 1:
  524. sex = list[index];
  525. break;
  526. }
  527. });
  528. Navigator.pop(context);
  529. },
  530. child: Padding(
  531. padding: const EdgeInsets.all(10),
  532. child: Text(
  533. ' ${list[index]} ',
  534. style: TextStyle(fontSize: 18),
  535. ),
  536. ),
  537. ),
  538. ),
  539. ),
  540. ),
  541. );
  542. },
  543. );
  544. }
  545. }