diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 37f7207..8d14093 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -43,6 +43,7 @@ android:name="android.permission.CAMERA" /> - + + + \ No newline at end of file diff --git a/assets/images/company_name.png b/assets/images/company_name.png new file mode 100644 index 0000000..9098a56 Binary files /dev/null and b/assets/images/company_name.png differ diff --git a/assets/images/rocket.gif b/assets/images/rocket.gif new file mode 100644 index 0000000..ea6e97b Binary files /dev/null and b/assets/images/rocket.gif differ diff --git a/assets/images/rocket.png b/assets/images/rocket.png new file mode 100644 index 0000000..466bd9a Binary files /dev/null and b/assets/images/rocket.png differ diff --git a/lib/apis/index.dart b/lib/apis/index.dart index 60bafaf..7f8d2b3 100644 --- a/lib/apis/index.dart +++ b/lib/apis/index.dart @@ -7,7 +7,7 @@ import 'package:sk_base_mobile/services/dio.service.dart'; import '../constants/constants.dart'; class Api { -// 登录 + /// 登录 static Future login(String username, String password) { return DioService.dio.post( Urls.login, @@ -15,6 +15,13 @@ class Api { ); } + /// 查询参数配置信息By key + static Future getSystemParamConfigByCode(String code) { + return DioService.dio.get( + '${Urls.systemParamConfig}/key/$code', + ); + } + // 获取个人信息 static Future getUserInfo() { return DioService.dio.get( diff --git a/lib/app_theme.dart b/lib/app_theme.dart index 89f3493..965b94d 100644 --- a/lib/app_theme.dart +++ b/lib/app_theme.dart @@ -28,6 +28,7 @@ class AppTheme { } final theme = ThemeData( + platform: TargetPlatform.iOS, primarySwatch: MaterialColor(AppTheme.primaryColor.value, const { 50: AppTheme.primaryColorLight, 100: AppTheme.primaryColorLight, diff --git a/lib/config.dart b/lib/config.dart index 605fa68..02b0257 100644 --- a/lib/config.dart +++ b/lib/config.dart @@ -2,11 +2,11 @@ // Global config class GloablConfig { - static const BASE_URL = "http://10.0.2.2:8001/api/"; - static const OSS_URL = "http://10.0.2.2:8001"; + // static const BASE_URL = "http://10.0.2.2:8001/api/"; + // static const OSS_URL = "http://10.0.2.2:8001"; - // static const BASE_URL = "http://144.123.43.138:3001/api/"; - // static const OSS_URL = "http://144.123.43.138:3001"; + static const BASE_URL = "http://144.123.43.138:3001/api/"; + static const OSS_URL = "http://144.123.43.138:3001"; // static const BASE_URL = "http://192.168.60.220:8001/api/"; // static const OSS_URL = "http://192.168.60.220:8001"; static const DOMAIN_NAME = "山矿通"; diff --git a/lib/constants/constants.dart b/lib/constants/constants.dart index d9b6a08..437b5ba 100644 --- a/lib/constants/constants.dart +++ b/lib/constants/constants.dart @@ -6,3 +6,4 @@ export 'global_url.dart'; export 'cache_key.dart'; export 'router.dart'; export 'text_enum.dart'; +export 'system_param_config.dart'; diff --git a/lib/constants/global_url.dart b/lib/constants/global_url.dart index e41caf7..c9b6561 100644 --- a/lib/constants/global_url.dart +++ b/lib/constants/global_url.dart @@ -13,4 +13,6 @@ class Urls { static String updateAvatar = 'user/updateAvatar'; static String getDictType = 'system/dict-type/all'; static String uploadAttachemnt = 'tools/upload'; + static String systemParamConfig = 'system/param-config'; + static String accountMenus = 'account/menus'; } diff --git a/lib/constants/system_param_config.dart b/lib/constants/system_param_config.dart new file mode 100644 index 0000000..59c88cf --- /dev/null +++ b/lib/constants/system_param_config.dart @@ -0,0 +1,4 @@ +class SystemParamConfig { + static const String appVersion = "app_version"; + static const String isForceUpgrade = "is_app_force_upgrade"; +} diff --git a/lib/main.dart b/lib/main.dart index 686a923..a297254 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,7 +8,7 @@ Future main() async { try { await Global.init(); } catch (e) { - LoggerUtil().error('Init failed, please try again.$e'); + LoggerUtil().error('Init failed, please try again. $e'); } // await SentryFlutter.init( // (options) { diff --git a/lib/models/inventory_inout.model.dart b/lib/models/inventory_inout.model.dart index 6cc8ed3..271c877 100644 --- a/lib/models/inventory_inout.model.dart +++ b/lib/models/inventory_inout.model.dart @@ -7,7 +7,7 @@ class InventoryInOutModel { required this.id, required this.createdAt, required this.updatedAt, - required this.inventoryNumber, + required this.inventoryInOutNumber, required this.productId, required this.inOrOut, required this.time, @@ -28,7 +28,7 @@ class InventoryInOutModel { final int? id; final DateTime? createdAt; final DateTime? updatedAt; - final String? inventoryNumber; + final String? inventoryInOutNumber; final int? productId; final int? inOrOut; final DateTime? time; @@ -47,12 +47,12 @@ class InventoryInOutModel { factory InventoryInOutModel.fromJson(Map json) { return InventoryInOutModel( id: json["id"], - createdAt: DateTime.tryParse(json["createdAt"] ?? ""), - updatedAt: DateTime.tryParse(json["updatedAt"] ?? ""), - inventoryNumber: json["inventoryNumber"], + createdAt: DateTime.tryParse(json["createdAt"] ?? "")?.toLocal(), + updatedAt: DateTime.tryParse(json["updatedAt"] ?? "")?.toLocal(), + inventoryInOutNumber: json["inventoryInOutNumber"], productId: json["productId"], inOrOut: json["inOrOut"], - time: DateTime.tryParse(json["time"] ?? ""), + time: DateTime.tryParse(json["time"] ?? "")?.toLocal(), quantity: json["quantity"], unitPrice: json["unitPrice"], amount: json["amount"], @@ -81,7 +81,7 @@ class InventoryInOutModel { "id": id, "createdAt": createdAt?.toIso8601String(), "updatedAt": updatedAt?.toIso8601String(), - "inventoryNumber": inventoryNumber, + "inventoryInOutNumber": inventoryInOutNumber, "productId": productId, "inOrOut": inOrOut, "time": time, diff --git a/lib/screens/inventory/inventory.dart b/lib/screens/inventory/inventory.dart index a8d8e35..d5aca44 100644 --- a/lib/screens/inventory/inventory.dart +++ b/lib/screens/inventory/inventory.dart @@ -3,12 +3,13 @@ import 'package:sk_base_mobile/screens/new_inventory_inout/components/inventory_ import 'package:sk_base_mobile/widgets/sk_appbar.dart'; class InventoryPage extends StatelessWidget { - const InventoryPage({super.key}); + final bool isPage; + const InventoryPage({super.key, this.isPage = false}); @override Widget build(BuildContext context) { return Scaffold( - appBar: const SkAppbar(title: '库存管理'), + appBar: SkAppbar(title: '库存管理', hideLeading: isPage), body: InventorySearch(), ); } diff --git a/lib/screens/inventory_inout/components/inventory_inout_card.dart b/lib/screens/inventory_inout/components/inventory_inout_card.dart index f316c0b..3026a68 100644 --- a/lib/screens/inventory_inout/components/inventory_inout_card.dart +++ b/lib/screens/inventory_inout/components/inventory_inout_card.dart @@ -109,7 +109,11 @@ class InventoryInoutCard extends StatelessWidget { ), ), Text( - controller.list[ind][index].agent ?? '-', + '${DateUtil.format(controller.list[ind][index].time!, formats: [ + 'HH', + ':', + "nn" + ])} ${controller.list[ind][index].agent ?? '-'}', style: TextStyle( fontSize: ScreenAdaper.height(20), fontWeight: FontWeight.w600), diff --git a/lib/screens/inventory_inout/components/inventory_inout_info.dart b/lib/screens/inventory_inout/components/inventory_inout_info.dart index 86430fb..b7c529e 100644 --- a/lib/screens/inventory_inout/components/inventory_inout_info.dart +++ b/lib/screens/inventory_inout/components/inventory_inout_info.dart @@ -61,9 +61,21 @@ class InventoryInoutInfo extends StatelessWidget { customDivider(), ], buildListItem( - leading: '出入库时间', - trailing: DateUtil.format( - controller.inventoryInoutInfo.value!.time!)), + leading: '出入库时间', + trailing: DateUtil.format( + controller.inventoryInoutInfo.value!.time!, + formats: [ + 'yyyy', + '-', + 'mm', + '-', + 'dd', + " ", + 'HH', + ":", + "nn" + ]), + ), customDivider(), buildListItem( leading: '所属公司', @@ -99,6 +111,16 @@ class InventoryInoutInfo extends StatelessWidget { trailing: controller.inventoryInoutInfo.value?.remark), customDivider(), + buildListItem( + leading: '出入库单号', + trailing: controller + .inventoryInoutInfo.value?.inventoryInOutNumber), + customDivider(), + buildListItem( + leading: '库存编号', + trailing: controller.inventoryInoutInfo.value + ?.inventory?.inventoryNumber), + customDivider(), buildListItem( leading: '照片', ), @@ -156,14 +178,31 @@ class InventoryInoutInfo extends StatelessWidget { } Widget buildListItem({String? leading, dynamic trailing}) { - return ListTile( - leading: Text( - '${leading ?? ''}: ', - style: TextStyle( - fontSize: ScreenAdaper.height(25), fontWeight: FontWeight.w600), - ), - trailing: Text('${trailing ?? ''}', - style: TextStyle(fontSize: ScreenAdaper.height(25)))); + return Container( + padding: EdgeInsets.symmetric( + vertical: ScreenAdaper.height(20), + horizontal: ScreenAdaper.width(20)), + child: Row( + children: [ + Text( + '${leading ?? ''}: ', + style: TextStyle( + fontSize: ScreenAdaper.height(30), fontWeight: FontWeight.w600), + ), + Spacer(), + Text('${trailing ?? ''}', + style: TextStyle(fontSize: ScreenAdaper.height(30))) + ], + ), + ); + // return ListTile( + // leading: Text( + // '${leading ?? ''}: ', + // style: TextStyle( + // fontSize: ScreenAdaper.height(25), fontWeight: FontWeight.w600), + // ), + // trailing: Text('${trailing ?? ''}', + // style: TextStyle(fontSize: ScreenAdaper.height(25)))); } } diff --git a/lib/screens/inventory_inout/inventory_inout_controller.dart b/lib/screens/inventory_inout/inventory_inout_controller.dart index 7cb6346..4042325 100644 --- a/lib/screens/inventory_inout/inventory_inout_controller.dart +++ b/lib/screens/inventory_inout/inventory_inout_controller.dart @@ -6,7 +6,9 @@ import 'package:sk_base_mobile/app_theme.dart'; import 'package:sk_base_mobile/constants/enum.dart'; import 'package:sk_base_mobile/db_helper/db_help.dart'; import 'package:sk_base_mobile/screens/inventory_inout/components/inventory_inout_info.dart'; +import 'package:sk_base_mobile/screens/landing/landing_controller.dart'; import 'package:sk_base_mobile/screens/new_inventory_inout/new_inventory_inout.dart'; +import 'package:sk_base_mobile/services/app_info.service.dart'; import 'package:sk_base_mobile/util/date.util.dart'; import 'package:sk_base_mobile/util/modal.util.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; @@ -236,7 +238,7 @@ class InventoryInoutController extends GetxController { Future showInventoryInoutInfoDialog(int id) async { ModalUtil.showGeneralDialog( width: ScreenAdaper.screenShortDistance() - ScreenAdaper.width(100), - height: ScreenAdaper.height(Get.height - 100), + height: Get.height - 100 < 400 ? 400 : Get.height - 100, content: InventoryInoutInfo(inventoryInoutId: id), offset: const Offset(0, -1)) .then((value) => {Get.delete()}); @@ -258,6 +260,7 @@ class InventoryInoutController extends GetxController { } return []; } catch (e) { + print(e); return []; } finally { loading.value = false; @@ -335,7 +338,7 @@ class InventoryInoutController extends GetxController { // } // case 2: // { - // ModalUtil.confirm( + // ModalUtil.alert( // 'Delete Task', 'Are you want to sure to remove', 'Confirm', () { // list[ind].remove(list[ind][index]); // db.delete( diff --git a/lib/screens/landing/landing_controller.dart b/lib/screens/landing/landing_controller.dart index 604163f..31d9097 100644 --- a/lib/screens/landing/landing_controller.dart +++ b/lib/screens/landing/landing_controller.dart @@ -1,10 +1,16 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:sk_base_mobile/apis/index.dart'; import 'package:sk_base_mobile/models/app_bottom_nav_item.dart'; import 'package:sk_base_mobile/screens/inventory/inventory.dart'; import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout.dart'; import 'package:sk_base_mobile/screens/mine/mine.dart'; import 'package:sk_base_mobile/screens/workbench/workbench.dart'; +import 'package:sk_base_mobile/services/app_info.service.dart'; +import 'package:sk_base_mobile/util/device.util.dart'; +import 'package:sk_base_mobile/util/modal.util.dart'; + +import '../../constants/constants.dart'; class LandingController extends GetxController { RxInt currentIndex = 0.obs; @@ -20,7 +26,7 @@ class LandingController extends GetxController { icon: Icons.inventory_outlined, activeIcon: Icons.inventory_rounded, label: '库存', - page: const InventoryPage()), + page: const InventoryPage(isPage: true)), AppBottomNavItem( icon: Icons.widgets_outlined, activeIcon: Icons.widgets_rounded, @@ -36,5 +42,6 @@ class LandingController extends GetxController { onInit() { super.onInit(); pages = bottomNavItems!.map((e) => e.page!).toList(); + AppInfoService.to.checkVersion(); } } diff --git a/lib/screens/login/login.controller.dart b/lib/screens/login/login.controller.dart index 0fa2d7e..983cfd8 100644 --- a/lib/screens/login/login.controller.dart +++ b/lib/screens/login/login.controller.dart @@ -1,6 +1,9 @@ import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; +import 'package:sk_base_mobile/apis/index.dart'; +import 'package:sk_base_mobile/util/device.util.dart'; import 'package:sk_base_mobile/util/snack_bar.util.dart'; +import '../../constants/constants.dart'; import '../../store/auth.store.dart'; // import 'package:sentry/sentry.dart'; diff --git a/lib/screens/mine/mine.dart b/lib/screens/mine/mine.dart index 11c55f5..6d49041 100644 --- a/lib/screens/mine/mine.dart +++ b/lib/screens/mine/mine.dart @@ -35,11 +35,14 @@ class _MinePageState extends State Widget _buildBody() { return Column(children: [ Container( - height: ScreenAdaper.height(300), - decoration: const BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - image: AssetImage('assets/images/yeyazhijia_bg.jpg'))), + height: ScreenAdaper.height(350), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [AppTheme.primaryColorLight, AppTheme.primaryColor]) + // image: DecorationImage( + // fit: BoxFit.cover, + // image: AssetImage('assets/images/yeyazhijia_bg.jpg')) + ), // decoration: BoxDecoration( // gradient: LinearGradient( // colors: [AppTheme.primaryColorLight, AppTheme.primaryColor])), @@ -49,7 +52,7 @@ class _MinePageState extends State vertical: ScreenAdaper.height(20)), child: Column(children: [ SizedBox( - height: ScreenAdaper.height(80), + height: ScreenAdaper.height(100), ), Row( mainAxisAlignment: MainAxisAlignment.center, @@ -69,7 +72,7 @@ class _MinePageState extends State AuthStore.to.userInfo.value.nickname ?? '', style: TextStyle( letterSpacing: ScreenAdaper.width(5), - fontSize: ScreenAdaper.height(30), + fontSize: ScreenAdaper.height(35), fontWeight: FontWeight.bold, foreground: Paint() ..style = PaintingStyle.stroke @@ -81,7 +84,7 @@ class _MinePageState extends State style: TextStyle( letterSpacing: ScreenAdaper.width(5), color: Colors.white, - fontSize: ScreenAdaper.height(30), + fontSize: ScreenAdaper.height(35), fontWeight: FontWeight.bold), ), ], diff --git a/lib/screens/mine/settings/mine_settings.dart b/lib/screens/mine/settings/mine_settings.dart index 03435c6..87706c1 100644 --- a/lib/screens/mine/settings/mine_settings.dart +++ b/lib/screens/mine/settings/mine_settings.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:sk_base_mobile/app_theme.dart'; +import 'package:sk_base_mobile/constants/bg_color.dart'; +import 'package:sk_base_mobile/services/app_info.service.dart'; import 'package:sk_base_mobile/store/auth.store.dart'; +import 'package:sk_base_mobile/util/device.util.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; class MineSettingsPage extends StatelessWidget { @@ -18,7 +21,7 @@ class MineSettingsPage extends StatelessWidget { border: Border.all(), borderRadius: BorderRadius.circular(15), color: AppTheme.nearlyWhite), - width: ScreenAdaper.width(400), + width: ScreenAdaper.width(600), padding: EdgeInsets.symmetric(vertical: ScreenAdaper.width(10)), child: InkWell( @@ -35,7 +38,44 @@ class MineSettingsPage extends StatelessWidget { Text( '退出登录', style: TextStyle( - fontSize: ScreenAdaper.height(20), + fontSize: ScreenAdaper.height(30), + fontWeight: FontWeight.w600), + ), + ], + )))), + SizedBox( + height: ScreenAdaper.height(defaultPadding), + ), + Container( + decoration: BoxDecoration( + border: Border.all(), + borderRadius: BorderRadius.circular(15), + color: AppTheme.nearlyWhite), + width: ScreenAdaper.width(600), + padding: + EdgeInsets.symmetric(vertical: ScreenAdaper.width(10)), + child: InkWell( + onTap: () async { + await AppInfoService.to.checkVersion(); + }, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: ScreenAdaper.width(20), + vertical: ScreenAdaper.width(20)), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'v${AppInfoService.to.versionNumber}', + style: TextStyle( + fontSize: ScreenAdaper.height(25), + fontWeight: FontWeight.w400), + ), + const Spacer(), + Text( + '检查更新', + style: TextStyle( + fontSize: ScreenAdaper.height(30), fontWeight: FontWeight.w600), ), ], diff --git a/lib/screens/new_inventory_inout/new_inventory_inout.dart b/lib/screens/new_inventory_inout/new_inventory_inout.dart index 2143f66..029cbdc 100644 --- a/lib/screens/new_inventory_inout/new_inventory_inout.dart +++ b/lib/screens/new_inventory_inout/new_inventory_inout.dart @@ -84,10 +84,10 @@ class NewInventoryInout extends StatelessWidget { SizedBox( height: ScreenAdaper.height(formVerticalGap), ), - buildDatePicker(), - SizedBox( - height: ScreenAdaper.height(formVerticalGap), - ), + // buildDatePicker(), + // SizedBox( + // height: ScreenAdaper.height(formVerticalGap), + // ), buildAgent(), SizedBox( height: ScreenAdaper.height(formVerticalGap), diff --git a/lib/screens/new_inventory_inout/new_inventory_inout_controller.dart b/lib/screens/new_inventory_inout/new_inventory_inout_controller.dart index 97be14f..2a98f89 100644 --- a/lib/screens/new_inventory_inout/new_inventory_inout_controller.dart +++ b/lib/screens/new_inventory_inout/new_inventory_inout_controller.dart @@ -128,13 +128,29 @@ class NewInventoryInoutController extends GetxController { ); return; } - if (payload['time'] == null) { - SnackBarUtil().error( - '时间不能为空', - ); - return; - } + // 暂时时间定位提交时间 + // if (payload['time'] == null) { + // SnackBarUtil().error( + // '时间不能为空', + // ); + // return; + // } + + payload['time'] = DateUtil.format(DateTime.now(), formats: [ + 'yyyy', + '-', + 'mm', + '-', + 'dd', + ' ', + 'HH', + ':', + 'nn', + ":", + 'ss' + ]); payload['quantity'] = quantityTextController.text; + if (payload['quantity'].isEmpty || payload['quantity'] == '0') { SnackBarUtil().error( '数量必须大于1', diff --git a/lib/screens/sale_quotation/sale_quotation.controller.dart b/lib/screens/sale_quotation/sale_quotation.controller.dart index 286de44..fad7411 100644 --- a/lib/screens/sale_quotation/sale_quotation.controller.dart +++ b/lib/screens/sale_quotation/sale_quotation.controller.dart @@ -8,9 +8,7 @@ import 'package:sk_base_mobile/models/base_search_more_controller.dart'; import 'package:sk_base_mobile/models/sale_quotation.model.dart'; import 'package:sk_base_mobile/screens/sale_quotation/components/sale_quotation_group_search.dart'; import 'package:sk_base_mobile/services/storage.service.dart'; -import 'package:sk_base_mobile/util/snack_bar.util.dart'; import 'package:sk_base_mobile/widgets/core/sk_muti_search_more.dart'; -import 'package:sk_base_mobile/widgets/core/sk_single_search_more.dart'; import 'package:sk_base_mobile/util/modal.util.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; import 'package:pinyin/pinyin.dart'; @@ -20,19 +18,25 @@ class SaleQuotationController extends GetxController { final RxList editingcell = RxList([null, null, null]); final GlobalKey scaffoldKey = GlobalKey(); 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: '矿用本安型支架控制器', unit: '台', spec: 'ZDYZ-Z', cost: 4700), + SaleQuotationItemModel(name: '矿用本安型电磁阀驱动器', cost: 1200), + SaleQuotationItemModel(name: '矿用隔爆兼本安型电源', cost: 5700), + SaleQuotationItemModel(name: '矿用本安型隔离耦合器', cost: 1200), + SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', cost: 600), + SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-控制器', cost: 400), + SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-驱动器', cost: 500), + SaleQuotationItemModel( + name: '钢丝编织橡胶护套连接器', remark: '控制器-隔离耦合器', cost: 2000), + SaleQuotationItemModel(name: '矿用本安型支架控制器', cost: 4700), + SaleQuotationItemModel(name: '矿用本安型电磁阀驱动器', cost: 1200), + SaleQuotationItemModel(name: '矿用隔爆兼本安型电源', cost: 5700), + SaleQuotationItemModel( + name: '电液换向阀(10功能10接口)', remark: '中间过渡架主阀组', cost: 13200), + SaleQuotationItemModel( + name: '电液换向阀(20功能20接口)', remark: '端头架主阀组', cost: 26500), + SaleQuotationItemModel( + name: '自动反冲洗过滤装置', remark: '流量:900L/min,过滤精度25μm', cost: 2000), SaleQuotationItemModel(name: '全自动反冲洗过滤器电缆', remark: '控制器-自动反冲洗'), SaleQuotationItemModel(name: '矿用本安型位移传感器'), SaleQuotationItemModel(name: '矿用本安型压力传感器'), @@ -187,18 +191,54 @@ class SaleQuotationController extends GetxController { }, leadingBuilder: (index) { return Container( - padding: EdgeInsets.symmetric( - horizontal: ScreenAdaper.width(5), - vertical: ScreenAdaper.height(10)), - child: Row( - children: [ - Text( - controller.list[index].name, - style: TextStyle(fontSize: ScreenAdaper.height(25)), - ), - ], - ), - ); + padding: EdgeInsets.symmetric( + horizontal: ScreenAdaper.width(5), + vertical: ScreenAdaper.height(10)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + controller.list[index].name, + style: TextStyle( + fontSize: ScreenAdaper.height(30)), + ), + ], + ), + if (controller.list[index].spec != null) + Row( + children: [ + Text( + '型号:${controller.list[index].spec ?? ''}', + textAlign: TextAlign.start, + style: TextStyle( + fontSize: ScreenAdaper.height(25)), + ), + ], + ), + Row( + children: [ + Text( + '单价:¥${controller.list[index].cost}', + textAlign: TextAlign.start, + style: TextStyle( + fontSize: ScreenAdaper.height(25)), + ), + ], + ), + if (controller.list[index].remark != null) + Row( + children: [ + Text( + '备注:${controller.list[index].remark ?? ''}', + textAlign: TextAlign.start, + style: TextStyle( + fontSize: ScreenAdaper.height(25)), + ), + ], + ), + ])); }, ), width: Get.width - ScreenAdaper.width(50)) @@ -239,19 +279,25 @@ class ItemSearchMoreController extends GetxController @override Future> getData({bool isRefresh = false}) async { List newList = [ - 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: '矿用本安型支架控制器', unit: '台', spec: 'ZDYZ-Z', cost: 4700), + SaleQuotationItemModel(name: '矿用本安型电磁阀驱动器', cost: 1200), + SaleQuotationItemModel(name: '矿用隔爆兼本安型电源', cost: 5700), + SaleQuotationItemModel(name: '矿用本安型隔离耦合器', cost: 1200), + SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', cost: 600), + SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-控制器', cost: 400), + SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-驱动器', cost: 500), + SaleQuotationItemModel( + name: '钢丝编织橡胶护套连接器', remark: '控制器-隔离耦合器', cost: 2000), + SaleQuotationItemModel(name: '矿用本安型支架控制器', cost: 4700), + SaleQuotationItemModel(name: '矿用本安型电磁阀驱动器', cost: 1200), + SaleQuotationItemModel(name: '矿用隔爆兼本安型电源', cost: 5700), + SaleQuotationItemModel( + name: '电液换向阀(10功能10接口)', remark: '中间过渡架主阀组', cost: 13200), + SaleQuotationItemModel( + name: '电液换向阀(20功能20接口)', remark: '端头架主阀组', cost: 26500), + SaleQuotationItemModel( + name: '自动反冲洗过滤装置', remark: '流量:900L/min,过滤精度25μm', cost: 2000), SaleQuotationItemModel(name: '全自动反冲洗过滤器电缆', remark: '控制器-自动反冲洗'), SaleQuotationItemModel(name: '矿用本安型位移传感器'), SaleQuotationItemModel(name: '矿用本安型压力传感器'), diff --git a/lib/screens/sale_quotation/sale_quotation.dart b/lib/screens/sale_quotation/sale_quotation.dart index c45e52c..1d6013e 100644 --- a/lib/screens/sale_quotation/sale_quotation.dart +++ b/lib/screens/sale_quotation/sale_quotation.dart @@ -35,7 +35,7 @@ class SaleQuotationPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( key: controller.scaffoldKey, - endDrawer: Drawer( + endDrawer: const Drawer( // 从右到左出现 child: SaleQuotationEndDrawer(), ), @@ -47,7 +47,23 @@ class SaleQuotationPage extends StatelessWidget { controller.scaffoldKey.currentState?.openEndDrawer(); }, icon: const Icon(Icons.more_horiz_outlined, color: AppTheme.white), - ) + ), + Container( + padding: EdgeInsets.symmetric( + vertical: ScreenAdaper.height(10), + horizontal: ScreenAdaper.width(20)), + child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + GestureDetector( + onTap: () { + controller.addGroup(); + }, + child: Icon( + Icons.add, + size: ScreenAdaper.height(40), + ), + ) + ]), + ), ], ), body: SafeArea( @@ -65,6 +81,8 @@ class SaleQuotationPage extends StatelessWidget { (index, e) => buildBody(index)) .toList(), ))), + // 当键盘弹起时,不显示 + SizedBox( height: ScreenAdaper.height(100), child: buildTotalCostRow(), @@ -76,7 +94,7 @@ class SaleQuotationPage extends StatelessWidget { ], ), // Positioned( - // bottom: ScreenAdaper.height(10), + // bottom: ScreenAdaper.height(220), // right: ScreenAdaper.height(10), // child: IconButton( // padding: EdgeInsets.all(ScreenAdaper.height(20)), @@ -339,8 +357,8 @@ class SaleQuotationPage extends StatelessWidget { const Spacer(), IconButton( onPressed: () { - ModalUtil.confirm( - title: '确定要删除此组吗?', + ModalUtil.alert( + contentText: '确定要删除此组吗?', onConfirm: () { controller.removeGroup(groupIndex); }); @@ -464,7 +482,7 @@ class SaleQuotationPage extends StatelessWidget { ], ), ), - VerticalDivider(), + const VerticalDivider(), buildEditCell( Container( alignment: Alignment.center, diff --git a/lib/screens/workbench/workbench.dart b/lib/screens/workbench/workbench.dart index e47def3..9411965 100644 --- a/lib/screens/workbench/workbench.dart +++ b/lib/screens/workbench/workbench.dart @@ -7,6 +7,7 @@ import 'package:sk_base_mobile/constants/router.dart'; import 'package:sk_base_mobile/screens/workbench/workbench_controller.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; import 'package:sk_base_mobile/util/snack_bar.util.dart'; +import 'package:sk_base_mobile/widgets/sk_appbar.dart'; class WorkBenchPage extends StatelessWidget { WorkBenchPage({super.key}); @@ -15,31 +16,8 @@ class WorkBenchPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - leading: const SizedBox(), - title: const Text( - '工作台', - ), - ), - body: buildList() - // Container( - // padding: EdgeInsets.all(ScreenAdaper.width(20)), - // child: GridView.builder( - // shrinkWrap: true, - // physics: const NeverScrollableScrollPhysics(), - // itemCount: works.length, - // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - // crossAxisCount: Get.width > 800 ? 5 : 3, - // crossAxisSpacing: ScreenAdaper.width(20), - // mainAxisSpacing: ScreenAdaper.height(20), - // childAspectRatio: 1.0), - // itemBuilder: (BuildContext context, int index) { - // return buildCard(index); - // }, - // ), - // ) - - ); + appBar: const SkAppbar(title: '工作台', hideLeading: true), + body: buildList()); } Widget buildList() { diff --git a/lib/screens/workbench/workbench_controller.dart b/lib/screens/workbench/workbench_controller.dart index fbc8537..4603dad 100644 --- a/lib/screens/workbench/workbench_controller.dart +++ b/lib/screens/workbench/workbench_controller.dart @@ -3,7 +3,6 @@ import 'package:get/get.dart'; import 'package:sk_base_mobile/models/workbench.model.dart'; class WorkBenchController extends GetxController { - late final AnimationController animationController; final List menus = [ WorkBenchModel(title: '库存', route: '/inventory', icon: 'inventory.svg'), WorkBenchModel(title: '产品', route: '/product', icon: 'product.svg'), @@ -15,9 +14,4 @@ class WorkBenchController extends GetxController { WorkBenchModel( title: '报价计算', route: '/sale_quotation', icon: 'sale_quotation.svg'), ]; - @override - void onClose() { - animationController.dispose(); - super.onClose(); - } } diff --git a/lib/services/app_info.service.dart b/lib/services/app_info.service.dart index a6d3ee7..4eea238 100644 --- a/lib/services/app_info.service.dart +++ b/lib/services/app_info.service.dart @@ -1,9 +1,26 @@ +import 'dart:io'; + +import 'package:decimal/decimal.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; +import 'package:install_plugin/install_plugin.dart'; import 'package:package_info/package_info.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:sk_base_mobile/apis/index.dart'; +import 'package:sk_base_mobile/app_theme.dart'; +import 'package:sk_base_mobile/config.dart'; import 'package:sk_base_mobile/models/app_config.dart'; import 'package:sk_base_mobile/services/service.dart'; +import 'package:sk_base_mobile/util/device.util.dart'; import 'package:sk_base_mobile/util/logger_util.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/util/snack_bar.util.dart'; +import 'package:sk_base_mobile/widgets/upgrade_confirm.dart'; import '../constants/constants.dart'; +import 'package:dio/dio.dart'; +import 'package:path_provider/path_provider.dart'; class AppInfoService extends GetxService { static AppInfoService get to => Get.find(); @@ -12,14 +29,16 @@ class AppInfoService extends GetxService { final scale = RxDouble(1.0); final isLarge = RxBool(false); final isCameraing = RxBool(false); - + final downloadProgress = RxDouble(0.0); Future init() async { LoggerUtil() .info("[service-appInfo] Register app-related information service"); try { - // await Future.wait( - // [getDeviceInfo(), getPackageInfo(), getAppConfig(), getossPolicy()]); + await Future.wait([ + getDeviceInfo(), + getPackageInfo() /* , getAppConfig(), getossPolicy() */ + ]); requestPermission(); } catch (e) { LoggerUtil().error(e); @@ -93,6 +112,125 @@ class AppInfoService extends GetxService { // } // } } + Future checkVersion() async { + final res = await Future.wait([ + Api.getSystemParamConfigByCode(SystemParamConfig.appVersion), + Api.getSystemParamConfigByCode(SystemParamConfig.isForceUpgrade) + ]); + final newVersion = res[0].data; + final isForceUpgrade = res[1].data; + if (newVersion != null) { + final currentVersion = await DeviceUtil.getAppVersion(); + if (newVersion != currentVersion) { + ModalUtil.alert( + // title: '有新版本', + builder: (_) => UpgradeConfirm( + onConfirm: () { + upgradeApp(newVersion); + }, + forceUpgrade: isForceUpgrade == '1', + ), + // contentText: isForceUpgrade == '1' ? '此版本非常重要,强制更新' : '请更新', + ); + } + } + } + + Future upgradeApp(String version) async { + if (await checkPermission()) { + /// 下载安卓更新包 + String url = '${GloablConfig.OSS_URL}/upload/shankuangtong_v$version.apk'; + + /// 创建存储文件 + Directory? storageDir = await getExternalStorageDirectory(); + if (storageDir != null) { + String storagePath = storageDir.path; + File file = File('$storagePath/shankuangtong_v${version}.apk'); + + if (!file.existsSync()) { + file.createSync(); + } + + try { + /// 下载 + downloadProgress.value = 0; + Get.back(); + + ModalUtil.alert( + barrierDismissible: false, + contentPadding: EdgeInsets.symmetric(vertical: 0), + showActions: false, + content: + // 进度条 + Obx( + () => Stack( + children: [ + Container( + height: ScreenAdaper.height(40), + child: LinearProgressIndicator( + value: downloadProgress.value, + ), + ), + Positioned( + left: 0, + right: 0, + child: Text( + '${downloadProgress.value * 100}%', + textAlign: TextAlign.center, + style: TextStyle(fontSize: ScreenAdaper.height(30)), + )) + ], + ), + )); + await DioService.dio.download(url, file.path, + onReceiveProgress: (num received, num total) => + onReceiveProgress(received, total), + options: Options( + responseType: ResponseType.bytes, + followRedirects: false, + )); + Get.back(); + InstallPlugin.install( + file.path, + ).then((result) {}).catchError((error) {}); + } catch (e) { + SnackBarUtil().warning('暂时无法更新,请重新下载安装, 或者请联系管理员'); + } + } + } + } + + /// 展示下载进度 + void onReceiveProgress(num received, num total) { + if (total != -1) { + downloadProgress.value = + Decimal.parse((received / total).toStringAsFixed(2)) + .toDouble() + .toPrecision(2); + } + } + + /// 检查是否有权限,用于安卓 + Future checkPermission() async { + if (await DeviceUtil.getPlatForm() == 'android') { + // 检查是否有storage权限,没有的话请求权限 + if (await Permission.storage.request().isGranted) { + return true; + // PermissionStatus permission = await PermissionHandler() + // .checkPermissionStatus(PermissionGroup.storage); + // if (permission != PermissionStatus.granted) { + // Map permissions = + // await PermissionHandler() + // .requestPermissions([PermissionGroup.storage]); + // if (permissions[PermissionGroup.storage] == PermissionStatus.granted) { + // return true; + // } + } else { + return false; + } + } + return false; + } T getConfigByCode(String code) { List items = appConfig.items!; diff --git a/lib/services/dio.service.dart b/lib/services/dio.service.dart index 4e56bb0..e0f4dd7 100644 --- a/lib/services/dio.service.dart +++ b/lib/services/dio.service.dart @@ -64,7 +64,9 @@ class DioService extends get_package.GetxService { } else if (e.response?.statusCode == 401) { // dio.lock(); LoggerUtil().error('[Service-dio] logout:${e.response}'); - await AuthStore().logout(force: true); + Future.delayed(Duration(seconds: 1), () { + AuthStore().logout(force: true); + }); SnackBarUtil().error('请重新登录'); } else if (e.response?.statusCode == 403) { await SnackBarUtil().error( @@ -126,6 +128,7 @@ class DioService extends get_package.GetxService { void onResponse(Response response, ResponseInterceptorHandler handler) async { /* LoggerUtil().info('[Service-dio] ${response.data}'); */ + if (whiteList.contains(response.requestOptions.path)) { handler.next(response); return; diff --git a/lib/store/auth.store.dart b/lib/store/auth.store.dart index 3a64631..812cb7c 100644 --- a/lib/store/auth.store.dart +++ b/lib/store/auth.store.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:dio/dio.dart' as dio_package; +import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:sk_base_mobile/apis/index.dart'; import 'package:sk_base_mobile/store/dict.store.dart'; @@ -57,9 +58,11 @@ class AuthStore extends GetxService { await StorageService.to.remove(CacheKeys.userInfo, isWithUser: false); LoggerUtil().info('[Store-Auth] Logout succeed.'); // 如果当前已经在login界面 不需要跳转 + // 判断是否Get已经注册 if (Get.currentRoute != RouteConfig.login) { Get.offAllNamed(RouteConfig.login); } + // 不用getx跳转登录页 } Future login( @@ -72,7 +75,7 @@ class AuthStore extends GetxService { // return; // } - LoadingUtil.to.show(); + await LoadingUtil.to.show(); TapToDismissKeyboard.dismissOf(context: Get.context!); try { await Future.delayed(const Duration(seconds: 1)); @@ -89,7 +92,7 @@ class AuthStore extends GetxService { Get.offNamed(RouteConfig.home); } } catch (e) { - await SnackBarUtil().error('账号密码错误$e'); + await SnackBarUtil().error('账号密码错误'); LoggerUtil().error(e); } finally { LoadingUtil.to.dismiss(); diff --git a/lib/util/date.util.dart b/lib/util/date.util.dart index 969d8be..aae1a53 100644 --- a/lib/util/date.util.dart +++ b/lib/util/date.util.dart @@ -3,7 +3,7 @@ import 'package:date_format/date_format.dart'; class DateUtil { /// 格式化日期 默认 YYYY-MM-DD static String format(DateTime date, {List? formats}) { - return formatDate(date, formats ?? ['yyyy', '-', 'mm', '-', 'dd']); + return formatDate(date, formats ?? ['yyyy', '-', 'MM', '-', 'dd']); } /// 获取几月 diff --git a/lib/util/device.util.dart b/lib/util/device.util.dart new file mode 100644 index 0000000..5022370 --- /dev/null +++ b/lib/util/device.util.dart @@ -0,0 +1,19 @@ +import 'dart:io'; +import 'package:package_info/package_info.dart'; + +class DeviceUtil { + /// 获取当前版本 + static Future getAppVersion() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + return packageInfo.version; + } + + /// 获取平台信息 + static Future getPlatForm() async { + if (Platform.isAndroid) { + return 'android'; + } else { + return 'ios'; + } + } +} diff --git a/lib/util/modal.util.dart b/lib/util/modal.util.dart index 8ce91e0..768e5ae 100644 --- a/lib/util/modal.util.dart +++ b/lib/util/modal.util.dart @@ -6,95 +6,134 @@ 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 confirm( - {String? title, String? button, VoidCallback? onConfirm}) async { + static Future alert( + {String? title, + String? contentText, + String? confirmText, + Widget? content, + VoidCallback? onConfirm, + Widget Function(BuildContext)? builder, + EdgeInsetsGeometry? contentPadding, + bool showActions = true, + bool barrierDismissible = true, + bool showCancel = true}) async { bool confirmed = false; await showDialog( context: Get.overlayContext!, - builder: (context) { - return AlertDialog( - clipBehavior: Clip.hardEdge, - backgroundColor: AppTheme.nearlyWhite, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(ScreenAdaper.sp(20)), - ), - actionsPadding: EdgeInsets.zero, - titlePadding: EdgeInsets.zero, - title: title != null - ? Container( - padding: EdgeInsets.symmetric( - vertical: ScreenAdaper.height(30), - horizontal: ScreenAdaper.width(30)), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: AppTheme.dividerColor, - width: ScreenAdaper.height(2)))), - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - Icons.error_outline, - color: AppTheme.dangerColor, - ), - SizedBox( - width: ScreenAdaper.width(10), - ), - Text( - title, - style: TextStyle( - fontSize: ScreenAdaper.height(30), - fontWeight: FontWeight.w500), - ) - ]), - ) - : null, - actions: [ - 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.height(30)), - )), - )), - const 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.height(30)), - ), + barrierDismissible: barrierDismissible, + builder: builder ?? + (context) { + return AlertDialog( + clipBehavior: Clip.hardEdge, + backgroundColor: AppTheme.nearlyWhite, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(ScreenAdaper.sp(20)), + ), + actionsPadding: EdgeInsets.zero, + titlePadding: EdgeInsets.zero, + contentPadding: contentPadding ?? + EdgeInsets.symmetric( + vertical: ScreenAdaper.height(10), ), - )), - ], - ) - ], - ); - }, + title: title != null + ? Container( + padding: EdgeInsets.symmetric( + vertical: ScreenAdaper.height(20), + ), + decoration: const BoxDecoration( + border: Border( + bottom: + BorderSide(color: AppTheme.dividerColor))), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.error_outline, + color: AppTheme.dangerColor, + ), + SizedBox( + width: ScreenAdaper.width(10), + ), + Text( + title, + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: ScreenAdaper.height(30), + color: AppTheme.black, + ), + ) + ], + ), + ) + : null, + content: content ?? + (contentText != null + ? Container( + padding: EdgeInsets.symmetric( + vertical: ScreenAdaper.height(20), + ), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: AppTheme.dividerColor, + width: ScreenAdaper.height(2)))), + child: Text( + // '${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title}${title} ${title}${title}${title}${title}', + contentText, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: ScreenAdaper.height(30), + fontWeight: FontWeight.w500), + )) + : null), + actions: !showActions + ? null + : [ + Row( + children: [ + if (showCancel) + 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.height(30)), + )), + )), + 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( + confirmText ?? '确定', + style: TextStyle( + color: Colors.black, + fontSize: ScreenAdaper.height(30)), + ), + ), + )), + ], + ) + ], + ); + }, ); return confirmed; } diff --git a/lib/widgets/core/sk_muti_search_more.dart b/lib/widgets/core/sk_muti_search_more.dart index bbb2328..d741444 100644 --- a/lib/widgets/core/sk_muti_search_more.dart +++ b/lib/widgets/core/sk_muti_search_more.dart @@ -59,6 +59,7 @@ class SkMutilSearchMore extends StatelessWidget { if (isDialog) { Get.back(); } + controller.selectedIndex.clear(); }, buttonText: '确定', ) diff --git a/lib/widgets/core/sk_number_input.dart b/lib/widgets/core/sk_number_input.dart index 87c94be..2ff57c9 100644 --- a/lib/widgets/core/sk_number_input.dart +++ b/lib/widgets/core/sk_number_input.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:sk_base_mobile/app_theme.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; -import 'package:sk_base_mobile/util/snack_bar.util.dart'; class SkNumberInput extends StatefulWidget { final TextEditingController textController; @@ -17,8 +16,8 @@ class SkNumberInput extends StatefulWidget { final bool isRequired; final String labelText; final String? hint; - ValueChanged? onFieldSubmitted; - SkNumberInput( + final ValueChanged? onFieldSubmitted; + const SkNumberInput( {super.key, required this.textController, this.onTap, diff --git a/lib/widgets/core/sk_text_input.dart b/lib/widgets/core/sk_text_input.dart index 304d534..62e8233 100644 --- a/lib/widgets/core/sk_text_input.dart +++ b/lib/widgets/core/sk_text_input.dart @@ -15,8 +15,8 @@ class SkTextInput extends StatefulWidget { final String? Function(String?)? validator; final EdgeInsetsGeometry? contentPadding; final bool autoFocus; - ValueChanged? onFieldSubmitted; - SkTextInput( + final ValueChanged? onFieldSubmitted; + const SkTextInput( {super.key, required this.textController, this.onTap, diff --git a/lib/widgets/gradient_button.dart b/lib/widgets/gradient_button.dart index 952538d..d90220c 100644 --- a/lib/widgets/gradient_button.dart +++ b/lib/widgets/gradient_button.dart @@ -30,7 +30,7 @@ class GradientButton extends StatelessWidget { Size(double.infinity, ScreenAdaper.height(80))), shape: MaterialStateProperty.all( RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0), + borderRadius: BorderRadius.circular(10), ), ), ), diff --git a/lib/widgets/my_avatar.dart b/lib/widgets/my_avatar.dart index 16d6fe5..97a45b1 100644 --- a/lib/widgets/my_avatar.dart +++ b/lib/widgets/my_avatar.dart @@ -22,8 +22,8 @@ class MyAvatarWidget extends StatelessWidget { border: Border.all( color: AppTheme.white, width: ScreenAdaper.sp(2)), borderRadius: BorderRadius.circular(50)), - height: ScreenAdaper.width(120), - width: ScreenAdaper.width(120), + height: ScreenAdaper.width(150), + width: ScreenAdaper.width(150), child: const SizedBox(), )), Positioned( diff --git a/lib/widgets/upgrade_confirm.dart b/lib/widgets/upgrade_confirm.dart new file mode 100644 index 0000000..e8597e1 --- /dev/null +++ b/lib/widgets/upgrade_confirm.dart @@ -0,0 +1,111 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; +import 'package:sk_base_mobile/app_theme.dart'; +import 'package:sk_base_mobile/services/app_info.service.dart'; +import 'package:sk_base_mobile/util/screen_adaper_util.dart'; +import 'package:sk_base_mobile/widgets/gradient_button.dart'; + +class UpgradeConfirm extends StatelessWidget { + void Function()? onConfirm; + bool forceUpgrade; + UpgradeConfirm({super.key, this.onConfirm, this.forceUpgrade = true}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(ScreenAdaper.radius(30))), + margin: EdgeInsets.only(bottom: ScreenAdaper.height(30)), + alignment: Alignment.center, + child: Stack( + children: [ + Container( + height: ScreenAdaper.height(600), + constraints: BoxConstraints(maxHeight: ScreenAdaper.height(600)), + width: ScreenAdaper.width(800), + margin: EdgeInsets.only( + top: ScreenAdaper.height(100), + ), + padding: EdgeInsets.only( + top: ScreenAdaper.height(50), bottom: ScreenAdaper.height(30)), + decoration: BoxDecoration( + color: AppTheme.nearlyWhite, + borderRadius: BorderRadius.circular(ScreenAdaper.radius(30))), + child: Column( + children: [ + Text( + '有新的版本更新啦', + style: TextStyle( + decoration: TextDecoration.none, + fontSize: ScreenAdaper.height(35), + color: AppTheme.nearlyBlack, + ), + ), + SizedBox( + height: ScreenAdaper.height(30), + ), + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + Text('1.修复bug', + style: TextStyle( + decoration: TextDecoration.none, + fontSize: ScreenAdaper.height(30), + color: AppTheme.grey, + fontWeight: FontWeight.w400)), + Text('2.优化体验', + style: TextStyle( + decoration: TextDecoration.none, + fontSize: ScreenAdaper.height(30), + color: AppTheme.grey, + fontWeight: FontWeight.w400)), + ], + ))), + SizedBox( + height: ScreenAdaper.height(30), + ), + Container( + width: ScreenAdaper.height(400), + child: GradientButton( + buttonText: '去更新', + onPressed: () { + if (onConfirm != null) onConfirm!(); + }, + ), + ) + ], + ), + ), + if (!forceUpgrade) + Positioned( + right: 0, + top: ScreenAdaper.height(100), + child: // 更新内容 + IconButton( + onPressed: () { + Get.back(); + }, + icon: const Icon(Icons.close)), + ), + // 悬浮图标 + Positioned( + left: 0, + right: 0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image( + image: const AssetImage('assets/images/rocket.png'), + height: ScreenAdaper.height(150), + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 5096f32..b098a7f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -520,6 +520,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.1+1" + install_plugin: + dependency: "direct main" + description: + name: install_plugin + sha256: "6fb67ba0781e75de4f2f2266ed25e835bfd277c5bfc2ed034af52774355857c6" + url: "https://pub.dev" + source: hosted + version: "2.1.0" intl: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 76bcb4f..84493cd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,7 @@ dependencies: flutter_slidable: ^3.1.0 pinyin: ^3.2.0 math_expressions: ^2.4.0 + install_plugin: ^2.1.0 dev_dependencies: flutter_test: sdk: flutter