diff --git a/lib/app_theme.dart b/lib/app_theme.dart index 859d638..1911a30 100644 --- a/lib/app_theme.dart +++ b/lib/app_theme.dart @@ -6,11 +6,11 @@ class AppTheme { static const Color primaryColor = Color(0xFFC89607); static const Color primaryColorLight = Color.fromARGB(255, 255, 206, 70); static const Color primaryColorDark = Color.fromARGB(255, 163, 120, 0); - + static const Color primaryTextColorWithBg = Color(0x00000000); static const Color secondPrimaryColor = Color(0xFFc12a3a); static const Color secondPrimaryColorLight = Color.fromARGB(255, 230, 79, 94); static const Color secondPrimaryColorDark = Color.fromARGB(255, 141, 12, 25); - + static const Color secondPrimaryTextColorWithBg = Color(0xFFFFFFFF); static const Color white = Color(0xFFFFFFFF); static const Color nearlyWhite = Color(0xFFFEFEFE); static const Color black = Color(0xFF000000); @@ -23,6 +23,7 @@ class AppTheme { static const String fontName = 'NotoSans'; static const Color activeNavigationBarColor = primaryColor; static const Color notActiveNavigationBarColor = Colors.grey; + static const Color dangerColor = Colors.red; static const Color dividerColor = Color.fromARGB(255, 224, 224, 224); } diff --git a/lib/constants/router.dart b/lib/constants/router.dart index cba8d47..21901e9 100644 --- a/lib/constants/router.dart +++ b/lib/constants/router.dart @@ -18,6 +18,6 @@ class RouteConfig { GetPage(name: home, page: () => LandingPage()), GetPage(name: userinfo, page: () => UserInfoPage()), GetPage(name: inventory, page: () => const InventoryPage()), - GetPage(name: saleQuotation, page: () => const SaleQuotationPage()) + GetPage(name: saleQuotation, page: () => SaleQuotationPage()) ]; } diff --git a/lib/screens/inventory_inout/inventory_inout_controller.dart b/lib/screens/inventory_inout/inventory_inout_controller.dart index 3cbefa4..7cb6346 100644 --- a/lib/screens/inventory_inout/inventory_inout_controller.dart +++ b/lib/screens/inventory_inout/inventory_inout_controller.dart @@ -333,17 +333,17 @@ class InventoryInoutController extends GetxController { // db.update(key, 'status', 'complete'); // }); // } - case 2: - { - ModalUtil.showWarningDialog( - 'Delete Task', 'Are you want to sure to remove', 'Confirm', () { - list[ind].remove(list[ind][index]); - db.delete( - key, - 'Tasks', - ); - }); - } + // case 2: + // { + // ModalUtil.confirm( + // 'Delete Task', 'Are you want to sure to remove', 'Confirm', () { + // list[ind].remove(list[ind][index]); + // db.delete( + // key, + // 'Tasks', + // ); + // }); + // } } } } diff --git a/lib/screens/sale_quotation/sale_quotation.dart b/lib/screens/sale_quotation/sale_quotation.dart index 2a9fecf..0d85e5e 100644 --- a/lib/screens/sale_quotation/sale_quotation.dart +++ b/lib/screens/sale_quotation/sale_quotation.dart @@ -1,48 +1,259 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/app_theme.dart'; import 'package:sk_base_mobile/screens/sale_quotation/components/data_table.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 { - const SaleQuotationPage({super.key}); - + 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.secondPrimaryTextColorWithBg); @override Widget build(BuildContext context) { return Scaffold( appBar: const SkAppbar(title: '报价计算'), - body: buildBody(), + body: Column( + children: [ + Container( + decoration: BoxDecoration( + color: AppTheme.secondPrimaryColorLight, + border: Border(bottom: BorderSide(color: Colors.grey[200]!))), + 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: CustomScrollView( + slivers: controller.groups.map((e) => buildBody(e)).toList(), + )), + ], + ), ); } - Widget buildBody() { - return DataTable2FixedNMDemo(); - // return SingleChildScrollView( - // child: Column( - // children: [Text('11')], - // ), - // ); - // return SliverStickyHeader.builder( - // builder: (context, state) => Container( - // height: 60.0, - // color: (state.isPinned ? Colors.pink : Colors.lightBlue) - // .withOpacity(1.0 - state.scrollPercentage), - // padding: EdgeInsets.symmetric(horizontal: 16.0), - // alignment: Alignment.centerLeft, - // child: Text( - // 'Header #1', - // style: const TextStyle(color: Colors.white), - // ), - // ), - // sliver: SliverList( - // delegate: SliverChildBuilderDelegate( - // (context, i) => ListTile( - // leading: CircleAvatar( - // child: Text('0'), - // ), - // title: Text('List tile #$i'), - // ), - // childCount: 4, - // ), - // ), - // ); + Widget buildBody(SaleQuotationModel group) { + final titleStyle = TextStyle( + fontSize: ScreenAdaper.sp(40), + color: AppTheme.secondPrimaryTextColorWithBg, + 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: AppTheme.secondPrimaryColorLight + .withOpacity(1.0 - state.scrollPercentage), + padding: EdgeInsets.symmetric(horizontal: ScreenAdaper.width(20)), + alignment: Alignment.centerLeft, + child: Row( + children: [ + Text( + group.name, + style: titleStyle, + ), + Spacer(), + IconButton( + onPressed: () { + ModalUtil.confirm(title: '确定要删除此组吗?', onConfirm: () {}); + }, + icon: Icon( + // Icons.add_circle_outline, + Icons.remove_circle_outline_outlined, + color: AppTheme.secondPrimaryTextColorWithBg, + )) + ], + )), + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (context, i) => Container( + padding: EdgeInsets.only( + left: ScreenAdaper.width(20), + top: ScreenAdaper.height(15), + bottom: ScreenAdaper.height(15)), + constraints: BoxConstraints(minHeight: ScreenAdaper.height(80)), + 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( + '${controller.products[i].name}', + style: TextStyle(fontSize: ScreenAdaper.sp(35)), + )) + ]), + if (controller.products[i].spec != null) + Row( + children: [ + Text( + '规格、型号: ', + style: subTextStyle, + ), + Text( + '${controller.products[i].spec ?? ''}', + style: subTextStyle, + ) + ], + ), + if (controller.products[i].unit != null) + Row( + children: [ + Text( + '单位: ', + style: subTextStyle, + ), + Text( + '${controller.products[i].unit ?? ''}', + style: subTextStyle, + ) + ], + ), + if (controller.products[i].remark != null) + Row( + children: [ + Text( + '备注: ', + style: subTextStyle, + ), + Expanded( + child: Text( + '${controller.products[i].remark ?? ''}${controller.products[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.products.length, + ), + ), + ); } } + +class SaleQuotationModel { + final String name; + List? items; + SaleQuotationModel({required this.name, 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(); + + List products = [ + 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([ + SaleQuotationModel(name: '中间过渡架电控部分'), + SaleQuotationModel(name: '端头架电控部分'), + SaleQuotationModel(name: '主阀部分'), + SaleQuotationModel(name: '自动反冲洗过滤器部分'), + SaleQuotationModel(name: '位移测量部分'), + SaleQuotationModel(name: '压力检测部分'), + SaleQuotationModel(name: '煤机定位部分'), + SaleQuotationModel(name: '姿态检测部分'), + ]); +} diff --git a/lib/util/modal.util.dart b/lib/util/modal.util.dart index 7660244..e312422 100644 --- a/lib/util/modal.util.dart +++ b/lib/util/modal.util.dart @@ -1,41 +1,98 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:sk_base_mobile/app_theme.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; import 'package:sk_base_mobile/widgets/core/sk_bottomsheet_picker.dart'; class ModalUtil { - static Future showWarningDialog( - String title, String msg, String button, VoidCallback onConfirm) async { + static Future confirm( + {String? title, String? button, VoidCallback? onConfirm}) async { bool confirmed = false; await showDialog( context: Get.overlayContext!, builder: (context) { return AlertDialog( - title: Text(title), - content: Text(msg), + clipBehavior: Clip.hardEdge, + backgroundColor: AppTheme.nearlyWhite, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(ScreenAdaper.sp(20)), + ), + actionsPadding: EdgeInsets.symmetric(), + contentPadding: EdgeInsets.symmetric( + horizontal: ScreenAdaper.width(20), + vertical: ScreenAdaper.height(20)), + titlePadding: EdgeInsets.symmetric(), + title: title != null + ? Container( + padding: + EdgeInsets.symmetric(vertical: ScreenAdaper.height(20)), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: AppTheme.dividerColor, + width: ScreenAdaper.height(2)))), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.error_outline, + color: AppTheme.dangerColor, + ), + SizedBox( + width: ScreenAdaper.width(10), + ), + Text( + title, + style: TextStyle( + fontSize: ScreenAdaper.sp(40), + fontWeight: FontWeight.w500), + ) + ]), + ) + : null, + // actionsAlignment: MainAxisAlignment.spaceEvenly, actions: [ - TextButton( - child: const Text( - 'Cancel', - style: TextStyle(color: Colors.black), - ), - onPressed: () { - Navigator.of(context).pop(); - confirmed = false; - }, - ), - TextButton( - child: Text( - button, - style: const TextStyle(color: Colors.orange), - ), - onPressed: () { - onConfirm(); - Navigator.pop(context); - confirmed = true; - }, - ), + Row( + children: [ + Expanded( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + confirmed = false; + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: ScreenAdaper.height(15)), + alignment: Alignment.center, + child: Text( + '取消', + style: TextStyle( + color: Colors.black, fontSize: ScreenAdaper.sp(40)), + )), + )), + VerticalDivider(), + Expanded( + child: InkWell( + onTap: () { + if (onConfirm != null) onConfirm(); + Navigator.pop(context); + confirmed = true; + }, + child: Container( + padding: + EdgeInsets.symmetric(vertical: ScreenAdaper.height(15)), + alignment: Alignment.center, + child: Text( + '确定', + style: TextStyle( + color: Colors.black, fontSize: ScreenAdaper.sp(40)), + ), + ), + )), + ], + ) ], ); },