|
@@ -0,0 +1,416 @@
|
|
|
+import 'package:fis_jsonrpc/rpc.dart';
|
|
|
+import 'package:flutter/foundation.dart';
|
|
|
+import 'package:flutter/material.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
+import 'package:intl/intl.dart';
|
|
|
+import 'package:vitalapp/components/appbar.dart';
|
|
|
+import 'package:vitalapp/consts/styles.dart';
|
|
|
+import 'package:vitalapp/database/entities/defines.dart';
|
|
|
+import 'package:vitalapp/pages/check/follow_up/widgets/follow_up_from.dart';
|
|
|
+import 'package:vitalapp/pages/check/follow_up_record/controller.dart';
|
|
|
+import 'package:vitalapp/pages/check/tuberculosis_management_record/controller.dart';
|
|
|
+import 'package:vitalapp/pages/check/tuberculosis_management_record/widget/FormSelectDialog.dart';
|
|
|
+import 'package:vitalapp/pages/check/widgets/configurable_card.dart';
|
|
|
+import 'package:vitalapp/pages/medical/controller.dart';
|
|
|
+import 'package:vitalapp/pages/patient/list/widgets/status.dart';
|
|
|
+import 'package:vitalapp/pages/widgets/record_common_item.dart';
|
|
|
+
|
|
|
+class TuberculosisManagementView extends GetView<FollowUpRecordController> {
|
|
|
+ const TuberculosisManagementView({
|
|
|
+ Key? key,
|
|
|
+ required this.followUpType,
|
|
|
+ }) : super(key: key);
|
|
|
+ final String followUpType;
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return GetBuilder(
|
|
|
+ init: FollowUpRecordController(
|
|
|
+ followUpType: followUpType,
|
|
|
+ ),
|
|
|
+ builder: (_) {
|
|
|
+ return Scaffold(
|
|
|
+ backgroundColor: const Color.fromRGBO(238, 238, 238, 1),
|
|
|
+ appBar: VAppBar(
|
|
|
+ titleWidget: Text('肺结核患者随访管理'),
|
|
|
+ actions: [
|
|
|
+ IconButton(
|
|
|
+ onPressed: () {
|
|
|
+ Get.dialog(FormSelectDialog(onConfirm: (type) {
|
|
|
+ String key = "FollowUpTuberculosisFirstRecord";
|
|
|
+ switch (type) {
|
|
|
+ case 1:
|
|
|
+ key = "FollowUpTuberculosisFirstRecord";
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ key = "FollowUpTuberculosisRecord";
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ key = "FollowUpTuberculosisResultRecord";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ _changePage(key);
|
|
|
+ Get.back();
|
|
|
+ }));
|
|
|
+ },
|
|
|
+ icon: Icon(
|
|
|
+ Icons.add,
|
|
|
+ size: 48,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ SizedBox(
|
|
|
+ width: 8,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ body: Stack(
|
|
|
+ children: [
|
|
|
+ Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.start,
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ _buildDiagram(),
|
|
|
+ _buildListView(),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ void _changePage(String key) async {
|
|
|
+
|
|
|
+ await Get.put(MedicalController());
|
|
|
+ controller.followUpController.state.followUpTime = DateTime.now();
|
|
|
+ controller.followUpController.state.nextFollowUpTime = null;
|
|
|
+ controller.followUpController.state.followUpMode =
|
|
|
+ FollowUpModeEnum.Outpatient;
|
|
|
+ controller.followUpController.state.followUpPhoto = '';
|
|
|
+ await Get.to(
|
|
|
+ ConfigurableCard(
|
|
|
+ cardKey: key,
|
|
|
+ callBack: (key, templateCode, data) async {
|
|
|
+ final result = await controller.followUpController.createFollowUp(
|
|
|
+ key,
|
|
|
+ templateCode,
|
|
|
+ data,
|
|
|
+ );
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+ followUpWidget: FollowUpFrom(
|
|
|
+ cardKey: key,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ transition: Transition.rightToLeft,
|
|
|
+ );
|
|
|
+ await controller.getFollowUpRecordList();
|
|
|
+ await Get.find<MedicalController>().initRecordDataState();
|
|
|
+
|
|
|
+ await Get.delete<MedicalController>();
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildDiagram() {
|
|
|
+ return Expanded(
|
|
|
+ flex: 1,
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.all(16.0).copyWith(right: 0),
|
|
|
+ child: Container(
|
|
|
+
|
|
|
+ padding: const EdgeInsets.all(16),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Colors.white,
|
|
|
+ border: Border.all(
|
|
|
+ color: Colors.white,
|
|
|
+ ),
|
|
|
+ borderRadius: GlobalStyles.borderRadius,
|
|
|
+ ),
|
|
|
+ child: Image.asset(
|
|
|
+ 'assets/images/exam/normalMeasurementChart.png',
|
|
|
+ height: double.infinity,
|
|
|
+ fit: BoxFit.fitWidth,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildListView() {
|
|
|
+ return Expanded(
|
|
|
+ flex: 2,
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.all(16),
|
|
|
+ child: RefreshIndicator(
|
|
|
+ child: Obx(
|
|
|
+ () {
|
|
|
+ final list = controller.state.followUpDTOList;
|
|
|
+ final children = <Widget>[];
|
|
|
+ for (var i = 0; i < list.length; i++) {
|
|
|
+ final dto = list[i];
|
|
|
+ final offlineSyncArr = controller.offlineSyncTemp[i];
|
|
|
+ final records = dto.followUpRecordDatas;
|
|
|
+ if (records == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ for (var j = 0; j < records.length; j++) {
|
|
|
+ final data = records[j];
|
|
|
+ OfflineDataSyncState? offlineSyncState;
|
|
|
+ offlineSyncState = kIsWeb ? null : offlineSyncArr[j];
|
|
|
+ children.add(
|
|
|
+ _followUpRecordCard(
|
|
|
+ index: j,
|
|
|
+ dto: dto,
|
|
|
+ dataDto: data,
|
|
|
+ syncState: offlineSyncState,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return list.isEmpty
|
|
|
+ ? Container(
|
|
|
+ margin: const EdgeInsets.only(top: 80),
|
|
|
+ child: Column(
|
|
|
+ children: [
|
|
|
+ Center(
|
|
|
+ child: Image.asset(
|
|
|
+ "assets/images/no_data.png",
|
|
|
+ width: 300,
|
|
|
+ height: 300,
|
|
|
+ fit: BoxFit.cover,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const Text(
|
|
|
+ "暂无数据,先看看别的吧",
|
|
|
+ style: TextStyle(fontSize: 18),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ : GridView(
|
|
|
+ gridDelegate:
|
|
|
+ const SliverGridDelegateWithFixedCrossAxisCount(
|
|
|
+ crossAxisCount: 1,
|
|
|
+ mainAxisSpacing: 16,
|
|
|
+ crossAxisSpacing: 20,
|
|
|
+ childAspectRatio: 900 / 180,
|
|
|
+ ),
|
|
|
+ children: children,
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ onRefresh: () async {}),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class _followUpRecordCard extends StatelessWidget {
|
|
|
+ final FollowUpRecordDTO dto;
|
|
|
+ final FollowUpRecordDataDTO dataDto;
|
|
|
+ final int index;
|
|
|
+ final OfflineDataSyncState? syncState;
|
|
|
+ _followUpRecordCard({
|
|
|
+ required this.dto,
|
|
|
+ required this.dataDto,
|
|
|
+ required this.index,
|
|
|
+ this.syncState,
|
|
|
+ });
|
|
|
+ final controller = Get.find<FollowUpRecordController>();
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final body = Stack(
|
|
|
+ children: [
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ Expanded(
|
|
|
+ flex: 10,
|
|
|
+ child: Container(
|
|
|
+ padding: const EdgeInsets.symmetric(
|
|
|
+ horizontal: 30,
|
|
|
+ vertical: 12,
|
|
|
+ ),
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ const SizedBox(
|
|
|
+ height: 8,
|
|
|
+ ),
|
|
|
+ LayoutBuilder(builder: (context, c) {
|
|
|
+ final width = c.maxWidth - 100;
|
|
|
+ return SizedBox(
|
|
|
+ width: width,
|
|
|
+ child: _buildBaseInfoRow(),
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ const SizedBox(
|
|
|
+ height: 20,
|
|
|
+ ),
|
|
|
+ Wrap(
|
|
|
+ alignment: WrapAlignment.start,
|
|
|
+ spacing: 20,
|
|
|
+ runSpacing: 8,
|
|
|
+ children: [
|
|
|
+ SizedBox(
|
|
|
+ width: 300,
|
|
|
+ child: RecordCommonItem(
|
|
|
+ itemName: '姓名',
|
|
|
+ itemValue: dto.patientName ?? "",
|
|
|
+ fontSize: 18,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ RecordCommonItem(
|
|
|
+ itemName: '随访类型',
|
|
|
+ itemValue:
|
|
|
+ controller.getFollowUpMode(dataDto.followUpMode),
|
|
|
+ fontSize: 18,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ const SizedBox(
|
|
|
+ height: 20,
|
|
|
+ ),
|
|
|
+ Wrap(
|
|
|
+ alignment: WrapAlignment.start,
|
|
|
+ spacing: 20,
|
|
|
+ runSpacing: 8,
|
|
|
+ children: [
|
|
|
+ SizedBox(
|
|
|
+ width: 300,
|
|
|
+ child: RecordCommonItem(
|
|
|
+ itemName: '随访医生',
|
|
|
+ itemValue: dataDto.followUpDoctor ?? "",
|
|
|
+ fontSize: 18,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ RecordCommonItem(
|
|
|
+ itemName: '随访时间',
|
|
|
+ itemValue: dataDto.followUpTime != null
|
|
|
+ ? DateFormat("yyyy-MM-dd")
|
|
|
+ .format(dataDto.followUpTime!.toLocal())
|
|
|
+ : "",
|
|
|
+ fontSize: 18,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Expanded(
|
|
|
+ child: IconButton(
|
|
|
+ onPressed: () {
|
|
|
+ controller.toCheckPage(dataDto, isCreateFromOldDto: true);
|
|
|
+ },
|
|
|
+ icon: Icon(
|
|
|
+ Icons.add,
|
|
|
+ size: 56,
|
|
|
+ color: Colors.grey.shade400,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ Positioned(
|
|
|
+ top: 16,
|
|
|
+ right: 0,
|
|
|
+ child: _FollowUpRecordSignStatusTag(
|
|
|
+ dataDto: dataDto,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+
|
|
|
+ Positioned(
|
|
|
+ top: 16,
|
|
|
+ right: 100,
|
|
|
+ child: _OfflineSyncTag(syncState: syncState),
|
|
|
+ ),
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ return Material(
|
|
|
+ borderRadius: GlobalStyles.borderRadius,
|
|
|
+ child: Ink(
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Colors.white,
|
|
|
+ borderRadius: GlobalStyles.borderRadius,
|
|
|
+ ),
|
|
|
+ child: InkWell(
|
|
|
+ borderRadius: GlobalStyles.borderRadius,
|
|
|
+ onTap: () {
|
|
|
+
|
|
|
+ controller.toCheckPage(dataDto);
|
|
|
+ },
|
|
|
+ child: body,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildBaseInfoRow() {
|
|
|
+ return SizedBox(
|
|
|
+ child: RecordCommonItem(
|
|
|
+ itemName: '随访名称',
|
|
|
+ itemValue: controller.getFollowUpValueByKey(dataDto.key ?? ""),
|
|
|
+ fontSize: 20,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class _FollowUpRecordSignStatusTag extends StatelessWidget {
|
|
|
+ final FollowUpRecordDataDTO dataDto;
|
|
|
+
|
|
|
+ _FollowUpRecordSignStatusTag({required this.dataDto});
|
|
|
+ final controller = Get.find<FollowUpRecordController>();
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return Container(
|
|
|
+ alignment: Alignment.centerRight,
|
|
|
+ width: 120,
|
|
|
+ child: StatusLabel(
|
|
|
+ title: controller.followUpStateTransition(dataDto.followUpState),
|
|
|
+ color: controller.followUpStateColors(dataDto.followUpState),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _OfflineSyncTag extends StatelessWidget {
|
|
|
+ final OfflineDataSyncState? syncState;
|
|
|
+
|
|
|
+ const _OfflineSyncTag({required this.syncState});
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ if (syncState == null || syncState == OfflineDataSyncState.success) {
|
|
|
+ return const SizedBox();
|
|
|
+ }
|
|
|
+ return Container(
|
|
|
+ height: 30,
|
|
|
+ alignment: Alignment.center,
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ borderRadius: BorderRadius.circular(16),
|
|
|
+ color: Colors.red,
|
|
|
+ ),
|
|
|
+ child: Text(
|
|
|
+ syncState!.getDescription(),
|
|
|
+ style: const TextStyle(color: Colors.white, fontSize: 14),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|