import 'dart:math'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:get/get.dart'; import 'package:sk_base_mobile/app_theme.dart'; import 'package:sk_base_mobile/util/modal.util.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; import 'package:sk_base_mobile/widgets/sk_appbar.dart'; import 'package:flutter_sticky_header/flutter_sticky_header.dart'; class SaleQuotationPage extends StatelessWidget { SaleQuotationPage({super.key}); final controller = Get.put(SaleQuotationController()); final quantityWidth = 55.0; final unitPriceWidth = 80.0; final amountWidth = 85.0; final headerTitleStyle = TextStyle( fontSize: ScreenAdaper.sp(40), fontWeight: FontWeight.w600, color: AppTheme.nearlyBlack); final headerBgcolor = Color.fromARGB(255, 238, 238, 238); @override Widget build(BuildContext context) { return Scaffold( appBar: SkAppbar( title: '报价计算', action: [ TextButton( onPressed: () {}, child: Row( children: [ Icon(Icons.add, color: AppTheme.white), Text( '添加组', style: TextStyle( color: AppTheme.white, fontSize: ScreenAdaper.sp(35), fontWeight: FontWeight.w600), ) ], )) ], ), body: SafeArea( bottom: ScreenAdaper.isLandspace() ? false : true, child: Column( children: [ Container( decoration: BoxDecoration( color: headerBgcolor, border: Border( bottom: BorderSide( color: AppTheme.nearlyBlack.withOpacity(0.5)))), padding: EdgeInsets.only( left: ScreenAdaper.width(20), top: ScreenAdaper.height(10), bottom: ScreenAdaper.height(10)), child: Row( children: [ Text( '名称', style: headerTitleStyle, ), const Spacer(), Container( alignment: Alignment.center, width: quantityWidth, // constraints: BoxConstraints(minWidth: quantityWidth), child: Text( '数量', style: headerTitleStyle, ), ), Container( alignment: Alignment.center, width: unitPriceWidth, // constraints: BoxConstraints(minWidth: unitPriceWidth), child: Text( '单价', style: headerTitleStyle, ), ), Container( alignment: Alignment.center, width: amountWidth, child: Text( '总价', style: headerTitleStyle, ), ), ], )), Expanded( child: Obx(() => CustomScrollView( slivers: controller.groups .mapIndexed((index, e) => buildBody(e, index)) .toList(), ))), ], ), ), ); } Widget buildBody(SaleQuotationModel group, int index) { final titleStyle = TextStyle( fontSize: ScreenAdaper.sp(40), color: AppTheme.nearlyBlack, fontWeight: FontWeight.w600); final subTextStyle = TextStyle(color: AppTheme.grey, fontSize: ScreenAdaper.sp(30)); return SliverStickyHeader.builder( builder: (context, state) => Container( height: ScreenAdaper.height(80), color: headerBgcolor.withOpacity(1.0 - state.scrollPercentage), alignment: Alignment.centerLeft, child: InkWell( onTap: () { controller.groups[index].isExpanded.value = !controller.groups[index].isExpanded.value; }, child: Row( children: [ Obx(() => controller.groups[index].isExpanded.value ? IconButton( padding: EdgeInsets.zero, onPressed: () { controller.groups[index].isExpanded.value = false; }, icon: const Icon( Icons.expand_more, color: AppTheme.nearlyBlack, ), ) : IconButton( padding: EdgeInsets.zero, onPressed: () { controller.groups[index].isExpanded.value = true; }, icon: const Icon( Icons.chevron_right, color: AppTheme.nearlyBlack, ), )), Text( group.name, style: titleStyle, ), const Spacer(), IconButton( onPressed: () { ModalUtil.confirm(title: '确定要删除此组吗?', onConfirm: () {}); }, icon: const Icon( Icons.remove_circle_outline_outlined, color: AppTheme.nearlyBlack, )), IconButton( onPressed: () {}, icon: const Icon( Icons.add_circle_outline, color: AppTheme.nearlyBlack, )), ], ))), sliver: Obx(() => !controller.groups[index].isExpanded.value ? SliverList( delegate: SliverChildBuilderDelegate( (context, i) => SizedBox(), childCount: 0, )) : SliverList( delegate: SliverChildBuilderDelegate( (context, i) => Slidable( key: UniqueKey(), endActionPane: ActionPane( extentRatio: 0.2, motion: const DrawerMotion(), children: [ SlidableAction( padding: EdgeInsets.zero, onPressed: (_) {}, backgroundColor: AppTheme.dangerColor, foregroundColor: Colors.white, icon: Icons.delete, label: 'Delete', ), ], ), child: Container( padding: EdgeInsets.only( left: ScreenAdaper.width(20), top: ScreenAdaper.height(15), bottom: ScreenAdaper.height(15), ), constraints: BoxConstraints(minHeight: ScreenAdaper.height(100)), decoration: BoxDecoration( border: Border( bottom: BorderSide(width: 1, color: Colors.grey[200]!), ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( '${group.items[i].name}', style: TextStyle( fontSize: ScreenAdaper.sp(35)), ), ), ], ), if (group.items[i].spec != null) Row( children: [ Text( '规格、型号: ', style: subTextStyle, ), Text( '${group.items[i].spec ?? ''}', style: subTextStyle, ), ], ), if (group.items[i].unit != null) Row( children: [ Text( '单位: ', style: subTextStyle, ), Text( '${group.items[i].unit ?? ''}', style: subTextStyle, ), ], ), if (group.items[i].remark != null) Row( children: [ Text( '备注: ', style: subTextStyle, ), Expanded( child: Text( '${group.items[i].remark ?? ''}${group.items[i].remark ?? ''}${controller.products[i].remark ?? ''}', overflow: TextOverflow.ellipsis, style: subTextStyle, ), ), ], ), ], ), ), VerticalDivider(), Container( alignment: Alignment.center, width: quantityWidth, child: Text('13500'), ), Container( alignment: Alignment.center, width: unitPriceWidth, child: Text('¥470000'), ), Container( alignment: Alignment.center, width: amountWidth, child: Text('¥63450000'), ), ], ), ), ), childCount: !controller.groups[index].isExpanded.value ? 0 : group.items.length, ), )), ); } } class SaleQuotationModel { final String name; RxBool isExpanded = true.obs; List items; SaleQuotationModel({required this.name, required this.items}); } class SaleQuotationItemModel { final String name; // 规格 final String? spec; final String? unit; final String? remark; // 成本 final double? cost; SaleQuotationItemModel( {required this.name, this.spec, this.unit, this.remark, this.cost}); } class SaleQuotationController extends GetxController { static SaleQuotationController get to => Get.find(); RxList products = RxList([ SaleQuotationItemModel(name: '矿用本安型支架控制器', unit: '台', spec: 'ZDYZ-Z'), SaleQuotationItemModel(name: '矿用本安型电磁阀驱动器'), SaleQuotationItemModel(name: '矿用隔爆兼本安型电源'), SaleQuotationItemModel(name: '矿用本安型隔离耦合器'), SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器'), SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-控制器'), SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-驱动器'), SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-隔离耦合器'), SaleQuotationItemModel(name: '矿用本安型支架无线遥控器'), SaleQuotationItemModel(name: '矿用隔爆兼本安型电源'), SaleQuotationItemModel(name: '电液换向阀(10功能10接口)', remark: '中间过渡架主阀组'), SaleQuotationItemModel(name: '电液换向阀(20功能20接口)', remark: '端头架主阀组'), SaleQuotationItemModel(name: '自动反冲洗过滤装置', remark: '流量:900L/min,过滤精度25μm'), SaleQuotationItemModel(name: '全自动反冲洗过滤器电缆', remark: '控制器-自动反冲洗'), SaleQuotationItemModel(name: '矿用本安型位移传感器'), SaleQuotationItemModel(name: '矿用本安型压力传感器'), SaleQuotationItemModel(name: '矿用本安型红外发射器'), SaleQuotationItemModel(name: '矿用本安型LED信号灯'), SaleQuotationItemModel(name: '倾角传感器'), SaleQuotationItemModel(name: '各类安装附件'), ]); RxList groups = RxList([]); @override void onReady() { groups.assignAll([ SaleQuotationModel(name: '中间过渡架电控部分', items: products), SaleQuotationModel(name: '端头架电控部分', items: products), SaleQuotationModel(name: '主阀部分', items: products), SaleQuotationModel(name: '自动反冲洗过滤器部分', items: products), SaleQuotationModel(name: '位移测量部分', items: products), SaleQuotationModel(name: '压力检测部分', items: products), SaleQuotationModel(name: '煤机定位部分', items: products), SaleQuotationModel(name: '姿态检测部分', items: products), ]); super.onReady(); } }