online_consultation_page.dart 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:auto_route/auto_route.dart';
  4. import 'package:eitc_erm_dental_flutter/app_router.gr.dart';
  5. import 'package:eitc_erm_dental_flutter/entity/history_item_info.dart';
  6. import 'package:eitc_erm_dental_flutter/funcs.dart';
  7. import 'package:flutter/foundation.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter_inappwebview/flutter_inappwebview.dart';
  10. import 'package:flutter_screenutil/flutter_screenutil.dart';
  11. import '../../widget/webview_progress_bar.dart';
  12. import '../history/select_history_page.dart';
  13. ///在线问诊页面
  14. @RoutePage(name: "onlineConsultationRoute")
  15. class OnlineConsultationPage extends StatefulWidget {
  16. final String url;
  17. final bool backAlert;
  18. const OnlineConsultationPage(
  19. {super.key, required this.url, this.backAlert = false});
  20. @override
  21. State<OnlineConsultationPage> createState() => _OnlineConsultationPageState();
  22. }
  23. class _OnlineConsultationPageState extends State<OnlineConsultationPage> {
  24. final GlobalKey _webViewKey = GlobalKey();
  25. InAppWebViewController? _webViewController;
  26. final InAppWebViewSettings _settings = InAppWebViewSettings(
  27. isInspectable: kDebugMode,
  28. mediaPlaybackRequiresUserGesture: true,
  29. allowsInlineMediaPlayback: true,
  30. iframeAllowFullscreen: true,
  31. javaScriptEnabled: true,
  32. allowFileAccess: true,
  33. allowFileAccessFromFileURLs: true);
  34. final WebviewProgressBarController _progressBarController =
  35. WebviewProgressBarController();
  36. @override
  37. void initState() {
  38. super.initState();
  39. }
  40. @override
  41. void dispose() {
  42. super.dispose();
  43. _progressBarController.dispose();
  44. }
  45. @override
  46. Widget build(BuildContext context) {
  47. return PopScope(
  48. canPop: !widget.backAlert,
  49. onPopInvokedWithResult: _onPop,
  50. child: Scaffold(
  51. body: SafeArea(
  52. child: Stack(
  53. children: [
  54. InAppWebView(
  55. key: _webViewKey,
  56. initialSettings: _settings,
  57. onWebViewCreated: (controller) {
  58. _webViewController = controller;
  59. _load();
  60. _initHandler();
  61. },
  62. onLoadStart: (controller, url) {
  63. logd("onLoadStart,url=$url");
  64. },
  65. onPermissionRequest: (controller, request) async {
  66. return PermissionResponse(
  67. resources: request.resources,
  68. action: PermissionResponseAction.GRANT);
  69. },
  70. onLoadStop: (controller, url) async {
  71. logd("onLoadStop,url=$url");
  72. },
  73. onReceivedError: (controller, request, error) {
  74. loge("onReceivedError", error: error);
  75. },
  76. onProgressChanged: (controller, progress) {
  77. logd("onProgressChanged,progress=$progress");
  78. _progressBarController.setProgress(progress);
  79. },
  80. onConsoleMessage: (controller, consoleMessage) {
  81. if (kDebugMode) {
  82. logd(consoleMessage);
  83. }
  84. },
  85. ),
  86. Align(
  87. alignment: Alignment.topLeft,
  88. child: WebviewProgressBar(controller: _progressBarController),
  89. )
  90. ],
  91. )),
  92. ));
  93. }
  94. void _onPop(bool didPop, dynamic result) async {
  95. if (didPop) {
  96. return;
  97. }
  98. bool? bo = await showDialog(
  99. context: context,
  100. builder: (ctx) {
  101. return AlertDialog(
  102. title: Text(getS().hint),
  103. content: Text(getS().closeCurrentPageHint),
  104. actions: [
  105. TextButton(
  106. onPressed: () => Navigator.pop(ctx, false),
  107. child: Text(getS().cancel)),
  108. TextButton(
  109. onPressed: () => Navigator.pop(ctx, true),
  110. child: Text(getS().confirm)),
  111. ],
  112. shape: RoundedRectangleBorder(
  113. borderRadius: BorderRadius.circular(15.r)),
  114. );
  115. });
  116. if (bo ?? false) {
  117. if (mounted) {
  118. Navigator.pop(context);
  119. }
  120. }
  121. }
  122. ///加载
  123. void _load() {
  124. if (widget.url.isEmpty) {
  125. return;
  126. }
  127. _webViewController?.loadUrl(
  128. urlRequest: URLRequest(url: WebUri(widget.url)));
  129. }
  130. void _initHandler() {
  131. _webViewController?.addJavaScriptHandler(
  132. handlerName: "closePage", callback: _onClosePage);
  133. _webViewController?.addJavaScriptHandler(
  134. handlerName: "openUrl", callback: _onOpenUrl);
  135. _webViewController?.addJavaScriptHandler(
  136. handlerName: "selectPhoto", callback: _onSelectPhoto);
  137. _webViewController?.addJavaScriptHandler(
  138. handlerName: "viewPhoto", callback: _onViewPhoto);
  139. }
  140. ///关闭页面
  141. void _onClosePage(List<dynamic> args) {
  142. Navigator.pop(context);
  143. }
  144. ///打开连接
  145. void _onOpenUrl(List<dynamic> args) {
  146. if (args.isEmpty) {
  147. return;
  148. }
  149. String url = args[0];
  150. bool isBlank = false;
  151. if (args.length > 1) {
  152. isBlank = args[0] == 1;
  153. }
  154. logd("H5打开新URL,url=$url,isBlank=$isBlank");
  155. if (isBlank) {
  156. _webViewController?.loadUrl(urlRequest: URLRequest(url: WebUri(url)));
  157. } else {
  158. context.pushRoute(OnlineConsultationRoute(url: url, backAlert: true));
  159. }
  160. }
  161. ///选择照片
  162. Future<List<String>> _onSelectPhoto(List<dynamic> args) async {
  163. int maxCount = 0;
  164. if (args.isNotEmpty) {
  165. maxCount = args[0];
  166. }
  167. logd("H5选择照片,最大数量=$maxCount");
  168. List<HistoryItemInfo>? list =
  169. await context.pushRoute<List<HistoryItemInfo>>(SelectHistoryRoute(
  170. selectType: SelectHistoryType.photo,
  171. isFillterPatient: false,
  172. isMultiSelect: maxCount > 0,
  173. maxCount: maxCount));
  174. if (list == null) {
  175. logd("没有选择照片");
  176. return [];
  177. }
  178. //把图片转成base64编码,直接给文件路径H5没法使用
  179. List<String> datas = [];
  180. Stream<HistoryItemInfo> stream = Stream.fromIterable(list);
  181. await for (HistoryItemInfo info in stream) {
  182. try {
  183. File file = File(info.fileUri!.toFilePath());
  184. Uint8List data = await file.readAsBytes();
  185. String base64 = base64Encode(data);
  186. datas.add(base64);
  187. } catch (e) {
  188. loge("H5选择图片,转为base64异常", error: e);
  189. }
  190. }
  191. return datas;
  192. }
  193. ///查看图片
  194. void _onViewPhoto(List<dynamic> args) async {
  195. if (args.isEmpty) {
  196. return;
  197. }
  198. context.pushRoute(OnlinePictureViewRoute(url: args[0]));
  199. }
  200. }