123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- import 'package:date_format/date_format.dart';
- import 'package:fis_jsonrpc/rpc.dart';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- import 'package:vnoteapp/architecture/utils/datetime.dart';
- import 'package:vnoteapp/components/button.dart';
- import 'package:vnoteapp/components/panel.dart';
- import 'package:vnoteapp/components/search_input.dart';
- import 'package:vnoteapp/consts/rpc_enum_labels.dart';
- import 'controller.dart';
- class PatientListPage extends GetView<PatientListController> {
- const PatientListPage({super.key});
- @override
- Widget build(BuildContext context) {
- return Container(
- padding: const EdgeInsets.all(8),
- color: Colors.grey.shade200,
- child: Column(
- mainAxisSize: MainAxisSize.max,
- children: [
- _HeaderWidget(),
- const SizedBox(height: 20),
- Expanded(child: _buildListView()),
- // Obx(
- // () {
- // if (controller.state.hasNextPage == false) {
- // return Container(
- // alignment: Alignment.center,
- // padding: const EdgeInsets.symmetric(vertical: 8),
- // child: const Text(
- // "没有更多数据了~",
- // style: TextStyle(color: Colors.grey, fontSize: 14),
- // ),
- // );
- // } else {
- // return const SizedBox();
- // }
- // },
- // ),
- ],
- ),
- );
- }
- Widget _buildListView() {
- final scrollController = ScrollController();
- scrollController.addListener(
- () {
- // 如果滑动到底部
- try {
- if (scrollController.position.atEdge) {
- if (scrollController.position.pixels != 0) {
- if (controller.state.hasNextPage) {
- controller.loadNextPageList();
- }
- }
- }
- } catch (e) {
- // logger.e("listViewScrollController exception:", e);
- }
- },
- );
- return RefreshIndicator(
- onRefresh: () async {
- controller.reloadList();
- },
- child: Obx(
- () {
- final list = controller.state.dataList;
- final children = <Widget>[];
- for (var i = 0; i < list.length; i++) {
- children.add(_PatientCard(dto: list[i]));
- }
- return Scrollbar(
- trackVisibility: true,
- controller: scrollController,
- child: GridView(
- shrinkWrap: true,
- controller: scrollController,
- gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: 3,
- mainAxisSpacing: 16,
- crossAxisSpacing: 20,
- childAspectRatio: 360 / 180,
- ),
- children: children,
- ),
- );
- },
- ),
- );
- }
- }
- class _HeaderWidget extends GetView<PatientListController> {
- @override
- Widget build(BuildContext context) {
- return SizedBox(
- height: 76,
- child: Row(
- children: [
- Expanded(
- child: SizedBox(
- height: 70,
- child: VSearchInput(
- placeholder: "身份证号码/姓名/手机号",
- onSearch: (value) {
- controller.state.searchString = value;
- controller.reloadList();
- },
- ),
- ),
- ),
- const SizedBox(width: 8),
- SizedBox(
- width: 180,
- height: 70,
- child: VButton(
- child: const Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(Icons.note_add_outlined, size: 24),
- Text("新建档案", style: TextStyle(fontSize: 20)),
- ],
- ),
- onTap: () {
- controller.onCreateClicked();
- },
- ),
- ),
- const SizedBox(width: 8),
- SizedBox(
- width: 150,
- height: 70,
- child: VButton(
- child: const Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(Icons.filter_alt, size: 24),
- Text("筛选", style: TextStyle(fontSize: 20)),
- ],
- ),
- onTap: () {
- controller.onFilterClicked();
- },
- ),
- ),
- ],
- ),
- );
- }
- }
- class _PatientCard extends StatelessWidget {
- final PatientDTO dto;
- const _PatientCard({super.key, required this.dto});
- @override
- Widget build(BuildContext context) {
- final body = Stack(
- children: [
- Container(
- padding: const EdgeInsets.symmetric(
- horizontal: 16,
- vertical: 12,
- ),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const SizedBox(height: 8),
- LayoutBuilder(
- builder: (context, c) {
- final width = c.maxWidth - 80 - 20;
- // 不和状态标签重叠,并保持一定距离
- return SizedBox(width: width, child: _buildBaseInfoRow());
- },
- ),
- const SizedBox(height: 12),
- _buildClassTags(),
- ],
- ),
- ),
- Positioned(
- top: 0,
- right: 0,
- child: _PatientSignStatusTag(),
- ),
- ],
- );
- return Material(
- borderRadius: BorderRadius.circular(8),
- child: Ink(
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(8),
- ),
- child: InkWell(
- borderRadius: BorderRadius.circular(8),
- onTap: () {
- Get.find<PatientListController>().gotoDetail(dto.code!);
- },
- child: body,
- ),
- ),
- );
- }
- Widget _buildBaseInfoRow() {
- final birthday = dto.birthday!.toLocal();
- final age = DataTimeUtils.calculateAge(birthday);
- return Row(
- mainAxisSize: MainAxisSize.max,
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- SizedBox(
- width: 100,
- child: Text(
- dto.patientName!,
- style: const TextStyle(
- color: Colors.black,
- fontSize: 20,
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- Expanded(
- child: Row(
- mainAxisSize: MainAxisSize.max,
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Expanded(
- child: Text(
- RpcEnumLabels.gender[dto.patientGender] ?? "未知",
- style: const TextStyle(
- color: Colors.grey,
- fontSize: 20,
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- Expanded(
- child: Text(
- "$age岁",
- style: const TextStyle(
- color: Colors.grey,
- fontSize: 20,
- ),
- ),
- ),
- ],
- ),
- ),
- ],
- );
- }
- Widget _buildClassTags() {
- fn(String x) => Text(
- x,
- style: const TextStyle(color: Colors.grey, fontSize: 18),
- );
- return ConstrainedBox(
- constraints: const BoxConstraints(minWidth: double.infinity),
- child: Wrap(
- alignment: WrapAlignment.start,
- spacing: 20,
- runSpacing: 8,
- children: [
- fn("一般人群"),
- fn("高血压"),
- fn("冠心病"),
- fn("冠心病"),
- fn("精神病"),
- ],
- ),
- );
- }
- }
- class _PatientSignStatusTag extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- const radius = Radius.circular(8);
- return Container(
- width: 80,
- height: 36,
- alignment: Alignment.center,
- decoration: BoxDecoration(
- color: Theme.of(context).primaryColor,
- borderRadius: BorderRadius.only(
- topRight: radius,
- bottomLeft: radius,
- ),
- ),
- child: Text(
- "已签约",
- style: TextStyle(color: Colors.white, fontSize: 14),
- ),
- );
- }
- }
|