123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758 |
- import 'dart:convert';
- import 'dart:math';
- import 'package:fis_i18n/i18n.dart';
- import 'package:fis_jsonrpc/rpc.dart';
- import 'package:fis_lib_report/report_info/report_info.dart';
- import 'package:fis_theme/theme.dart';
- import 'package:fis_ui/base_define/page.dart';
- import 'package:fis_ui/index.dart';
- import 'package:fis_ui/interface/interactive_container.dart';
- import 'package:fis_ui/widgets/tree/flutter_treeview/lib/flutter_treeview.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- // import 'package:flyinsono/pages/remedical/vocabulary_entry/view.dart';
- import 'package:get/get.dart' hide Node;
- import 'package:path/path.dart';
- import 'package:vitalapp/architecture/services/entity/report_editor_setting.dart';
- import 'package:vitalapp/architecture/services/report_editor_configuration.dart';
- import 'package:vitalapp/pages/consultation_record_view/widgets/search_input.dart';
- import 'package:vitalapp/pages/image_report_inner_view/widgets/expandable_icon_text.dart';
- import 'package:vitalapp/pages/report_edit/controller.dart';
- ///报告中词条选择
- class VocabularyEntryReport extends StatefulWidget implements FPage {
- @override
- State<VocabularyEntryReport> createState() => _VocabularyEntryReportState();
- ///关闭事件
- final void Function() onClose;
- VocabularyEntryReport({
- required this.onClose,
- });
- @override
- final String pageName = 'VocabularyEntryReport';
- }
- class _VocabularyEntryReportState extends State<VocabularyEntryReport> {
- /// 词条树顶层结构
- late List<Node<dynamic>> treeViewTopData = [];
- late TextEditingController _textEditingController =
- TextEditingController(text: keyWords);
- final entrysScrollController = ScrollController();
- double _maxHeight = 0;
- double _maxWidth = 0;
- final double _scale = 0.45;
- /// 当前选中项
- String selectedKey = '';
- /// 关键字搜索
- String keyWords = '';
- /// 当前词条分类的词条卡片内容
- List<ThesaurusItemDTO> vocabularyCard = [];
- /// 序列化存储的词条列表
- List<dynamic> defaultThesaurusList = [];
- /// 树形选择器控制器
- TreeViewController _treeViewController = TreeViewController();
- /// 本地报告编辑器服务
- LocalReportEditorService localReportEditorService =
- Get.find<LocalReportEditorService>();
- ReportEditorSetting reportEditorSetting = ReportEditorSetting.ins;
- String? _focusItem;
- void _listenKeyboardEvent(RawKeyEvent event) {
- if (event.isKeyPressed(LogicalKeyboardKey.enter) ||
- event.isKeyPressed(LogicalKeyboardKey.numpadEnter)) {
- getEntryByKeyWords();
- }
- }
- /// 报告控制器
- final reportEditController = Get.put(ReportEditController());
- /// 检查是否需要重新打开上次打开的节点
- void checkReopenNode() {
- /// 上次打开的词条分类和词条项
- final lastEntryCategoryCode = reportEditorSetting.lastEntryCategoryCode;
- final lastEntryCode = reportEditorSetting.lastEntryCode;
- var entryCategoryCodeToReopen = '';
- var entryCodeToReopen = '';
- treeViewTopData.forEach((element) {
- if (element.key == lastEntryCategoryCode) {
- entryCategoryCodeToReopen = element.key;
- }
- element.children.forEach((child) {
- if (child.key == lastEntryCode) {
- entryCodeToReopen = child.key;
- }
- });
- });
- if (entryCategoryCodeToReopen == '') return;
- List<Node> newdata =
- _treeViewController.expandToNode(entryCategoryCodeToReopen);
- if (entryCodeToReopen == '') {
- _treeViewController = _treeViewController.copyWith(children: newdata);
- } else {
- _treeViewController = _treeViewController.copyWith(
- children: newdata, selectedKey: entryCodeToReopen);
- vocabularyCard = reportEditController.state.allThesaurusList
- .where((element) => element.parentItemCode == entryCodeToReopen)
- .toList();
- }
- }
- /// 下拉项点击
- void onExpansionChanged(String code, bool isDrop) async {
- reportEditorSetting.setLastEntryCategoryCode(code);
- localReportEditorService.save();
- if (isDrop) {
- List<Node> newdata = _treeViewController.expandToNode(code);
- _treeViewController = _treeViewController.copyWith(children: newdata);
- } else {
- List<Node> newdata = _treeViewController.collapseToNode(code);
- _treeViewController = _treeViewController.copyWith(children: newdata);
- }
- setState(() {});
- }
- /// 词条分类的选中
- void onNodeTap(String code) {
- reportEditorSetting.setLastEntryCode(code);
- localReportEditorService.save();
- _treeViewController = _treeViewController.copyWith(selectedKey: code);
- if (reportEditController.state.allThesaurusList.isNotEmpty) {
- vocabularyCard = reportEditController.state.allThesaurusList
- .where((element) => element.parentItemCode == code)
- .toList();
- }
- setState(() {
- selectedKey = code;
- });
- }
- /// 搜索的方法
- void getEntryByKeyWords() {
- List<ThesaurusItemDTO> thesaurusItem = [];
- var allThesaurusList = reportEditController.state.allThesaurusList;
- allThesaurusList.forEach(
- (e) {
- if (e.thesaurusItemName?.contains(keyWords) == true ||
- e.thesaurusItemConclusion?.contains(keyWords) == true ||
- e.thesaurusItemDescription?.contains(keyWords) == true) {
- if (e.parentItemCode != '') {
- allThesaurusList.forEach(
- (element) {
- if (element.thesaurusItemCode == e.parentItemCode) {
- thesaurusItem.add(element);
- if (element.parentItemCode != '') {
- allThesaurusList.forEach(
- (key) {
- if (key.thesaurusItemCode == element.parentItemCode) {
- thesaurusItem.add(key);
- }
- },
- );
- }
- }
- },
- );
- }
- thesaurusItem.add(e);
- }
- },
- );
- thesaurusItem = thesaurusItem.toSet().toList();
- treeViewTopData = getThesaurusItemsAsyncList(thesaurusItem);
- setState(() {
- _treeViewController = TreeViewController(
- children: treeViewTopData,
- selectedKey: selectedKey,
- );
- });
- }
- void _initThesaurusList() {
- treeViewTopData = getThesaurusItemsAsyncList(
- reportEditController.state.allThesaurusList,
- );
- if (treeViewTopData.isNotEmpty) {
- var firstThesaurus = treeViewTopData.first;
- treeViewTopData[0] = firstThesaurus.copyWith(
- expanded: true,
- );
- if (firstThesaurus.children.isNotEmpty) {
- selectedKey = firstThesaurus.children.first.key;
- } else {
- selectedKey = firstThesaurus.key;
- }
- }
- _treeViewController = TreeViewController(
- children: treeViewTopData,
- selectedKey: selectedKey,
- );
- vocabularyCard = reportEditController.state.allThesaurusList
- .where((element) => element.parentItemCode == selectedKey)
- .toList();
- }
- /// 数据处理
- List<Node> getThesaurusItemsAsyncList(
- List<ThesaurusItemDTO> allThesaurusItemsAsyncList,
- ) {
- List<Node> treeView = [];
- allThesaurusItemsAsyncList.forEach(
- (element) {
- List<Node> treeviewChild = [];
- final lista = allThesaurusItemsAsyncList.where(
- (e) => e.parentItemCode == element.thesaurusItemCode,
- );
- lista.forEach((element) {
- if (element.thesaurusItemType != ThesaurusItemTypeEnum.Contents) {
- treeviewChild.add(
- Node(
- key: element.thesaurusItemCode ?? '',
- label: element.thesaurusItemName ?? '',
- ),
- );
- }
- });
- if (element.parentItemCode == '' || element.parentItemCode == null) {
- treeView.add(
- Node(
- key: element.thesaurusItemCode!,
- label: element.thesaurusItemName!,
- children: treeviewChild,
- ),
- );
- }
- },
- );
- return treeView;
- }
- @override
- void initState() {
- super.initState();
- RawKeyboard.instance.addListener(_listenKeyboardEvent);
- entrysScrollController.addListener(_scrollListener);
- _checkIsShowRightScrol();
- /// 初始化形成所需的树结构
- _initThesaurusList();
- }
- @override
- void didUpdateWidget(VocabularyEntryReport oldWidget) {
- super.didUpdateWidget(oldWidget);
- }
- @override
- void dispose() {
- RawKeyboard.instance.removeListener(_listenKeyboardEvent);
- entrysScrollController.dispose();
- super.dispose();
- }
- /// 左边能否滑动
- bool _isLeftCanScroll = false;
- /// 右边能否滑动
- bool _isRightCanScroll = false;
- @override
- Widget build(BuildContext context) {
- final mediaQuery = MediaQuery.of(context);
- _maxWidth = mediaQuery.size.width * _scale;
- return LayoutBuilder(
- builder: (BuildContext context, BoxConstraints constraints) {
- _maxHeight = constraints.maxHeight;
- return Container(
- width: _maxWidth,
- decoration: BoxDecoration(
- boxShadow: [
- BoxShadow(
- color: Colors.grey,
- blurRadius: 4,
- offset: Offset(2, 2),
- ),
- ],
- color: Colors.white,
- border: Border.all(
- color: Colors.grey,
- ),
- borderRadius: BorderRadius.circular(8),
- ),
- child: Column(
- children: [
- _buildHeader(),
- _buildEntrysSelected(),
- const FSizedBox(height: 5),
- Row(
- children: [
- Expanded(
- child: SearchInput(
- margin:
- const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
- businessParent: widget,
- onChanged: (value) {
- keyWords = value;
- },
- serchOnPressed: () {
- getEntryByKeyWords();
- },
- controller: _textEditingController,
- hintText: i18nBook.remedical.searchKeyword.t,
- ),
- ),
- ],
- ),
- _buildVocabularyTreeview(context),
- ],
- ),
- );
- });
- }
- Widget _buildVocabularyTreeview(BuildContext context) {
- return Container(
- width: _maxWidth,
- decoration: BoxDecoration(
- border: Border(
- top: BorderSide(
- color: Color.fromRGBO(211, 211, 211, 1),
- ),
- ),
- ),
- margin: EdgeInsets.symmetric(
- vertical: 4,
- ),
- child: Row(
- children: [
- Expanded(
- flex: 4,
- child: _buildEntryTree(),
- ),
- FExpanded(
- flex: 11,
- child: FContainer(
- height: _maxHeight - 180,
- child: _EntriesItem(
- vocabularyCard: vocabularyCard,
- ),
- ),
- ),
- ],
- ),
- );
- }
- Widget _buildEntryTree() {
- return Obx(() {
- if (reportEditController.state.allThesaurusList.isEmpty) {
- return FSizedBox();
- }
- return FContainer(
- height: _maxHeight - 180,
- child: FTreeView(
- theme: FTreeViewTheme(
- levelPadding: 15,
- horizontalSpacing: 15,
- colorScheme: ColorScheme.dark(
- primary: const Color(0xff2c77e5),
- ),
- ),
- onNodeTap: (code) {
- onNodeTap(code);
- },
- onExpansionChanged: (code, isDrop) {
- onExpansionChanged(
- code,
- isDrop,
- );
- },
- // shrinkWrap: true,
- controller: _treeViewController,
- nodeBuilder: (buildContext, node) {
- return _EntryTreeView(
- node: node,
- selectedKey: selectedKey,
- );
- },
- ),
- );
- });
- }
- FWidget _buildHeader() {
- return FContainer(
- decoration: BoxDecoration(
- color: const Color(0xff2c77e5),
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(8),
- topRight: Radius.circular(8),
- ),
- ),
- child: FRow(
- children: [
- const FSizedBox(
- width: 10,
- height: 40,
- ),
- FText(
- i18nBook.remedical.wordSelectBox.t,
- style: TextStyle(
- color: Colors.white,
- fontSize: 18,
- ),
- ),
- FExpanded(child: FSizedBox()),
- FInkWell(
- onTap: () => widget.onClose.call(),
- child: FIcon(
- Icons.close,
- color: Colors.white,
- ),
- ),
- const FSizedBox(
- width: 10,
- ),
- ],
- ),
- );
- }
- void _scrollListener() {
- if (entrysScrollController.offset <=
- entrysScrollController.position.minScrollExtent) {
- setState(() {
- _isLeftCanScroll = false;
- _isRightCanScroll = true;
- });
- } else if (entrysScrollController.offset >=
- entrysScrollController.position.maxScrollExtent) {
- setState(() {
- _isLeftCanScroll = true;
- _isRightCanScroll = false;
- });
- } else {
- setState(() {
- _isLeftCanScroll = true;
- _isRightCanScroll = true;
- });
- }
- }
- Widget _buildEntrysSelected() {
- return Obx(() {
- var entryInfos = reportEditController.state.entryInfos;
- if (entryInfos.isEmpty) {
- return SizedBox();
- }
- return Container(
- height: 40,
- alignment: Alignment.center,
- width: _maxWidth - 20,
- margin: EdgeInsets.symmetric(horizontal: 5),
- child: Row(
- children: [
- InkWell(
- child: FIcon(
- Icons.chevron_left_rounded,
- color: _isLeftCanScroll ? Colors.black : Colors.grey,
- size: 50,
- ),
- onTap: () {
- var target = entrysScrollController.offset - 60;
- entrysScrollController.jumpTo(target > 0 ? target : 0);
- },
- ),
- const FSizedBox(
- width: 10,
- ),
- Expanded(
- child: ListView(
- shrinkWrap: true,
- scrollDirection: Axis.horizontal,
- controller: entrysScrollController,
- children: entryInfos
- .map(
- (e) => ExpandableIconText(
- icon: Icons.book,
- isDistinguishChinese: false,
- isExpandChild: false,
- horizontalMargin: 10,
- isSelected:
- reportEditController.state.selectedEntryCode ==
- e.thesaurusCode,
- onPressed: () async {
- reportEditController.state.selectedEntryCode =
- e.thesaurusCode ?? '';
- await reportEditController.thesaurusController
- .getDefaultThesaurus(e.thesaurusCode ?? '');
- _initThesaurusList();
- setState(() {});
- },
- onHoverChange: (v) {
- if (v) {
- setState(() {
- _focusItem = e.thesaurusCode;
- });
- } else {
- setState(() {
- _focusItem = reportEditController
- .state.selectedEntryCode;
- });
- }
- },
- text: e.thesaurusName ?? '',
- isExpand: _focusItem == e.thesaurusCode,
- ),
- )
- .toList(),
- ),
- ),
- const FSizedBox(width: 10),
- FInkWell(
- child: FIcon(
- Icons.chevron_right_rounded,
- size: 50,
- color: _isRightCanScroll ? Colors.black : Colors.grey,
- ),
- onTap: () {
- var target = entrysScrollController.offset + 60;
- var allLength =
- entrysScrollController.position.maxScrollExtent;
- entrysScrollController.jumpTo(
- target > allLength ? allLength.toDouble() : target);
- },
- ),
- ],
- ));
- });
- }
- void _checkIsShowRightScrol() {
- Future.delayed(Duration(milliseconds: 500), () {
- var target = entrysScrollController.offset + 1;
- var allLength = entrysScrollController.position.maxScrollExtent;
- entrysScrollController
- .jumpTo(target > allLength ? allLength.toDouble() : target);
- entrysScrollController.jumpTo(0);
- });
- }
- }
- class _EntryTreeView extends FStatefulWidget implements FInteractiveContainer {
- _EntryTreeView({Key? key, required this.node, this.selectedKey = ''})
- : super(key: key);
- /// 当前下拉节点
- final Node<dynamic> node;
- @override
- final String pageName = 'EntryTreeView';
- /// 当前选中项
- final String? selectedKey;
- @override
- FState<_EntryTreeView> createState() => _EntryTreeViewState();
- }
- class _EntryTreeViewState extends FState<_EntryTreeView> {
- final EdgeInsets _padding = const EdgeInsets.symmetric(vertical: 4);
- bool hovering = false;
- @override
- FWidget build(BuildContext context) {
- var isNormalOption = widget.selectedKey != widget.node.key;
- return FContainer(
- margin: EdgeInsets.only(right: 15),
- child: FMouseRegion(
- cursor: SystemMouseCursors.click,
- onEnter: (e) {
- setState(() {
- hovering = true;
- });
- },
- onExit: (e) {
- setState(() {
- hovering = false;
- });
- },
- child: FGestureDetector(
- name: "${widget.node.label}",
- businessParent: this.widget,
- child: FColumn(
- children: [
- hovering
- ? FRow(
- children: [
- FExpanded(
- child: FContainer(
- child: _SelectText(
- label: widget.node.label,
- isSelected: isNormalOption,
- padding: this._padding,
- ),
- ),
- ),
- ],
- )
- : FRow(
- children: [
- FExpanded(
- child: FContainer(
- padding: _padding,
- child: FText(
- widget.node.label,
- style: widget.selectedKey == widget.node.key
- ? TextStyle(
- color: Colors.white,
- )
- : TextStyle(
- color: Colors.black,
- ),
- ),
- ),
- ),
- ],
- ),
- ],
- ),
- ),
- ),
- );
- }
- }
- /// 词条分类选中样式
- class _SelectText extends FStatelessWidget {
- _SelectText({
- required this.isSelected,
- required this.label,
- required this.padding,
- });
- final bool isSelected;
- final String label;
- final EdgeInsetsGeometry padding;
- @override
- FWidget build(BuildContext context) {
- return FContainer(
- padding: padding,
- child: FText(
- label,
- style: TextStyle(
- color: isSelected ? Colors.black : Colors.white,
- ),
- ),
- );
- }
- }
- class _EntriesItem extends FStatelessWidget {
- _EntriesItem({
- this.vocabularyCard,
- });
- /// 词条卡片内容
- final List<ThesaurusItemDTO>? vocabularyCard;
- @override
- FWidget build(BuildContext context) {
- return FContainer(
- child: FReorderableListView(
- shrinkWrap: true,
- buildDefaultDragHandles: false,
- children: vocabularyCard!
- .map(
- (item) => FContainer(
- key: Key(
- item.thesaurusItemCode.toString(),
- ),
- child: SwipeCard(
- isForbiddenAnimation: true,
- forbiddenAnimationMargin: EdgeInsets.all(0),
- forbiddenAnimationPadding:
- EdgeInsets.only(left: 5, top: 5, right: 5),
- child: FColumn(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- FContainer(
- child: FText(
- i18nBook.remedical.description.t,
- style: TextStyle(
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- FRow(
- mainAxisSize: MainAxisSize.max,
- children: [
- FExpanded(
- child: FContainer(
- child: FText(
- item.thesaurusItemDescription!,
- textAlign: TextAlign.left,
- ),
- ),
- )
- ],
- ),
- FSizedBox(
- height: 5,
- ),
- FContainer(
- child: FText(
- i18nBook.remedical.conclusion.t,
- style: TextStyle(
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- FRow(
- mainAxisSize: MainAxisSize.max,
- children: [
- FExpanded(
- child: FContainer(
- child: FText(
- item.thesaurusItemConclusion!,
- textAlign: TextAlign.left,
- ),
- ),
- )
- ],
- ),
- FSizedBox(
- height: 10,
- ),
- ],
- ),
- onTap: () {
- FReportInfo.instance.insertDiagnostic(
- item.thesaurusItemDescription ?? '',
- item.thesaurusItemConclusion ?? '',
- );
- },
- isActive: false,
- ),
- ),
- )
- .toList(),
- onReorder: (int oldIndex, int newIndex) {
- /// 拖拽的方法
- },
- ),
- );
- }
- }
|