import 'dart:convert'; import 'dart:io'; import 'package:auto_route/auto_route.dart'; import 'package:eitc_erm_dental_flutter/app_router.gr.dart'; import 'package:eitc_erm_dental_flutter/entity/history_item_info.dart'; import 'package:eitc_erm_dental_flutter/funcs.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../widget/webview_progress_bar.dart'; import '../history/select_history_page.dart'; ///在线问诊页面 @RoutePage(name: "onlineConsultationRoute") class OnlineConsultationPage extends StatefulWidget { final String url; final bool backAlert; const OnlineConsultationPage( {super.key, required this.url, this.backAlert = false}); @override State createState() => _OnlineConsultationPageState(); } class _OnlineConsultationPageState extends State { final GlobalKey _webViewKey = GlobalKey(); InAppWebViewController? _webViewController; final InAppWebViewSettings _settings = InAppWebViewSettings( isInspectable: kDebugMode, mediaPlaybackRequiresUserGesture: true, allowsInlineMediaPlayback: true, iframeAllowFullscreen: true, javaScriptEnabled: true, allowFileAccess: true, allowFileAccessFromFileURLs: true); final WebviewProgressBarController _progressBarController = WebviewProgressBarController(); @override void initState() { super.initState(); } @override void dispose() { super.dispose(); _progressBarController.dispose(); } @override Widget build(BuildContext context) { return PopScope( canPop: !widget.backAlert, onPopInvokedWithResult: _onPop, child: Scaffold( body: SafeArea( child: Stack( children: [ InAppWebView( key: _webViewKey, initialSettings: _settings, onWebViewCreated: (controller) { _webViewController = controller; _load(); _initHandler(); }, onLoadStart: (controller, url) { logd("onLoadStart,url=$url"); }, onPermissionRequest: (controller, request) async { return PermissionResponse( resources: request.resources, action: PermissionResponseAction.GRANT); }, onLoadStop: (controller, url) async { logd("onLoadStop,url=$url"); }, onReceivedError: (controller, request, error) { loge("onReceivedError", error: error); }, onProgressChanged: (controller, progress) { logd("onProgressChanged,progress=$progress"); _progressBarController.setProgress(progress); }, onConsoleMessage: (controller, consoleMessage) { if (kDebugMode) { logd(consoleMessage); } }, ), Align( alignment: Alignment.topLeft, child: WebviewProgressBar(controller: _progressBarController), ) ], )), )); } void _onPop(bool didPop, dynamic result) async { if (didPop) { return; } bool? bo = await showDialog( context: context, builder: (ctx) { return AlertDialog( title: Text(getS().hint), content: Text(getS().closeCurrentPageHint), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: Text(getS().cancel)), TextButton( onPressed: () => Navigator.pop(ctx, true), child: Text(getS().confirm)), ], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15.r)), ); }); if (bo ?? false) { if (mounted) { Navigator.pop(context); } } } ///加载 void _load() { if (widget.url.isEmpty) { return; } _webViewController?.loadUrl( urlRequest: URLRequest(url: WebUri(widget.url))); } void _initHandler() { _webViewController?.addJavaScriptHandler( handlerName: "closePage", callback: _onClosePage); _webViewController?.addJavaScriptHandler( handlerName: "openUrl", callback: _onOpenUrl); _webViewController?.addJavaScriptHandler( handlerName: "selectPhoto", callback: _onSelectPhoto); _webViewController?.addJavaScriptHandler( handlerName: "viewPhoto", callback: _onViewPhoto); } ///关闭页面 void _onClosePage(List args) { Navigator.pop(context); } ///打开连接 void _onOpenUrl(List args) { if (args.isEmpty) { return; } String url = args[0]; bool isBlank = false; if (args.length > 1) { isBlank = args[0] == 1; } logd("H5打开新URL,url=$url,isBlank=$isBlank"); if (isBlank) { _webViewController?.loadUrl(urlRequest: URLRequest(url: WebUri(url))); } else { context.pushRoute(OnlineConsultationRoute(url: url, backAlert: true)); } } ///选择照片 Future> _onSelectPhoto(List args) async { int maxCount = 0; if (args.isNotEmpty) { maxCount = args[0]; } logd("H5选择照片,最大数量=$maxCount"); List? list = await context.pushRoute>(SelectHistoryRoute( selectType: SelectHistoryType.photo, isFillterPatient: false, isMultiSelect: maxCount > 0, maxCount: maxCount)); if (list == null) { logd("没有选择照片"); return []; } //把图片转成base64编码,直接给文件路径H5没法使用 List datas = []; Stream stream = Stream.fromIterable(list); await for (HistoryItemInfo info in stream) { try { File file = File(info.fileUri!.toFilePath()); Uint8List data = await file.readAsBytes(); String base64 = base64Encode(data); datas.add(base64); } catch (e) { loge("H5选择图片,转为base64异常", error: e); } } return datas; } ///查看图片 void _onViewPhoto(List args) async { if (args.isEmpty) { return; } context.pushRoute(OnlinePictureViewRoute(url: args[0])); } }