import 'dart:convert'; import 'dart:ui'; import 'package:barcode/barcode.dart'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; import 'package:vitalapp/architecture/defines.dart'; import 'package:vitalapp/architecture/storage/text_storage.dart'; import 'package:vitalapp/architecture/utils/datetime.dart'; import 'package:vitalapp/architecture/utils/prompt_box.dart'; import 'package:vitalapp/global.dart'; import 'package:vitalapp/managers/interfaces/exam.dart'; import 'package:vitalapp/managers/interfaces/health_check_record.dart'; import 'package:vitalapp/managers/interfaces/registration.dart'; import 'package:vitalapp/pages/check/health_check_record/components/health_check.dart'; import 'package:vitalapp/pages/check/health_check_record/state.dart'; import 'package:vitalapp/pages/check/models/form.dart'; import 'package:vitalapp/pages/medical_checkup_station/registration/controller.dart'; import 'package:vitalapp/pages/medical_checkup_station/registration/state/list.dart'; import 'package:vitalapp/pages/medical_checkup_station/usb_print/module/printer_info.dart'; import 'package:vitalapp/rpc.dart'; import 'package:vitalapp/store/store.dart'; import 'package:webviewx/webviewx.dart'; import 'package:barcode_image/barcode_image.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'controllers/list_controller.dart'; class HealthCheckRecordController extends FControllerBase { late final ListController listController; /// 表格loading bool tableLoading = true; /// 当前表格页数 int currPageIndex = 1; /// 预约列表的总数 int appointmentModelListLength = 0; /// 体检列表 List residentList = []; HealthCheckRecordController() { listController = ListController(this); } final state = HealthCheckRecordState(); final _healthCheckRecordManager = Get.find(); final _examManager = Get.find(); final registrationManager = Get.find(); late String patientCode; PrinterInfo? printInfo; List menuList = [ MenuItem(label: "一般状况", value: 'ZZYBZK'), MenuItem(label: "辅助检查", value: 'FZJC'), MenuItem(label: "生活方式", value: 'SHFS'), MenuItem(label: "脏器及查体", value: 'ZQCT'), MenuItem(label: "现存主要健康问题", value: 'XCZYWT'), MenuItem(label: "住院及用药情况", value: 'ZYYYFMYGHYFJZS'), MenuItem(label: "健康评价及指导", value: 'JKPJJZD'), ]; @override void onReady() { super.onReady(); _initData(); } _initData() { update(["contract_records"]); patientCode = Store.user.currentSelectPatientInfo?.code ?? ''; _getExamRecordList(); getRegisterInfoPage(keyword: patientCode); } Future _getExamRecordList() async { try { var result = await _healthCheckRecordManager.getExamRecordList(patientCode); if (result != null) { state.examRecordDTOList = result; } } catch (e) { print(e); return; } } Future updateExamByBatchNumberAsync(key, batchNumber, data) async { if (!kIsOnline) { // TODO: 暂不支持离线体检 PromptBox.toast("请检查网络连接"); return; } TextStorage template = TextStorage( fileName: key, directory: "patient/$patientCode/exam", ); final result = await _examManager .updateExamByBatchNumberAsync(UpdateExamByBatchNumberRequest( key: key, batchNumber: batchNumber, examData: data, patientCode: patientCode, )); if (result ?? false) { try { template.save(data); PromptBox.toast('保存成功'); await _getExamRecordList(); } catch (err) { PromptBox.toast('保存失败'); } } } ///读取静态Html Future loadingLocalAsset() async { ///加载 String htmlData = await rootBundle.loadString('assets/docs/examTable.html'); print("加载数据完成 $htmlData"); return htmlData; } Future toExamDetailPage(int index, ExamRecordDTO dto) async { var initialData = await loadingLocalAsset(); var examRecordDatas = state.examRecordDTOList[index].examRecordDatas; Map examData = {}; examRecordDatas?.forEach((element) { examData.addAll(jsonDecode(element.examData ?? '{}')); }); // 将数据转换为 JSON 字符串 var jsonData = jsonEncode({ "patientInfo": { "patientName": dto.patientName, }, "examData": examData, "docterName": dto.examDoctor, "examTime": DataTimeUtils.formatDateString(dto.examTime ?? DateTime.now()), }); _openExamDetail(initialData, jsonData); } Future toCheckPage( ExamRecordDTO dto, List? dataDTO, int index, ) async { Get.dialog( HealthCheckDialog( examRecord: dto, examRecordDatas: dataDTO, index: index, ), ); } String getHealthCheckRecordType(String key) { switch (key) { case 'ZZYBZK': return '症状、一般状况'; case 'SHFS': return '生活方式'; case 'ZQCT': return '脏器、查体'; case 'FZJC': return '辅助检查'; case 'XCZYWT': return '现存主要问题'; case 'ZYYYFMYGHYFJZS': return '住院、用药、非免疫规划预防接种史'; case 'JKPJJZD': return '健康评价及指导'; default: return ""; } } String examStateTransition(ExamStateEnum state) { switch (state) { case ExamStateEnum.Unchecked: return "未体检"; case ExamStateEnum.Invalid: return "已作废"; case ExamStateEnum.Inspected: return "已体检"; default: return ""; } } MaterialColor examStateColors(ExamStateEnum state) { switch (state) { case ExamStateEnum.Unchecked: return Colors.grey; case ExamStateEnum.Invalid: return Colors.red; case ExamStateEnum.Inspected: return Colors.green; default: return Colors.blue; } } void _openExamDetail( String initialData, String jsonData, ) { // 将 JSON 字符串作为参数传递给 evaluateJavascript 方法 Get.dialog(Column( children: [ Container( width: 900, alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20, top: 10), color: Colors.white, child: IconButton( onPressed: () { Get.back(); }, icon: const Icon( Icons.close, ), ), ), Expanded( child: Container( color: Colors.white, width: 900, height: double.maxFinite, child: _buildWebView(initialData, jsonData), ), ), ], )); } Widget _buildAppWebView( String initialData, String jsonData, ) { return InAppWebView( initialData: InAppWebViewInitialData( data: '$initialData ', mimeType: 'text/html', encoding: 'utf-8', ), onWebViewCreated: (controller) { controller.evaluateJavascript(source: "window.globalData = $jsonData;"); }, onConsoleMessage: (controller, consoleMessage) { // print(consoleMessage); }, ); } Widget _buildWebwebview( String initialData, String jsonData, ) { return WebViewX( height: MediaQuery.of(Get.context!).size.height, width: MediaQuery.of(Get.context!).size.width, initialSourceType: SourceType.html, initialContent: '$initialData ', javascriptMode: JavascriptMode.unrestricted, onWebResourceError: (p0) {}, onWebViewCreated: (controller) async { await controller.evalRawJavascript( "window.globalData = $jsonData;", inGlobalContext: true, ); }, ); // return FutureBuilder( // future: _loadLocalHtml(context, // '${controller.state.templateContent}'), // builder: (context, snapshot) { // if (!snapshot.hasData) { // return const Center(child: CircularProgressIndicator()); // // return FCenter(child: FText("${i18nBook.common.loading.t}...")); // } else { // return WebViewX( // height: MediaQuery.of(Get.context!).size.height, // width: MediaQuery.of(Get.context!).size.width, // initialSourceType: SourceType.html, // initialContent: // '${controller.state.templateContent}', // javascriptMode: JavascriptMode.unrestricted, // onWebResourceError: (p0) {}, // onWebViewCreated: (controller) { // // webviewControllerManager.initWebviewController(controller); // }, // ); // } // }, // ); } Widget _buildWebView( String initialData, String jsonData, ) { if (kIsWeb) { return _buildWebwebview(initialData, jsonData); } else { return _buildAppWebView(initialData, jsonData); } } void getExamLabelsByExamNoAsync(ResidentModel rowData) async { List barCodes = []; var labels = await registrationManager.getExamLabelsByExamNoAsync( physicalExamNumber: rowData.physicalExamNumber!); for (var element in labels.eaxmLabels!) { var barCode = await drawRedRect(element, rowData); if (barCode.isNotEmpty) { barCodes.add(barCode); } } if (barCodes.length > 0) { rpc.platform.printLabels(barCodes); return; } } Future drawRedRect( HealthExamLabelDTO labelDto, ResidentModel rowData) async { const size = Size(360, 240); final svg = Barcode.code128().toSvg(labelDto.uniquedCode!, height: 80); final PictureInfo pictureInfo = await vg.loadPicture(SvgStringLoader(svg), null); var a = await _capturePainterToImage( MyPainter(pictureInfo, labelDto, rowData), BgPainter(pictureInfo), size); String base64Image = base64Encode(a!); print(base64Image); return base64Image; } /// 将CustomPainter绘制的内容转换为图片 Future _capturePainterToImage( CustomPainter painter, CustomPainter bgPainter, Size size) async { final bounds = Offset.zero & size; // final bounds2 = Offset.zero & Size(size.width - 20, size.height - 20); final picture = PictureRecorder(); final pictureCanvas = Canvas(picture); // 给Canvas设置绘制范围 pictureCanvas.clipRect(bounds); painter.paint(pictureCanvas, size); // 在Canvas上进行绘制 bgPainter.paint(pictureCanvas, size); // 结束绘制 final recordedPicture = picture.endRecording(); final image = await recordedPicture.toImage(size.width.toInt(), size.height.toInt()); // 转换为字节数组 final byteData = await image.toByteData(format: ImageByteFormat.png); final bytes = byteData?.buffer.asUint8List(); return bytes; } Future getRegisterInfoPage({ int? pageSize = 10, int? pageIndex = 1, String? keyword = "", DateTime? startTime, DateTime? endTime, }) async { tableLoading = true; currPageIndex = pageIndex!; var result = await registrationManager.getRegisterInfoPageAsync( pageSize: pageSize, pageIndex: pageIndex, keyword: keyword, startTime: startTime, endTime: endTime, ); List _residentList = []; if (result?.pageData != null) { for (RegisterInfoDTO i in result!.pageData!) { String statusStr = ''; ExamStateEnum status = i.state; switch (status) { case ExamStateEnum.Unchecked: statusStr = "未体检"; break; case ExamStateEnum.Invalid: statusStr = "已作废"; break; case ExamStateEnum.Inspected: statusStr = "已体检"; break; case ExamStateEnum.Reported: statusStr = "已报告"; break; } _residentList.add( ResidentModel( name: i.name ?? '', idNumber: i.iDCardNo ?? '', code: i.code ?? '', homeAddress: i.adress, age: getAgeOfIdNumber(i.iDCardNo ?? ''), physicalExamNumber: i.physicalExamNumber, phone: i.phone, finishedExamKeys: i.finishedExamKeys, physicalExamStatus: statusStr, birthDay: i.birthday, sex: i.sex, batchNumber: i.batchNumber, ), ); } appointmentModelListLength = result.totalCount; } residentList = _residentList; tableLoading = false; update(["HealCheckRecord"]); } String getAgeOfIdNumber(String idNumber) { if (idNumber.isEmpty) return ''; final idCardRegex = RegExp(r'^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})(\d|X)$'); final match = idCardRegex.firstMatch(idNumber); if (match != null) { final year = int.parse(match.group(2)!); final month = int.parse(match.group(3)!); final day = int.parse(match.group(4)!); final birthDate = DateTime(year, month, day); String age = DataTimeUtils.calculateAge(birthDate); return age; } return ''; // 返回一个默认值 } }