import 'package:fis_common/index.dart'; import 'package:fis_i18n/i18n.dart'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:fis_ui/index.dart'; import 'package:flutter/material.dart'; class TerminalImage { String? previewUrl; String? imageUrl; String? coverImageUrl; TerminalImage({ this.previewUrl, this.imageUrl, this.coverImageUrl, }); factory TerminalImage.fromJson(Map map) { return TerminalImage( previewUrl: map['PreviewUrl'], imageUrl: map['ImageUrl'], coverImageUrl: map['CoverImageUrl'], ); } Map toJson() { final map = Map(); if (previewUrl != null) map['PreviewUrl'] = previewUrl; if (imageUrl != null) map['ImageUrl'] = imageUrl; if (coverImageUrl != null) map['CoverImageUrl'] = coverImageUrl; return map; } } /// 所有图片的入口 class FContentImage extends StatelessWidget implements FWidget { /// 图片参数 final RemedicalInfoDTO? remedicalInfo; /// 是否是测量页面 final bool? isMeasure; /// 改变图片地址 final VoidCallback? onDoubleTap; /// 图片单机事件 final VoidCallback? onTap; /// AI 良恶性 late final DiagnosisConclusionEnum diagnosisConclusion = remedicalInfo?.diagnosisConclusion ?? DiagnosisConclusionEnum.NotRequired; /// 图片类型 late RemedicalFileDataTypeEnum? fileDataType; /// 图片地址 late TerminalImage? terminalImage; /// AI测量的器官 late final List? diagnosisOrgans = remedicalInfo?.diagnosisOrgans ?? [DiagnosisOrganEnum.Null]; bool get isCarotidResult => remedicalInfo?.carotidResult != null; /// 判断是否有AI器官 bool get hasDiagnosisOrgans => diagnosisOrgans?.length != 0; /// 判断是否展示ai字 bool get isShowDiagnosisOrgans => [ DiagnosisConclusionEnum.NoObviousLesion, DiagnosisConclusionEnum.Benign, DiagnosisConclusionEnum.Malignant, DiagnosisConclusionEnum.BenignAndMalignant ].contains(diagnosisConclusion); /// 是否是选择状态 final bool isPureImage; ///是否显示左上角序号 final bool? ifShowIndex; ///图像宽度 final double contentWidth; ///图像高度 final double contentHeight; ///序号 final int serialNo; ///图片文字描述 final String? description; /// 图像定位描述描述 final String? locationDescription; FContentImage({ Key? key, this.terminalImage, this.fileDataType, this.remedicalInfo, this.isMeasure = false, this.onDoubleTap, this.onTap, this.isPureImage = false, this.ifShowIndex = true, this.serialNo = 0, this.description = '', this.locationDescription = '', this.contentHeight = 200, this.contentWidth = 300, }) : super(key: key); @override FWidget build(BuildContext context) { if (terminalImage == null) { terminalImage = new TerminalImage( previewUrl: remedicalInfo?.terminalImages?.previewUrl ?? '', imageUrl: remedicalInfo?.terminalImages?.imageUrl ?? '', coverImageUrl: remedicalInfo?.terminalImages?.coverImageUrl ?? ''); } if (fileDataType == null) { fileDataType = remedicalInfo?.fileDataType; } if (isPureImage) { return FContainer( color: Colors.black, child: FImage.network( terminalImage!.coverImageUrl!, width: contentWidth, height: contentHeight, errorBuilder: ((context, error, stackTrace) { return Container( child: Text(i18nBook.common.error.t), ); }), ), ); } else return _buildFContentImage( fileDataType!, terminalImage!.previewUrl!, ); } FWidget _buildIndex() { return FPositioned( left: 5, child: FText( (serialNo).toString(), style: TextStyle( color: Colors.white, ), ), ); } FWidget _buildFContentImage( RemedicalFileDataTypeEnum fileDataType, String previewUrl, ) { switch (fileDataType) { case RemedicalFileDataTypeEnum.Image: case RemedicalFileDataTypeEnum.ThirdVidSingle: case RemedicalFileDataTypeEnum.VinnoVidSingle: return _buildImageCard( previewUrl, ); case RemedicalFileDataTypeEnum.ThirdVidMovie: case RemedicalFileDataTypeEnum.VinnoVidMovie: return _buildVidMovieCard( previewUrl, ); default: return FContainer( child: FText(i18nBook.common.error.t), ); } } ///判断是否是肝脏、胆囊、肾脏、脾脏、腹部器官 bool _ifAbdominalOrgans(DiagnosisOrganEnum diagnosisOrgan) { final abdominalOrgansList = [ DiagnosisOrganEnum.Liver, DiagnosisOrganEnum.Cholecyst, DiagnosisOrganEnum.Kidney, DiagnosisOrganEnum.Spleen, DiagnosisOrganEnum.Abdomen ]; return abdominalOrgansList.contains(diagnosisOrgan); } FWidget _buildLeftAIOrCarotidLogo() { final List aIDiagnosticOrgansIconList = []; if (isCarotidResult) { var conclustionTemp = diagnosisConclusion; conclustionTemp = (conclustionTemp.index > DiagnosisConclusionEnum.Benign.index) ? DiagnosisConclusionEnum.NoObviousLesion : conclustionTemp; var colorCarotid = _buildAITextColor( conclustionTemp, ); aIDiagnosticOrgansIconList.add(FIcon( FIcons.arteria_carotis, color: colorCarotid, )); if (diagnosisOrgans != null && diagnosisOrgans!.isNotEmpty) { var hasThyroid = diagnosisOrgans!.contains(DiagnosisOrganEnum.Thyroid); if (hasThyroid) { aIDiagnosticOrgansIconList .add(_buildAIDiagnosticOrgans(DiagnosisOrganEnum.Thyroid)); } } return FPositioned( bottom: 5, left: 5, child: FRow( children: aIDiagnosticOrgansIconList, ), ); } else if (hasDiagnosisOrgans) { int count = 0; for (var i = 0; i < diagnosisOrgans!.length; i++) { if (_ifAbdominalOrgans(diagnosisOrgans![i])) { //当diagnosisOrgans返回值为肝脏、胆囊、肾脏、脾脏,都只显示一个“腹部”图标 if (count <= 0) { aIDiagnosticOrgansIconList.add( _buildAIDiagnosticOrgans(DiagnosisOrganEnum.Abdomen), ); } count++; } else { aIDiagnosticOrgansIconList.add( _buildAIDiagnosticOrgans( diagnosisOrgans?[i], ), ); } } return FPositioned( bottom: 5, left: 5, child: FRow( children: aIDiagnosticOrgansIconList, ), ); } return FPositioned( bottom: 5, left: 5, right: 5, child: _buildApplication(), ); } ///构建描述字段 FWidget _buildApplication() { return FContainer( child: FText( description ?? "", softWrap: true, style: TextStyle( color: Colors.white, fontSize: 10, ), ), ); } /// 构建图像定位描述 FWidget _buildImageLocationDescription() { return FPositioned( right: 5, child: FText( locationDescription ?? "", style: TextStyle( color: Colors.white, fontSize: 10, overflow: TextOverflow.ellipsis, ), ), ); } FWidget _buildRigthAIText() { var cDNMdlFile = remedicalInfo?.carotidResult?.cDNMdlFile; var surfaceFile = remedicalInfo?.carotidResult?.surfaceFile; return FPositioned( bottom: 5, right: 5, child: FRow( children: [ if (isCarotidResult && cDNMdlFile.isNotNullOrEmpty && surfaceFile.isNotNullOrEmpty) ...[ FIcon( FIcons.three_dimensional, color: Colors.lightBlue, ), ], if (isShowDiagnosisOrgans) ...[ const FSizedBox( width: 5, ), FMaterialTooltip( textStyle: TextStyle( fontSize: 16, color: Colors.white, ), message: _buildAIText(diagnosisConclusion), child: FText( 'AI', style: TextStyle( color: _buildAITextColor( diagnosisConclusion, ), fontSize: 20, ), ), ), ], ], ), ); } FWidget _buildVidMovieCard(String previewUrl) { return FContainer( width: 190, height: 160, color: Colors.black, child: FStack( children: [ FCenter( child: FImage.network( previewUrl, errorBuilder: ((context, error, stackTrace) { return Container( child: Text(i18nBook.common.error.t), ); }), ), ), FInkWell( onDoubleTap: () { onDoubleTap?.call(); }, onTap: () { onTap?.call(); }, child: Center( child: Container( child: Icon( Icons.play_circle_outline_rounded, color: Colors.white, size: 50, ), ), ), ), _buildLeftAIOrCarotidLogo(), _buildRigthAIText(), _buildImageLocationDescription(), if (ifShowIndex!) _buildIndex(), ], ), ); } FWidget _buildImageCard( String previewUrl, ) { return FInkWell( onDoubleTap: () { onDoubleTap?.call(); }, onTap: () { onTap?.call(); }, child: Container( width: 190, height: 160, color: Colors.black, child: Stack( children: [ Center( child: Image.network( previewUrl, errorBuilder: ((context, error, stackTrace) { return Container( child: Text(i18nBook.common.error.t), ); }), ), ), _buildLeftAIOrCarotidLogo(), _buildImageLocationDescription(), _buildRigthAIText(), if (ifShowIndex!) _buildIndex(), ], ), ), ); } String _buildAIText(DiagnosisConclusionEnum diagnosisConclusion) { switch (diagnosisConclusion) { case DiagnosisConclusionEnum.NotRequired: return i18nBook.remedical.noNeedAIYet.t; case DiagnosisConclusionEnum.InProcess: return i18nBook.remedical.didNotHandle.t; case DiagnosisConclusionEnum.Unrecognized: return i18nBook.remedical.didNotIdentify.t; case DiagnosisConclusionEnum.NoObviousLesion: return i18nBook.remedical.noAbnormal.t; case DiagnosisConclusionEnum.Benign: return i18nBook.remedical.benign.t; case DiagnosisConclusionEnum.Malignant: return i18nBook.remedical.benignWithMalignant.t; case DiagnosisConclusionEnum.BenignAndMalignant: return i18nBook.remedical.benignWithMalignant.t; default: return i18nBook.remedical.didNotIdentify.t; } } dynamic _buildAITextColor(DiagnosisConclusionEnum diagnosisConclusion) { switch (diagnosisConclusion) { case DiagnosisConclusionEnum.NoObviousLesion: return Colors.lightBlue; case DiagnosisConclusionEnum.Benign: return Colors.greenAccent; case DiagnosisConclusionEnum.Malignant: return Colors.orangeAccent; case DiagnosisConclusionEnum.BenignAndMalignant: return Colors.orangeAccent; default: return Colors.transparent; } } FWidget _buildAIDiagnosticOrgans(DiagnosisOrganEnum? diagnosisOrganEnum) { var isCarotird = diagnosisOrganEnum == DiagnosisOrganEnum.CarotidArtery; var realConculsion = (isCarotird && diagnosisConclusion.index > DiagnosisConclusionEnum.Benign.index) ? DiagnosisConclusionEnum.NoObviousLesion : diagnosisConclusion; switch (diagnosisOrganEnum) { case DiagnosisOrganEnum.Breast: return FIcon( FIcons.fis_breast, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.Abdomen: return FIcon( FIcons.fis_abdomen, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.Liver: return FIcon( FIcons.fis_liver, color: _buildAITextColor(realConculsion), ); case DiagnosisOrganEnum.Cholecyst: return FIcon( FIcons.fis_gallbladder, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.Kidney: return FIcon( FIcons.fis_kidney, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.Spleen: return FIcon( FIcons.fis_spleen, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.CarotidArtery: return FIcon( FIcons.arteria_carotis, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.Thyroid: return FIcon( FIcons.fis_thyroid, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.Neck: return FIcon( //图标待定 FIcons.fis_thyroid, color: _buildAITextColor( realConculsion, ), ); case DiagnosisOrganEnum.Null: if (diagnosisOrgans?.length == 1) { //如果diagnosisOrgans只有一个值且该值为null值,就返回文字,否则返回空 return _buildApplication(); } else { return FText(''); } default: return _buildApplication(); } } }