From 3db1afb244af9443740274db66ca1c0562edd4d2 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Thu, 14 Dec 2023 10:02:52 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=97=B6=E9=97=B4=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=99=A8=20=E7=A1=AE=E5=AE=9A=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorizedAdmin/authorizedAdmin_page.dart | 10 +- .../volumeAuthorizationLock_page.dart | 6 +- .../card/addCardType/addCardType_page.dart | 115 +- .../otherTypeKeyChangeDate_page.dart | 45 +- .../otherTypeKeyChangeValidityDate_page.dart | 88 +- .../checkingInSetHolidays_page.dart | 136 +- .../checkingInSetWorkTime_page.dart | 91 +- .../electronicKeyDetailChangeDate_page.dart | 14 +- .../electronicKeyPeriodValidity_page.dart | 6 +- .../massSendElectronicKey_page.dart | 6 +- .../sendElectronicKey_page.dart | 6 +- .../face/addFaceType/addFaceType_page.dart | 104 +- .../addFingerprintType_page.dart | 114 +- .../nDaysUnopened/nDaysUnopened_page.dart | 6 +- .../normallyOpenMode_page.dart | 234 +- .../passwordKey_perpetual_page.dart | 11 +- .../addRemoteControl_page.dart | 108 +- .../addAuthorizedAdministrator_page.dart | 6 +- .../adminDetailChangeDate_page.dart | 6 +- .../expireLockChangeDate_page.dart | 6 +- .../address_picker/locations_data.dart | 4311 +++++++++++++++++ .../route/address_picker_route.dart | 462 ++ .../tools/pickers/more_pickers/init_data.dart | 76 + .../route/multiple_link_picker_route.dart | 493 ++ .../route/multiple_picker_route.dart | 332 ++ .../route/single_picker_route.dart | 362 ++ star_lock/lib/tools/pickers/pickers.dart | 252 + .../tools/pickers/style/default_style.dart | 205 + .../lib/tools/pickers/style/picker_style.dart | 186 + .../time_picker/model/date_item_model.dart | 57 + .../pickers/time_picker/model/date_mode.dart | 53 + .../time_picker/model/date_time_data.dart | 72 + .../pickers/time_picker/model/date_type.dart | 10 + .../pickers/time_picker/model/pduration.dart | 109 + .../pickers/time_picker/model/suffix.dart | 47 + .../time_picker/route/date_picker_route.dart | 861 ++++ .../tools/pickers/time_picker/time_utils.dart | 73 + star_lock/lib/tools/pickers/utils/check.dart | 45 + star_lock/pubspec.yaml | 2 +- 39 files changed, 8659 insertions(+), 467 deletions(-) create mode 100644 star_lock/lib/tools/pickers/address_picker/locations_data.dart create mode 100644 star_lock/lib/tools/pickers/address_picker/route/address_picker_route.dart create mode 100644 star_lock/lib/tools/pickers/more_pickers/init_data.dart create mode 100644 star_lock/lib/tools/pickers/more_pickers/route/multiple_link_picker_route.dart create mode 100644 star_lock/lib/tools/pickers/more_pickers/route/multiple_picker_route.dart create mode 100644 star_lock/lib/tools/pickers/more_pickers/route/single_picker_route.dart create mode 100644 star_lock/lib/tools/pickers/pickers.dart create mode 100644 star_lock/lib/tools/pickers/style/default_style.dart create mode 100644 star_lock/lib/tools/pickers/style/picker_style.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/model/date_item_model.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/model/date_mode.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/model/date_time_data.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/model/date_type.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/model/pduration.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/model/suffix.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/route/date_picker_route.dart create mode 100644 star_lock/lib/tools/pickers/time_picker/time_utils.dart create mode 100644 star_lock/lib/tools/pickers/utils/check.dart diff --git a/star_lock/lib/main/lockDetail/authorizedAdmin/authorizedAdmin/authorizedAdmin_page.dart b/star_lock/lib/main/lockDetail/authorizedAdmin/authorizedAdmin/authorizedAdmin_page.dart index a3dfa961..fd4d5b61 100644 --- a/star_lock/lib/main/lockDetail/authorizedAdmin/authorizedAdmin/authorizedAdmin_page.dart +++ b/star_lock/lib/main/lockDetail/authorizedAdmin/authorizedAdmin/authorizedAdmin_page.dart @@ -1,12 +1,14 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_native_contact_picker/flutter_native_contact_picker.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/storage.dart'; import 'package:star_lock/tools/toast.dart'; @@ -327,9 +329,9 @@ class _AuthorizedAdminPageState extends State { var entity = await ApiRepository.to.setRoomStatusData( lockId: state.keyInfo.value.lockId!, - roomStatus:1, + roomStatus: 1, ); - if(entity.errorCode!.codeIsSuccessful){ + if (entity.errorCode!.codeIsSuccessful) { print("标记为已入住成功啦啦啦啦啦"); Toast.show(msg: "标记成功"); setState(() {}); diff --git a/star_lock/lib/main/lockDetail/authorizedAdmin/volumeAuthorizationLock/volumeAuthorizationLock_page.dart b/star_lock/lib/main/lockDetail/authorizedAdmin/volumeAuthorizationLock/volumeAuthorizationLock_page.dart index 968e1d8b..7d69352d 100644 --- a/star_lock/lib/main/lockDetail/authorizedAdmin/volumeAuthorizationLock/volumeAuthorizationLock_page.dart +++ b/star_lock/lib/main/lockDetail/authorizedAdmin/volumeAuthorizationLock/volumeAuthorizationLock_page.dart @@ -1,13 +1,15 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_native_contact_picker/flutter_native_contact_picker.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/toast.dart'; import '../../../../appRouters.dart'; diff --git a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart index 1af59b4b..a0f2b691 100644 --- a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart +++ b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart @@ -1,10 +1,11 @@ - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; @@ -16,13 +17,18 @@ import '../../../../translations/trans_lib.dart'; import 'addCardType_logic.dart'; class AddCardPage extends StatefulWidget { - final String seletType;// 永久限时循环下标 + final String seletType; // 永久限时循环下标 final int lockId; - final int fromType;// // 1从添加钥匙列表进入 2从考勤添加员工入口进入 - final String fromTypeTwoStaffName;// 从添加员工进入 传入员工名字 + final int fromType; // // 1从添加钥匙列表进入 2从考勤添加员工入口进入 + final String fromTypeTwoStaffName; // 从添加员工进入 传入员工名字 const AddCardPage( - {Key? key, required this.seletType, required this.lockId, required this.fromType, required this.fromTypeTwoStaffName}) : super(key: key); + {Key? key, + required this.seletType, + required this.lockId, + required this.fromType, + required this.fromTypeTwoStaffName}) + : super(key: key); @override State createState() => _AddCardPageState(); @@ -52,8 +58,10 @@ class _AddCardPageState extends State { // return sendElectronicKeySucceed(); return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyBottomWidget() ], ); @@ -63,8 +71,10 @@ class _AddCardPageState extends State { // 限时 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyTimeLimitWidget(), SizedBox(height: 10.h), keyBottomWidget() @@ -76,18 +86,24 @@ class _AddCardPageState extends State { // 循环 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), CommonItem( leftTitel: TranslationLoader.lanKeys!.periodValidity!.tr, rightTitle: "", isHaveDirection: true, action: () async { - Map result = await Get.toNamed(Routers.electronicKeyPeriodValidityPage); + Map result = await Get.toNamed( + Routers.electronicKeyPeriodValidityPage); state.weekdaysList.value = result['validityValue']; - state.effectiveDateTime.value = result['starDate'].millisecondsSinceEpoch; - state.failureDateTime.value = result['endDate'].millisecondsSinceEpoch; - print('得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); + state.effectiveDateTime.value = + result['starDate'].millisecondsSinceEpoch; + state.failureDateTime.value = + result['endDate'].millisecondsSinceEpoch; + print( + '得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); }), SizedBox(height: 10.h), keyBottomWidget() @@ -127,13 +143,17 @@ class _AddCardPageState extends State { action: () async { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.beginTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.beginTimeTimestamp.value = DateTime.parse(state.beginTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.beginTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.beginTimeTimestamp.value = + DateTime.parse(state.beginTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, @@ -142,13 +162,17 @@ class _AddCardPageState extends State { action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.endTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.endTimeTimestamp.value = DateTime.parse(state.endTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.endTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.endTimeTimestamp.value = + DateTime.parse(state.endTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Container(height: 10.h), ], @@ -166,23 +190,23 @@ class _AddCardPageState extends State { rightWidget: SizedBox( width: 60.w, height: 50.h, child: _isStressFingerprint())), SizedBox(height: 30.h), - SubmitBtn(btnName: TranslationLoader.lanKeys!.next!.tr, onClick: () async { + SubmitBtn( + btnName: TranslationLoader.lanKeys!.next!.tr, + onClick: () async { + var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); + if (isDemoMode == false) { + // print("state.seletType:${state.seletType.value}"); + if (state.nameController.text.isEmpty) { + Toast.show(msg: "请输入姓名"); + return; + } - var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); - if(isDemoMode == false){ - // print("state.seletType:${state.seletType.value}"); - if(state.nameController.text.isEmpty){ - Toast.show(msg: "请输入姓名"); - return; - } - - logic.addCardData(); - }else{ - // Get.toNamed(Routers.seletLockTypePage); - Toast.show(msg: "演示模式"); - } - - }), + logic.addCardData(); + } else { + // Get.toNamed(Routers.seletLockTypePage); + Toast.show(msg: "演示模式"); + } + }), ], ); } @@ -322,5 +346,4 @@ class _AddCardPageState extends State { }, ); } - } diff --git a/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeDate/otherTypeKeyChangeDate_page.dart b/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeDate/otherTypeKeyChangeDate_page.dart index 84b96760..536fd0a7 100644 --- a/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeDate/otherTypeKeyChangeDate_page.dart +++ b/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeDate/otherTypeKeyChangeDate_page.dart @@ -1,9 +1,10 @@ - import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../app_settings/app_colors.dart'; import '../../../../tools/commonItem.dart'; @@ -15,10 +16,12 @@ class OtherTypeKeyChangeDatePage extends StatefulWidget { const OtherTypeKeyChangeDatePage({Key? key}) : super(key: key); @override - State createState() => _OtherTypeKeyChangeDatePageState(); + State createState() => + _OtherTypeKeyChangeDatePageState(); } -class _OtherTypeKeyChangeDatePageState extends State { +class _OtherTypeKeyChangeDatePageState + extends State { final logic = Get.put(OtherTypeKeyChangeDateLogic()); final state = Get.find().state; @@ -27,7 +30,8 @@ class _OtherTypeKeyChangeDatePageState extends State return Scaffold( backgroundColor: AppColors.mainBackgroundColor, appBar: TitleAppBar( - barTitle: "${TranslationLoader.lanKeys!.amend!.tr}${TranslationLoader.lanKeys!.periodValidity!.tr}", + barTitle: + "${TranslationLoader.lanKeys!.amend!.tr}${TranslationLoader.lanKeys!.periodValidity!.tr}", haveBack: true, backgroundColor: AppColors.mainColor, actionsList: [ @@ -48,7 +52,6 @@ class _OtherTypeKeyChangeDatePageState extends State logic.editFingerprintsData(); break; case 2: - break; default: break; @@ -72,12 +75,14 @@ class _OtherTypeKeyChangeDatePageState extends State action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - state.beginTimeTimestamp.value = DateTime.parse( - '${p.year}-${p.month.toString().padLeft(2,'0')}-${p.day.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}').millisecondsSinceEpoch; - state.beginTime.value = "${p.year}.${p.month.toString().padLeft(2,'0')}.${p.day.toString().padLeft(2,'0')} ${p.hour.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}"; - }); - }); + setState(() { + state.beginTimeTimestamp.value = DateTime.parse( + '${p.year}-${p.month.toString().padLeft(2, '0')}-${p.day.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}') + .millisecondsSinceEpoch; + state.beginTime.value = + "${p.year}.${p.month.toString().padLeft(2, '0')}.${p.day.toString().padLeft(2, '0')} ${p.hour.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}"; + }); + }); })), Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, @@ -86,12 +91,14 @@ class _OtherTypeKeyChangeDatePageState extends State action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - state.endTimeTimestamp.value = DateTime.parse( - '${p.year}-${p.month.toString().padLeft(2,'0')}-${p.day.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}').millisecondsSinceEpoch; - state.endTime.value = "${p.year}.${p.month.toString().padLeft(2,'0')}.${p.day.toString().padLeft(2,'0')} ${p.hour.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}"; - }); - }); + setState(() { + state.endTimeTimestamp.value = DateTime.parse( + '${p.year}-${p.month.toString().padLeft(2, '0')}-${p.day.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}') + .millisecondsSinceEpoch; + state.endTime.value = + "${p.year}.${p.month.toString().padLeft(2, '0')}.${p.day.toString().padLeft(2, '0')} ${p.hour.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}"; + }); + }); })), ], ); diff --git a/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeValidityDate/otherTypeKeyChangeValidityDate_page.dart b/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeValidityDate/otherTypeKeyChangeValidityDate_page.dart index d4f192d2..54155847 100644 --- a/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeValidityDate/otherTypeKeyChangeValidityDate_page.dart +++ b/star_lock/lib/main/lockDetail/card/otherTypeKeyChangeValidityDate/otherTypeKeyChangeValidityDate_page.dart @@ -1,9 +1,10 @@ - import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../app_settings/app_colors.dart'; import '../../../../tools/commonItem.dart'; @@ -16,10 +17,12 @@ class OtherTypeKeyChangeValidityDatePage extends StatefulWidget { const OtherTypeKeyChangeValidityDatePage({Key? key}) : super(key: key); @override - State createState() => _OtherTypeKeyChangeValidityDatePageState(); + State createState() => + _OtherTypeKeyChangeValidityDatePageState(); } -class _OtherTypeKeyChangeValidityDatePageState extends State { +class _OtherTypeKeyChangeValidityDatePageState + extends State { final logic = Get.put(OtherTypeKeyChangeValidityDateLogic()); final state = Get.find().state; @@ -45,9 +48,9 @@ class _OtherTypeKeyChangeValidityDatePageState extends State Container( - width: 40.w, - height: 40.w, - margin: EdgeInsets.all(10.w), - decoration: BoxDecoration( - color: state.weekDay.value.contains(index) ? AppColors.mainColor :Colors.white, - border: Border.all(width: 1, color: AppColors.btnDisableColor), - borderRadius: BorderRadius.circular(30.w), - ), - child: Center( - child: Text( + width: 40.w, + height: 40.w, + margin: EdgeInsets.all(10.w), + decoration: BoxDecoration( + color: state.weekDay.value.contains(index) + ? AppColors.mainColor + : Colors.white, + border: Border.all(width: 1, color: AppColors.btnDisableColor), + borderRadius: BorderRadius.circular(30.w), + ), + child: Center( + child: Text( dateStr, - style: TextStyle(fontSize: 20.sp, color: state.weekDay.value.contains(index) ? Colors.white : AppColors.darkGrayTextColor), + style: TextStyle( + fontSize: 20.sp, + color: state.weekDay.value.contains(index) + ? Colors.white + : AppColors.darkGrayTextColor), )), - )), + )), ); } @@ -152,34 +163,38 @@ class _OtherTypeKeyChangeValidityDatePageState extends State CommonItem( leftTitel: - "${TranslationLoader.lanKeys!.begin!.tr}${TranslationLoader.lanKeys!.time!.tr}", + "${TranslationLoader.lanKeys!.begin!.tr}${TranslationLoader.lanKeys!.time!.tr}", rightTitle: state.beginTime.value, isHaveDirection: true, isHaveLine: true, action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - state.beginTimeTimestamp.value = DateTime.parse( - '${p.year}-${p.month.toString().padLeft(2,'0')}-${p.day.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}').millisecondsSinceEpoch; - state.beginTime.value = "${p.year}.${p.month.toString().padLeft(2,'0')}.${p.day.toString().padLeft(2,'0')} ${p.hour.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}"; - }); - }); + setState(() { + state.beginTimeTimestamp.value = DateTime.parse( + '${p.year}-${p.month.toString().padLeft(2, '0')}-${p.day.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}') + .millisecondsSinceEpoch; + state.beginTime.value = + "${p.year}.${p.month.toString().padLeft(2, '0')}.${p.day.toString().padLeft(2, '0')} ${p.hour.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}"; + }); + }); })), Obx(() => CommonItem( leftTitel: - "${TranslationLoader.lanKeys!.end!.tr}${TranslationLoader.lanKeys!.time!.tr}", + "${TranslationLoader.lanKeys!.end!.tr}${TranslationLoader.lanKeys!.time!.tr}", rightTitle: state.endTime.value, isHaveDirection: true, action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - state.endTimeTimestamp.value = DateTime.parse( - '${p.year}-${p.month.toString().padLeft(2,'0')}-${p.day.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}').millisecondsSinceEpoch; - state.endTime.value = "${p.year}.${p.month.toString().padLeft(2,'0')}.${p.day.toString().padLeft(2,'0')} ${p.hour.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}"; - }); - }); + setState(() { + state.endTimeTimestamp.value = DateTime.parse( + '${p.year}-${p.month.toString().padLeft(2, '0')}-${p.day.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}') + .millisecondsSinceEpoch; + state.endTime.value = + "${p.year}.${p.month.toString().padLeft(2, '0')}.${p.day.toString().padLeft(2, '0')} ${p.hour.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}"; + }); + }); })), Container(height: 10.h), ], @@ -188,5 +203,4 @@ class _OtherTypeKeyChangeValidityDatePageState extends State { actionsList: [ GestureDetector( onTap: () async { - var data = await Get.toNamed(Routers.checkingInAddHolidaysPage, arguments: { - "companyId": state.companyId.value - }); - if(data != null) { + var data = await Get.toNamed( + Routers.checkingInAddHolidaysPage, + arguments: {"companyId": state.companyId.value}); + if (data != null) { logic.editStaffLoadData(); } }, @@ -59,47 +64,60 @@ class _CheckingInSetHolidaysPageState extends State { ], ), body: Obx(() { - return state.holidaysListData.value!.isNotEmpty ? ListView.builder( - itemCount: state.holidaysListData.value!.length, - itemBuilder: (c, index) { - HolidaysMonthListData holidaysMonthListData = state.holidaysListData.value![index]; - return _checkingInListMouthItem(holidaysMonthListData); - }):const NoData(); - }) - ); + return state.holidaysListData.value!.isNotEmpty + ? ListView.builder( + itemCount: state.holidaysListData.value!.length, + itemBuilder: (c, index) { + HolidaysMonthListData holidaysMonthListData = + state.holidaysListData.value![index]; + return _checkingInListMouthItem(holidaysMonthListData); + }) + : const NoData(); + })); } Widget _checkingInListMouthItem(HolidaysMonthListData holidaysMonthListData) { return GestureDetector( child: Container( - height: 140.h*holidaysMonthListData.listItem!.length + 20.w, + height: 140.h * holidaysMonthListData.listItem!.length + 20.w, padding: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w), child: Row( children: [ Container( - color: colorWithMonth(int.parse(holidaysMonthListData.listItem![0].month.toString())), + color: colorWithMonth(int.parse( + holidaysMonthListData.listItem![0].month.toString())), width: 100.w, - height: 140.h*holidaysMonthListData.listItem!.length, + height: 140.h * holidaysMonthListData.listItem!.length, child: Center( child: Text( - "${holidaysMonthListData.listItem![0].month}\n${TranslationLoader.lanKeys!.month!.tr}", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 28.sp, color: Colors.white), - ))), + "${holidaysMonthListData.listItem![0].month}\n${TranslationLoader.lanKeys!.month!.tr}", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 28.sp, color: Colors.white), + ))), SizedBox( - height: 140.h*holidaysMonthListData.listItem!.length, - width: 1.sw - 100.w - 20.w*2, + height: 140.h * holidaysMonthListData.listItem!.length, + width: 1.sw - 100.w - 20.w * 2, child: ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: holidaysMonthListData.listItem!.length, itemBuilder: (c, index) { ListItem listItem = holidaysMonthListData.listItem![index]; - return _checkingInListItem(index, listItem.vacationName, DateTool().dateToYMDString(listItem.vacationStartDate.toString()), DateTool().dateToYMDString(listItem.vacationEndDate.toString()), listItem.fillClassDate!.isNotEmpty ? DateTool().dateToYMDString(listItem.fillClassDate.toString()):"", () async { - var data = await Get.toNamed(Routers.checkingInDeletHolidaysPage, arguments: { - "listItem": listItem - }); - if(data != null) { + return _checkingInListItem( + index, + listItem.vacationName, + DateTool().dateToYMDString( + listItem.vacationStartDate.toString()), + DateTool().dateToYMDString( + listItem.vacationEndDate.toString()), + listItem.fillClassDate!.isNotEmpty + ? DateTool().dateToYMDString( + listItem.fillClassDate.toString()) + : "", () async { + var data = await Get.toNamed( + Routers.checkingInDeletHolidaysPage, + arguments: {"listItem": listItem}); + if (data != null) { logic.editStaffLoadData(); } }); @@ -111,13 +129,19 @@ class _CheckingInSetHolidaysPageState extends State { ); } - Widget _checkingInListItem(int index, String? lockTypeTitle, String? vacationStartDate, String? vacationEndDate, String? makeUpClass, Function() action) { + Widget _checkingInListItem( + int index, + String? lockTypeTitle, + String? vacationStartDate, + String? vacationEndDate, + String? makeUpClass, + Function() action) { return GestureDetector( onTap: action, child: Column( children: [ Container( - color:Colors.white, + color: Colors.white, height: 140.h, padding: EdgeInsets.only(left: 20.w, right: 20.w, top: 10.h), child: Row( @@ -174,27 +198,27 @@ class _CheckingInSetHolidaysPageState extends State { showListType(); }, child: Obx(() => Container( - width: 300.w, - height: 50.h, - color: AppColors.mainColor, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "${state.seletYear.value}${TranslationLoader.lanKeys!.year!.tr}", - style: TextStyle(color: Colors.white, fontSize: 26.sp), + width: 300.w, + height: 50.h, + color: AppColors.mainColor, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "${state.seletYear.value}${TranslationLoader.lanKeys!.year!.tr}", + style: TextStyle(color: Colors.white, fontSize: 26.sp), + ), + SizedBox( + width: 5.w, + ), + Image.asset( + 'images/main/icon_lockDetail_checkIn_topTitle.png', + width: 22.w, + height: 16.w, + ) + ], ), - SizedBox( - width: 5.w, - ), - Image.asset( - 'images/main/icon_lockDetail_checkIn_topTitle.png', - width: 22.w, - height: 16.w, - ) - ], - ), - )), + )), ); } @@ -242,9 +266,9 @@ class _CheckingInSetHolidaysPageState extends State { ); } - Color colorWithMonth(int month){ + Color colorWithMonth(int month) { Color colorType; - switch (month){ + switch (month) { case 1: colorType = const Color(0xFFb8d152); break; diff --git a/star_lock/lib/main/lockDetail/checkingIn/checkingInSetWorkTime/checkingInSetWorkTime_page.dart b/star_lock/lib/main/lockDetail/checkingIn/checkingInSetWorkTime/checkingInSetWorkTime_page.dart index d6801b82..1999e94e 100644 --- a/star_lock/lib/main/lockDetail/checkingIn/checkingInSetWorkTime/checkingInSetWorkTime_page.dart +++ b/star_lock/lib/main/lockDetail/checkingIn/checkingInSetWorkTime/checkingInSetWorkTime_page.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/toast.dart'; import '../../../../app_settings/app_colors.dart'; @@ -16,7 +18,8 @@ class CheckingInSetWorkTimePage extends StatefulWidget { const CheckingInSetWorkTimePage({Key? key}) : super(key: key); @override - State createState() => _CheckingInSetWorkTimePageState(); + State createState() => + _CheckingInSetWorkTimePageState(); } class _CheckingInSetWorkTimePageState extends State { @@ -27,77 +30,100 @@ class _CheckingInSetWorkTimePageState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.mainBackgroundColor, - appBar: TitleAppBar(barTitle: "${TranslationLoader.lanKeys!.work!.tr} ${TranslationLoader.lanKeys!.time!.tr} ${TranslationLoader.lanKeys!.set!.tr}", haveBack:true, backgroundColor: AppColors.mainColor), + appBar: TitleAppBar( + barTitle: + "${TranslationLoader.lanKeys!.work!.tr} ${TranslationLoader.lanKeys!.time!.tr} ${TranslationLoader.lanKeys!.set!.tr}", + haveBack: true, + backgroundColor: AppColors.mainColor), body: buildMainUI(), ); } - Widget buildMainUI(){ + Widget buildMainUI() { return Column( children: [ - Obx(() => CommonItem(leftTitel:TranslationLoader.lanKeys!.officeHours!.tr, rightTitle:state.beginTime.value, isHaveDirection: true, isHaveLine: true, action:(){ - Pickers.showDatePicker(context, mode: DateMode.HM, - onConfirm: (p) { + Obx(() => CommonItem( + leftTitel: TranslationLoader.lanKeys!.officeHours!.tr, + rightTitle: state.beginTime.value, + isHaveDirection: true, + isHaveLine: true, + action: () { + Pickers.showDatePicker(context, mode: DateMode.HM, + onConfirm: (p) { setState(() { DateTime today = DateTime.now(); state.beginTimeTimestamp.value = DateTime.parse( - '${today.year}-${today.month.toString().padLeft(2,'0')}-${today.day.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}').millisecondsSinceEpoch.toString(); - state.beginTime.value = "${p.hour.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}"; + '${today.year}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}') + .millisecondsSinceEpoch + .toString(); + state.beginTime.value = + "${p.hour.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}"; }); }); - })), - Obx(() => CommonItem(leftTitel:TranslationLoader.lanKeys!.closingTime!.tr, rightTitle:state.endTime.value, isHaveDirection: true, action:(){ - Pickers.showDatePicker(context, mode: DateMode.HM, - onConfirm: (p) { + })), + Obx(() => CommonItem( + leftTitel: TranslationLoader.lanKeys!.closingTime!.tr, + rightTitle: state.endTime.value, + isHaveDirection: true, + action: () { + Pickers.showDatePicker(context, mode: DateMode.HM, + onConfirm: (p) { setState(() { DateTime today = DateTime.now(); state.endTimeTimestamp.value = DateTime.parse( - '${today.year}-${today.month.toString().padLeft(2,'0')}-${today.day.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}').millisecondsSinceEpoch.toString(); - state.endTime.value = "${p.hour.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}"; + '${today.year}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}') + .millisecondsSinceEpoch + .toString(); + state.endTime.value = + "${p.hour.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}"; }); }); - })), - SizedBox(height: 30.h,), - SubmitBtn(btnName: TranslationLoader.lanKeys!.sure!.tr, + })), + SizedBox( + height: 30.h, + ), + SubmitBtn( + btnName: TranslationLoader.lanKeys!.sure!.tr, borderRadius: 20.w, fontSize: 32.sp, margin: EdgeInsets.only(left: 30.w, right: 30.w, top: 20.w), padding: EdgeInsets.only(top: 20.w, bottom: 20.w), onClick: () { - if(state.beginTimeTimestamp.value.isEmpty){ + if (state.beginTimeTimestamp.value.isEmpty) { Toast.show(msg: "请选择开始时间"); return; } - if(state.endTimeTimestamp.value.isEmpty){ + if (state.endTimeTimestamp.value.isEmpty) { Toast.show(msg: "请选择结束时间"); return; } - if(int.parse(state.beginTimeTimestamp.value) > int.parse(state.endTimeTimestamp.value)){ + if (int.parse(state.beginTimeTimestamp.value) > + int.parse(state.endTimeTimestamp.value)) { Toast.show(msg: "结束时间不能大于开始时间"); return; } - if(state.pushType.value == "2"){ + if (state.pushType.value == "2") { logic.editCheckInSetInfoData(); - }else{ + } else { Get.back(result: { - "beginTime":state.beginTime.value, - "beginTimeTimestamp":state.beginTimeTimestamp.value, - "endTime":state.endTime.value, - "endTimeTimestamp":state.endTimeTimestamp.value, + "beginTime": state.beginTime.value, + "beginTimeTimestamp": state.beginTimeTimestamp.value, + "endTime": state.endTime.value, + "endTimeTimestamp": state.endTimeTimestamp.value, }); } - } - ), + }), ], ); } - String getNowDate(){ + String getNowDate() { // 获取当前时间对象 DateTime today = DateTime.now(); - String dateSlug ="${today.hour.toString().padLeft(2,'0')}:${today.minute.toString().padLeft(2,'0')}"; + String dateSlug = + "${today.hour.toString().padLeft(2, '0')}:${today.minute.toString().padLeft(2, '0')}"; // //获取当前时间的年 // int year = now.year; @@ -115,5 +141,4 @@ class _CheckingInSetWorkTimePageState extends State { // print("组合 $year-$month-$day $hour:$minute:$millisecond"); return dateSlug; } - } diff --git a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart index a58df7b4..125126cf 100644 --- a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart +++ b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/keyOperationRecordEntity.dart'; @@ -8,6 +8,8 @@ import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyList/entity import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKeyEntity.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/toast.dart'; import '../../../../../app_settings/app_colors.dart'; @@ -36,7 +38,7 @@ class _ElectronicKeyDetailChangeDateState late List weekDays = []; late String pwdId = ''; late String lockId = ''; - late String fromType = '';// 1 从指纹详情进入 + late String fromType = ''; // 1 从指纹详情进入 @override Widget build(BuildContext context) { @@ -67,9 +69,8 @@ class _ElectronicKeyDetailChangeDateState style: TextStyle(color: Colors.white, fontSize: 24.sp), ), onPressed: () { - if(fromType == "1"){ - - }else{ + if (fromType == "1") { + } else { if (lockId.isNotEmpty && pwdId.isNotEmpty) { updatePwdRequest(); } else { @@ -158,7 +159,6 @@ class _ElectronicKeyDetailChangeDateState } } - String intToStr(int v) { return (v < 10) ? "0$v" : "$v"; } diff --git a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyPeriodValidity/electronicKeyPeriodValidity_page.dart b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyPeriodValidity/electronicKeyPeriodValidity_page.dart index f9faa8da..e8cbf9d3 100644 --- a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyPeriodValidity/electronicKeyPeriodValidity_page.dart +++ b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyPeriodValidity/electronicKeyPeriodValidity_page.dart @@ -1,11 +1,13 @@ import 'package:date_format/date_format.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyPeriodValidity/KeyPeriodValidityModel.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyPeriodValidity/electronicKeyPeriodValidity_logic.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/toast.dart'; import '../../../../app_settings/app_colors.dart'; diff --git a/star_lock/lib/main/lockDetail/electronicKey/massSendElectronicKey/massSendElectronicKey_page.dart b/star_lock/lib/main/lockDetail/electronicKey/massSendElectronicKey/massSendElectronicKey_page.dart index e2c8b141..c9a28952 100644 --- a/star_lock/lib/main/lockDetail/electronicKey/massSendElectronicKey/massSendElectronicKey_page.dart +++ b/star_lock/lib/main/lockDetail/electronicKey/massSendElectronicKey/massSendElectronicKey_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:flutter_native_contact_picker/flutter_native_contact_picker.dart'; @@ -9,6 +9,8 @@ import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/main/lockDetail/electronicKey/massSendElectronicKey/massSendLockGroupList/lockUserList/lockUserListEntity.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/toast.dart'; import '../../../../../tools/commonItem.dart'; diff --git a/star_lock/lib/main/lockDetail/electronicKey/sendElectronicKey/sendElectronicKey/sendElectronicKey_page.dart b/star_lock/lib/main/lockDetail/electronicKey/sendElectronicKey/sendElectronicKey/sendElectronicKey_page.dart index 91dc8ad0..715764e9 100644 --- a/star_lock/lib/main/lockDetail/electronicKey/sendElectronicKey/sendElectronicKey/sendElectronicKey_page.dart +++ b/star_lock/lib/main/lockDetail/electronicKey/sendElectronicKey/sendElectronicKey/sendElectronicKey_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/app_settings/app_colors.dart'; @@ -10,6 +10,8 @@ import 'package:flutter_native_contact_picker/flutter_native_contact_picker.dart import 'package:star_lock/main/lockDetail/electronicKey/sendElectronicKey/sendElectronicKey/sendElectronicKey_logic.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/storage.dart'; import 'package:star_lock/tools/toast.dart'; diff --git a/star_lock/lib/main/lockDetail/face/addFaceType/addFaceType_page.dart b/star_lock/lib/main/lockDetail/face/addFaceType/addFaceType_page.dart index 4bcd02e0..1ea3ef6e 100644 --- a/star_lock/lib/main/lockDetail/face/addFaceType/addFaceType_page.dart +++ b/star_lock/lib/main/lockDetail/face/addFaceType/addFaceType_page.dart @@ -1,11 +1,11 @@ - - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; @@ -31,7 +31,6 @@ class _AddFaceTypePageState extends State { @override Widget build(BuildContext context) { - return indexChangeWidget(); } @@ -43,8 +42,10 @@ class _AddFaceTypePageState extends State { // return sendElectronicKeySucceed(); return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyBottomWidget() ], ); @@ -54,8 +55,10 @@ class _AddFaceTypePageState extends State { // 限时 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyTimeLimitWidget(), SizedBox(height: 10.h), keyBottomWidget() @@ -67,18 +70,24 @@ class _AddFaceTypePageState extends State { // 循环 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), CommonItem( leftTitel: TranslationLoader.lanKeys!.periodValidity!.tr, rightTitle: "", isHaveDirection: true, action: () async { - Map result = await Get.toNamed(Routers.electronicKeyPeriodValidityPage); + Map result = await Get.toNamed( + Routers.electronicKeyPeriodValidityPage); state.weekdaysList.value = result['validityValue']; - state.effectiveDateTime.value = result['starDate'].millisecondsSinceEpoch; - state.failureDateTime.value = result['endDate'].millisecondsSinceEpoch; - print('得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); + state.effectiveDateTime.value = + result['starDate'].millisecondsSinceEpoch; + state.failureDateTime.value = + result['endDate'].millisecondsSinceEpoch; + print( + '得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); }), SizedBox(height: 10.h), keyBottomWidget() @@ -118,13 +127,17 @@ class _AddFaceTypePageState extends State { action: () async { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.beginTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.beginTimeTimestamp.value = DateTime.parse(state.beginTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.beginTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.beginTimeTimestamp.value = + DateTime.parse(state.beginTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, @@ -133,13 +146,17 @@ class _AddFaceTypePageState extends State { action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.endTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.endTimeTimestamp.value = DateTime.parse(state.endTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.endTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.endTimeTimestamp.value = + DateTime.parse(state.endTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Container(height: 10.h), ], @@ -157,23 +174,23 @@ class _AddFaceTypePageState extends State { // rightWidget: SizedBox( // width: 60.w, height: 50.h, child: _isStressFingerprint())), SizedBox(height: 30.h), - SubmitBtn(btnName: TranslationLoader.lanKeys!.next!.tr, onClick: () async { + SubmitBtn( + btnName: TranslationLoader.lanKeys!.next!.tr, + onClick: () async { + var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); + if (isDemoMode == false) { + // print("state.seletType:${state.seletType.value}"); + if (state.nameController.text.isEmpty) { + Toast.show(msg: "请输入姓名"); + return; + } - var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); - if(isDemoMode == false){ - // print("state.seletType:${state.seletType.value}"); - if(state.nameController.text.isEmpty){ - Toast.show(msg: "请输入姓名"); - return; - } - - Get.toNamed(Routers.addFaceTipPage); - }else{ - // Get.toNamed(Routers.seletLockTypePage); - Toast.show(msg: "演示模式"); - } - - }), + Get.toNamed(Routers.addFaceTipPage); + } else { + // Get.toNamed(Routers.seletLockTypePage); + Toast.show(msg: "演示模式"); + } + }), ], ); } @@ -294,5 +311,4 @@ class _AddFaceTypePageState extends State { }, ); } - } diff --git a/star_lock/lib/main/lockDetail/fingerprint/addFingerprintSeletType/addFingerprintType_page.dart b/star_lock/lib/main/lockDetail/fingerprint/addFingerprintSeletType/addFingerprintType_page.dart index 77d6d00d..2dd6c869 100644 --- a/star_lock/lib/main/lockDetail/fingerprint/addFingerprintSeletType/addFingerprintType_page.dart +++ b/star_lock/lib/main/lockDetail/fingerprint/addFingerprintSeletType/addFingerprintType_page.dart @@ -1,10 +1,11 @@ - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; @@ -16,12 +17,18 @@ import '../../../../translations/trans_lib.dart'; import 'addFingerprintType_logic.dart'; class AddFingerprintTypePage extends StatefulWidget { - final String seletType;// 永久限时循环下标 + final String seletType; // 永久限时循环下标 final int lockId; - final int fromType;// // 1从添加钥匙列表进入 2从考勤添加员工入口进入 - final String fromTypeTwoStaffName;// 从添加员工进入 传入员工名字 + final int fromType; // // 1从添加钥匙列表进入 2从考勤添加员工入口进入 + final String fromTypeTwoStaffName; // 从添加员工进入 传入员工名字 - const AddFingerprintTypePage({Key? key, required this.seletType, required this.lockId, required this.fromType, required this.fromTypeTwoStaffName}) : super(key: key); + const AddFingerprintTypePage( + {Key? key, + required this.seletType, + required this.lockId, + required this.fromType, + required this.fromTypeTwoStaffName}) + : super(key: key); @override State createState() => _AddFingerprintTypePageState(); @@ -51,7 +58,10 @@ class _AddFingerprintTypePageState extends State { // return sendElectronicKeySucceed(); return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyBottomWidget() ], ); @@ -61,7 +71,10 @@ class _AddFingerprintTypePageState extends State { // 限时 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyTimeLimitWidget(), SizedBox(height: 10.h), keyBottomWidget() @@ -73,18 +86,24 @@ class _AddFingerprintTypePageState extends State { // 循环 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), CommonItem( leftTitel: TranslationLoader.lanKeys!.periodValidity!.tr, rightTitle: "", isHaveDirection: true, action: () async { - Map result = await Get.toNamed(Routers.electronicKeyPeriodValidityPage); + Map result = await Get.toNamed( + Routers.electronicKeyPeriodValidityPage); state.weekdaysList.value = result['validityValue']; - state.effectiveDateTime.value = result['starDate'].millisecondsSinceEpoch; - state.failureDateTime.value = result['endDate'].millisecondsSinceEpoch; - print('得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); + state.effectiveDateTime.value = + result['starDate'].millisecondsSinceEpoch; + state.failureDateTime.value = + result['endDate'].millisecondsSinceEpoch; + print( + '得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); }), SizedBox(height: 10.h), keyBottomWidget() @@ -124,13 +143,17 @@ class _AddFingerprintTypePageState extends State { action: () async { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.beginTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.beginTimeTimestamp.value = DateTime.parse(state.beginTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.beginTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.beginTimeTimestamp.value = + DateTime.parse(state.beginTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, @@ -139,13 +162,17 @@ class _AddFingerprintTypePageState extends State { action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.endTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.endTimeTimestamp.value = DateTime.parse(state.endTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.endTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.endTimeTimestamp.value = + DateTime.parse(state.endTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Container(height: 10.h), ], @@ -163,23 +190,23 @@ class _AddFingerprintTypePageState extends State { rightWidget: SizedBox( width: 60.w, height: 50.h, child: _isStressFingerprint())), SizedBox(height: 30.h), - SubmitBtn(btnName: TranslationLoader.lanKeys!.next!.tr, onClick: () async { + SubmitBtn( + btnName: TranslationLoader.lanKeys!.next!.tr, + onClick: () async { + var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); + if (isDemoMode == false) { + // print("state.seletType:${state.seletType.value}"); + if (state.nameController.text.isEmpty) { + Toast.show(msg: "请输入姓名"); + return; + } - var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); - if(isDemoMode == false){ - // print("state.seletType:${state.seletType.value}"); - if(state.nameController.text.isEmpty){ - Toast.show(msg: "请输入姓名"); - return; - } - - logic.addFingerprintsData(); - }else{ - // Get.toNamed(Routers.seletLockTypePage); - Toast.show(msg: "演示模式"); - } - - }), + logic.addFingerprintsData(); + } else { + // Get.toNamed(Routers.seletLockTypePage); + Toast.show(msg: "演示模式"); + } + }), ], ); } @@ -300,5 +327,4 @@ class _AddFingerprintTypePageState extends State { }, ); } - } diff --git a/star_lock/lib/main/lockDetail/lcokSet/msgNotification/nDaysUnopened/nDaysUnopened_page.dart b/star_lock/lib/main/lockDetail/lcokSet/msgNotification/nDaysUnopened/nDaysUnopened_page.dart index 241a6716..ea0b3aea 100644 --- a/star_lock/lib/main/lockDetail/lcokSet/msgNotification/nDaysUnopened/nDaysUnopened_page.dart +++ b/star_lock/lib/main/lockDetail/lcokSet/msgNotification/nDaysUnopened/nDaysUnopened_page.dart @@ -1,11 +1,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/style/default_style.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/style/default_style.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/appRouters.dart'; import 'package:star_lock/tools/commonItem.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/style/default_style.dart'; import 'package:star_lock/tools/submitBtn.dart'; import '../../../../../app_settings/app_colors.dart'; diff --git a/star_lock/lib/main/lockDetail/lcokSet/normallyOpenMode/normallyOpenMode_page.dart b/star_lock/lib/main/lockDetail/lcokSet/normallyOpenMode/normallyOpenMode_page.dart index f807b103..bf3d2bd4 100644 --- a/star_lock/lib/main/lockDetail/lcokSet/normallyOpenMode/normallyOpenMode_page.dart +++ b/star_lock/lib/main/lockDetail/lcokSet/normallyOpenMode/normallyOpenMode_page.dart @@ -1,9 +1,11 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../app_settings/app_colors.dart'; import '../../../../tools/commonItem.dart'; @@ -32,89 +34,91 @@ class _NormallyOpenModePageState extends State { haveBack: true, backgroundColor: AppColors.mainColor), body: Obx(() => ListView( - children: [ - CommonItem( - leftTitel: TranslationLoader.lanKeys!.normallyOpenMode!.tr, - rightTitle: "", - isHaveLine: false, - isHaveRightWidget: true, - rightWidget: - SizedBox(width: 60.w, height: 50.h, child: _normallyOpenModeSwitch())), - SizedBox( - height: 1.h, - ), - Container( - padding: EdgeInsets.only( - left: 30.w, right: 30.w, top: 20.w, bottom: 20.w), - color: Colors.white, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Expanded( - child: Text( + children: [ + CommonItem( + leftTitel: TranslationLoader.lanKeys!.normallyOpenMode!.tr, + rightTitle: "", + isHaveLine: false, + isHaveRightWidget: true, + rightWidget: SizedBox( + width: 60.w, + height: 50.h, + child: _normallyOpenModeSwitch())), + SizedBox( + height: 1.h, + ), + Container( + padding: EdgeInsets.only( + left: 30.w, right: 30.w, top: 20.w, bottom: 20.w), + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Text( TranslationLoader.lanKeys!.normallyOpenModeTip!.tr, style: TextStyle(fontSize: 20.sp), )), - ], - ), - ), - SizedBox( - height: 10.h, - ), - Visibility( - visible: state.isOpenNormallyOpenMode.value, - child: Container( - color: Colors.white, - child: Column( - children: [ - // CommonItem( - // leftTitel: TranslationLoader.lanKeys!.automaticUnLock!.tr, - // rightTitle: "", - // isHaveLine: false, - // isHaveRightWidget: true, - // rightWidget: - // SizedBox(width: 60.w, height: 50.h, child: _autoUnlockSwitch())), - // Container( - // height: 1.h, - // color: AppColors.mainBackgroundColor, - // ), - // Container( - // padding: EdgeInsets.only( - // left: 30.w, right: 30.w, top: 20.w, bottom: 20.w), - // color: Colors.white, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // Expanded( - // child: Text( - // TranslationLoader.lanKeys!.automaticUnLockTip!.tr, - // style: TextStyle(fontSize: 20.sp), - // )), - // ], - // ), - // ), - // Container( - // height: 10.h, - // color: AppColors.mainBackgroundColor, - // ), - topWidget(), - SizedBox( - height: 10.h, - ), - bottomWidget() ], ), - )), - Container( - margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 30.h), - child: SubmitBtn( - btnName: TranslationLoader.lanKeys!.save!.tr, - onClick: () { - logic.sendAutoLock(); - }), - ), - ], - ))); + ), + SizedBox( + height: 10.h, + ), + Visibility( + visible: state.isOpenNormallyOpenMode.value, + child: Container( + color: Colors.white, + child: Column( + children: [ + // CommonItem( + // leftTitel: TranslationLoader.lanKeys!.automaticUnLock!.tr, + // rightTitle: "", + // isHaveLine: false, + // isHaveRightWidget: true, + // rightWidget: + // SizedBox(width: 60.w, height: 50.h, child: _autoUnlockSwitch())), + // Container( + // height: 1.h, + // color: AppColors.mainBackgroundColor, + // ), + // Container( + // padding: EdgeInsets.only( + // left: 30.w, right: 30.w, top: 20.w, bottom: 20.w), + // color: Colors.white, + // child: Row( + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // Expanded( + // child: Text( + // TranslationLoader.lanKeys!.automaticUnLockTip!.tr, + // style: TextStyle(fontSize: 20.sp), + // )), + // ], + // ), + // ), + // Container( + // height: 10.h, + // color: AppColors.mainBackgroundColor, + // ), + topWidget(), + SizedBox( + height: 10.h, + ), + bottomWidget() + ], + ), + )), + Container( + margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 30.h), + child: SubmitBtn( + btnName: TranslationLoader.lanKeys!.save!.tr, + onClick: () { + logic.sendAutoLock(); + }), + ), + ], + ))); } Widget topWidget() { @@ -180,9 +184,9 @@ class _NormallyOpenModePageState extends State { } return GestureDetector( onTap: () { - if(state.weekDays.value.contains(index)){ + if (state.weekDays.value.contains(index)) { state.weekDays.value.remove(index); - }else{ + } else { state.weekDays.value.add(index); } state.weekDays.value.sort(); @@ -190,20 +194,26 @@ class _NormallyOpenModePageState extends State { // print("index:$index data:${state.normallyOpenPeriod.value}"); }, child: Obx(() => Container( - width: 40.w, - height: 40.w, - margin: EdgeInsets.all(10.w), - decoration: BoxDecoration( - color: state.weekDays.value.contains(index) ? AppColors.mainColor :Colors.white, - border: Border.all(width: 1, color: AppColors.btnDisableColor), - borderRadius: BorderRadius.circular(30.w), - ), - child: Center( - child: Text( + width: 40.w, + height: 40.w, + margin: EdgeInsets.all(10.w), + decoration: BoxDecoration( + color: state.weekDays.value.contains(index) + ? AppColors.mainColor + : Colors.white, + border: Border.all(width: 1, color: AppColors.btnDisableColor), + borderRadius: BorderRadius.circular(30.w), + ), + child: Center( + child: Text( dateStr, - style: TextStyle(fontSize: 20.sp, color: state.weekDays.value.contains(index) ? Colors.white : AppColors.darkGrayTextColor), + style: TextStyle( + fontSize: 20.sp, + color: state.weekDays.value.contains(index) + ? Colors.white + : AppColors.darkGrayTextColor), )), - )), + )), ); } @@ -216,16 +226,16 @@ class _NormallyOpenModePageState extends State { ), Obx(() => CommonItem( leftTitel: - "${TranslationLoader.lanKeys!.normallyOpen!.tr}${TranslationLoader.lanKeys!.time!.tr}", + "${TranslationLoader.lanKeys!.normallyOpen!.tr}${TranslationLoader.lanKeys!.time!.tr}", rightTitle: "", isHaveLine: true, isHaveRightWidget: true, rightWidget: GestureDetector( onTap: () { // 选择全天模式 - if(state.isAllDay.value == 1){ + if (state.isAllDay.value == 1) { state.isAllDay.value = 0; - }else{ + } else { state.isAllDay.value = 1; } setState(() {}); @@ -240,7 +250,9 @@ class _NormallyOpenModePageState extends State { width: 5.w, ), Image.asset( - state.isAllDay.value == 1 ? 'images/icon_round_selet.png': 'images/icon_round_unSelet.png', + state.isAllDay.value == 1 + ? 'images/icon_round_selet.png' + : 'images/icon_round_unSelet.png', width: 30.w, height: 30.w, ), @@ -255,32 +267,34 @@ class _NormallyOpenModePageState extends State { children: [ Obx(() => CommonItem( leftTitel: - "${TranslationLoader.lanKeys!.begin!.tr}${TranslationLoader.lanKeys!.time!.tr}", + "${TranslationLoader.lanKeys!.begin!.tr}${TranslationLoader.lanKeys!.time!.tr}", rightTitle: state.beginTime.value, isHaveDirection: true, isHaveLine: true, action: () { Pickers.showDatePicker(context, mode: DateMode.HM, onConfirm: (p) { - setState(() { - state.beginTimeMinute.value = p.hour!*60 + p.minute!; - state.beginTime.value = "${p.hour}:${p.minute!}"; - }); - }); + setState(() { + state.beginTimeMinute.value = + p.hour! * 60 + p.minute!; + state.beginTime.value = "${p.hour}:${p.minute!}"; + }); + }); })), Obx(() => CommonItem( leftTitel: - "${TranslationLoader.lanKeys!.end!.tr}${TranslationLoader.lanKeys!.time!.tr}", + "${TranslationLoader.lanKeys!.end!.tr}${TranslationLoader.lanKeys!.time!.tr}", rightTitle: state.endTime.value, isHaveDirection: true, action: () { Pickers.showDatePicker(context, mode: DateMode.HM, onConfirm: (p) { - setState(() { - state.endTimeMinute.value = p.hour!*60 + p.minute!; - state.endTime.value = "${p.hour}:${p.minute!}"; - }); - }); + setState(() { + state.endTimeMinute.value = + p.hour! * 60 + p.minute!; + state.endTime.value = "${p.hour}:${p.minute!}"; + }); + }); })), Container(height: 10.h), ], diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart index d6c63233..be6b10fb 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart @@ -2,13 +2,16 @@ import 'package:date_format/date_format.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/style/default_style.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/style/default_style.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/style/default_style.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/storage.dart'; import 'package:star_lock/tools/toast.dart'; @@ -329,8 +332,6 @@ class _PasswordKeyPerpetualPageState extends State { state.loopFailureDate.value = "${formatDate(state.failureDateTime.value, [HH])}:00"; state.loopEndHours.value = p.hour!; - // state.selectFailureDate.value = - // formatDate(state.failureDateTime.value, [HH]); } else { // 处理日期不合法的情况,可以使用默认值或者其他策略 } diff --git a/star_lock/lib/main/lockDetail/remoteControl/addRemoteControl/addRemoteControl_page.dart b/star_lock/lib/main/lockDetail/remoteControl/addRemoteControl/addRemoteControl_page.dart index 01b5a447..2b7a9fc3 100644 --- a/star_lock/lib/main/lockDetail/remoteControl/addRemoteControl/addRemoteControl_page.dart +++ b/star_lock/lib/main/lockDetail/remoteControl/addRemoteControl/addRemoteControl_page.dart @@ -1,10 +1,11 @@ - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; @@ -18,7 +19,8 @@ import 'addRemoteControl_logic.dart'; class AddRemoteControlPage extends StatefulWidget { final String seletType; - const AddRemoteControlPage({Key? key, required this.seletType}) : super(key: key); + const AddRemoteControlPage({Key? key, required this.seletType}) + : super(key: key); @override State createState() => _AddRemoteControlPageState(); @@ -30,7 +32,6 @@ class _AddRemoteControlPageState extends State { @override Widget build(BuildContext context) { - return indexChangeWidget(); } @@ -42,8 +43,10 @@ class _AddRemoteControlPageState extends State { // return sendElectronicKeySucceed(); return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyBottomWidget() ], ); @@ -53,8 +56,10 @@ class _AddRemoteControlPageState extends State { // 限时 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), keyTimeLimitWidget(), SizedBox(height: 10.h), keyBottomWidget() @@ -66,18 +71,24 @@ class _AddRemoteControlPageState extends State { // 循环 return Column( children: [ - perpetualKeyWidget(TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, state.nameController), + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), CommonItem( leftTitel: TranslationLoader.lanKeys!.periodValidity!.tr, rightTitle: "", isHaveDirection: true, action: () async { - Map result = await Get.toNamed(Routers.electronicKeyPeriodValidityPage); + Map result = await Get.toNamed( + Routers.electronicKeyPeriodValidityPage); state.weekdaysList.value = result['validityValue']; - state.effectiveDateTime.value = result['starDate'].millisecondsSinceEpoch; - state.failureDateTime.value = result['endDate'].millisecondsSinceEpoch; - print('得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); + state.effectiveDateTime.value = + result['starDate'].millisecondsSinceEpoch; + state.failureDateTime.value = + result['endDate'].millisecondsSinceEpoch; + print( + '得到的有效期数据:${state.weekdaysList.value} == ${state.effectiveDateTime.value} == ${state.failureDateTime.value}'); }), SizedBox(height: 10.h), keyBottomWidget() @@ -117,13 +128,17 @@ class _AddRemoteControlPageState extends State { action: () async { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.beginTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.beginTimeTimestamp.value = DateTime.parse(state.beginTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.beginTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.beginTimeTimestamp.value = + DateTime.parse(state.beginTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, @@ -132,13 +147,17 @@ class _AddRemoteControlPageState extends State { action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - setState(() { - state.endTime.value = '${p.year}-${p.month!.toString().padLeft(2,'0')}-${p.day!.toString().padLeft(2,'0')} ${p.hour!.toString().padLeft(2,'0')}:${p.minute!.toString().padLeft(2,'0')}'; - state.endTimeTimestamp.value = DateTime.parse(state.endTime.value).millisecondsSinceEpoch.toString(); - }); - }); + setState(() { + setState(() { + state.endTime.value = + '${p.year}-${p.month!.toString().padLeft(2, '0')}-${p.day!.toString().padLeft(2, '0')} ${p.hour!.toString().padLeft(2, '0')}:${p.minute!.toString().padLeft(2, '0')}'; + state.endTimeTimestamp.value = + DateTime.parse(state.endTime.value) + .millisecondsSinceEpoch + .toString(); }); + }); + }); })), Container(height: 10.h), ], @@ -156,23 +175,23 @@ class _AddRemoteControlPageState extends State { // rightWidget: SizedBox( // width: 60.w, height: 50.h, child: _isStressFingerprint())), SizedBox(height: 30.h), - SubmitBtn(btnName: TranslationLoader.lanKeys!.next!.tr, onClick: () async { - - var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); - if(isDemoMode == false){ - // print("state.seletType:${state.seletType.value}"); - if(state.nameController.text.isEmpty){ - Toast.show(msg: "请输入姓名"); - return; - } - Toast.show(msg: "请确保在设备附近"); - // logic.addFingerprintsData(); - }else{ - // Get.toNamed(Routers.seletLockTypePage); - Toast.show(msg: "演示模式"); - } - - }), + SubmitBtn( + btnName: TranslationLoader.lanKeys!.next!.tr, + onClick: () async { + var isDemoMode = await Storage.getBool(ifIsDemoModeOrNot); + if (isDemoMode == false) { + // print("state.seletType:${state.seletType.value}"); + if (state.nameController.text.isEmpty) { + Toast.show(msg: "请输入姓名"); + return; + } + Toast.show(msg: "请确保在设备附近"); + // logic.addFingerprintsData(); + } else { + // Get.toNamed(Routers.seletLockTypePage); + Toast.show(msg: "演示模式"); + } + }), ], ); } @@ -293,5 +312,4 @@ class _AddRemoteControlPageState extends State { }, ); } - } diff --git a/star_lock/lib/mine/mineSet/addAuthorizedAdministrator/addAuthorizedAdministrator_page.dart b/star_lock/lib/mine/mineSet/addAuthorizedAdministrator/addAuthorizedAdministrator_page.dart index ef820af2..a42b2904 100644 --- a/star_lock/lib/mine/mineSet/addAuthorizedAdministrator/addAuthorizedAdministrator_page.dart +++ b/star_lock/lib/mine/mineSet/addAuthorizedAdministrator/addAuthorizedAdministrator_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_native_contact_picker/flutter_native_contact_picker.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get_utils/get_utils.dart'; import 'package:star_lock/appRouters.dart'; @@ -10,6 +10,8 @@ import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; import 'package:star_lock/tools/commonItem.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/submitBtn.dart'; import 'package:star_lock/tools/toast.dart'; import 'package:star_lock/translations/trans_lib.dart'; diff --git a/star_lock/lib/mine/mineSet/authorizedAdministrator/administratorDetails/adminDetailChangeDate_page.dart b/star_lock/lib/mine/mineSet/authorizedAdministrator/administratorDetails/adminDetailChangeDate_page.dart index 0535d515..ec95a42e 100644 --- a/star_lock/lib/mine/mineSet/authorizedAdministrator/administratorDetails/adminDetailChangeDate_page.dart +++ b/star_lock/lib/mine/mineSet/authorizedAdministrator/administratorDetails/adminDetailChangeDate_page.dart @@ -1,12 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyList/entity/ElectronicKeyListEntity.dart'; import 'package:star_lock/mine/mineSet/authorizedAdministrator/authorizedAdminListEntity.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/toast.dart'; import '../../../../../app_settings/app_colors.dart'; diff --git a/star_lock/lib/mine/mineSet/lockUserManage/expireLockList/expireLockChangeDate_page.dart b/star_lock/lib/mine/mineSet/lockUserManage/expireLockList/expireLockChangeDate_page.dart index c71279e9..102064af 100644 --- a/star_lock/lib/mine/mineSet/lockUserManage/expireLockList/expireLockChangeDate_page.dart +++ b/star_lock/lib/mine/mineSet/lockUserManage/expireLockList/expireLockChangeDate_page.dart @@ -1,12 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:flutter_pickers/pickers.dart'; -import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/pickers.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/keyOperationRecordEntity.dart'; import 'package:star_lock/mine/mineSet/lockUserManage/expireLockList/expireLockListEntity.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/pickers/pickers.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import 'package:star_lock/tools/toast.dart'; import '../../../../../app_settings/app_colors.dart'; diff --git a/star_lock/lib/tools/pickers/address_picker/locations_data.dart b/star_lock/lib/tools/pickers/address_picker/locations_data.dart new file mode 100644 index 00000000..89484820 --- /dev/null +++ b/star_lock/lib/tools/pickers/address_picker/locations_data.dart @@ -0,0 +1,4311 @@ +import '../utils/check.dart'; + +/// 数据地址:https://github.com/airyland/china-area-data/blob/master/data.json +const locations = { + "86": { + "110000": "北京市", + "120000": "天津市", + "130000": "河北省", + "140000": "山西省", + "150000": "内蒙古自治区", + "210000": "辽宁省", + "220000": "吉林省", + "230000": "黑龙江省", + "310000": "上海市", + "320000": "江苏省", + "330000": "浙江省", + "340000": "安徽省", + "350000": "福建省", + "360000": "江西省", + "370000": "山东省", + "410000": "河南省", + "420000": "湖北省", + "430000": "湖南省", + "440000": "广东省", + "450000": "广西壮族自治区", + "460000": "海南省", + "500000": "重庆市", + "510000": "四川省", + "520000": "贵州省", + "530000": "云南省", + "540000": "西藏自治区", + "610000": "陕西省", + "620000": "甘肃省", + "630000": "青海省", + "640000": "宁夏回族自治区", + "650000": "新疆维吾尔自治区", + "710000": "台湾省", + "810000": "香港特别行政区", + "820000": "澳门特别行政区" + }, + "110000": {"110100": "市辖区"}, + "110100": { + "110101": "东城区", + "110102": "西城区", + "110105": "朝阳区", + "110106": "丰台区", + "110107": "石景山区", + "110108": "海淀区", + "110109": "门头沟区", + "110111": "房山区", + "110112": "通州区", + "110113": "顺义区", + "110114": "昌平区", + "110115": "大兴区", + "110116": "怀柔区", + "110117": "平谷区", + "110118": "密云区", + "110119": "延庆区" + }, + "120000": {"120100": "市辖区"}, + "120100": { + "120101": "和平区", + "120102": "河东区", + "120103": "河西区", + "120104": "南开区", + "120105": "河北区", + "120106": "红桥区", + "120110": "东丽区", + "120111": "西青区", + "120112": "津南区", + "120113": "北辰区", + "120114": "武清区", + "120115": "宝坻区", + "120116": "滨海新区", + "120117": "宁河区", + "120118": "静海区", + "120119": "蓟州区" + }, + "130000": { + "130100": "石家庄市", + "130200": "唐山市", + "130300": "秦皇岛市", + "130400": "邯郸市", + "130500": "邢台市", + "130600": "保定市", + "130700": "张家口市", + "130800": "承德市", + "130900": "沧州市", + "131000": "廊坊市", + "131100": "衡水市" + }, + "130100": { + "130101": "市辖区", + "130102": "长安区", + "130104": "桥西区", + "130105": "新华区", + "130107": "井陉矿区", + "130108": "裕华区", + "130109": "藁城区", + "130110": "鹿泉区", + "130111": "栾城区", + "130121": "井陉县", + "130123": "正定县", + "130125": "行唐县", + "130126": "灵寿县", + "130127": "高邑县", + "130128": "深泽县", + "130129": "赞皇县", + "130130": "无极县", + "130131": "平山县", + "130132": "元氏县", + "130133": "赵县", + "130171": "石家庄高新技术产业开发区", + "130172": "石家庄循环化工园区", + "130181": "辛集市", + "130183": "晋州市", + "130184": "新乐市" + }, + "130200": { + "130201": "市辖区", + "130202": "路南区", + "130203": "路北区", + "130204": "古冶区", + "130205": "开平区", + "130207": "丰南区", + "130208": "丰润区", + "130209": "曹妃甸区", + "130224": "滦南县", + "130225": "乐亭县", + "130227": "迁西县", + "130229": "玉田县", + "130271": "河北唐山芦台经济开发区", + "130272": "唐山市汉沽管理区", + "130273": "唐山高新技术产业开发区", + "130274": "河北唐山海港经济开发区", + "130281": "遵化市", + "130283": "迁安市", + "130284": "滦州市" + }, + "130300": { + "130301": "市辖区", + "130302": "海港区", + "130303": "山海关区", + "130304": "北戴河区", + "130306": "抚宁区", + "130321": "青龙满族自治县", + "130322": "昌黎县", + "130324": "卢龙县", + "130371": "秦皇岛市经济技术开发区", + "130372": "北戴河新区" + }, + "130400": { + "130401": "市辖区", + "130402": "邯山区", + "130403": "丛台区", + "130404": "复兴区", + "130406": "峰峰矿区", + "130407": "肥乡区", + "130408": "永年区", + "130423": "临漳县", + "130424": "成安县", + "130425": "大名县", + "130426": "涉县", + "130427": "磁县", + "130430": "邱县", + "130431": "鸡泽县", + "130432": "广平县", + "130433": "馆陶县", + "130434": "魏县", + "130435": "曲周县", + "130471": "邯郸经济技术开发区", + "130473": "邯郸冀南新区", + "130481": "武安市" + }, + "130500": { + "130501": "市辖区", + "130502": "桥东区", + "130503": "桥西区", + "130521": "邢台县", + "130522": "临城县", + "130523": "内丘县", + "130524": "柏乡县", + "130525": "隆尧县", + "130526": "任县", + "130527": "南和县", + "130528": "宁晋县", + "130529": "巨鹿县", + "130530": "新河县", + "130531": "广宗县", + "130532": "平乡县", + "130533": "威县", + "130534": "清河县", + "130535": "临西县", + "130571": "河北邢台经济开发区", + "130581": "南宫市", + "130582": "沙河市" + }, + "130600": { + "130601": "市辖区", + "130602": "竞秀区", + "130606": "莲池区", + "130607": "满城区", + "130608": "清苑区", + "130609": "徐水区", + "130623": "涞水县", + "130624": "阜平县", + "130626": "定兴县", + "130627": "唐县", + "130628": "高阳县", + "130629": "容城县", + "130630": "涞源县", + "130631": "望都县", + "130632": "安新县", + "130633": "易县", + "130634": "曲阳县", + "130635": "蠡县", + "130636": "顺平县", + "130637": "博野县", + "130638": "雄县", + "130671": "保定高新技术产业开发区", + "130672": "保定白沟新城", + "130681": "涿州市", + "130682": "定州市", + "130683": "安国市", + "130684": "高碑店市" + }, + "130700": { + "130701": "市辖区", + "130702": "桥东区", + "130703": "桥西区", + "130705": "宣化区", + "130706": "下花园区", + "130708": "万全区", + "130709": "崇礼区", + "130722": "张北县", + "130723": "康保县", + "130724": "沽源县", + "130725": "尚义县", + "130726": "蔚县", + "130727": "阳原县", + "130728": "怀安县", + "130730": "怀来县", + "130731": "涿鹿县", + "130732": "赤城县", + "130771": "张家口经济开发区", + "130772": "张家口市察北管理区", + "130773": "张家口市塞北管理区" + }, + "130800": { + "130801": "市辖区", + "130802": "双桥区", + "130803": "双滦区", + "130804": "鹰手营子矿区", + "130821": "承德县", + "130822": "兴隆县", + "130824": "滦平县", + "130825": "隆化县", + "130826": "丰宁满族自治县", + "130827": "宽城满族自治县", + "130828": "围场满族蒙古族自治县", + "130871": "承德高新技术产业开发区", + "130881": "平泉市" + }, + "130900": { + "130901": "市辖区", + "130902": "新华区", + "130903": "运河区", + "130921": "沧县", + "130922": "青县", + "130923": "东光县", + "130924": "海兴县", + "130925": "盐山县", + "130926": "肃宁县", + "130927": "南皮县", + "130928": "吴桥县", + "130929": "献县", + "130930": "孟村回族自治县", + "130971": "河北沧州经济开发区", + "130972": "沧州高新技术产业开发区", + "130973": "沧州渤海新区", + "130981": "泊头市", + "130982": "任丘市", + "130983": "黄骅市", + "130984": "河间市" + }, + "131000": { + "131001": "市辖区", + "131002": "安次区", + "131003": "广阳区", + "131022": "固安县", + "131023": "永清县", + "131024": "香河县", + "131025": "大城县", + "131026": "文安县", + "131028": "大厂回族自治县", + "131071": "廊坊经济技术开发区", + "131081": "霸州市", + "131082": "三河市" + }, + "131100": { + "131101": "市辖区", + "131102": "桃城区", + "131103": "冀州区", + "131121": "枣强县", + "131122": "武邑县", + "131123": "武强县", + "131124": "饶阳县", + "131125": "安平县", + "131126": "故城县", + "131127": "景县", + "131128": "阜城县", + "131171": "河北衡水高新技术产业开发区", + "131172": "衡水滨湖新区", + "131182": "深州市" + }, + "140000": { + "140100": "太原市", + "140200": "大同市", + "140300": "阳泉市", + "140400": "长治市", + "140500": "晋城市", + "140600": "朔州市", + "140700": "晋中市", + "140800": "运城市", + "140900": "忻州市", + "141000": "临汾市", + "141100": "吕梁市" + }, + "140100": { + "140101": "市辖区", + "140105": "小店区", + "140106": "迎泽区", + "140107": "杏花岭区", + "140108": "尖草坪区", + "140109": "万柏林区", + "140110": "晋源区", + "140121": "清徐县", + "140122": "阳曲县", + "140123": "娄烦县", + "140171": "山西转型综合改革示范区", + "140181": "古交市" + }, + "140200": { + "140201": "市辖区", + "140212": "新荣区", + "140213": "平城区", + "140214": "云冈区", + "140215": "云州区", + "140221": "阳高县", + "140222": "天镇县", + "140223": "广灵县", + "140224": "灵丘县", + "140225": "浑源县", + "140226": "左云县", + "140271": "山西大同经济开发区" + }, + "140300": {"140301": "市辖区", "140302": "城区", "140303": "矿区", "140311": "郊区", "140321": "平定县", "140322": "盂县"}, + "140400": { + "140401": "市辖区", + "140403": "潞州区", + "140404": "上党区", + "140405": "屯留区", + "140406": "潞城区", + "140423": "襄垣县", + "140425": "平顺县", + "140426": "黎城县", + "140427": "壶关县", + "140428": "长子县", + "140429": "武乡县", + "140430": "沁县", + "140431": "沁源县", + "140471": "山西长治高新技术产业园区" + }, + "140500": { + "140501": "市辖区", + "140502": "城区", + "140521": "沁水县", + "140522": "阳城县", + "140524": "陵川县", + "140525": "泽州县", + "140581": "高平市" + }, + "140600": { + "140601": "市辖区", + "140602": "朔城区", + "140603": "平鲁区", + "140621": "山阴县", + "140622": "应县", + "140623": "右玉县", + "140671": "山西朔州经济开发区", + "140681": "怀仁市" + }, + "140700": { + "140701": "市辖区", + "140702": "榆次区", + "140721": "榆社县", + "140722": "左权县", + "140723": "和顺县", + "140724": "昔阳县", + "140725": "寿阳县", + "140726": "太谷县", + "140727": "祁县", + "140728": "平遥县", + "140729": "灵石县", + "140781": "介休市" + }, + "140800": { + "140801": "市辖区", + "140802": "盐湖区", + "140821": "临猗县", + "140822": "万荣县", + "140823": "闻喜县", + "140824": "稷山县", + "140825": "新绛县", + "140826": "绛县", + "140827": "垣曲县", + "140828": "夏县", + "140829": "平陆县", + "140830": "芮城县", + "140881": "永济市", + "140882": "河津市" + }, + "140900": { + "140901": "市辖区", + "140902": "忻府区", + "140921": "定襄县", + "140922": "五台县", + "140923": "代县", + "140924": "繁峙县", + "140925": "宁武县", + "140926": "静乐县", + "140927": "神池县", + "140928": "五寨县", + "140929": "岢岚县", + "140930": "河曲县", + "140931": "保德县", + "140932": "偏关县", + "140971": "五台山风景名胜区", + "140981": "原平市" + }, + "141000": { + "141001": "市辖区", + "141002": "尧都区", + "141021": "曲沃县", + "141022": "翼城县", + "141023": "襄汾县", + "141024": "洪洞县", + "141025": "古县", + "141026": "安泽县", + "141027": "浮山县", + "141028": "吉县", + "141029": "乡宁县", + "141030": "大宁县", + "141031": "隰县", + "141032": "永和县", + "141033": "蒲县", + "141034": "汾西县", + "141081": "侯马市", + "141082": "霍州市" + }, + "141100": { + "141101": "市辖区", + "141102": "离石区", + "141121": "文水县", + "141122": "交城县", + "141123": "兴县", + "141124": "临县", + "141125": "柳林县", + "141126": "石楼县", + "141127": "岚县", + "141128": "方山县", + "141129": "中阳县", + "141130": "交口县", + "141181": "孝义市", + "141182": "汾阳市" + }, + "150000": { + "150100": "呼和浩特市", + "150200": "包头市", + "150300": "乌海市", + "150400": "赤峰市", + "150500": "通辽市", + "150600": "鄂尔多斯市", + "150700": "呼伦贝尔市", + "150800": "巴彦淖尔市", + "150900": "乌兰察布市", + "152200": "兴安盟", + "152500": "锡林郭勒盟", + "152900": "阿拉善盟" + }, + "150100": { + "150101": "市辖区", + "150102": "新城区", + "150103": "回民区", + "150104": "玉泉区", + "150105": "赛罕区", + "150121": "土默特左旗", + "150122": "托克托县", + "150123": "和林格尔县", + "150124": "清水河县", + "150125": "武川县", + "150171": "呼和浩特金海工业园区", + "150172": "呼和浩特经济技术开发区" + }, + "150200": { + "150201": "市辖区", + "150202": "东河区", + "150203": "昆都仑区", + "150204": "青山区", + "150205": "石拐区", + "150206": "白云鄂博矿区", + "150207": "九原区", + "150221": "土默特右旗", + "150222": "固阳县", + "150223": "达尔罕茂明安联合旗", + "150271": "包头稀土高新技术产业开发区" + }, + "150300": {"150301": "市辖区", "150302": "海勃湾区", "150303": "海南区", "150304": "乌达区"}, + "150400": { + "150401": "市辖区", + "150402": "红山区", + "150403": "元宝山区", + "150404": "松山区", + "150421": "阿鲁科尔沁旗", + "150422": "巴林左旗", + "150423": "巴林右旗", + "150424": "林西县", + "150425": "克什克腾旗", + "150426": "翁牛特旗", + "150428": "喀喇沁旗", + "150429": "宁城县", + "150430": "敖汉旗" + }, + "150500": { + "150501": "市辖区", + "150502": "科尔沁区", + "150521": "科尔沁左翼中旗", + "150522": "科尔沁左翼后旗", + "150523": "开鲁县", + "150524": "库伦旗", + "150525": "奈曼旗", + "150526": "扎鲁特旗", + "150571": "通辽经济技术开发区", + "150581": "霍林郭勒市" + }, + "150600": { + "150601": "市辖区", + "150602": "东胜区", + "150603": "康巴什区", + "150621": "达拉特旗", + "150622": "准格尔旗", + "150623": "鄂托克前旗", + "150624": "鄂托克旗", + "150625": "杭锦旗", + "150626": "乌审旗", + "150627": "伊金霍洛旗" + }, + "150700": { + "150701": "市辖区", + "150702": "海拉尔区", + "150703": "扎赉诺尔区", + "150721": "阿荣旗", + "150722": "莫力达瓦达斡尔族自治旗", + "150723": "鄂伦春自治旗", + "150724": "鄂温克族自治旗", + "150725": "陈巴尔虎旗", + "150726": "新巴尔虎左旗", + "150727": "新巴尔虎右旗", + "150781": "满洲里市", + "150782": "牙克石市", + "150783": "扎兰屯市", + "150784": "额尔古纳市", + "150785": "根河市" + }, + "150800": { + "150801": "市辖区", + "150802": "临河区", + "150821": "五原县", + "150822": "磴口县", + "150823": "乌拉特前旗", + "150824": "乌拉特中旗", + "150825": "乌拉特后旗", + "150826": "杭锦后旗" + }, + "150900": { + "150901": "市辖区", + "150902": "集宁区", + "150921": "卓资县", + "150922": "化德县", + "150923": "商都县", + "150924": "兴和县", + "150925": "凉城县", + "150926": "察哈尔右翼前旗", + "150927": "察哈尔右翼中旗", + "150928": "察哈尔右翼后旗", + "150929": "四子王旗", + "150981": "丰镇市" + }, + "152200": { + "152201": "乌兰浩特市", + "152202": "阿尔山市", + "152221": "科尔沁右翼前旗", + "152222": "科尔沁右翼中旗", + "152223": "扎赉特旗", + "152224": "突泉县" + }, + "152500": { + "152501": "二连浩特市", + "152502": "锡林浩特市", + "152522": "阿巴嘎旗", + "152523": "苏尼特左旗", + "152524": "苏尼特右旗", + "152525": "东乌珠穆沁旗", + "152526": "西乌珠穆沁旗", + "152527": "太仆寺旗", + "152528": "镶黄旗", + "152529": "正镶白旗", + "152530": "正蓝旗", + "152531": "多伦县", + "152571": "乌拉盖管委会" + }, + "152900": {"152921": "阿拉善左旗", "152922": "阿拉善右旗", "152923": "额济纳旗", "152971": "内蒙古阿拉善经济开发区"}, + "210000": { + "210100": "沈阳市", + "210200": "大连市", + "210300": "鞍山市", + "210400": "抚顺市", + "210500": "本溪市", + "210600": "丹东市", + "210700": "锦州市", + "210800": "营口市", + "210900": "阜新市", + "211000": "辽阳市", + "211100": "盘锦市", + "211200": "铁岭市", + "211300": "朝阳市", + "211400": "葫芦岛市" + }, + "210100": { + "210101": "市辖区", + "210102": "和平区", + "210103": "沈河区", + "210104": "大东区", + "210105": "皇姑区", + "210106": "铁西区", + "210111": "苏家屯区", + "210112": "浑南区", + "210113": "沈北新区", + "210114": "于洪区", + "210115": "辽中区", + "210123": "康平县", + "210124": "法库县", + "210181": "新民市" + }, + "210200": { + "210201": "市辖区", + "210202": "中山区", + "210203": "西岗区", + "210204": "沙河口区", + "210211": "甘井子区", + "210212": "旅顺口区", + "210213": "金州区", + "210214": "普兰店区", + "210224": "长海县", + "210281": "瓦房店市", + "210283": "庄河市" + }, + "210300": { + "210301": "市辖区", + "210302": "铁东区", + "210303": "铁西区", + "210304": "立山区", + "210311": "千山区", + "210321": "台安县", + "210323": "岫岩满族自治县", + "210381": "海城市" + }, + "210400": { + "210401": "市辖区", + "210402": "新抚区", + "210403": "东洲区", + "210404": "望花区", + "210411": "顺城区", + "210421": "抚顺县", + "210422": "新宾满族自治县", + "210423": "清原满族自治县" + }, + "210500": { + "210501": "市辖区", + "210502": "平山区", + "210503": "溪湖区", + "210504": "明山区", + "210505": "南芬区", + "210521": "本溪满族自治县", + "210522": "桓仁满族自治县" + }, + "210600": { + "210601": "市辖区", + "210602": "元宝区", + "210603": "振兴区", + "210604": "振安区", + "210624": "宽甸满族自治县", + "210681": "东港市", + "210682": "凤城市" + }, + "210700": { + "210701": "市辖区", + "210702": "古塔区", + "210703": "凌河区", + "210711": "太和区", + "210726": "黑山县", + "210727": "义县", + "210781": "凌海市", + "210782": "北镇市" + }, + "210800": { + "210801": "市辖区", + "210802": "站前区", + "210803": "西市区", + "210804": "鲅鱼圈区", + "210811": "老边区", + "210881": "盖州市", + "210882": "大石桥市" + }, + "210900": { + "210901": "市辖区", + "210902": "海州区", + "210903": "新邱区", + "210904": "太平区", + "210905": "清河门区", + "210911": "细河区", + "210921": "阜新蒙古族自治县", + "210922": "彰武县" + }, + "211000": { + "211001": "市辖区", + "211002": "白塔区", + "211003": "文圣区", + "211004": "宏伟区", + "211005": "弓长岭区", + "211011": "太子河区", + "211021": "辽阳县", + "211081": "灯塔市" + }, + "211100": {"211101": "市辖区", "211102": "双台子区", "211103": "兴隆台区", "211104": "大洼区", "211122": "盘山县"}, + "211200": { + "211201": "市辖区", + "211202": "银州区", + "211204": "清河区", + "211221": "铁岭县", + "211223": "西丰县", + "211224": "昌图县", + "211281": "调兵山市", + "211282": "开原市" + }, + "211300": { + "211301": "市辖区", + "211302": "双塔区", + "211303": "龙城区", + "211321": "朝阳县", + "211322": "建平县", + "211324": "喀喇沁左翼蒙古族自治县", + "211381": "北票市", + "211382": "凌源市" + }, + "211400": { + "211401": "市辖区", + "211402": "连山区", + "211403": "龙港区", + "211404": "南票区", + "211421": "绥中县", + "211422": "建昌县", + "211481": "兴城市" + }, + "220000": { + "220100": "长春市", + "220200": "吉林市", + "220300": "四平市", + "220400": "辽源市", + "220500": "通化市", + "220600": "白山市", + "220700": "松原市", + "220800": "白城市", + "222400": "延边朝鲜族自治州" + }, + "220100": { + "220101": "市辖区", + "220102": "南关区", + "220103": "宽城区", + "220104": "朝阳区", + "220105": "二道区", + "220106": "绿园区", + "220112": "双阳区", + "220113": "九台区", + "220122": "农安县", + "220171": "长春经济技术开发区", + "220172": "长春净月高新技术产业开发区", + "220173": "长春高新技术产业开发区", + "220174": "长春汽车经济技术开发区", + "220182": "榆树市", + "220183": "德惠市" + }, + "220200": { + "220201": "市辖区", + "220202": "昌邑区", + "220203": "龙潭区", + "220204": "船营区", + "220211": "丰满区", + "220221": "永吉县", + "220271": "吉林经济开发区", + "220272": "吉林高新技术产业开发区", + "220273": "吉林中国新加坡食品区", + "220281": "蛟河市", + "220282": "桦甸市", + "220283": "舒兰市", + "220284": "磐石市" + }, + "220300": { + "220301": "市辖区", + "220302": "铁西区", + "220303": "铁东区", + "220322": "梨树县", + "220323": "伊通满族自治县", + "220381": "公主岭市", + "220382": "双辽市" + }, + "220400": {"220401": "市辖区", "220402": "龙山区", "220403": "西安区", "220421": "东丰县", "220422": "东辽县"}, + "220500": { + "220501": "市辖区", + "220502": "东昌区", + "220503": "二道江区", + "220521": "通化县", + "220523": "辉南县", + "220524": "柳河县", + "220581": "梅河口市", + "220582": "集安市" + }, + "220600": { + "220601": "市辖区", + "220602": "浑江区", + "220605": "江源区", + "220621": "抚松县", + "220622": "靖宇县", + "220623": "长白朝鲜族自治县", + "220681": "临江市" + }, + "220700": { + "220701": "市辖区", + "220702": "宁江区", + "220721": "前郭尔罗斯蒙古族自治县", + "220722": "长岭县", + "220723": "乾安县", + "220771": "吉林松原经济开发区", + "220781": "扶余市" + }, + "220800": { + "220801": "市辖区", + "220802": "洮北区", + "220821": "镇赉县", + "220822": "通榆县", + "220871": "吉林白城经济开发区", + "220881": "洮南市", + "220882": "大安市" + }, + "222400": { + "222401": "延吉市", + "222402": "图们市", + "222403": "敦化市", + "222404": "珲春市", + "222405": "龙井市", + "222406": "和龙市", + "222424": "汪清县", + "222426": "安图县" + }, + "230000": { + "230100": "哈尔滨市", + "230200": "齐齐哈尔市", + "230300": "鸡西市", + "230400": "鹤岗市", + "230500": "双鸭山市", + "230600": "大庆市", + "230700": "伊春市", + "230800": "佳木斯市", + "230900": "七台河市", + "231000": "牡丹江市", + "231100": "黑河市", + "231200": "绥化市", + "232700": "大兴安岭地区" + }, + "230100": { + "230101": "市辖区", + "230102": "道里区", + "230103": "南岗区", + "230104": "道外区", + "230108": "平房区", + "230109": "松北区", + "230110": "香坊区", + "230111": "呼兰区", + "230112": "阿城区", + "230113": "双城区", + "230123": "依兰县", + "230124": "方正县", + "230125": "宾县", + "230126": "巴彦县", + "230127": "木兰县", + "230128": "通河县", + "230129": "延寿县", + "230183": "尚志市", + "230184": "五常市" + }, + "230200": { + "230201": "市辖区", + "230202": "龙沙区", + "230203": "建华区", + "230204": "铁锋区", + "230205": "昂昂溪区", + "230206": "富拉尔基区", + "230207": "碾子山区", + "230208": "梅里斯达斡尔族区", + "230221": "龙江县", + "230223": "依安县", + "230224": "泰来县", + "230225": "甘南县", + "230227": "富裕县", + "230229": "克山县", + "230230": "克东县", + "230231": "拜泉县", + "230281": "讷河市" + }, + "230300": { + "230301": "市辖区", + "230302": "鸡冠区", + "230303": "恒山区", + "230304": "滴道区", + "230305": "梨树区", + "230306": "城子河区", + "230307": "麻山区", + "230321": "鸡东县", + "230381": "虎林市", + "230382": "密山市" + }, + "230400": { + "230401": "市辖区", + "230402": "向阳区", + "230403": "工农区", + "230404": "南山区", + "230405": "兴安区", + "230406": "东山区", + "230407": "兴山区", + "230421": "萝北县", + "230422": "绥滨县" + }, + "230500": { + "230501": "市辖区", + "230502": "尖山区", + "230503": "岭东区", + "230505": "四方台区", + "230506": "宝山区", + "230521": "集贤县", + "230522": "友谊县", + "230523": "宝清县", + "230524": "饶河县" + }, + "230600": { + "230601": "市辖区", + "230602": "萨尔图区", + "230603": "龙凤区", + "230604": "让胡路区", + "230605": "红岗区", + "230606": "大同区", + "230621": "肇州县", + "230622": "肇源县", + "230623": "林甸县", + "230624": "杜尔伯特蒙古族自治县", + "230671": "大庆高新技术产业开发区" + }, + "230700": { + "230701": "市辖区", + "230717": "伊美区", + "230718": "乌翠区", + "230719": "友好区", + "230722": "嘉荫县", + "230723": "汤旺县", + "230724": "丰林县", + "230725": "大箐山县", + "230726": "南岔县", + "230751": "金林区", + "230781": "铁力市" + }, + "230800": { + "230801": "市辖区", + "230803": "向阳区", + "230804": "前进区", + "230805": "东风区", + "230811": "郊区", + "230822": "桦南县", + "230826": "桦川县", + "230828": "汤原县", + "230881": "同江市", + "230882": "富锦市", + "230883": "抚远市" + }, + "230900": {"230901": "市辖区", "230902": "新兴区", "230903": "桃山区", "230904": "茄子河区", "230921": "勃利县"}, + "231000": { + "231001": "市辖区", + "231002": "东安区", + "231003": "阳明区", + "231004": "爱民区", + "231005": "西安区", + "231025": "林口县", + "231071": "牡丹江经济技术开发区", + "231081": "绥芬河市", + "231083": "海林市", + "231084": "宁安市", + "231085": "穆棱市", + "231086": "东宁市" + }, + "231100": { + "231101": "市辖区", + "231102": "爱辉区", + "231123": "逊克县", + "231124": "孙吴县", + "231181": "北安市", + "231182": "五大连池市", + "231183": "嫩江市" + }, + "231200": { + "231201": "市辖区", + "231202": "北林区", + "231221": "望奎县", + "231222": "兰西县", + "231223": "青冈县", + "231224": "庆安县", + "231225": "明水县", + "231226": "绥棱县", + "231281": "安达市", + "231282": "肇东市", + "231283": "海伦市" + }, + "232700": { + "232701": "漠河市", + "232721": "呼玛县", + "232722": "塔河县", + "232761": "加格达奇区", + "232762": "松岭区", + "232763": "新林区", + "232764": "呼中区" + }, + "310000": {"310100": "市辖区"}, + "310100": { + "310101": "黄浦区", + "310104": "徐汇区", + "310105": "长宁区", + "310106": "静安区", + "310107": "普陀区", + "310109": "虹口区", + "310110": "杨浦区", + "310112": "闵行区", + "310113": "宝山区", + "310114": "嘉定区", + "310115": "浦东新区", + "310116": "金山区", + "310117": "松江区", + "310118": "青浦区", + "310120": "奉贤区", + "310151": "崇明区" + }, + "320000": { + "320100": "南京市", + "320200": "无锡市", + "320300": "徐州市", + "320400": "常州市", + "320500": "苏州市", + "320600": "南通市", + "320700": "连云港市", + "320800": "淮安市", + "320900": "盐城市", + "321000": "扬州市", + "321100": "镇江市", + "321200": "泰州市", + "321300": "宿迁市" + }, + "320100": { + "320101": "市辖区", + "320102": "玄武区", + "320104": "秦淮区", + "320105": "建邺区", + "320106": "鼓楼区", + "320111": "浦口区", + "320113": "栖霞区", + "320114": "雨花台区", + "320115": "江宁区", + "320116": "六合区", + "320117": "溧水区", + "320118": "高淳区" + }, + "320200": { + "320201": "市辖区", + "320205": "锡山区", + "320206": "惠山区", + "320211": "滨湖区", + "320213": "梁溪区", + "320214": "新吴区", + "320281": "江阴市", + "320282": "宜兴市" + }, + "320300": { + "320301": "市辖区", + "320302": "鼓楼区", + "320303": "云龙区", + "320305": "贾汪区", + "320311": "泉山区", + "320312": "铜山区", + "320321": "丰县", + "320322": "沛县", + "320324": "睢宁县", + "320371": "徐州经济技术开发区", + "320381": "新沂市", + "320382": "邳州市" + }, + "320400": { + "320401": "市辖区", + "320402": "天宁区", + "320404": "钟楼区", + "320411": "新北区", + "320412": "武进区", + "320413": "金坛区", + "320481": "溧阳市" + }, + "320500": { + "320501": "市辖区", + "320505": "虎丘区", + "320506": "吴中区", + "320507": "相城区", + "320508": "姑苏区", + "320509": "吴江区", + "320571": "苏州工业园区", + "320581": "常熟市", + "320582": "张家港市", + "320583": "昆山市", + "320585": "太仓市" + }, + "320600": { + "320601": "市辖区", + "320602": "崇川区", + "320611": "港闸区", + "320612": "通州区", + "320623": "如东县", + "320671": "南通经济技术开发区", + "320681": "启东市", + "320682": "如皋市", + "320684": "海门市", + "320685": "海安市" + }, + "320700": { + "320701": "市辖区", + "320703": "连云区", + "320706": "海州区", + "320707": "赣榆区", + "320722": "东海县", + "320723": "灌云县", + "320724": "灌南县", + "320771": "连云港经济技术开发区", + "320772": "连云港高新技术产业开发区" + }, + "320800": { + "320801": "市辖区", + "320803": "淮安区", + "320804": "淮阴区", + "320812": "清江浦区", + "320813": "洪泽区", + "320826": "涟水县", + "320830": "盱眙县", + "320831": "金湖县", + "320871": "淮安经济技术开发区" + }, + "320900": { + "320901": "市辖区", + "320902": "亭湖区", + "320903": "盐都区", + "320904": "大丰区", + "320921": "响水县", + "320922": "滨海县", + "320923": "阜宁县", + "320924": "射阳县", + "320925": "建湖县", + "320971": "盐城经济技术开发区", + "320981": "东台市" + }, + "321000": { + "321001": "市辖区", + "321002": "广陵区", + "321003": "邗江区", + "321012": "江都区", + "321023": "宝应县", + "321071": "扬州经济技术开发区", + "321081": "仪征市", + "321084": "高邮市" + }, + "321100": { + "321101": "市辖区", + "321102": "京口区", + "321111": "润州区", + "321112": "丹徒区", + "321171": "镇江新区", + "321181": "丹阳市", + "321182": "扬中市", + "321183": "句容市" + }, + "321200": { + "321201": "市辖区", + "321202": "海陵区", + "321203": "高港区", + "321204": "姜堰区", + "321271": "泰州医药高新技术产业开发区", + "321281": "兴化市", + "321282": "靖江市", + "321283": "泰兴市" + }, + "321300": { + "321301": "市辖区", + "321302": "宿城区", + "321311": "宿豫区", + "321322": "沭阳县", + "321323": "泗阳县", + "321324": "泗洪县", + "321371": "宿迁经济技术开发区" + }, + "330000": { + "330100": "杭州市", + "330200": "宁波市", + "330300": "温州市", + "330400": "嘉兴市", + "330500": "湖州市", + "330600": "绍兴市", + "330700": "金华市", + "330800": "衢州市", + "330900": "舟山市", + "331000": "台州市", + "331100": "丽水市" + }, + "330100": { + "330101": "市辖区", + "330102": "上城区", + "330103": "下城区", + "330104": "江干区", + "330105": "拱墅区", + "330106": "西湖区", + "330108": "滨江区", + "330109": "萧山区", + "330110": "余杭区", + "330111": "富阳区", + "330112": "临安区", + "330122": "桐庐县", + "330127": "淳安县", + "330182": "建德市" + }, + "330200": { + "330201": "市辖区", + "330203": "海曙区", + "330205": "江北区", + "330206": "北仑区", + "330211": "镇海区", + "330212": "鄞州区", + "330213": "奉化区", + "330225": "象山县", + "330226": "宁海县", + "330281": "余姚市", + "330282": "慈溪市" + }, + "330300": { + "330301": "市辖区", + "330302": "鹿城区", + "330303": "龙湾区", + "330304": "瓯海区", + "330305": "洞头区", + "330324": "永嘉县", + "330326": "平阳县", + "330327": "苍南县", + "330328": "文成县", + "330329": "泰顺县", + "330371": "温州经济技术开发区", + "330381": "瑞安市", + "330382": "乐清市", + "330383": "龙港市" + }, + "330400": { + "330401": "市辖区", + "330402": "南湖区", + "330411": "秀洲区", + "330421": "嘉善县", + "330424": "海盐县", + "330481": "海宁市", + "330482": "平湖市", + "330483": "桐乡市" + }, + "330500": {"330501": "市辖区", "330502": "吴兴区", "330503": "南浔区", "330521": "德清县", "330522": "长兴县", "330523": "安吉县"}, + "330600": { + "330601": "市辖区", + "330602": "越城区", + "330603": "柯桥区", + "330604": "上虞区", + "330624": "新昌县", + "330681": "诸暨市", + "330683": "嵊州市" + }, + "330700": { + "330701": "市辖区", + "330702": "婺城区", + "330703": "金东区", + "330723": "武义县", + "330726": "浦江县", + "330727": "磐安县", + "330781": "兰溪市", + "330782": "义乌市", + "330783": "东阳市", + "330784": "永康市" + }, + "330800": { + "330801": "市辖区", + "330802": "柯城区", + "330803": "衢江区", + "330822": "常山县", + "330824": "开化县", + "330825": "龙游县", + "330881": "江山市" + }, + "330900": {"330901": "市辖区", "330902": "定海区", "330903": "普陀区", "330921": "岱山县", "330922": "嵊泗县"}, + "331000": { + "331001": "市辖区", + "331002": "椒江区", + "331003": "黄岩区", + "331004": "路桥区", + "331022": "三门县", + "331023": "天台县", + "331024": "仙居县", + "331081": "温岭市", + "331082": "临海市", + "331083": "玉环市" + }, + "331100": { + "331101": "市辖区", + "331102": "莲都区", + "331121": "青田县", + "331122": "缙云县", + "331123": "遂昌县", + "331124": "松阳县", + "331125": "云和县", + "331126": "庆元县", + "331127": "景宁畲族自治县", + "331181": "龙泉市" + }, + "340000": { + "340100": "合肥市", + "340200": "芜湖市", + "340300": "蚌埠市", + "340400": "淮南市", + "340500": "马鞍山市", + "340600": "淮北市", + "340700": "铜陵市", + "340800": "安庆市", + "341000": "黄山市", + "341100": "滁州市", + "341200": "阜阳市", + "341300": "宿州市", + "341500": "六安市", + "341600": "亳州市", + "341700": "池州市", + "341800": "宣城市" + }, + "340100": { + "340101": "市辖区", + "340102": "瑶海区", + "340103": "庐阳区", + "340104": "蜀山区", + "340111": "包河区", + "340121": "长丰县", + "340122": "肥东县", + "340123": "肥西县", + "340124": "庐江县", + "340171": "合肥高新技术产业开发区", + "340172": "合肥经济技术开发区", + "340173": "合肥新站高新技术产业开发区", + "340181": "巢湖市" + }, + "340200": { + "340201": "市辖区", + "340202": "镜湖区", + "340203": "弋江区", + "340207": "鸠江区", + "340208": "三山区", + "340221": "芜湖县", + "340222": "繁昌县", + "340223": "南陵县", + "340225": "无为县", + "340271": "芜湖经济技术开发区", + "340272": "安徽芜湖长江大桥经济开发区" + }, + "340300": { + "340301": "市辖区", + "340302": "龙子湖区", + "340303": "蚌山区", + "340304": "禹会区", + "340311": "淮上区", + "340321": "怀远县", + "340322": "五河县", + "340323": "固镇县", + "340371": "蚌埠市高新技术开发区", + "340372": "蚌埠市经济开发区" + }, + "340400": { + "340401": "市辖区", + "340402": "大通区", + "340403": "田家庵区", + "340404": "谢家集区", + "340405": "八公山区", + "340406": "潘集区", + "340421": "凤台县", + "340422": "寿县" + }, + "340500": { + "340501": "市辖区", + "340503": "花山区", + "340504": "雨山区", + "340506": "博望区", + "340521": "当涂县", + "340522": "含山县", + "340523": "和县" + }, + "340600": {"340601": "市辖区", "340602": "杜集区", "340603": "相山区", "340604": "烈山区", "340621": "濉溪县"}, + "340700": {"340701": "市辖区", "340705": "铜官区", "340706": "义安区", "340711": "郊区", "340722": "枞阳县"}, + "340800": { + "340801": "市辖区", + "340802": "迎江区", + "340803": "大观区", + "340811": "宜秀区", + "340822": "怀宁县", + "340825": "太湖县", + "340826": "宿松县", + "340827": "望江县", + "340828": "岳西县", + "340871": "安徽安庆经济开发区", + "340881": "桐城市", + "340882": "潜山市" + }, + "341000": { + "341001": "市辖区", + "341002": "屯溪区", + "341003": "黄山区", + "341004": "徽州区", + "341021": "歙县", + "341022": "休宁县", + "341023": "黟县", + "341024": "祁门县" + }, + "341100": { + "341101": "市辖区", + "341102": "琅琊区", + "341103": "南谯区", + "341122": "来安县", + "341124": "全椒县", + "341125": "定远县", + "341126": "凤阳县", + "341171": "苏滁现代产业园", + "341172": "滁州经济技术开发区", + "341181": "天长市", + "341182": "明光市" + }, + "341200": { + "341201": "市辖区", + "341202": "颍州区", + "341203": "颍东区", + "341204": "颍泉区", + "341221": "临泉县", + "341222": "太和县", + "341225": "阜南县", + "341226": "颍上县", + "341271": "阜阳合肥现代产业园区", + "341272": "阜阳经济技术开发区", + "341282": "界首市" + }, + "341300": { + "341301": "市辖区", + "341302": "埇桥区", + "341321": "砀山县", + "341322": "萧县", + "341323": "灵璧县", + "341324": "泗县", + "341371": "宿州马鞍山现代产业园区", + "341372": "宿州经济技术开发区" + }, + "341500": { + "341501": "市辖区", + "341502": "金安区", + "341503": "裕安区", + "341504": "叶集区", + "341522": "霍邱县", + "341523": "舒城县", + "341524": "金寨县", + "341525": "霍山县" + }, + "341600": {"341601": "市辖区", "341602": "谯城区", "341621": "涡阳县", "341622": "蒙城县", "341623": "利辛县"}, + "341700": {"341701": "市辖区", "341702": "贵池区", "341721": "东至县", "341722": "石台县", "341723": "青阳县"}, + "341800": { + "341801": "市辖区", + "341802": "宣州区", + "341821": "郎溪县", + "341823": "泾县", + "341824": "绩溪县", + "341825": "旌德县", + "341871": "宣城市经济开发区", + "341881": "宁国市", + "341882": "广德市" + }, + "350000": { + "350100": "福州市", + "350200": "厦门市", + "350300": "莆田市", + "350400": "三明市", + "350500": "泉州市", + "350600": "漳州市", + "350700": "南平市", + "350800": "龙岩市", + "350900": "宁德市" + }, + "350100": { + "350101": "市辖区", + "350102": "鼓楼区", + "350103": "台江区", + "350104": "仓山区", + "350105": "马尾区", + "350111": "晋安区", + "350112": "长乐区", + "350121": "闽侯县", + "350122": "连江县", + "350123": "罗源县", + "350124": "闽清县", + "350125": "永泰县", + "350128": "平潭县", + "350181": "福清市" + }, + "350200": { + "350201": "市辖区", + "350203": "思明区", + "350205": "海沧区", + "350206": "湖里区", + "350211": "集美区", + "350212": "同安区", + "350213": "翔安区" + }, + "350300": {"350301": "市辖区", "350302": "城厢区", "350303": "涵江区", "350304": "荔城区", "350305": "秀屿区", "350322": "仙游县"}, + "350400": { + "350401": "市辖区", + "350402": "梅列区", + "350403": "三元区", + "350421": "明溪县", + "350423": "清流县", + "350424": "宁化县", + "350425": "大田县", + "350426": "尤溪县", + "350427": "沙县", + "350428": "将乐县", + "350429": "泰宁县", + "350430": "建宁县", + "350481": "永安市" + }, + "350500": { + "350501": "市辖区", + "350502": "鲤城区", + "350503": "丰泽区", + "350504": "洛江区", + "350505": "泉港区", + "350521": "惠安县", + "350524": "安溪县", + "350525": "永春县", + "350526": "德化县", + "350527": "金门县", + "350581": "石狮市", + "350582": "晋江市", + "350583": "南安市" + }, + "350600": { + "350601": "市辖区", + "350602": "芗城区", + "350603": "龙文区", + "350622": "云霄县", + "350623": "漳浦县", + "350624": "诏安县", + "350625": "长泰县", + "350626": "东山县", + "350627": "南靖县", + "350628": "平和县", + "350629": "华安县", + "350681": "龙海市" + }, + "350700": { + "350701": "市辖区", + "350702": "延平区", + "350703": "建阳区", + "350721": "顺昌县", + "350722": "浦城县", + "350723": "光泽县", + "350724": "松溪县", + "350725": "政和县", + "350781": "邵武市", + "350782": "武夷山市", + "350783": "建瓯市" + }, + "350800": { + "350801": "市辖区", + "350802": "新罗区", + "350803": "永定区", + "350821": "长汀县", + "350823": "上杭县", + "350824": "武平县", + "350825": "连城县", + "350881": "漳平市" + }, + "350900": { + "350901": "市辖区", + "350902": "蕉城区", + "350921": "霞浦县", + "350922": "古田县", + "350923": "屏南县", + "350924": "寿宁县", + "350925": "周宁县", + "350926": "柘荣县", + "350981": "福安市", + "350982": "福鼎市" + }, + "360000": { + "360100": "南昌市", + "360200": "景德镇市", + "360300": "萍乡市", + "360400": "九江市", + "360500": "新余市", + "360600": "鹰潭市", + "360700": "赣州市", + "360800": "吉安市", + "360900": "宜春市", + "361000": "抚州市", + "361100": "上饶市" + }, + "360100": { + "360101": "市辖区", + "360102": "东湖区", + "360103": "西湖区", + "360104": "青云谱区", + "360105": "湾里区", + "360111": "青山湖区", + "360112": "新建区", + "360121": "南昌县", + "360123": "安义县", + "360124": "进贤县" + }, + "360200": {"360201": "市辖区", "360202": "昌江区", "360203": "珠山区", "360222": "浮梁县", "360281": "乐平市"}, + "360300": {"360301": "市辖区", "360302": "安源区", "360313": "湘东区", "360321": "莲花县", "360322": "上栗县", "360323": "芦溪县"}, + "360400": { + "360401": "市辖区", + "360402": "濂溪区", + "360403": "浔阳区", + "360404": "柴桑区", + "360423": "武宁县", + "360424": "修水县", + "360425": "永修县", + "360426": "德安县", + "360428": "都昌县", + "360429": "湖口县", + "360430": "彭泽县", + "360481": "瑞昌市", + "360482": "共青城市", + "360483": "庐山市" + }, + "360500": {"360501": "市辖区", "360502": "渝水区", "360521": "分宜县"}, + "360600": {"360601": "市辖区", "360602": "月湖区", "360603": "余江区", "360681": "贵溪市"}, + "360700": { + "360701": "市辖区", + "360702": "章贡区", + "360703": "南康区", + "360704": "赣县区", + "360722": "信丰县", + "360723": "大余县", + "360724": "上犹县", + "360725": "崇义县", + "360726": "安远县", + "360727": "龙南县", + "360728": "定南县", + "360729": "全南县", + "360730": "宁都县", + "360731": "于都县", + "360732": "兴国县", + "360733": "会昌县", + "360734": "寻乌县", + "360735": "石城县", + "360781": "瑞金市" + }, + "360800": { + "360801": "市辖区", + "360802": "吉州区", + "360803": "青原区", + "360821": "吉安县", + "360822": "吉水县", + "360823": "峡江县", + "360824": "新干县", + "360825": "永丰县", + "360826": "泰和县", + "360827": "遂川县", + "360828": "万安县", + "360829": "安福县", + "360830": "永新县", + "360881": "井冈山市" + }, + "360900": { + "360901": "市辖区", + "360902": "袁州区", + "360921": "奉新县", + "360922": "万载县", + "360923": "上高县", + "360924": "宜丰县", + "360925": "靖安县", + "360926": "铜鼓县", + "360981": "丰城市", + "360982": "樟树市", + "360983": "高安市" + }, + "361000": { + "361001": "市辖区", + "361002": "临川区", + "361003": "东乡区", + "361021": "南城县", + "361022": "黎川县", + "361023": "南丰县", + "361024": "崇仁县", + "361025": "乐安县", + "361026": "宜黄县", + "361027": "金溪县", + "361028": "资溪县", + "361030": "广昌县" + }, + "361100": { + "361101": "市辖区", + "361102": "信州区", + "361103": "广丰区", + "361104": "广信区", + "361123": "玉山县", + "361124": "铅山县", + "361125": "横峰县", + "361126": "弋阳县", + "361127": "余干县", + "361128": "鄱阳县", + "361129": "万年县", + "361130": "婺源县", + "361181": "德兴市" + }, + "370000": { + "370100": "济南市", + "370200": "青岛市", + "370300": "淄博市", + "370400": "枣庄市", + "370500": "东营市", + "370600": "烟台市", + "370700": "潍坊市", + "370800": "济宁市", + "370900": "泰安市", + "371000": "威海市", + "371100": "日照市", + "371300": "临沂市", + "371400": "德州市", + "371500": "聊城市", + "371600": "滨州市", + "371700": "菏泽市" + }, + "370100": { + "370101": "市辖区", + "370102": "历下区", + "370103": "市中区", + "370104": "槐荫区", + "370105": "天桥区", + "370112": "历城区", + "370113": "长清区", + "370114": "章丘区", + "370115": "济阳区", + "370116": "莱芜区", + "370117": "钢城区", + "370124": "平阴县", + "370126": "商河县", + "370171": "济南高新技术产业开发区" + }, + "370200": { + "370201": "市辖区", + "370202": "市南区", + "370203": "市北区", + "370211": "黄岛区", + "370212": "崂山区", + "370213": "李沧区", + "370214": "城阳区", + "370215": "即墨区", + "370271": "青岛高新技术产业开发区", + "370281": "胶州市", + "370283": "平度市", + "370285": "莱西市" + }, + "370300": { + "370301": "市辖区", + "370302": "淄川区", + "370303": "张店区", + "370304": "博山区", + "370305": "临淄区", + "370306": "周村区", + "370321": "桓台县", + "370322": "高青县", + "370323": "沂源县" + }, + "370400": { + "370401": "市辖区", + "370402": "市中区", + "370403": "薛城区", + "370404": "峄城区", + "370405": "台儿庄区", + "370406": "山亭区", + "370481": "滕州市" + }, + "370500": { + "370501": "市辖区", + "370502": "东营区", + "370503": "河口区", + "370505": "垦利区", + "370522": "利津县", + "370523": "广饶县", + "370571": "东营经济技术开发区", + "370572": "东营港经济开发区" + }, + "370600": { + "370601": "市辖区", + "370602": "芝罘区", + "370611": "福山区", + "370612": "牟平区", + "370613": "莱山区", + "370634": "长岛县", + "370671": "烟台高新技术产业开发区", + "370672": "烟台经济技术开发区", + "370681": "龙口市", + "370682": "莱阳市", + "370683": "莱州市", + "370684": "蓬莱市", + "370685": "招远市", + "370686": "栖霞市", + "370687": "海阳市" + }, + "370700": { + "370701": "市辖区", + "370702": "潍城区", + "370703": "寒亭区", + "370704": "坊子区", + "370705": "奎文区", + "370724": "临朐县", + "370725": "昌乐县", + "370772": "潍坊滨海经济技术开发区", + "370781": "青州市", + "370782": "诸城市", + "370783": "寿光市", + "370784": "安丘市", + "370785": "高密市", + "370786": "昌邑市" + }, + "370800": { + "370801": "市辖区", + "370811": "任城区", + "370812": "兖州区", + "370826": "微山县", + "370827": "鱼台县", + "370828": "金乡县", + "370829": "嘉祥县", + "370830": "汶上县", + "370831": "泗水县", + "370832": "梁山县", + "370871": "济宁高新技术产业开发区", + "370881": "曲阜市", + "370883": "邹城市" + }, + "370900": { + "370901": "市辖区", + "370902": "泰山区", + "370911": "岱岳区", + "370921": "宁阳县", + "370923": "东平县", + "370982": "新泰市", + "370983": "肥城市" + }, + "371000": { + "371001": "市辖区", + "371002": "环翠区", + "371003": "文登区", + "371071": "威海火炬高技术产业开发区", + "371072": "威海经济技术开发区", + "371073": "威海临港经济技术开发区", + "371082": "荣成市", + "371083": "乳山市" + }, + "371100": {"371101": "市辖区", "371102": "东港区", "371103": "岚山区", "371121": "五莲县", "371122": "莒县", "371171": "日照经济技术开发区"}, + "371300": { + "371301": "市辖区", + "371302": "兰山区", + "371311": "罗庄区", + "371312": "河东区", + "371321": "沂南县", + "371322": "郯城县", + "371323": "沂水县", + "371324": "兰陵县", + "371325": "费县", + "371326": "平邑县", + "371327": "莒南县", + "371328": "蒙阴县", + "371329": "临沭县", + "371371": "临沂高新技术产业开发区", + "371372": "临沂经济技术开发区", + "371373": "临沂临港经济开发区" + }, + "371400": { + "371401": "市辖区", + "371402": "德城区", + "371403": "陵城区", + "371422": "宁津县", + "371423": "庆云县", + "371424": "临邑县", + "371425": "齐河县", + "371426": "平原县", + "371427": "夏津县", + "371428": "武城县", + "371471": "德州经济技术开发区", + "371472": "德州运河经济开发区", + "371481": "乐陵市", + "371482": "禹城市" + }, + "371500": { + "371501": "市辖区", + "371502": "东昌府区", + "371503": "茌平区", + "371521": "阳谷县", + "371522": "莘县", + "371524": "东阿县", + "371525": "冠县", + "371526": "高唐县", + "371581": "临清市" + }, + "371600": { + "371601": "市辖区", + "371602": "滨城区", + "371603": "沾化区", + "371621": "惠民县", + "371622": "阳信县", + "371623": "无棣县", + "371625": "博兴县", + "371681": "邹平市" + }, + "371700": { + "371701": "市辖区", + "371702": "牡丹区", + "371703": "定陶区", + "371721": "曹县", + "371722": "单县", + "371723": "成武县", + "371724": "巨野县", + "371725": "郓城县", + "371726": "鄄城县", + "371728": "东明县", + "371771": "菏泽经济技术开发区", + "371772": "菏泽高新技术开发区" + }, + "410000": { + "410100": "郑州市", + "410200": "开封市", + "410300": "洛阳市", + "410400": "平顶山市", + "410500": "安阳市", + "410600": "鹤壁市", + "410700": "新乡市", + "410800": "焦作市", + "410900": "濮阳市", + "411000": "许昌市", + "411100": "漯河市", + "411200": "三门峡市", + "411300": "南阳市", + "411400": "商丘市", + "411500": "信阳市", + "411600": "周口市", + "411700": "驻马店市", + "419000": "省直辖县级行政区划" + }, + "410100": { + "410101": "市辖区", + "410102": "中原区", + "410103": "二七区", + "410104": "管城回族区", + "410105": "金水区", + "410106": "上街区", + "410108": "惠济区", + "410122": "中牟县", + "410171": "郑州经济技术开发区", + "410172": "郑州高新技术产业开发区", + "410173": "郑州航空港经济综合实验区", + "410181": "巩义市", + "410182": "荥阳市", + "410183": "新密市", + "410184": "新郑市", + "410185": "登封市" + }, + "410200": { + "410201": "市辖区", + "410202": "龙亭区", + "410203": "顺河回族区", + "410204": "鼓楼区", + "410205": "禹王台区", + "410212": "祥符区", + "410221": "杞县", + "410222": "通许县", + "410223": "尉氏县", + "410225": "兰考县" + }, + "410300": { + "410301": "市辖区", + "410302": "老城区", + "410303": "西工区", + "410304": "瀍河回族区", + "410305": "涧西区", + "410306": "吉利区", + "410311": "洛龙区", + "410322": "孟津县", + "410323": "新安县", + "410324": "栾川县", + "410325": "嵩县", + "410326": "汝阳县", + "410327": "宜阳县", + "410328": "洛宁县", + "410329": "伊川县", + "410371": "洛阳高新技术产业开发区", + "410381": "偃师市" + }, + "410400": { + "410401": "市辖区", + "410402": "新华区", + "410403": "卫东区", + "410404": "石龙区", + "410411": "湛河区", + "410421": "宝丰县", + "410422": "叶县", + "410423": "鲁山县", + "410425": "郏县", + "410471": "平顶山高新技术产业开发区", + "410472": "平顶山市城乡一体化示范区", + "410481": "舞钢市", + "410482": "汝州市" + }, + "410500": { + "410501": "市辖区", + "410502": "文峰区", + "410503": "北关区", + "410505": "殷都区", + "410506": "龙安区", + "410522": "安阳县", + "410523": "汤阴县", + "410526": "滑县", + "410527": "内黄县", + "410571": "安阳高新技术产业开发区", + "410581": "林州市" + }, + "410600": { + "410601": "市辖区", + "410602": "鹤山区", + "410603": "山城区", + "410611": "淇滨区", + "410621": "浚县", + "410622": "淇县", + "410671": "鹤壁经济技术开发区" + }, + "410700": { + "410701": "市辖区", + "410702": "红旗区", + "410703": "卫滨区", + "410704": "凤泉区", + "410711": "牧野区", + "410721": "新乡县", + "410724": "获嘉县", + "410725": "原阳县", + "410726": "延津县", + "410727": "封丘县", + "410771": "新乡高新技术产业开发区", + "410772": "新乡经济技术开发区", + "410773": "新乡市平原城乡一体化示范区", + "410781": "卫辉市", + "410782": "辉县市", + "410783": "长垣市" + }, + "410800": { + "410801": "市辖区", + "410802": "解放区", + "410803": "中站区", + "410804": "马村区", + "410811": "山阳区", + "410821": "修武县", + "410822": "博爱县", + "410823": "武陟县", + "410825": "温县", + "410871": "焦作城乡一体化示范区", + "410882": "沁阳市", + "410883": "孟州市" + }, + "410900": { + "410901": "市辖区", + "410902": "华龙区", + "410922": "清丰县", + "410923": "南乐县", + "410926": "范县", + "410927": "台前县", + "410928": "濮阳县", + "410971": "河南濮阳工业园区", + "410972": "濮阳经济技术开发区" + }, + "411000": { + "411001": "市辖区", + "411002": "魏都区", + "411003": "建安区", + "411024": "鄢陵县", + "411025": "襄城县", + "411071": "许昌经济技术开发区", + "411081": "禹州市", + "411082": "长葛市" + }, + "411100": { + "411101": "市辖区", + "411102": "源汇区", + "411103": "郾城区", + "411104": "召陵区", + "411121": "舞阳县", + "411122": "临颍县", + "411171": "漯河经济技术开发区" + }, + "411200": { + "411201": "市辖区", + "411202": "湖滨区", + "411203": "陕州区", + "411221": "渑池县", + "411224": "卢氏县", + "411271": "河南三门峡经济开发区", + "411281": "义马市", + "411282": "灵宝市" + }, + "411300": { + "411301": "市辖区", + "411302": "宛城区", + "411303": "卧龙区", + "411321": "南召县", + "411322": "方城县", + "411323": "西峡县", + "411324": "镇平县", + "411325": "内乡县", + "411326": "淅川县", + "411327": "社旗县", + "411328": "唐河县", + "411329": "新野县", + "411330": "桐柏县", + "411371": "南阳高新技术产业开发区", + "411372": "南阳市城乡一体化示范区", + "411381": "邓州市" + }, + "411400": { + "411401": "市辖区", + "411402": "梁园区", + "411403": "睢阳区", + "411421": "民权县", + "411422": "睢县", + "411423": "宁陵县", + "411424": "柘城县", + "411425": "虞城县", + "411426": "夏邑县", + "411471": "豫东综合物流产业聚集区", + "411472": "河南商丘经济开发区", + "411481": "永城市" + }, + "411500": { + "411501": "市辖区", + "411502": "浉河区", + "411503": "平桥区", + "411521": "罗山县", + "411522": "光山县", + "411523": "新县", + "411524": "商城县", + "411525": "固始县", + "411526": "潢川县", + "411527": "淮滨县", + "411528": "息县", + "411571": "信阳高新技术产业开发区" + }, + "411600": { + "411601": "市辖区", + "411602": "川汇区", + "411603": "淮阳区", + "411621": "扶沟县", + "411622": "西华县", + "411623": "商水县", + "411624": "沈丘县", + "411625": "郸城县", + "411627": "太康县", + "411628": "鹿邑县", + "411671": "河南周口经济开发区", + "411681": "项城市" + }, + "411700": { + "411701": "市辖区", + "411702": "驿城区", + "411721": "西平县", + "411722": "上蔡县", + "411723": "平舆县", + "411724": "正阳县", + "411725": "确山县", + "411726": "泌阳县", + "411727": "汝南县", + "411728": "遂平县", + "411729": "新蔡县", + "411771": "河南驻马店经济开发区" + }, + "419000": {"419001": "济源市"}, + "420000": { + "420100": "武汉市", + "420200": "黄石市", + "420300": "十堰市", + "420500": "宜昌市", + "420600": "襄阳市", + "420700": "鄂州市", + "420800": "荆门市", + "420900": "孝感市", + "421000": "荆州市", + "421100": "黄冈市", + "421200": "咸宁市", + "421300": "随州市", + "422800": "恩施土家族苗族自治州", + "429000": "省直辖县级行政区划" + }, + "420100": { + "420101": "市辖区", + "420102": "江岸区", + "420103": "江汉区", + "420104": "硚口区", + "420105": "汉阳区", + "420106": "武昌区", + "420107": "青山区", + "420111": "洪山区", + "420112": "东西湖区", + "420113": "汉南区", + "420114": "蔡甸区", + "420115": "江夏区", + "420116": "黄陂区", + "420117": "新洲区" + }, + "420200": { + "420201": "市辖区", + "420202": "黄石港区", + "420203": "西塞山区", + "420204": "下陆区", + "420205": "铁山区", + "420222": "阳新县", + "420281": "大冶市" + }, + "420300": { + "420301": "市辖区", + "420302": "茅箭区", + "420303": "张湾区", + "420304": "郧阳区", + "420322": "郧西县", + "420323": "竹山县", + "420324": "竹溪县", + "420325": "房县", + "420381": "丹江口市" + }, + "420500": { + "420501": "市辖区", + "420502": "西陵区", + "420503": "伍家岗区", + "420504": "点军区", + "420505": "猇亭区", + "420506": "夷陵区", + "420525": "远安县", + "420526": "兴山县", + "420527": "秭归县", + "420528": "长阳土家族自治县", + "420529": "五峰土家族自治县", + "420581": "宜都市", + "420582": "当阳市", + "420583": "枝江市" + }, + "420600": { + "420601": "市辖区", + "420602": "襄城区", + "420606": "樊城区", + "420607": "襄州区", + "420624": "南漳县", + "420625": "谷城县", + "420626": "保康县", + "420682": "老河口市", + "420683": "枣阳市", + "420684": "宜城市" + }, + "420700": {"420701": "市辖区", "420702": "梁子湖区", "420703": "华容区", "420704": "鄂城区"}, + "420800": {"420801": "市辖区", "420802": "东宝区", "420804": "掇刀区", "420822": "沙洋县", "420881": "钟祥市", "420882": "京山市"}, + "420900": { + "420901": "市辖区", + "420902": "孝南区", + "420921": "孝昌县", + "420922": "大悟县", + "420923": "云梦县", + "420981": "应城市", + "420982": "安陆市", + "420984": "汉川市" + }, + "421000": { + "421001": "市辖区", + "421002": "沙市区", + "421003": "荆州区", + "421022": "公安县", + "421023": "监利县", + "421024": "江陵县", + "421071": "荆州经济技术开发区", + "421081": "石首市", + "421083": "洪湖市", + "421087": "松滋市" + }, + "421100": { + "421101": "市辖区", + "421102": "黄州区", + "421121": "团风县", + "421122": "红安县", + "421123": "罗田县", + "421124": "英山县", + "421125": "浠水县", + "421126": "蕲春县", + "421127": "黄梅县", + "421171": "龙感湖管理区", + "421181": "麻城市", + "421182": "武穴市" + }, + "421200": { + "421201": "市辖区", + "421202": "咸安区", + "421221": "嘉鱼县", + "421222": "通城县", + "421223": "崇阳县", + "421224": "通山县", + "421281": "赤壁市" + }, + "421300": {"421301": "市辖区", "421303": "曾都区", "421321": "随县", "421381": "广水市"}, + "422800": { + "422801": "恩施市", + "422802": "利川市", + "422822": "建始县", + "422823": "巴东县", + "422825": "宣恩县", + "422826": "咸丰县", + "422827": "来凤县", + "422828": "鹤峰县" + }, + "429000": {"429004": "仙桃市", "429005": "潜江市", "429006": "天门市", "429021": "神农架林区"}, + "430000": { + "430100": "长沙市", + "430200": "株洲市", + "430300": "湘潭市", + "430400": "衡阳市", + "430500": "邵阳市", + "430600": "岳阳市", + "430700": "常德市", + "430800": "张家界市", + "430900": "益阳市", + "431000": "郴州市", + "431100": "永州市", + "431200": "怀化市", + "431300": "娄底市", + "433100": "湘西土家族苗族自治州" + }, + "430100": { + "430101": "市辖区", + "430102": "芙蓉区", + "430103": "天心区", + "430104": "岳麓区", + "430105": "开福区", + "430111": "雨花区", + "430112": "望城区", + "430121": "长沙县", + "430181": "浏阳市", + "430182": "宁乡市" + }, + "430200": { + "430201": "市辖区", + "430202": "荷塘区", + "430203": "芦淞区", + "430204": "石峰区", + "430211": "天元区", + "430212": "渌口区", + "430223": "攸县", + "430224": "茶陵县", + "430225": "炎陵县", + "430271": "云龙示范区", + "430281": "醴陵市" + }, + "430300": { + "430301": "市辖区", + "430302": "雨湖区", + "430304": "岳塘区", + "430321": "湘潭县", + "430371": "湖南湘潭高新技术产业园区", + "430372": "湘潭昭山示范区", + "430373": "湘潭九华示范区", + "430381": "湘乡市", + "430382": "韶山市" + }, + "430400": { + "430401": "市辖区", + "430405": "珠晖区", + "430406": "雁峰区", + "430407": "石鼓区", + "430408": "蒸湘区", + "430412": "南岳区", + "430421": "衡阳县", + "430422": "衡南县", + "430423": "衡山县", + "430424": "衡东县", + "430426": "祁东县", + "430471": "衡阳综合保税区", + "430472": "湖南衡阳高新技术产业园区", + "430473": "湖南衡阳松木经济开发区", + "430481": "耒阳市", + "430482": "常宁市" + }, + "430500": { + "430501": "市辖区", + "430502": "双清区", + "430503": "大祥区", + "430511": "北塔区", + "430522": "新邵县", + "430523": "邵阳县", + "430524": "隆回县", + "430525": "洞口县", + "430527": "绥宁县", + "430528": "新宁县", + "430529": "城步苗族自治县", + "430581": "武冈市", + "430582": "邵东市" + }, + "430600": { + "430601": "市辖区", + "430602": "岳阳楼区", + "430603": "云溪区", + "430611": "君山区", + "430621": "岳阳县", + "430623": "华容县", + "430624": "湘阴县", + "430626": "平江县", + "430671": "岳阳市屈原管理区", + "430681": "汨罗市", + "430682": "临湘市" + }, + "430700": { + "430701": "市辖区", + "430702": "武陵区", + "430703": "鼎城区", + "430721": "安乡县", + "430722": "汉寿县", + "430723": "澧县", + "430724": "临澧县", + "430725": "桃源县", + "430726": "石门县", + "430771": "常德市西洞庭管理区", + "430781": "津市市" + }, + "430800": {"430801": "市辖区", "430802": "永定区", "430811": "武陵源区", "430821": "慈利县", "430822": "桑植县"}, + "430900": { + "430901": "市辖区", + "430902": "资阳区", + "430903": "赫山区", + "430921": "南县", + "430922": "桃江县", + "430923": "安化县", + "430971": "益阳市大通湖管理区", + "430972": "湖南益阳高新技术产业园区", + "430981": "沅江市" + }, + "431000": { + "431001": "市辖区", + "431002": "北湖区", + "431003": "苏仙区", + "431021": "桂阳县", + "431022": "宜章县", + "431023": "永兴县", + "431024": "嘉禾县", + "431025": "临武县", + "431026": "汝城县", + "431027": "桂东县", + "431028": "安仁县", + "431081": "资兴市" + }, + "431100": { + "431101": "市辖区", + "431102": "零陵区", + "431103": "冷水滩区", + "431121": "祁阳县", + "431122": "东安县", + "431123": "双牌县", + "431124": "道县", + "431125": "江永县", + "431126": "宁远县", + "431127": "蓝山县", + "431128": "新田县", + "431129": "江华瑶族自治县", + "431171": "永州经济技术开发区", + "431172": "永州市金洞管理区", + "431173": "永州市回龙圩管理区" + }, + "431200": { + "431201": "市辖区", + "431202": "鹤城区", + "431221": "中方县", + "431222": "沅陵县", + "431223": "辰溪县", + "431224": "溆浦县", + "431225": "会同县", + "431226": "麻阳苗族自治县", + "431227": "新晃侗族自治县", + "431228": "芷江侗族自治县", + "431229": "靖州苗族侗族自治县", + "431230": "通道侗族自治县", + "431271": "怀化市洪江管理区", + "431281": "洪江市" + }, + "431300": {"431301": "市辖区", "431302": "娄星区", "431321": "双峰县", "431322": "新化县", "431381": "冷水江市", "431382": "涟源市"}, + "433100": { + "433101": "吉首市", + "433122": "泸溪县", + "433123": "凤凰县", + "433124": "花垣县", + "433125": "保靖县", + "433126": "古丈县", + "433127": "永顺县", + "433130": "龙山县", + "433173": "湖南永顺经济开发区" + }, + "440000": { + "440100": "广州市", + "440200": "韶关市", + "440300": "深圳市", + "440400": "珠海市", + "440500": "汕头市", + "440600": "佛山市", + "440700": "江门市", + "440800": "湛江市", + "440900": "茂名市", + "441200": "肇庆市", + "441300": "惠州市", + "441400": "梅州市", + "441500": "汕尾市", + "441600": "河源市", + "441700": "阳江市", + "441800": "清远市", + "441900": "东莞市", + "442000": "中山市", + "445100": "潮州市", + "445200": "揭阳市", + "445300": "云浮市" + }, + "440100": { + "440101": "市辖区", + "440103": "荔湾区", + "440104": "越秀区", + "440105": "海珠区", + "440106": "天河区", + "440111": "白云区", + "440112": "黄埔区", + "440113": "番禺区", + "440114": "花都区", + "440115": "南沙区", + "440117": "从化区", + "440118": "增城区" + }, + "440200": { + "440201": "市辖区", + "440203": "武江区", + "440204": "浈江区", + "440205": "曲江区", + "440222": "始兴县", + "440224": "仁化县", + "440229": "翁源县", + "440232": "乳源瑶族自治县", + "440233": "新丰县", + "440281": "乐昌市", + "440282": "南雄市" + }, + "440300": { + "440301": "市辖区", + "440303": "罗湖区", + "440304": "福田区", + "440305": "南山区", + "440306": "宝安区", + "440307": "龙岗区", + "440308": "盐田区", + "440309": "龙华区", + "440310": "坪山区", + "440311": "光明区" + }, + "440400": {"440401": "市辖区", "440402": "香洲区", "440403": "斗门区", "440404": "金湾区"}, + "440500": { + "440501": "市辖区", + "440507": "龙湖区", + "440511": "金平区", + "440512": "濠江区", + "440513": "潮阳区", + "440514": "潮南区", + "440515": "澄海区", + "440523": "南澳县" + }, + "440600": {"440601": "市辖区", "440604": "禅城区", "440605": "南海区", "440606": "顺德区", "440607": "三水区", "440608": "高明区"}, + "440700": { + "440701": "市辖区", + "440703": "蓬江区", + "440704": "江海区", + "440705": "新会区", + "440781": "台山市", + "440783": "开平市", + "440784": "鹤山市", + "440785": "恩平市" + }, + "440800": { + "440801": "市辖区", + "440802": "赤坎区", + "440803": "霞山区", + "440804": "坡头区", + "440811": "麻章区", + "440823": "遂溪县", + "440825": "徐闻县", + "440881": "廉江市", + "440882": "雷州市", + "440883": "吴川市" + }, + "440900": {"440901": "市辖区", "440902": "茂南区", "440904": "电白区", "440981": "高州市", "440982": "化州市", "440983": "信宜市"}, + "441200": { + "441201": "市辖区", + "441202": "端州区", + "441203": "鼎湖区", + "441204": "高要区", + "441223": "广宁县", + "441224": "怀集县", + "441225": "封开县", + "441226": "德庆县", + "441284": "四会市" + }, + "441300": {"441301": "市辖区", "441302": "惠城区", "441303": "惠阳区", "441322": "博罗县", "441323": "惠东县", "441324": "龙门县"}, + "441400": { + "441401": "市辖区", + "441402": "梅江区", + "441403": "梅县区", + "441422": "大埔县", + "441423": "丰顺县", + "441424": "五华县", + "441426": "平远县", + "441427": "蕉岭县", + "441481": "兴宁市" + }, + "441500": {"441501": "市辖区", "441502": "城区", "441521": "海丰县", "441523": "陆河县", "441581": "陆丰市"}, + "441600": { + "441601": "市辖区", + "441602": "源城区", + "441621": "紫金县", + "441622": "龙川县", + "441623": "连平县", + "441624": "和平县", + "441625": "东源县" + }, + "441700": {"441701": "市辖区", "441702": "江城区", "441704": "阳东区", "441721": "阳西县", "441781": "阳春市"}, + "441800": { + "441801": "市辖区", + "441802": "清城区", + "441803": "清新区", + "441821": "佛冈县", + "441823": "阳山县", + "441825": "连山壮族瑶族自治县", + "441826": "连南瑶族自治县", + "441881": "英德市", + "441882": "连州市" + }, + "441900": { + "441900003": "东城街道", + "441900004": "南城街道", + "441900005": "万江街道", + "441900006": "莞城街道", + "441900101": "石碣镇", + "441900102": "石龙镇", + "441900103": "茶山镇", + "441900104": "石排镇", + "441900105": "企石镇", + "441900106": "横沥镇", + "441900107": "桥头镇", + "441900108": "谢岗镇", + "441900109": "东坑镇", + "441900110": "常平镇", + "441900111": "寮步镇", + "441900112": "樟木头镇", + "441900113": "大朗镇", + "441900114": "黄江镇", + "441900115": "清溪镇", + "441900116": "塘厦镇", + "441900117": "凤岗镇", + "441900118": "大岭山镇", + "441900119": "长安镇", + "441900121": "虎门镇", + "441900122": "厚街镇", + "441900123": "沙田镇", + "441900124": "道滘镇", + "441900125": "洪梅镇", + "441900126": "麻涌镇", + "441900127": "望牛墩镇", + "441900128": "中堂镇", + "441900129": "高埗镇", + "441900401": "松山湖", + "441900402": "东莞港", + "441900403": "东莞生态园" + }, + "442000": { + "442000001": "石岐街道", + "442000002": "东区街道", + "442000003": "中山港街道", + "442000004": "西区街道", + "442000005": "南区街道", + "442000006": "五桂山街道", + "442000100": "小榄镇", + "442000101": "黄圃镇", + "442000102": "民众镇", + "442000103": "东凤镇", + "442000104": "东升镇", + "442000105": "古镇镇", + "442000106": "沙溪镇", + "442000107": "坦洲镇", + "442000108": "港口镇", + "442000109": "三角镇", + "442000110": "横栏镇", + "442000111": "南头镇", + "442000112": "阜沙镇", + "442000113": "南朗镇", + "442000114": "三乡镇", + "442000115": "板芙镇", + "442000116": "大涌镇", + "442000117": "神湾镇" + }, + "445100": {"445101": "市辖区", "445102": "湘桥区", "445103": "潮安区", "445122": "饶平县"}, + "445200": {"445201": "市辖区", "445202": "榕城区", "445203": "揭东区", "445222": "揭西县", "445224": "惠来县", "445281": "普宁市"}, + "445300": {"445301": "市辖区", "445302": "云城区", "445303": "云安区", "445321": "新兴县", "445322": "郁南县", "445381": "罗定市"}, + "450000": { + "450100": "南宁市", + "450200": "柳州市", + "450300": "桂林市", + "450400": "梧州市", + "450500": "北海市", + "450600": "防城港市", + "450700": "钦州市", + "450800": "贵港市", + "450900": "玉林市", + "451000": "百色市", + "451100": "贺州市", + "451200": "河池市", + "451300": "来宾市", + "451400": "崇左市" + }, + "450100": { + "450101": "市辖区", + "450102": "兴宁区", + "450103": "青秀区", + "450105": "江南区", + "450107": "西乡塘区", + "450108": "良庆区", + "450109": "邕宁区", + "450110": "武鸣区", + "450123": "隆安县", + "450124": "马山县", + "450125": "上林县", + "450126": "宾阳县", + "450127": "横县" + }, + "450200": { + "450201": "市辖区", + "450202": "城中区", + "450203": "鱼峰区", + "450204": "柳南区", + "450205": "柳北区", + "450206": "柳江区", + "450222": "柳城县", + "450223": "鹿寨县", + "450224": "融安县", + "450225": "融水苗族自治县", + "450226": "三江侗族自治县" + }, + "450300": { + "450301": "市辖区", + "450302": "秀峰区", + "450303": "叠彩区", + "450304": "象山区", + "450305": "七星区", + "450311": "雁山区", + "450312": "临桂区", + "450321": "阳朔县", + "450323": "灵川县", + "450324": "全州县", + "450325": "兴安县", + "450326": "永福县", + "450327": "灌阳县", + "450328": "龙胜各族自治县", + "450329": "资源县", + "450330": "平乐县", + "450332": "恭城瑶族自治县", + "450381": "荔浦市" + }, + "450400": { + "450401": "市辖区", + "450403": "万秀区", + "450405": "长洲区", + "450406": "龙圩区", + "450421": "苍梧县", + "450422": "藤县", + "450423": "蒙山县", + "450481": "岑溪市" + }, + "450500": {"450501": "市辖区", "450502": "海城区", "450503": "银海区", "450512": "铁山港区", "450521": "合浦县"}, + "450600": {"450601": "市辖区", "450602": "港口区", "450603": "防城区", "450621": "上思县", "450681": "东兴市"}, + "450700": {"450701": "市辖区", "450702": "钦南区", "450703": "钦北区", "450721": "灵山县", "450722": "浦北县"}, + "450800": {"450801": "市辖区", "450802": "港北区", "450803": "港南区", "450804": "覃塘区", "450821": "平南县", "450881": "桂平市"}, + "450900": { + "450901": "市辖区", + "450902": "玉州区", + "450903": "福绵区", + "450921": "容县", + "450922": "陆川县", + "450923": "博白县", + "450924": "兴业县", + "450981": "北流市" + }, + "451000": { + "451001": "市辖区", + "451002": "右江区", + "451003": "田阳区", + "451022": "田东县", + "451023": "平果县", + "451024": "德保县", + "451026": "那坡县", + "451027": "凌云县", + "451028": "乐业县", + "451029": "田林县", + "451030": "西林县", + "451031": "隆林各族自治县", + "451081": "靖西市" + }, + "451100": {"451101": "市辖区", "451102": "八步区", "451103": "平桂区", "451121": "昭平县", "451122": "钟山县", "451123": "富川瑶族自治县"}, + "451200": { + "451201": "市辖区", + "451202": "金城江区", + "451203": "宜州区", + "451221": "南丹县", + "451222": "天峨县", + "451223": "凤山县", + "451224": "东兰县", + "451225": "罗城仫佬族自治县", + "451226": "环江毛南族自治县", + "451227": "巴马瑶族自治县", + "451228": "都安瑶族自治县", + "451229": "大化瑶族自治县" + }, + "451300": { + "451301": "市辖区", + "451302": "兴宾区", + "451321": "忻城县", + "451322": "象州县", + "451323": "武宣县", + "451324": "金秀瑶族自治县", + "451381": "合山市" + }, + "451400": { + "451401": "市辖区", + "451402": "江州区", + "451421": "扶绥县", + "451422": "宁明县", + "451423": "龙州县", + "451424": "大新县", + "451425": "天等县", + "451481": "凭祥市" + }, + "460000": {"460100": "海口市", "460200": "三亚市", "460300": "三沙市", "460400": "儋州市", "469000": "省直辖县级行政区划"}, + "460100": {"460101": "市辖区", "460105": "秀英区", "460106": "龙华区", "460107": "琼山区", "460108": "美兰区"}, + "460200": {"460201": "市辖区", "460202": "海棠区", "460203": "吉阳区", "460204": "天涯区", "460205": "崖州区"}, + "460300": {"460321": "西沙群岛", "460322": "南沙群岛", "460323": "中沙群岛的岛礁及其海域"}, + "460400": { + "460400100": "那大镇", + "460400101": "和庆镇", + "460400102": "南丰镇", + "460400103": "大成镇", + "460400104": "雅星镇", + "460400105": "兰洋镇", + "460400106": "光村镇", + "460400107": "木棠镇", + "460400108": "海头镇", + "460400109": "峨蔓镇", + "460400111": "王五镇", + "460400112": "白马井镇", + "460400113": "中和镇", + "460400114": "排浦镇", + "460400115": "东成镇", + "460400116": "新州镇", + "460400499": "洋浦经济开发区", + "460400500": "华南热作学院" + }, + "469000": { + "469001": "五指山市", + "469002": "琼海市", + "469005": "文昌市", + "469006": "万宁市", + "469007": "东方市", + "469021": "定安县", + "469022": "屯昌县", + "469023": "澄迈县", + "469024": "临高县", + "469025": "白沙黎族自治县", + "469026": "昌江黎族自治县", + "469027": "乐东黎族自治县", + "469028": "陵水黎族自治县", + "469029": "保亭黎族苗族自治县", + "469030": "琼中黎族苗族自治县" + }, + "500000": {"500100": "市辖区", "500200": "县"}, + "500100": { + "500101": "万州区", + "500102": "涪陵区", + "500103": "渝中区", + "500104": "大渡口区", + "500105": "江北区", + "500106": "沙坪坝区", + "500107": "九龙坡区", + "500108": "南岸区", + "500109": "北碚区", + "500110": "綦江区", + "500111": "大足区", + "500112": "渝北区", + "500113": "巴南区", + "500114": "黔江区", + "500115": "长寿区", + "500116": "江津区", + "500117": "合川区", + "500118": "永川区", + "500119": "南川区", + "500120": "璧山区", + "500151": "铜梁区", + "500152": "潼南区", + "500153": "荣昌区", + "500154": "开州区", + "500155": "梁平区", + "500156": "武隆区" + }, + "500200": { + "500229": "城口县", + "500230": "丰都县", + "500231": "垫江县", + "500233": "忠县", + "500235": "云阳县", + "500236": "奉节县", + "500237": "巫山县", + "500238": "巫溪县", + "500240": "石柱土家族自治县", + "500241": "秀山土家族苗族自治县", + "500242": "酉阳土家族苗族自治县", + "500243": "彭水苗族土家族自治县" + }, + "510000": { + "510100": "成都市", + "510300": "自贡市", + "510400": "攀枝花市", + "510500": "泸州市", + "510600": "德阳市", + "510700": "绵阳市", + "510800": "广元市", + "510900": "遂宁市", + "511000": "内江市", + "511100": "乐山市", + "511300": "南充市", + "511400": "眉山市", + "511500": "宜宾市", + "511600": "广安市", + "511700": "达州市", + "511800": "雅安市", + "511900": "巴中市", + "512000": "资阳市", + "513200": "阿坝藏族羌族自治州", + "513300": "甘孜藏族自治州", + "513400": "凉山彝族自治州" + }, + "510100": { + "510101": "市辖区", + "510104": "锦江区", + "510105": "青羊区", + "510106": "金牛区", + "510107": "武侯区", + "510108": "成华区", + "510112": "龙泉驿区", + "510113": "青白江区", + "510114": "新都区", + "510115": "温江区", + "510116": "双流区", + "510117": "郫都区", + "510121": "金堂县", + "510129": "大邑县", + "510131": "蒲江县", + "510132": "新津县", + "510181": "都江堰市", + "510182": "彭州市", + "510183": "邛崃市", + "510184": "崇州市", + "510185": "简阳市" + }, + "510300": { + "510301": "市辖区", + "510302": "自流井区", + "510303": "贡井区", + "510304": "大安区", + "510311": "沿滩区", + "510321": "荣县", + "510322": "富顺县" + }, + "510400": {"510401": "市辖区", "510402": "东区", "510403": "西区", "510411": "仁和区", "510421": "米易县", "510422": "盐边县"}, + "510500": { + "510501": "市辖区", + "510502": "江阳区", + "510503": "纳溪区", + "510504": "龙马潭区", + "510521": "泸县", + "510522": "合江县", + "510524": "叙永县", + "510525": "古蔺县" + }, + "510600": { + "510601": "市辖区", + "510603": "旌阳区", + "510604": "罗江区", + "510623": "中江县", + "510681": "广汉市", + "510682": "什邡市", + "510683": "绵竹市" + }, + "510700": { + "510701": "市辖区", + "510703": "涪城区", + "510704": "游仙区", + "510705": "安州区", + "510722": "三台县", + "510723": "盐亭县", + "510725": "梓潼县", + "510726": "北川羌族自治县", + "510727": "平武县", + "510781": "江油市" + }, + "510800": { + "510801": "市辖区", + "510802": "利州区", + "510811": "昭化区", + "510812": "朝天区", + "510821": "旺苍县", + "510822": "青川县", + "510823": "剑阁县", + "510824": "苍溪县" + }, + "510900": {"510901": "市辖区", "510903": "船山区", "510904": "安居区", "510921": "蓬溪县", "510923": "大英县", "510981": "射洪市"}, + "511000": { + "511001": "市辖区", + "511002": "市中区", + "511011": "东兴区", + "511024": "威远县", + "511025": "资中县", + "511071": "内江经济开发区", + "511083": "隆昌市" + }, + "511100": { + "511101": "市辖区", + "511102": "市中区", + "511111": "沙湾区", + "511112": "五通桥区", + "511113": "金口河区", + "511123": "犍为县", + "511124": "井研县", + "511126": "夹江县", + "511129": "沐川县", + "511132": "峨边彝族自治县", + "511133": "马边彝族自治县", + "511181": "峨眉山市" + }, + "511300": { + "511301": "市辖区", + "511302": "顺庆区", + "511303": "高坪区", + "511304": "嘉陵区", + "511321": "南部县", + "511322": "营山县", + "511323": "蓬安县", + "511324": "仪陇县", + "511325": "西充县", + "511381": "阆中市" + }, + "511400": { + "511401": "市辖区", + "511402": "东坡区", + "511403": "彭山区", + "511421": "仁寿县", + "511423": "洪雅县", + "511424": "丹棱县", + "511425": "青神县" + }, + "511500": { + "511501": "市辖区", + "511502": "翠屏区", + "511503": "南溪区", + "511504": "叙州区", + "511523": "江安县", + "511524": "长宁县", + "511525": "高县", + "511526": "珙县", + "511527": "筠连县", + "511528": "兴文县", + "511529": "屏山县" + }, + "511600": { + "511601": "市辖区", + "511602": "广安区", + "511603": "前锋区", + "511621": "岳池县", + "511622": "武胜县", + "511623": "邻水县", + "511681": "华蓥市" + }, + "511700": { + "511701": "市辖区", + "511702": "通川区", + "511703": "达川区", + "511722": "宣汉县", + "511723": "开江县", + "511724": "大竹县", + "511725": "渠县", + "511771": "达州经济开发区", + "511781": "万源市" + }, + "511800": { + "511801": "市辖区", + "511802": "雨城区", + "511803": "名山区", + "511822": "荥经县", + "511823": "汉源县", + "511824": "石棉县", + "511825": "天全县", + "511826": "芦山县", + "511827": "宝兴县" + }, + "511900": { + "511901": "市辖区", + "511902": "巴州区", + "511903": "恩阳区", + "511921": "通江县", + "511922": "南江县", + "511923": "平昌县", + "511971": "巴中经济开发区" + }, + "512000": {"512001": "市辖区", "512002": "雁江区", "512021": "安岳县", "512022": "乐至县"}, + "513200": { + "513201": "马尔康市", + "513221": "汶川县", + "513222": "理县", + "513223": "茂县", + "513224": "松潘县", + "513225": "九寨沟县", + "513226": "金川县", + "513227": "小金县", + "513228": "黑水县", + "513230": "壤塘县", + "513231": "阿坝县", + "513232": "若尔盖县", + "513233": "红原县" + }, + "513300": { + "513301": "康定市", + "513322": "泸定县", + "513323": "丹巴县", + "513324": "九龙县", + "513325": "雅江县", + "513326": "道孚县", + "513327": "炉霍县", + "513328": "甘孜县", + "513329": "新龙县", + "513330": "德格县", + "513331": "白玉县", + "513332": "石渠县", + "513333": "色达县", + "513334": "理塘县", + "513335": "巴塘县", + "513336": "乡城县", + "513337": "稻城县", + "513338": "得荣县" + }, + "513400": { + "513401": "西昌市", + "513422": "木里藏族自治县", + "513423": "盐源县", + "513424": "德昌县", + "513425": "会理县", + "513426": "会东县", + "513427": "宁南县", + "513428": "普格县", + "513429": "布拖县", + "513430": "金阳县", + "513431": "昭觉县", + "513432": "喜德县", + "513433": "冕宁县", + "513434": "越西县", + "513435": "甘洛县", + "513436": "美姑县", + "513437": "雷波县" + }, + "520000": { + "520100": "贵阳市", + "520200": "六盘水市", + "520300": "遵义市", + "520400": "安顺市", + "520500": "毕节市", + "520600": "铜仁市", + "522300": "黔西南布依族苗族自治州", + "522600": "黔东南苗族侗族自治州", + "522700": "黔南布依族苗族自治州" + }, + "520100": { + "520101": "市辖区", + "520102": "南明区", + "520103": "云岩区", + "520111": "花溪区", + "520112": "乌当区", + "520113": "白云区", + "520115": "观山湖区", + "520121": "开阳县", + "520122": "息烽县", + "520123": "修文县", + "520181": "清镇市" + }, + "520200": {"520201": "钟山区", "520203": "六枝特区", "520221": "水城县", "520281": "盘州市"}, + "520300": { + "520301": "市辖区", + "520302": "红花岗区", + "520303": "汇川区", + "520304": "播州区", + "520322": "桐梓县", + "520323": "绥阳县", + "520324": "正安县", + "520325": "道真仡佬族苗族自治县", + "520326": "务川仡佬族苗族自治县", + "520327": "凤冈县", + "520328": "湄潭县", + "520329": "余庆县", + "520330": "习水县", + "520381": "赤水市", + "520382": "仁怀市" + }, + "520400": { + "520401": "市辖区", + "520402": "西秀区", + "520403": "平坝区", + "520422": "普定县", + "520423": "镇宁布依族苗族自治县", + "520424": "关岭布依族苗族自治县", + "520425": "紫云苗族布依族自治县" + }, + "520500": { + "520501": "市辖区", + "520502": "七星关区", + "520521": "大方县", + "520522": "黔西县", + "520523": "金沙县", + "520524": "织金县", + "520525": "纳雍县", + "520526": "威宁彝族回族苗族自治县", + "520527": "赫章县" + }, + "520600": { + "520601": "市辖区", + "520602": "碧江区", + "520603": "万山区", + "520621": "江口县", + "520622": "玉屏侗族自治县", + "520623": "石阡县", + "520624": "思南县", + "520625": "印江土家族苗族自治县", + "520626": "德江县", + "520627": "沿河土家族自治县", + "520628": "松桃苗族自治县" + }, + "522300": { + "522301": "兴义市", + "522302": "兴仁市", + "522323": "普安县", + "522324": "晴隆县", + "522325": "贞丰县", + "522326": "望谟县", + "522327": "册亨县", + "522328": "安龙县" + }, + "522600": { + "522601": "凯里市", + "522622": "黄平县", + "522623": "施秉县", + "522624": "三穗县", + "522625": "镇远县", + "522626": "岑巩县", + "522627": "天柱县", + "522628": "锦屏县", + "522629": "剑河县", + "522630": "台江县", + "522631": "黎平县", + "522632": "榕江县", + "522633": "从江县", + "522634": "雷山县", + "522635": "麻江县", + "522636": "丹寨县" + }, + "522700": { + "522701": "都匀市", + "522702": "福泉市", + "522722": "荔波县", + "522723": "贵定县", + "522725": "瓮安县", + "522726": "独山县", + "522727": "平塘县", + "522728": "罗甸县", + "522729": "长顺县", + "522730": "龙里县", + "522731": "惠水县", + "522732": "三都水族自治县" + }, + "530000": { + "530100": "昆明市", + "530300": "曲靖市", + "530400": "玉溪市", + "530500": "保山市", + "530600": "昭通市", + "530700": "丽江市", + "530800": "普洱市", + "530900": "临沧市", + "532300": "楚雄彝族自治州", + "532500": "红河哈尼族彝族自治州", + "532600": "文山壮族苗族自治州", + "532800": "西双版纳傣族自治州", + "532900": "大理白族自治州", + "533100": "德宏傣族景颇族自治州", + "533300": "怒江傈僳族自治州", + "533400": "迪庆藏族自治州" + }, + "530100": { + "530101": "市辖区", + "530102": "五华区", + "530103": "盘龙区", + "530111": "官渡区", + "530112": "西山区", + "530113": "东川区", + "530114": "呈贡区", + "530115": "晋宁区", + "530124": "富民县", + "530125": "宜良县", + "530126": "石林彝族自治县", + "530127": "嵩明县", + "530128": "禄劝彝族苗族自治县", + "530129": "寻甸回族彝族自治县", + "530181": "安宁市" + }, + "530300": { + "530301": "市辖区", + "530302": "麒麟区", + "530303": "沾益区", + "530304": "马龙区", + "530322": "陆良县", + "530323": "师宗县", + "530324": "罗平县", + "530325": "富源县", + "530326": "会泽县", + "530381": "宣威市" + }, + "530400": { + "530401": "市辖区", + "530402": "红塔区", + "530403": "江川区", + "530422": "澄江县", + "530423": "通海县", + "530424": "华宁县", + "530425": "易门县", + "530426": "峨山彝族自治县", + "530427": "新平彝族傣族自治县", + "530428": "元江哈尼族彝族傣族自治县" + }, + "530500": {"530501": "市辖区", "530502": "隆阳区", "530521": "施甸县", "530523": "龙陵县", "530524": "昌宁县", "530581": "腾冲市"}, + "530600": { + "530601": "市辖区", + "530602": "昭阳区", + "530621": "鲁甸县", + "530622": "巧家县", + "530623": "盐津县", + "530624": "大关县", + "530625": "永善县", + "530626": "绥江县", + "530627": "镇雄县", + "530628": "彝良县", + "530629": "威信县", + "530681": "水富市" + }, + "530700": { + "530701": "市辖区", + "530702": "古城区", + "530721": "玉龙纳西族自治县", + "530722": "永胜县", + "530723": "华坪县", + "530724": "宁蒗彝族自治县" + }, + "530800": { + "530801": "市辖区", + "530802": "思茅区", + "530821": "宁洱哈尼族彝族自治县", + "530822": "墨江哈尼族自治县", + "530823": "景东彝族自治县", + "530824": "景谷傣族彝族自治县", + "530825": "镇沅彝族哈尼族拉祜族自治县", + "530826": "江城哈尼族彝族自治县", + "530827": "孟连傣族拉祜族佤族自治县", + "530828": "澜沧拉祜族自治县", + "530829": "西盟佤族自治县" + }, + "530900": { + "530901": "市辖区", + "530902": "临翔区", + "530921": "凤庆县", + "530922": "云县", + "530923": "永德县", + "530924": "镇康县", + "530925": "双江拉祜族佤族布朗族傣族自治县", + "530926": "耿马傣族佤族自治县", + "530927": "沧源佤族自治县" + }, + "532300": { + "532301": "楚雄市", + "532322": "双柏县", + "532323": "牟定县", + "532324": "南华县", + "532325": "姚安县", + "532326": "大姚县", + "532327": "永仁县", + "532328": "元谋县", + "532329": "武定县", + "532331": "禄丰县" + }, + "532500": { + "532501": "个旧市", + "532502": "开远市", + "532503": "蒙自市", + "532504": "弥勒市", + "532523": "屏边苗族自治县", + "532524": "建水县", + "532525": "石屏县", + "532527": "泸西县", + "532528": "元阳县", + "532529": "红河县", + "532530": "金平苗族瑶族傣族自治县", + "532531": "绿春县", + "532532": "河口瑶族自治县" + }, + "532600": { + "532601": "文山市", + "532622": "砚山县", + "532623": "西畴县", + "532624": "麻栗坡县", + "532625": "马关县", + "532626": "丘北县", + "532627": "广南县", + "532628": "富宁县" + }, + "532800": {"532801": "景洪市", "532822": "勐海县", "532823": "勐腊县"}, + "532900": { + "532901": "大理市", + "532922": "漾濞彝族自治县", + "532923": "祥云县", + "532924": "宾川县", + "532925": "弥渡县", + "532926": "南涧彝族自治县", + "532927": "巍山彝族回族自治县", + "532928": "永平县", + "532929": "云龙县", + "532930": "洱源县", + "532931": "剑川县", + "532932": "鹤庆县" + }, + "533100": {"533102": "瑞丽市", "533103": "芒市", "533122": "梁河县", "533123": "盈江县", "533124": "陇川县"}, + "533300": {"533301": "泸水市", "533323": "福贡县", "533324": "贡山独龙族怒族自治县", "533325": "兰坪白族普米族自治县"}, + "533400": {"533401": "香格里拉市", "533422": "德钦县", "533423": "维西傈僳族自治县"}, + "540000": { + "540100": "拉萨市", + "540200": "日喀则市", + "540300": "昌都市", + "540400": "林芝市", + "540500": "山南市", + "540600": "那曲市", + "542500": "阿里地区" + }, + "540100": { + "540101": "市辖区", + "540102": "城关区", + "540103": "堆龙德庆区", + "540104": "达孜区", + "540121": "林周县", + "540122": "当雄县", + "540123": "尼木县", + "540124": "曲水县", + "540127": "墨竹工卡县", + "540171": "格尔木藏青工业园区", + "540172": "拉萨经济技术开发区", + "540173": "西藏文化旅游创意园区", + "540174": "达孜工业园区" + }, + "540200": { + "540202": "桑珠孜区", + "540221": "南木林县", + "540222": "江孜县", + "540223": "定日县", + "540224": "萨迦县", + "540225": "拉孜县", + "540226": "昂仁县", + "540227": "谢通门县", + "540228": "白朗县", + "540229": "仁布县", + "540230": "康马县", + "540231": "定结县", + "540232": "仲巴县", + "540233": "亚东县", + "540234": "吉隆县", + "540235": "聂拉木县", + "540236": "萨嘎县", + "540237": "岗巴县" + }, + "540300": { + "540302": "卡若区", + "540321": "江达县", + "540322": "贡觉县", + "540323": "类乌齐县", + "540324": "丁青县", + "540325": "察雅县", + "540326": "八宿县", + "540327": "左贡县", + "540328": "芒康县", + "540329": "洛隆县", + "540330": "边坝县" + }, + "540400": { + "540402": "巴宜区", + "540421": "工布江达县", + "540422": "米林县", + "540423": "墨脱县", + "540424": "波密县", + "540425": "察隅县", + "540426": "朗县" + }, + "540500": { + "540501": "市辖区", + "540502": "乃东区", + "540521": "扎囊县", + "540522": "贡嘎县", + "540523": "桑日县", + "540524": "琼结县", + "540525": "曲松县", + "540526": "措美县", + "540527": "洛扎县", + "540528": "加查县", + "540529": "隆子县", + "540530": "错那县", + "540531": "浪卡子县" + }, + "540600": { + "540602": "色尼区", + "540621": "嘉黎县", + "540622": "比如县", + "540623": "聂荣县", + "540624": "安多县", + "540625": "申扎县", + "540626": "索县", + "540627": "班戈县", + "540628": "巴青县", + "540629": "尼玛县", + "540630": "双湖县" + }, + "542500": { + "542521": "普兰县", + "542522": "札达县", + "542523": "噶尔县", + "542524": "日土县", + "542525": "革吉县", + "542526": "改则县", + "542527": "措勤县" + }, + "610000": { + "610100": "西安市", + "610200": "铜川市", + "610300": "宝鸡市", + "610400": "咸阳市", + "610500": "渭南市", + "610600": "延安市", + "610700": "汉中市", + "610800": "榆林市", + "610900": "安康市", + "611000": "商洛市" + }, + "610100": { + "610101": "市辖区", + "610102": "新城区", + "610103": "碑林区", + "610104": "莲湖区", + "610111": "灞桥区", + "610112": "未央区", + "610113": "雁塔区", + "610114": "阎良区", + "610115": "临潼区", + "610116": "长安区", + "610117": "高陵区", + "610118": "鄠邑区", + "610122": "蓝田县", + "610124": "周至县" + }, + "610200": {"610201": "市辖区", "610202": "王益区", "610203": "印台区", "610204": "耀州区", "610222": "宜君县"}, + "610300": { + "610301": "市辖区", + "610302": "渭滨区", + "610303": "金台区", + "610304": "陈仓区", + "610322": "凤翔县", + "610323": "岐山县", + "610324": "扶风县", + "610326": "眉县", + "610327": "陇县", + "610328": "千阳县", + "610329": "麟游县", + "610330": "凤县", + "610331": "太白县" + }, + "610400": { + "610401": "市辖区", + "610402": "秦都区", + "610403": "杨陵区", + "610404": "渭城区", + "610422": "三原县", + "610423": "泾阳县", + "610424": "乾县", + "610425": "礼泉县", + "610426": "永寿县", + "610428": "长武县", + "610429": "旬邑县", + "610430": "淳化县", + "610431": "武功县", + "610481": "兴平市", + "610482": "彬州市" + }, + "610500": { + "610501": "市辖区", + "610502": "临渭区", + "610503": "华州区", + "610522": "潼关县", + "610523": "大荔县", + "610524": "合阳县", + "610525": "澄城县", + "610526": "蒲城县", + "610527": "白水县", + "610528": "富平县", + "610581": "韩城市", + "610582": "华阴市" + }, + "610600": { + "610601": "市辖区", + "610602": "宝塔区", + "610603": "安塞区", + "610621": "延长县", + "610622": "延川县", + "610625": "志丹县", + "610626": "吴起县", + "610627": "甘泉县", + "610628": "富县", + "610629": "洛川县", + "610630": "宜川县", + "610631": "黄龙县", + "610632": "黄陵县", + "610681": "子长市" + }, + "610700": { + "610701": "市辖区", + "610702": "汉台区", + "610703": "南郑区", + "610722": "城固县", + "610723": "洋县", + "610724": "西乡县", + "610725": "勉县", + "610726": "宁强县", + "610727": "略阳县", + "610728": "镇巴县", + "610729": "留坝县", + "610730": "佛坪县" + }, + "610800": { + "610801": "市辖区", + "610802": "榆阳区", + "610803": "横山区", + "610822": "府谷县", + "610824": "靖边县", + "610825": "定边县", + "610826": "绥德县", + "610827": "米脂县", + "610828": "佳县", + "610829": "吴堡县", + "610830": "清涧县", + "610831": "子洲县", + "610881": "神木市" + }, + "610900": { + "610901": "市辖区", + "610902": "汉滨区", + "610921": "汉阴县", + "610922": "石泉县", + "610923": "宁陕县", + "610924": "紫阳县", + "610925": "岚皋县", + "610926": "平利县", + "610927": "镇坪县", + "610928": "旬阳县", + "610929": "白河县" + }, + "611000": { + "611001": "市辖区", + "611002": "商州区", + "611021": "洛南县", + "611022": "丹凤县", + "611023": "商南县", + "611024": "山阳县", + "611025": "镇安县", + "611026": "柞水县" + }, + "620000": { + "620100": "兰州市", + "620200": "嘉峪关市", + "620300": "金昌市", + "620400": "白银市", + "620500": "天水市", + "620600": "武威市", + "620700": "张掖市", + "620800": "平凉市", + "620900": "酒泉市", + "621000": "庆阳市", + "621100": "定西市", + "621200": "陇南市", + "622900": "临夏回族自治州", + "623000": "甘南藏族自治州" + }, + "620100": { + "620101": "市辖区", + "620102": "城关区", + "620103": "七里河区", + "620104": "西固区", + "620105": "安宁区", + "620111": "红古区", + "620121": "永登县", + "620122": "皋兰县", + "620123": "榆中县", + "620171": "兰州新区" + }, + "620200": {"620201": "市辖区"}, + "620300": {"620301": "市辖区", "620302": "金川区", "620321": "永昌县"}, + "620400": {"620401": "市辖区", "620402": "白银区", "620403": "平川区", "620421": "靖远县", "620422": "会宁县", "620423": "景泰县"}, + "620500": { + "620501": "市辖区", + "620502": "秦州区", + "620503": "麦积区", + "620521": "清水县", + "620522": "秦安县", + "620523": "甘谷县", + "620524": "武山县", + "620525": "张家川回族自治县" + }, + "620600": {"620601": "市辖区", "620602": "凉州区", "620621": "民勤县", "620622": "古浪县", "620623": "天祝藏族自治县"}, + "620700": { + "620701": "市辖区", + "620702": "甘州区", + "620721": "肃南裕固族自治县", + "620722": "民乐县", + "620723": "临泽县", + "620724": "高台县", + "620725": "山丹县" + }, + "620800": { + "620801": "市辖区", + "620802": "崆峒区", + "620821": "泾川县", + "620822": "灵台县", + "620823": "崇信县", + "620825": "庄浪县", + "620826": "静宁县", + "620881": "华亭市" + }, + "620900": { + "620901": "市辖区", + "620902": "肃州区", + "620921": "金塔县", + "620922": "瓜州县", + "620923": "肃北蒙古族自治县", + "620924": "阿克塞哈萨克族自治县", + "620981": "玉门市", + "620982": "敦煌市" + }, + "621000": { + "621001": "市辖区", + "621002": "西峰区", + "621021": "庆城县", + "621022": "环县", + "621023": "华池县", + "621024": "合水县", + "621025": "正宁县", + "621026": "宁县", + "621027": "镇原县" + }, + "621100": { + "621101": "市辖区", + "621102": "安定区", + "621121": "通渭县", + "621122": "陇西县", + "621123": "渭源县", + "621124": "临洮县", + "621125": "漳县", + "621126": "岷县" + }, + "621200": { + "621201": "市辖区", + "621202": "武都区", + "621221": "成县", + "621222": "文县", + "621223": "宕昌县", + "621224": "康县", + "621225": "西和县", + "621226": "礼县", + "621227": "徽县", + "621228": "两当县" + }, + "622900": { + "622901": "临夏市", + "622921": "临夏县", + "622922": "康乐县", + "622923": "永靖县", + "622924": "广河县", + "622925": "和政县", + "622926": "东乡族自治县", + "622927": "积石山保安族东乡族撒拉族自治县" + }, + "623000": { + "623001": "合作市", + "623021": "临潭县", + "623022": "卓尼县", + "623023": "舟曲县", + "623024": "迭部县", + "623025": "玛曲县", + "623026": "碌曲县", + "623027": "夏河县" + }, + "630000": { + "630100": "西宁市", + "630200": "海东市", + "632200": "海北藏族自治州", + "632300": "黄南藏族自治州", + "632500": "海南藏族自治州", + "632600": "果洛藏族自治州", + "632700": "玉树藏族自治州", + "632800": "海西蒙古族藏族自治州" + }, + "630100": { + "630101": "市辖区", + "630102": "城东区", + "630103": "城中区", + "630104": "城西区", + "630105": "城北区", + "630121": "大通回族土族自治县", + "630122": "湟中县", + "630123": "湟源县" + }, + "630200": { + "630202": "乐都区", + "630203": "平安区", + "630222": "民和回族土族自治县", + "630223": "互助土族自治县", + "630224": "化隆回族自治县", + "630225": "循化撒拉族自治县" + }, + "632200": {"632221": "门源回族自治县", "632222": "祁连县", "632223": "海晏县", "632224": "刚察县"}, + "632300": {"632321": "同仁县", "632322": "尖扎县", "632323": "泽库县", "632324": "河南蒙古族自治县"}, + "632500": {"632521": "共和县", "632522": "同德县", "632523": "贵德县", "632524": "兴海县", "632525": "贵南县"}, + "632600": {"632621": "玛沁县", "632622": "班玛县", "632623": "甘德县", "632624": "达日县", "632625": "久治县", "632626": "玛多县"}, + "632700": {"632701": "玉树市", "632722": "杂多县", "632723": "称多县", "632724": "治多县", "632725": "囊谦县", "632726": "曲麻莱县"}, + "632800": { + "632801": "格尔木市", + "632802": "德令哈市", + "632803": "茫崖市", + "632821": "乌兰县", + "632822": "都兰县", + "632823": "天峻县", + "632857": "大柴旦行政委员会" + }, + "640000": {"640100": "银川市", "640200": "石嘴山市", "640300": "吴忠市", "640400": "固原市", "640500": "中卫市"}, + "640100": { + "640101": "市辖区", + "640104": "兴庆区", + "640105": "西夏区", + "640106": "金凤区", + "640121": "永宁县", + "640122": "贺兰县", + "640181": "灵武市" + }, + "640200": {"640201": "市辖区", "640202": "大武口区", "640205": "惠农区", "640221": "平罗县"}, + "640300": {"640301": "市辖区", "640302": "利通区", "640303": "红寺堡区", "640323": "盐池县", "640324": "同心县", "640381": "青铜峡市"}, + "640400": {"640401": "市辖区", "640402": "原州区", "640422": "西吉县", "640423": "隆德县", "640424": "泾源县", "640425": "彭阳县"}, + "640500": {"640501": "市辖区", "640502": "沙坡头区", "640521": "中宁县", "640522": "海原县"}, + "650000": { + "650100": "乌鲁木齐市", + "650200": "克拉玛依市", + "650400": "吐鲁番市", + "650500": "哈密市", + "652300": "昌吉回族自治州", + "652700": "博尔塔拉蒙古自治州", + "652800": "巴音郭楞蒙古自治州", + "652900": "阿克苏地区", + "653000": "克孜勒苏柯尔克孜自治州", + "653100": "喀什地区", + "653200": "和田地区", + "654000": "伊犁哈萨克自治州", + "654200": "塔城地区", + "654300": "阿勒泰地区", + "659000": "自治区直辖县级行政区划" + }, + "650100": { + "650101": "市辖区", + "650102": "天山区", + "650103": "沙依巴克区", + "650104": "新市区", + "650105": "水磨沟区", + "650106": "头屯河区", + "650107": "达坂城区", + "650109": "米东区", + "650121": "乌鲁木齐县" + }, + "650200": {"650201": "市辖区", "650202": "独山子区", "650203": "克拉玛依区", "650204": "白碱滩区", "650205": "乌尔禾区"}, + "650400": {"650402": "高昌区", "650421": "鄯善县", "650422": "托克逊县"}, + "650500": {"650502": "伊州区", "650521": "巴里坤哈萨克自治县", "650522": "伊吾县"}, + "652300": { + "652301": "昌吉市", + "652302": "阜康市", + "652323": "呼图壁县", + "652324": "玛纳斯县", + "652325": "奇台县", + "652327": "吉木萨尔县", + "652328": "木垒哈萨克自治县" + }, + "652700": {"652701": "博乐市", "652702": "阿拉山口市", "652722": "精河县", "652723": "温泉县"}, + "652800": { + "652801": "库尔勒市", + "652822": "轮台县", + "652823": "尉犁县", + "652824": "若羌县", + "652825": "且末县", + "652826": "焉耆回族自治县", + "652827": "和静县", + "652828": "和硕县", + "652829": "博湖县", + "652871": "库尔勒经济技术开发区" + }, + "652900": { + "652901": "阿克苏市", + "652922": "温宿县", + "652923": "库车县", + "652924": "沙雅县", + "652925": "新和县", + "652926": "拜城县", + "652927": "乌什县", + "652928": "阿瓦提县", + "652929": "柯坪县" + }, + "653000": {"653001": "阿图什市", "653022": "阿克陶县", "653023": "阿合奇县", "653024": "乌恰县"}, + "653100": { + "653101": "喀什市", + "653121": "疏附县", + "653122": "疏勒县", + "653123": "英吉沙县", + "653124": "泽普县", + "653125": "莎车县", + "653126": "叶城县", + "653127": "麦盖提县", + "653128": "岳普湖县", + "653129": "伽师县", + "653130": "巴楚县", + "653131": "塔什库尔干塔吉克自治县" + }, + "653200": { + "653201": "和田市", + "653221": "和田县", + "653222": "墨玉县", + "653223": "皮山县", + "653224": "洛浦县", + "653225": "策勒县", + "653226": "于田县", + "653227": "民丰县" + }, + "654000": { + "654002": "伊宁市", + "654003": "奎屯市", + "654004": "霍尔果斯市", + "654021": "伊宁县", + "654022": "察布查尔锡伯自治县", + "654023": "霍城县", + "654024": "巩留县", + "654025": "新源县", + "654026": "昭苏县", + "654027": "特克斯县", + "654028": "尼勒克县" + }, + "654200": { + "654201": "塔城市", + "654202": "乌苏市", + "654221": "额敏县", + "654223": "沙湾县", + "654224": "托里县", + "654225": "裕民县", + "654226": "和布克赛尔蒙古自治县" + }, + "654300": { + "654301": "阿勒泰市", + "654321": "布尔津县", + "654322": "富蕴县", + "654323": "福海县", + "654324": "哈巴河县", + "654325": "青河县", + "654326": "吉木乃县" + }, + "659000": {"659001": "石河子市", "659002": "阿拉尔市", "659003": "图木舒克市", "659004": "五家渠市", "659006": "铁门关市"}, + "710000": { + "710100": "台北市", + "710200": "高雄市", + "710300": "基隆市", + "710400": "台中市", + "710500": "台南市", + "710600": "新竹市", + "710700": "嘉义市" + }, + "710100": { + "710101": "内湖区", + "710102": "南港区", + "710103": "中正区", + "710104": "松山区", + "710105": "信义区", + "710106": "大安区", + "710107": "中山区", + "710108": "文山区", + "710109": "大同区", + "710110": "万华区", + "710111": "士林区", + "710112": "北投区" + }, + "710200": { + "710201": "新兴区", + "710202": "前金区", + "710203": "芩雅区", + "710204": "盐埕区", + "710205": "鼓山区", + "710206": "旗津区", + "710207": "前镇区", + "710208": "三民区", + "710209": "左营区", + "710210": "楠梓区", + "710211": "小港区" + }, + "710300": {"710301": "仁爱区", "710302": "信义区", "710303": "中正区", "710304": "暖暖区", "710305": "安乐区", "710307": "七堵区"}, + "710400": { + "710301": "中区", + "710302": "东区", + "710303": "南区", + "710304": "西区", + "710305": "北区", + "710306": "北屯区", + "710307": "西屯区", + "710308": "南屯区" + }, + "710500": {"710501": "中西区", "710502": "东区", "710503": "南区", "710504": "北区", "710505": "安平区", "710506": "安南区"}, + "710600": {"710601": "东区", "710602": "北区", "710603": "香山区"}, + "710700": {"710701": "东区", "710702": "西区"}, + "810000": { + "810001": "中西區", + "810002": "灣仔區", + "810003": "東區", + "810004": "南區", + "810005": "油尖旺區", + "810006": "深水埗區", + "810007": "九龍城區", + "810008": "黃大仙區", + "810009": "觀塘區", + "810010": "荃灣區", + "810011": "屯門區", + "810012": "元朗區", + "810013": "北區", + "810014": "大埔區", + "810015": "西貢區", + "810016": "沙田區", + "810017": "葵青區", + "810018": "離島區" + }, + "820000": { + "820001": "花地瑪堂區", + "820002": "花王堂區", + "820003": "望德堂區", + "820004": "大堂區", + "820005": "風順堂區", + "820006": "嘉模堂區", + "820007": "路氹填海區", + "820008": "聖方濟各堂區" + } +}; + +class Address { + static List provinces = locations['86']!.values.toList(); + + // 是否在市、区级添加 全部选项 + static bool addAllItem = true; + + static getCities(String province) { + var emptyData = {'name': "全部", 'cityCode': ''}; + if (province == '全部' && addAllItem) return [emptyData]; + + String code = ''; + locations['86']!.forEach((key, value) { + if (value == province) { + code = key; + } + }); + + Map? areaList = locations[code]; + // print('longer >>>$code 城市数据:$areaList'); + var data = []; + if (areaList != null && addAllItem) data.add(emptyData); + areaList?.forEach((key, value) { + data.add({'name': value, 'cityCode': key}); + }); + + return data; + } + + static getTowns(cityCode) { + if (PicketUtil.strEmpty(cityCode)) return ['']; + + Map? areaList = locations[cityCode]; + if (PicketUtil.mapEmpty(areaList)) { + return ['']; + } else { + var data = areaList!.values.toList(); + if (addAllItem) data.insert(0, '全部'); + return data; + } + } + + // 拼接城市 + static String spliceCityName({String? pname, String? cname, String? tname}) { + if (PicketUtil.strEmpty(pname)) return '不限'; + StringBuffer sb = StringBuffer(); + sb.write(pname); + if (PicketUtil.strEmpty(cname)) return sb.toString(); + sb.write(' - '); + sb.write(cname); + if (PicketUtil.strEmpty(tname)) return sb.toString(); + sb.write(' - '); + sb.write(tname); + return sb.toString(); + } + + /// 根据城市名 找到城市编码 + /// simple use + /// List cityCode = Locations.getTownsCityCode("四川省","成都市","锦江区"); + /// return [510000,510100,510104] or [510000,510000] or [510000] or [] + static List getCityCodeByName({String? provinceName, String? cityName, String? townName}) { + List cityCode = []; + + if (PicketUtil.strEmpty(provinceName)) return cityCode; + String initialProvinceCode = ''; + locations['86']!.forEach((key, value) { + if (value == provinceName) { + initialProvinceCode = key; + } + }); + /////////////////////// + if (PicketUtil.strNoEmpty(initialProvinceCode)) { + cityCode.add(initialProvinceCode); + + // 市级 + if (PicketUtil.strEmpty(cityName)) { + // print('longer 区域代码 >>> $cityCode'); + return cityCode; + } + String initialCityCode = ''; + var initialProvinceList = locations[initialProvinceCode]; + if (initialProvinceList == null) { + // print('longer 区域代码 >>> $cityCode'); + return cityCode; + } + + initialProvinceList.forEach((key, value) { + if (value == cityName) { + initialCityCode = key; + } + }); + + /////////////////////// + if (PicketUtil.strNoEmpty(initialCityCode)) { + cityCode.add(initialCityCode); + + // 区域 + if (PicketUtil.strEmpty(townName)) { + // print('longer 区域代码 >>> $cityCode'); + return cityCode; + } + String initialTownCode = ''; + var initialTownList = locations[initialCityCode]; + if (initialTownList == null) { + // print('longer 区域代码 >>> $cityCode'); + return cityCode; + } + + initialTownList.forEach((key, value) { + if (value == townName) { + initialTownCode = key; + } + }); + + if (PicketUtil.strNoEmpty(initialTownCode)) { + cityCode.add(initialTownCode); + } + } + } + // print('longer 区域代码 >>> $cityCode'); + return cityCode; + } + + /// 通过城市code 返回城市名 + /// simple use + /// List cityName = Address.getCityNameByCode(provinceCode: "510000", cityCode: "510100", townCode: "510104"); + /// return [四川省, 成都市, 锦江区] or [四川省, 成都市] or [四川省] or [] + static List getCityNameByCode({String? provinceCode, String? cityCode, String? townCode}) { + List cityName = []; + + if (PicketUtil.strEmpty(provinceCode)) return cityName; + String provinceName = ''; + locations['86']!.forEach((key, value) { + if (key == provinceCode) { + provinceName = value; + } + }); + if (PicketUtil.strNoEmpty(provinceName)) { + cityName.add(provinceName); + + /////////////////////// + // 市级 + if (PicketUtil.strEmpty(cityCode)) return cityName; + String initialCityName = ''; + var initialProvinceList = locations[provinceCode]; + if (PicketUtil.mapEmpty(initialProvinceList)) { + // print('longer 区域名 >>> $cityName'); + return cityName; + } + + initialProvinceList!.forEach((key, value) { + if (key == cityCode) { + initialCityName = value; + } + }); + if (PicketUtil.strNoEmpty(initialCityName)) { + cityName.add(initialCityName); + + /////////////////////// + // 区域 + if (PicketUtil.strEmpty(townCode)) return cityName; + String initialTownName = ''; + var initialTownList = locations[cityCode]; + if (initialTownList == null) { + // print('longer 区域名 >>> $cityName'); + return cityName; + } + + initialTownList.forEach((key, value) { + if (key == townCode) { + initialTownName = value; + } + }); + + if (PicketUtil.strNoEmpty(initialTownName)) { + cityName.add(initialTownName); + } + } + } + // print('longer 区域名 >>> $cityName'); + return cityName; + } +} diff --git a/star_lock/lib/tools/pickers/address_picker/route/address_picker_route.dart b/star_lock/lib/tools/pickers/address_picker/route/address_picker_route.dart new file mode 100644 index 00000000..f09bad6f --- /dev/null +++ b/star_lock/lib/tools/pickers/address_picker/route/address_picker_route.dart @@ -0,0 +1,462 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:star_lock/tools/pickers/style/picker_style.dart'; +// import 'package:flutter_pickers/style/picker_style.dart'; + +import '../locations_data.dart'; + +typedef AddressCallback(String province, String city, String? town); + +/// 自定义 地区选择器 +/// [initProvince] 初始化 省 +/// [initCity] 初始化 市 +/// [initTown] 初始化 区 +/// [onChanged] 选择器发生变动 +/// [onConfirm] 选择器提交 +/// [addAllItem] 市、区是否添加 '全部' 选项 默认:true +class AddressPickerRoute extends PopupRoute { + AddressPickerRoute({ + required this.addAllItem, + required this.pickerStyle, + required this.initProvince, + required this.initCity, + this.initTown, + this.onChanged, + this.onConfirm, + this.onCancel, + this.theme, + this.barrierLabel, + RouteSettings? settings, + }) : super(settings: settings); + + late final String initProvince, initCity; + final String? initTown; + final AddressCallback? onChanged; + final AddressCallback? onConfirm; + final Function(bool isCancel)? onCancel; + final ThemeData? theme; + final bool addAllItem; + + late final PickerStyle pickerStyle; + + @override + Duration get transitionDuration => const Duration(milliseconds: 200); + + @override + bool get barrierDismissible => true; + + @override + bool didPop(T? result) { + if (onCancel != null) { + if (result == null) { + onCancel!(false); + } else if (!(result as bool)) { + onCancel!(true); + } + } + return super.didPop(result); + } + + @override + final String? barrierLabel; + + @override + Color get barrierColor => Colors.black54; + + AnimationController? _animationController; + + @override + AnimationController createAnimationController() { + assert(_animationController == null); + _animationController = + BottomSheet.createAnimationController(navigator!.overlay!); + return _animationController!; + } + + @override + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { + Widget bottomSheet = MediaQuery.removePadding( + context: context, + removeTop: true, + child: _PickerContentView( + initProvince: initProvince, + initCity: initCity, + initTown: initTown, + addAllItem: addAllItem, + pickerStyle: pickerStyle, + route: this, + ), + ); + if (theme != null) { + bottomSheet = Theme(data: theme!, child: bottomSheet); + } + + return bottomSheet; + } +} + +class _PickerContentView extends StatefulWidget { + _PickerContentView({ + Key? key, + required this.initProvince, + required this.initCity, + this.initTown, + required this.pickerStyle, + required this.addAllItem, + required this.route, + }) : super(key: key); + + final String initProvince, initCity; + final String? initTown; + final AddressPickerRoute route; + final bool addAllItem; + final PickerStyle pickerStyle; + + @override + State createState() => _PickerState(this.initProvince, + this.initCity, this.initTown, this.addAllItem, this.pickerStyle); +} + +class _PickerState extends State<_PickerContentView> { + final PickerStyle _pickerStyle; + late String _currentProvince, _currentCity; + String? _currentTown; + var cities = []; + var towns = []; + var provinces = []; + + // 是否显示县级 + bool hasTown = true; + + // 是否添加全部 + late final bool addAllItem; + + AnimationController? controller; + Animation? animation; + + late FixedExtentScrollController provinceScrollCtrl, + cityScrollCtrl, + townScrollCtrl; + + _PickerState(this._currentProvince, this._currentCity, this._currentTown, + this.addAllItem, this._pickerStyle) { + provinces = Address.provinces; + hasTown = this._currentTown != null; + + _init(); + } + + @override + void dispose() { + provinceScrollCtrl.dispose(); + cityScrollCtrl.dispose(); + townScrollCtrl.dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: AnimatedBuilder( + animation: widget.route.animation!, + builder: (BuildContext context, Widget? child) { + return ClipRect( + child: CustomSingleChildLayout( + delegate: _BottomPickerLayout( + widget.route.animation!.value, this._pickerStyle), + child: GestureDetector( + child: Material( + color: Colors.transparent, + child: _renderPickerView(), + ), + ), + ), + ); + }, + ), + ); + } + + _init() { + Address.addAllItem = addAllItem; + int pindex = 0; + int cindex = 0; + int tindex = 0; + pindex = provinces.indexWhere((p) => p == _currentProvince); + pindex = pindex >= 0 ? pindex : 0; + String? selectedProvince = provinces[pindex]; + if (selectedProvince != null) { + _currentProvince = selectedProvince; + + cities = Address.getCities(selectedProvince); + + cindex = cities.indexWhere((c) => c['name'] == _currentCity); + cindex = cindex >= 0 ? cindex : 0; + _currentCity = cities[cindex]['name']; + + // print('longer >>> 外面接到的$cities'); + + if (hasTown) { + towns = Address.getTowns(cities[cindex]['cityCode']); + tindex = towns.indexWhere((t) => t == _currentTown); + tindex = tindex >= 0 ? tindex : 0; + if (towns.length == 0) { + _currentTown = ''; + } else { + _currentTown = towns[tindex]; + } + } + } + + provinceScrollCtrl = new FixedExtentScrollController(initialItem: pindex); + cityScrollCtrl = new FixedExtentScrollController(initialItem: cindex); + townScrollCtrl = new FixedExtentScrollController(initialItem: tindex); + } + + void _setProvince(int index) { + String selectedProvince = provinces[index]; + // print('longer >>> index:$index _currentProvince:$_currentProvince selectedProvince:$selectedProvince '); + + if (_currentProvince != selectedProvince) { + setState(() { + _currentProvince = selectedProvince; + + cities = Address.getCities(selectedProvince); + // print('longer >>> 返回的城市数据:$cities'); + + _currentCity = cities[0]['name']; + cityScrollCtrl.jumpToItem(0); + if (hasTown) { + towns = Address.getTowns(cities[0]['cityCode']); + _currentTown = towns[0]; + townScrollCtrl.jumpToItem(0); + } + }); + + _notifyLocationChanged(); + } + } + + void _setCity(int index) { + index = cities.length > index ? index : 0; + String selectedCity = cities[index]['name']; + if (_currentCity != selectedCity) { + setState(() { + _currentCity = selectedCity; + if (hasTown) { + towns = Address.getTowns(cities[index]['cityCode']); + _currentTown = towns.isNotEmpty ? towns[0] : ''; + townScrollCtrl.jumpToItem(0); + } + }); + + _notifyLocationChanged(); + } + } + + void _setTown(int index) { + index = towns.length > index ? index : 0; + String selectedTown = towns[index]; + if (_currentTown != selectedTown) { + _currentTown = selectedTown; + _notifyLocationChanged(); + } + } + + void _notifyLocationChanged() { + if (widget.route.onChanged != null) { + widget.route.onChanged!(_currentProvince, _currentCity, _currentTown); + } + } + + double _pickerFontSize(String text) { + double ratio = hasTown ? 0.0 : 2.0; + if (text.length <= 6) { + return 18.0; + } else if (text.length < 9) { + return 16.0 + ratio; + } else if (text.length < 13) { + return 12.0 + ratio; + } else { + return 10.0 + ratio; + } + } + + Widget _renderPickerView() { + Widget itemView = _renderItemView(); + + if (!_pickerStyle.showTitleBar && _pickerStyle.menu == null) { + return itemView; + } + List viewList = []; + if (_pickerStyle.showTitleBar) { + viewList.add(_titleView()); + } + if (_pickerStyle.menu != null) { + viewList.add(_pickerStyle.menu!); + } + viewList.add(itemView); + + return Column(children: viewList); + } + + Widget _renderItemView() { + return Container( + height: _pickerStyle.pickerHeight, + color: _pickerStyle.backgroundColor, + child: Row( + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.all(8.0), + child: CupertinoPicker.builder( + scrollController: provinceScrollCtrl, + selectionOverlay: _pickerStyle.itemOverlay, + itemExtent: _pickerStyle.pickerItemHeight, + onSelectedItemChanged: (int index) { + _setProvince(index); + }, + childCount: Address.provinces.length, + itemBuilder: (_, index) { + String text = Address.provinces[index]; + return Align( + alignment: Alignment.center, + child: Text(text, + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: + _pickerStyle.textSize ?? _pickerFontSize(text), + ), + textAlign: TextAlign.start)); + }, + ), + ), + ), + Expanded( + child: Container( + padding: EdgeInsets.all(8.0), + child: CupertinoPicker.builder( + scrollController: cityScrollCtrl, + selectionOverlay: _pickerStyle.itemOverlay, + itemExtent: _pickerStyle.pickerItemHeight, + onSelectedItemChanged: (int index) { + _setCity(index); + }, + childCount: cities.length, + itemBuilder: (_, index) { + String text = cities[index]['name']; + return Align( + alignment: Alignment.center, + child: Text('$text', + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: + _pickerStyle.textSize ?? _pickerFontSize(text), + ), + textAlign: TextAlign.start), + ); + }, + )), + ), + hasTown + ? Expanded( + child: Container( + padding: EdgeInsets.all(8.0), + child: CupertinoPicker.builder( + scrollController: townScrollCtrl, + selectionOverlay: _pickerStyle.itemOverlay, + itemExtent: _pickerStyle.pickerItemHeight, + onSelectedItemChanged: (int index) { + _setTown(index); + }, + childCount: towns.length, + itemBuilder: (_, index) { + String text = towns[index]; + return Align( + alignment: Alignment.center, + child: Text(text, + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: _pickerStyle.textSize ?? + _pickerFontSize(text), + ), + textAlign: TextAlign.start), + ); + }, + )), + ) + : SizedBox() + ], + ), + ); + } + + // 选择器上面的view + Widget _titleView() { + return Container( + height: _pickerStyle.pickerTitleHeight, + decoration: _pickerStyle.headDecoration, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// 取消按钮 + InkWell( + onTap: () => Navigator.pop(context, false), + child: _pickerStyle.cancelButton), + + /// 标题 + Expanded(child: _pickerStyle.title), + + /// 确认按钮 + InkWell( + onTap: () { + if (widget.route.onConfirm != null) { + widget.route.onConfirm!( + _currentProvince, _currentCity, _currentTown); + } + Navigator.pop(context, true); + }, + child: _pickerStyle.commitButton) + ], + ), + ); + } +} + +class _BottomPickerLayout extends SingleChildLayoutDelegate { + _BottomPickerLayout(this.progress, this.pickerStyle); + + final double progress; + final PickerStyle pickerStyle; + + @override + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { + double maxHeight = pickerStyle.pickerHeight; + if (pickerStyle.showTitleBar) { + maxHeight += pickerStyle.pickerTitleHeight; + } + if (pickerStyle.menu != null) { + maxHeight += pickerStyle.menuHeight; + } + + return BoxConstraints( + minWidth: constraints.maxWidth, + maxWidth: constraints.maxWidth, + minHeight: 0.0, + maxHeight: maxHeight); + } + + @override + Offset getPositionForChild(Size size, Size childSize) { + double height = size.height - childSize.height * progress; + return Offset(0.0, height); + } + + @override + bool shouldRelayout(_BottomPickerLayout oldDelegate) { + return progress != oldDelegate.progress; + } +} diff --git a/star_lock/lib/tools/pickers/more_pickers/init_data.dart b/star_lock/lib/tools/pickers/more_pickers/init_data.dart new file mode 100644 index 00000000..4154da33 --- /dev/null +++ b/star_lock/lib/tools/pickers/more_pickers/init_data.dart @@ -0,0 +1,76 @@ +enum PickerDataType { + sex, // 性别 + education, // 学历 + subject, // 学科 + constellation, // 星座 + zodiac, // 生肖 + ethnicity, // 名族 +} + +var pickerData = { + PickerDataType.sex: ['不限', '男', '女'], + PickerDataType.education: ["高中以下", "高中", "大专", "本科", "硕士", "博士", "博士后", '其它'], + PickerDataType.subject: ["语文", "数学", "英语", "物理", "化学", "生物", "政治", "地理", "历史"], + PickerDataType.constellation: ["水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座"], + PickerDataType.zodiac: ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'], + PickerDataType.ethnicity: [ + '汉族', + '蒙古族', + '回族', + '藏族', + '维吾尔族', + '苗族', + '彝族', + '壮族', + '布依族', + '朝鲜族', + '满族', + '侗族', + '瑶族', + '白族', + '土家族', + '哈尼族', + '哈萨克族', + '傣族', + '黎族', + '傈僳族', + '佤族', + '畲族', + '高山族', + '拉祜族', + '水族', + '东乡族', + '纳西族', + '景颇族', + '柯尔克孜族', + '土族', + '达斡尔族', + '仫佬族', + '羌族', + '布朗族', + '撒拉族', + '毛难族', + '仡佬族', + '锡伯族', + '阿昌族', + '普米族', + '塔吉克族', + '怒族', + '乌孜别克族', + '俄罗斯族', + '鄂温克族', + '崩龙族', + '保安族', + '裕固族', + '京族', + '塔塔尔族', + '独龙族', + '鄂伦春族', + '赫哲族', + '门巴族', + '珞巴族', + '基诺族', + '其他', + '外国血统中国人士' + ], +}; diff --git a/star_lock/lib/tools/pickers/more_pickers/route/multiple_link_picker_route.dart b/star_lock/lib/tools/pickers/more_pickers/route/multiple_link_picker_route.dart new file mode 100644 index 00000000..10f5c35c --- /dev/null +++ b/star_lock/lib/tools/pickers/more_pickers/route/multiple_link_picker_route.dart @@ -0,0 +1,493 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:star_lock/tools/pickers/style/picker_style.dart'; +// import 'package:flutter_pickers/style/picker_style.dart'; + +typedef MultipleLinkCallback(List res, List position); + +/// 多项选择器 +/// 有关联 +class MultipleLinkPickerRoute extends PopupRoute { + MultipleLinkPickerRoute({ + required this.pickerStyle, + required this.data, + required this.selectData, + required this.columeNum, + this.suffix, + this.onChanged, + this.onConfirm, + this.onCancel, + this.theme, + this.barrierLabel, + RouteSettings? settings, + }) : super(settings: settings); + + final Map data; + final int columeNum; + final List selectData; + final List? suffix; + final MultipleLinkCallback? onChanged; + final MultipleLinkCallback? onConfirm; + final Function(bool isCancel)? onCancel; + final ThemeData? theme; + + final PickerStyle pickerStyle; + + @override + Duration get transitionDuration => const Duration(milliseconds: 200); + + @override + bool get barrierDismissible => true; + + @override + bool didPop(T? result) { + if (onCancel != null) { + if (result == null) { + onCancel!(false); + } else if (!(result as bool)) { + onCancel!(true); + } + } + return super.didPop(result); + } + + @override + final String? barrierLabel; + + @override + Color get barrierColor => Colors.black54; + + late AnimationController _animationController; + + @override + AnimationController createAnimationController() { + _animationController = + BottomSheet.createAnimationController(navigator!.overlay!); + return _animationController; + } + + @override + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { + Widget bottomSheet = MediaQuery.removePadding( + context: context, + removeTop: true, + child: _PickerContentView( + data: data, + columeNum: columeNum, + selectData: selectData, + pickerStyle: pickerStyle, + route: this, + ), + ); + if (theme != null) { + bottomSheet = Theme(data: theme!, child: bottomSheet); + } + + return bottomSheet; + } +} + +class _PickerContentView extends StatefulWidget { + _PickerContentView({ + Key? key, + required this.data, + required this.columeNum, + required this.pickerStyle, + required this.selectData, + required this.route, + }) : super(key: key); + + final Map data; + final int columeNum; + final List selectData; + final MultipleLinkPickerRoute route; + final PickerStyle pickerStyle; + + @override + State createState() => _PickerState( + this.data, this.selectData, this.pickerStyle, this.columeNum); +} + +class _PickerState extends State<_PickerContentView> { + final PickerStyle _pickerStyle; + + // 没有数据时占位字符 + static const placeData = ''; + + /// 选中数据 + late List _selectData; + + /// 选中数据下标 + late List _selectDataPosition; + + /// 原始数据 + Map _data; + + /// 有多少列 + final int _columeNum; + + /// 所有item 对应的数据 + late List _columnData = []; + + AnimationController? controller; + Animation? animation; + + List scrollCtrl = []; + + // 选择器 高度 单独提出来,用来解决修改数据 不及时更新的BUG + late double pickerItemHeight; + + _PickerState( + this._data, List mSelectData, this._pickerStyle, this._columeNum) { + this.pickerItemHeight = _pickerStyle.pickerItemHeight; + // 已选择器数据为准,因为初始化数据有可能和选择器对不上 + this._selectData = []; + this._selectDataPosition = []; + for (int i = 0; i < _columeNum; ++i) { + if (i >= mSelectData.length) { + this._selectData.add(''); + } else { + this._selectData.add(mSelectData[i]); + } + this._selectDataPosition.add(0); + } + + _init(mSelectData); + } + + @override + void dispose() { + scrollCtrl.forEach((element) { + element.dispose(); + }); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: AnimatedBuilder( + animation: widget.route.animation!, + builder: (BuildContext context, Widget? child) { + return ClipRect( + child: CustomSingleChildLayout( + delegate: _BottomPickerLayout(widget.route.animation!.value, + pickerStyle: _pickerStyle), + child: GestureDetector( + child: Material( + color: Colors.transparent, + child: _renderPickerView(), + ), + ), + ), + ); + }, + ), + ); + } + + _init(List mSelectData) { + int pindex; + scrollCtrl.clear(); + _columnData.clear(); + + for (int i = 0; i < _columeNum; ++i) { + pindex = 0; + + if (i == 0) { + /// 第一列 + pindex = _data.keys.toList().indexOf(_selectData[i]); + if (pindex < 0) { + _selectData[i] = _data.keys.first; + pindex = 0; + } + _selectDataPosition[i] = pindex; + + _columnData.add(_data.keys.toList()); + } else { + /// 其他列 + dynamic date = findNextData(i); + // print('longer 第$i列 >>> $date'); + + if (date is Map) { + pindex = date.keys.toList().indexOf(_selectData[i]); + if (pindex < 0) { + _selectData[i] = date.keys.first; + pindex = 0; + } + + _columnData.add(date.keys.toList()); + } else if (date is List) { + pindex = date.indexOf(_selectData[i]); + if (pindex < 0) { + _selectData[i] = date.first; + pindex = 0; + } + _columnData.add(date); + } else { + _selectData[i] = date; + pindex = 0; + + _columnData.add([date]); + } + + _selectDataPosition[i] = pindex; + } + + scrollCtrl.add(FixedExtentScrollController(initialItem: pindex)); + } + } + + /// [position] 变动的列 + /// [selectIndex] 对应列选中的index + /// [jump] 是否需要jumpToItem + void _setPicker(int position, int selectIndex, bool jump) { + // 得到新的选中的数据 + var selectValue = _columnData[position][selectIndex]; + // 更新选中数据 + _selectData[position] = selectValue; + _selectDataPosition[position] = selectIndex; + if (jump) { + scrollCtrl[position].jumpToItem(selectIndex); + } + + /// 如果不是最后一列 + /// 数据的变动都会造成剩下列的更新 + if (position < _columeNum - 1) { + // 先更新下一列所有数据 + // 如果这一列的所有数据都为空,下列直接也设为空数据(优化) + if (_columnData[position].length == 1 && + _columnData[position].first == placeData) { + _columnData[position + 1] = [placeData]; + } else { + _columnData[position + 1] = findColumeData(position + 1); + } + + // 再次递归 + _setPicker(position + 1, 0, true); + } else { + _notifyLocationChanged(); + } + } + + /// 找到对应位置的 下一列数据 + /// return map list other + dynamic findNextData(int position) { + dynamic nextData; + + for (int i = 0; i < position; i++) { + if (i == 0) { + // 肯定是map + nextData = _data[_selectData[0]]; + } else { + // 肯定是map + dynamic data = nextData[_selectData[i]]; + + if (data is Map) { + nextData = data; + } else if (data is List) { + nextData = data; + } else { + // 遍历到最后会返回该值 + nextData = [data]; + } + } + // print('longer i:$i >>> $nextData'); + + /// 如果数据 还没有到最后 就 已经不是Map + if (!(nextData is Map) && (i < position - 1)) { + return [placeData]; + } + } + + return nextData; + } + + /// 找到对应位置的数据 + /// 比如 position = 2; + /// 就是找到第2列数据 + /// return list + List findColumeData(int position) { + dynamic nextData; + for (int i = 0; i < position; i++) { + if (i == 0) { + // 肯定是map + nextData = _data[_selectData[0]]; + } else { + // print( + // 'longer 选中 >>> ${_selectData.join('-')} 当前选中: ${_selectData[i]}'); + // 肯定是map + dynamic data = nextData[_selectData[i]]; + + if (data is Map) { + nextData = data; + } else if (data is List) { + nextData = data; + } else { + // 遍历到最后会返回该值 + nextData = [data]; + } + } + // print('longer i:$i >>> $nextData'); + + /// 如果是map 并且是最后一列 返回他的key + if ((nextData is Map) && (i == position - 1)) { + return nextData.keys.toList(); + } + + /// 如果数据 还没有到最后 就 已经不是Map + if (!(nextData is Map) && (i < position - 1)) { + // print('longer2 第:$position列之前返回数据 >>> $nextData'); + return [placeData]; + } + } + + // print('longer 第:$position列返回数据 >>> $nextData'); + return nextData; + } + + void _notifyLocationChanged() { + setState(() { + /// FIX:https://github.com/flutter/flutter/issues/22999 + pickerItemHeight = + _pickerStyle.pickerItemHeight - Random().nextDouble() / 100000000; + }); + if (widget.route.onChanged != null) { + widget.route.onChanged!(_selectData, _selectDataPosition); + } + } + + Widget _renderPickerView() { + Widget itemView = _renderItemView(); + + if (!_pickerStyle.showTitleBar && _pickerStyle.menu == null) { + return itemView; + } + List viewList = []; + if (_pickerStyle.showTitleBar) { + viewList.add(_titleView()); + } + if (_pickerStyle.menu != null) { + viewList.add(_pickerStyle.menu!); + } + viewList.add(itemView); + + return Column(children: viewList); + } + + Widget _renderItemView() { + // 选择器 + List pickerList = + List.generate(_columeNum, (index) => pickerView(index)).toList(); + + return Container( + height: _pickerStyle.pickerHeight, + color: _pickerStyle.backgroundColor, + child: Row(children: pickerList), + ); + } + + Widget pickerView(int position) { + return Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: CupertinoPicker.builder( + scrollController: scrollCtrl[position], + itemExtent: pickerItemHeight, + selectionOverlay: _pickerStyle.itemOverlay, + onSelectedItemChanged: (int selectIndex) { + _setPicker(position, selectIndex, false); + }, + childCount: _columnData[position].length, + itemBuilder: (_, index) { + // String text = _data[position][index].toString(); + String suffix = ''; + if (widget.route.suffix != null && + position < widget.route.suffix!.length) { + suffix = widget.route.suffix![position]; + } + + String text = '${_columnData[position][index]}$suffix'; + return Align( + alignment: Alignment.center, + child: Text(text, + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: _pickerStyle.textSize ?? 18.0, + ), + textAlign: TextAlign.start)); + }, + ), + ), + ); + } + + // 选择器上面的view + Widget _titleView() { + return Container( + height: _pickerStyle.pickerTitleHeight, + decoration: _pickerStyle.headDecoration, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// 取消按钮 + InkWell( + onTap: () => Navigator.pop(context, false), + child: _pickerStyle.cancelButton), + + /// 标题 + Expanded(child: _pickerStyle.title), + + /// 确认按钮 + InkWell( + onTap: () { + if (widget.route.onConfirm != null) { + widget.route.onConfirm!(_selectData, _selectDataPosition); + } + Navigator.pop(context, true); + }, + child: _pickerStyle.commitButton) + ], + ), + ); + } +} + +class _BottomPickerLayout extends SingleChildLayoutDelegate { + _BottomPickerLayout(this.progress, {required this.pickerStyle}); + + final double progress; + final PickerStyle pickerStyle; + + @override + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { + double maxHeight = pickerStyle.pickerHeight; + if (pickerStyle.showTitleBar) { + maxHeight += pickerStyle.pickerTitleHeight; + } + if (pickerStyle.menu != null) { + maxHeight += pickerStyle.menuHeight; + } + + return BoxConstraints( + minWidth: constraints.maxWidth, + maxWidth: constraints.maxWidth, + minHeight: 0.0, + maxHeight: maxHeight); + } + + @override + Offset getPositionForChild(Size size, Size childSize) { + double height = size.height - childSize.height * progress; + return Offset(0.0, height); + } + + @override + bool shouldRelayout(_BottomPickerLayout oldDelegate) { + return progress != oldDelegate.progress; + } +} diff --git a/star_lock/lib/tools/pickers/more_pickers/route/multiple_picker_route.dart b/star_lock/lib/tools/pickers/more_pickers/route/multiple_picker_route.dart new file mode 100644 index 00000000..9ff6e06d --- /dev/null +++ b/star_lock/lib/tools/pickers/more_pickers/route/multiple_picker_route.dart @@ -0,0 +1,332 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:star_lock/tools/pickers/style/picker_style.dart'; +// import 'package:flutter_pickers/style/picker_style.dart'; + +typedef MultipleCallback(List res, List position); + +/// 多项选择器 +/// 无关联 +class MultiplePickerRoute extends PopupRoute { + MultiplePickerRoute({ + required this.pickerStyle, + required this.data, + required this.selectData, + this.suffix, + this.onChanged, + this.onConfirm, + this.onCancel, + this.theme, + this.barrierLabel, + RouteSettings? settings, + }) : super(settings: settings); + + final List data; + final List selectData; + final List? suffix; + final MultipleCallback? onChanged; + final MultipleCallback? onConfirm; + final Function(bool isCancel)? onCancel; + final ThemeData? theme; + + final PickerStyle pickerStyle; + + @override + Duration get transitionDuration => const Duration(milliseconds: 200); + + @override + bool get barrierDismissible => true; + + @override + bool didPop(T? result) { + if (onCancel != null) { + if (result == null) { + onCancel!(false); + } else if (!(result as bool)) { + onCancel!(true); + } + } + return super.didPop(result); + } + + @override + final String? barrierLabel; + + @override + Color get barrierColor => Colors.black54; + + late AnimationController _animationController; + + @override + AnimationController createAnimationController() { + _animationController = + BottomSheet.createAnimationController(navigator!.overlay!); + return _animationController; + } + + @override + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { + Widget bottomSheet = MediaQuery.removePadding( + context: context, + removeTop: true, + child: _PickerContentView( + data: data, + selectData: selectData, + pickerStyle: pickerStyle, + route: this, + ), + ); + if (theme != null) { + bottomSheet = Theme(data: theme!, child: bottomSheet); + } + + return bottomSheet; + } +} + +class _PickerContentView extends StatefulWidget { + _PickerContentView({ + Key? key, + required this.data, + required this.pickerStyle, + required this.selectData, + required this.route, + }) : super(key: key); + + final List data; + final List selectData; + final MultiplePickerRoute route; + final PickerStyle pickerStyle; + + @override + State createState() => + _PickerState(this.data, this.selectData, this.pickerStyle); +} + +class _PickerState extends State<_PickerContentView> { + final PickerStyle _pickerStyle; + late List _selectData; + late List _selectDataPosition; + List _data; + + AnimationController? controller; + Animation? animation; + + List scrollCtrl = []; + + _PickerState(this._data, List mSelectData, this._pickerStyle) { + // 已选择器数据为准,因为初始化数据有可能和选择器对不上 + this._selectData = []; + this._selectDataPosition = []; + this._data.asMap().keys.forEach((index) { + if (index >= mSelectData.length) { + this._selectData.add(''); + } else { + this._selectData.add(mSelectData[index]); + } + this._selectDataPosition.add(0); + }); + + _init(); + } + + @override + void dispose() { + scrollCtrl.forEach((element) { + element.dispose(); + }); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: AnimatedBuilder( + animation: widget.route.animation!, + builder: (BuildContext context, Widget? child) { + return ClipRect( + child: CustomSingleChildLayout( + delegate: _BottomPickerLayout(widget.route.animation!.value, + pickerStyle: _pickerStyle), + child: GestureDetector( + child: Material( + color: Colors.transparent, + child: _renderPickerView(), + ), + ), + ), + ); + }, + ), + ); + } + + _init() { + int pindex; + scrollCtrl.clear(); + + this._data.asMap().keys.forEach((index) { + pindex = 0; + pindex = _data[index].indexWhere( + (element) => element.toString() == _selectData[index].toString()); + // 如果没有匹配到选择器对应数据,我们得修改选择器选中数据 ,不然confirm 返回的事设置的数据 + if (pindex < 0) { + _selectData[index] = _data[index][0]; + pindex = 0; + } + _selectDataPosition[index] = pindex; + + scrollCtrl.add(new FixedExtentScrollController(initialItem: pindex)); + }); + } + + void _setPicker(int index, int selectIndex) { + var selectedName = _data[index][selectIndex]; + + // if (_selectData[index].toString() != selectedName.toString()) { + // setState(() { + // }); + // } + _selectData[index] = selectedName; + _selectDataPosition[index] = selectIndex; + + _notifyLocationChanged(); + } + + void _notifyLocationChanged() { + if (widget.route.onChanged != null) { + widget.route.onChanged!(_selectData, _selectDataPosition); + } + } + + Widget _renderPickerView() { + Widget itemView = _renderItemView(); + + if (!_pickerStyle.showTitleBar && _pickerStyle.menu == null) { + return itemView; + } + List viewList = []; + if (_pickerStyle.showTitleBar) { + viewList.add(_titleView()); + } + if (_pickerStyle.menu != null) { + viewList.add(_pickerStyle.menu!); + } + viewList.add(itemView); + + return Column(children: viewList); + } + + Widget _renderItemView() { + // 选择器 + List pickerList = + List.generate(this._data.length, (index) => pickerView(index)).toList(); + + return Container( + height: _pickerStyle.pickerHeight, + color: _pickerStyle.backgroundColor, + child: Row(children: pickerList), + ); + } + + Widget pickerView(int position) { + return Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: CupertinoPicker.builder( + scrollController: scrollCtrl[position], + selectionOverlay: _pickerStyle.itemOverlay, + itemExtent: _pickerStyle.pickerItemHeight, + onSelectedItemChanged: (int selectIndex) => + _setPicker(position, selectIndex), + childCount: _data[position].length, + itemBuilder: (_, index) { + // String text = _data[position][index].toString(); + String suffix = ''; + if (widget.route.suffix != null && + position < widget.route.suffix!.length) { + suffix = widget.route.suffix![position]; + } + + String text = '${_data[position][index]}$suffix'; + return Align( + alignment: Alignment.center, + child: Text(text, + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: _pickerStyle.textSize ?? 18, + ), + textAlign: TextAlign.start)); + }, + ), + ), + ); + } + + // 选择器上面的view + Widget _titleView() { + return Container( + height: _pickerStyle.pickerTitleHeight, + decoration: _pickerStyle.headDecoration, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// 取消按钮 + InkWell( + onTap: () => Navigator.pop(context, false), + child: _pickerStyle.cancelButton), + + /// 标题 + Expanded(child: _pickerStyle.title), + + /// 确认按钮 + InkWell( + onTap: () { + if (widget.route.onConfirm != null) { + widget.route.onConfirm!(_selectData, _selectDataPosition); + } + Navigator.pop(context, true); + }, + child: _pickerStyle.commitButton) + ], + ), + ); + } +} + +class _BottomPickerLayout extends SingleChildLayoutDelegate { + _BottomPickerLayout(this.progress, {required this.pickerStyle}); + + final double progress; + final PickerStyle pickerStyle; + + @override + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { + double maxHeight = pickerStyle.pickerHeight; + if (pickerStyle.showTitleBar) { + maxHeight += pickerStyle.pickerTitleHeight; + } + if (pickerStyle.menu != null) { + maxHeight += pickerStyle.menuHeight; + } + + return BoxConstraints( + minWidth: constraints.maxWidth, + maxWidth: constraints.maxWidth, + minHeight: 0.0, + maxHeight: maxHeight); + } + + @override + Offset getPositionForChild(Size size, Size childSize) { + double height = size.height - childSize.height * progress; + return Offset(0.0, height); + } + + @override + bool shouldRelayout(_BottomPickerLayout oldDelegate) { + return progress != oldDelegate.progress; + } +} diff --git a/star_lock/lib/tools/pickers/more_pickers/route/single_picker_route.dart b/star_lock/lib/tools/pickers/more_pickers/route/single_picker_route.dart new file mode 100644 index 00000000..435f4146 --- /dev/null +++ b/star_lock/lib/tools/pickers/more_pickers/route/single_picker_route.dart @@ -0,0 +1,362 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:star_lock/tools/pickers/more_pickers/init_data.dart'; +import 'package:star_lock/tools/pickers/style/picker_style.dart'; +// import 'package:flutter_pickers/more_pickers/init_data.dart'; +// import 'package:flutter_pickers/style/picker_style.dart'; + +typedef SingleCallback(var data, int position); + +class SinglePickerRoute extends PopupRoute { + SinglePickerRoute({ + required this.data, + this.selectData, + this.suffix, + this.onChanged, + this.onConfirm, + this.onCancel, + required this.theme, + this.barrierLabel, + required this.pickerStyle, + RouteSettings? settings, + }) : super(settings: settings); + + final dynamic selectData; + final dynamic data; + final SingleCallback? onChanged; + final SingleCallback? onConfirm; + final Function(bool isCancel)? onCancel; + final ThemeData theme; + + final String? suffix; + final PickerStyle pickerStyle; + + @override + Duration get transitionDuration => const Duration(milliseconds: 200); + + @override + bool get barrierDismissible => true; + + @override + final String? barrierLabel; + + @override + bool didPop(T? result) { + if (onCancel != null) { + if (result == null) { + onCancel!(false); + } else if (!(result as bool)) { + onCancel!(true); + } + } + return super.didPop(result); + } + + @override + Color get barrierColor => Colors.black54; + + late AnimationController _animationController; + + @override + AnimationController createAnimationController() { + _animationController = + BottomSheet.createAnimationController(navigator!.overlay!); + return _animationController; + } + + @override + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { + List mData = []; + // 初始化数据 + if (data is PickerDataType) { + mData = pickerData[data]!; + } else if (data is List) { + mData.addAll(data); + } + + Widget bottomSheet = MediaQuery.removePadding( + context: context, + removeTop: true, + child: _PickerContentView( + data: mData, + selectData: selectData, + pickerStyle: pickerStyle, + route: this, + ), + ); + bottomSheet = Theme(data: theme, child: bottomSheet); + + return bottomSheet; + } +} + +class _PickerContentView extends StatefulWidget { + _PickerContentView({ + Key? key, + required this.data, + this.selectData, + required this.pickerStyle, + required this.route, + }) : super(key: key); + + final List data; + final dynamic selectData; + final SinglePickerRoute route; + final PickerStyle pickerStyle; + + @override + State createState() => + _PickerState(this.data, this.selectData, this.pickerStyle); +} + +class _PickerState extends State<_PickerContentView> { + final PickerStyle _pickerStyle; + + // 选中数据 + var _selectData; + + // 选中数据下标 + int _selectPosition = 0; + + List _data = []; + + late FixedExtentScrollController scrollCtrl; + + // 单位widget Padding left + late double _laberLeft; + + _PickerState(this._data, this._selectData, this._pickerStyle) { + _init(); + } + + @override + void dispose() { + scrollCtrl.dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: AnimatedBuilder( + animation: widget.route.animation!, + builder: (BuildContext context, Widget? child) { + return ClipRect( + child: CustomSingleChildLayout( + delegate: _BottomPickerLayout(widget.route.animation!.value, + pickerStyle: _pickerStyle), + child: GestureDetector( + child: Material( + color: Colors.transparent, + child: _renderPickerView(), + ), + ), + ), + ); + }, + ), + ); + } + + _init() { + int pindex = 0; + pindex = _data + .indexWhere((element) => element.toString() == _selectData.toString()); + // 如果没有匹配到选择器对应数据,我们得修改选择器选中数据 ,不然confirm 返回的事设置的数据 + if (pindex < 0) { + _selectData = _data[0]; + pindex = 0; + } + _selectPosition = pindex; + + scrollCtrl = new FixedExtentScrollController(initialItem: pindex); + _laberLeft = _pickerLaberPadding(_data[pindex].toString()); + } + + void _setPicker(int index) { + var selectedProvince = _data[index]; + + // if (_selectData.toString() != selectedProvince.toString()) { + // setState(() { + // }); + _selectData = selectedProvince; + _selectPosition = index; + + _notifyLocationChanged(); + // } + } + + void _notifyLocationChanged() { + if (widget.route.onChanged != null) { + widget.route.onChanged!(_selectData, _selectPosition); + } + } + + double _pickerLaberPadding(String? text) { + double left = 60; + + if (text != null) { + left = left + text.length * 12; + } + return left; + } + + /// 动态计算itemTextSize + double _pickerFontSize(String text) { + if (text.length <= 6) { + return 18.0; + } else if (text.length < 9) { + return 16.0; + } else if (text.length < 13) { + return 12.0; + } else { + return 10.0; + } + } + + Widget _renderPickerView() { + Widget itemView = _renderItemView(); + + if (!_pickerStyle.showTitleBar && _pickerStyle.menu == null) { + return itemView; + } + List viewList = []; + if (_pickerStyle.showTitleBar) { + viewList.add(_titleView()); + } + if (_pickerStyle.menu != null) { + viewList.add(_pickerStyle.menu!); + } + viewList.add(itemView); + + return Column(children: viewList); + } + + Widget _renderItemView() { + // 选择器 + Widget cPicker = CupertinoPicker.builder( + scrollController: scrollCtrl, + itemExtent: _pickerStyle.pickerItemHeight, + selectionOverlay: _pickerStyle.itemOverlay, + onSelectedItemChanged: (int index) { + _setPicker(index); + if (widget.route.suffix != null && widget.route.suffix != '') { + // 如果设置了才计算 单位的paddingLeft + double resuleLeft = _pickerLaberPadding(_data[index].toString()); + if (resuleLeft != _laberLeft) { + setState(() { + _laberLeft = resuleLeft; + }); + } + } + }, + childCount: _data.length, + itemBuilder: (_, index) { + String text = _data[index].toString(); + return Align( + alignment: Alignment.center, + child: Text(text, + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: _pickerStyle.textSize ?? _pickerFontSize(text), + ), + textAlign: TextAlign.start)); + }, + ); + + Widget view; + // 单位 + if (widget.route.suffix != null && widget.route.suffix != '') { + Widget laberView = Center( + child: AnimatedPadding( + duration: Duration(milliseconds: 100), + padding: EdgeInsets.only(left: _laberLeft), + child: Text(widget.route.suffix!, + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: 20, + fontWeight: FontWeight.w500)), + )); + + view = Stack(children: [cPicker, laberView]); + } else { + view = cPicker; + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + height: _pickerStyle.pickerHeight, + color: _pickerStyle.backgroundColor, + child: view, + ); + } + + // 选择器上面的view + Widget _titleView() { + return Container( + height: _pickerStyle.pickerTitleHeight, + decoration: _pickerStyle.headDecoration, + child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// 取消按钮 + InkWell( + onTap: () => Navigator.pop(context, false), + child: _pickerStyle.cancelButton), + + /// 标题 + Expanded(child: _pickerStyle.title), + + /// 确认按钮 + InkWell( + onTap: () { + if (widget.route.onConfirm != null) { + print('longer _selectPosition >>> ${_selectPosition}'); + widget.route.onConfirm!(_selectData, _selectPosition); + } + Navigator.pop(context, true); + }, + child: _pickerStyle.commitButton) + ], + ), + ); + } +} + +class _BottomPickerLayout extends SingleChildLayoutDelegate { + _BottomPickerLayout(this.progress, {required this.pickerStyle}); + + final double progress; + final PickerStyle pickerStyle; + + @override + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { + double maxHeight = pickerStyle.pickerHeight; + if (pickerStyle.showTitleBar) { + maxHeight += pickerStyle.pickerTitleHeight; + } + if (pickerStyle.menu != null) { + maxHeight += pickerStyle.menuHeight; + } + + return BoxConstraints( + minWidth: constraints.maxWidth, + maxWidth: constraints.maxWidth, + minHeight: 0.0, + maxHeight: maxHeight); + } + + @override + Offset getPositionForChild(Size size, Size childSize) { + double height = size.height - childSize.height * progress; + return Offset(0.0, height); + } + + @override + bool shouldRelayout(_BottomPickerLayout oldDelegate) { + return progress != oldDelegate.progress; + } +} diff --git a/star_lock/lib/tools/pickers/pickers.dart b/star_lock/lib/tools/pickers/pickers.dart new file mode 100644 index 00000000..1930b822 --- /dev/null +++ b/star_lock/lib/tools/pickers/pickers.dart @@ -0,0 +1,252 @@ +import 'package:flutter/material.dart'; +import 'package:star_lock/tools/pickers/address_picker/route/address_picker_route.dart'; +import 'package:star_lock/tools/pickers/more_pickers/init_data.dart'; +import 'package:star_lock/tools/pickers/more_pickers/route/multiple_link_picker_route.dart'; +import 'package:star_lock/tools/pickers/more_pickers/route/multiple_picker_route.dart'; +import 'package:star_lock/tools/pickers/more_pickers/route/single_picker_route.dart'; +import 'package:star_lock/tools/pickers/style/default_style.dart'; +import 'package:star_lock/tools/pickers/style/picker_style.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/pduration.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/suffix.dart'; +import 'package:star_lock/tools/pickers/time_picker/route/date_picker_route.dart'; +// import 'package:flutter_pickers/address_picker/route/address_picker_route.dart'; +// import 'package:flutter_pickers/more_pickers/init_data.dart'; +// import 'package:flutter_pickers/more_pickers/route/multiple_link_picker_route.dart'; +// import 'package:flutter_pickers/more_pickers/route/multiple_picker_route.dart'; +// import 'package:flutter_pickers/more_pickers/route/single_picker_route.dart'; +// import 'package:flutter_pickers/style/default_style.dart'; +// import 'package:flutter_pickers/style/picker_style.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/time_picker/model/pduration.dart'; +// import 'package:flutter_pickers/time_picker/model/suffix.dart'; +// import 'package:flutter_pickers/time_picker/route/date_picker_route.dart'; + +import 'time_picker/model/date_item_model.dart'; + +/// [onChanged] 选择器发生变动 +/// [onConfirm] 选择器提交 +/// [pickerStyle] 样式 +/// [suffix] 后缀 +class Pickers { + /// 单列 通用选择器 + static void showSinglePicker(BuildContext context, + {required dynamic data, + dynamic selectData, + String? suffix, + PickerStyle? pickerStyle, + SingleCallback? onChanged, + SingleCallback? onConfirm, + Function(bool isCancel)? onCancel, + bool overlapTabBar = false}) { + assert((data is List) || (data is PickerDataType), + 'params : data must List or PickerDataType'); + + if (pickerStyle == null) { + pickerStyle = DefaultPickerStyle(); + } + if (pickerStyle.context == null) { + pickerStyle.context = context; + } + + Navigator.of(context, rootNavigator: overlapTabBar).push(SinglePickerRoute( + data: data, + suffix: suffix, + selectData: selectData, + pickerStyle: pickerStyle, + onChanged: onChanged, + onConfirm: onConfirm, + onCancel: onCancel, + // theme: Theme.of(context, shadowThemeOnly: true), + theme: Theme.of(context), + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + )); + } + + /// 通用 多列选择器 + /// 无关联 + static void showMultiPicker(BuildContext context, + {required List data, + List? selectData, + List? suffix, + PickerStyle? pickerStyle, + MultipleCallback? onChanged, + MultipleCallback? onConfirm, + Function(bool isCancel)? onCancel, + bool overlapTabBar = false}) { + if (selectData == null) { + selectData = []; + } + + if (pickerStyle == null) { + pickerStyle = DefaultPickerStyle(); + } + if (pickerStyle.context == null) { + pickerStyle.context = context; + } + + Navigator.of(context, rootNavigator: overlapTabBar) + .push(MultiplePickerRoute( + data: data, + selectData: selectData, + suffix: suffix, + pickerStyle: pickerStyle, + onChanged: onChanged, + onConfirm: onConfirm, + onCancel: onCancel, + // theme: Theme.of(context, shadowThemeOnly: true), + theme: Theme.of(context), + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + )); + } + + /// 通用 多列选择器 + /// 有关联 + /// [columeNum] 最大的列数 + static void showMultiLinkPicker(BuildContext context, + {required dynamic data, + required int columeNum, + List? selectData, + List? suffix, + PickerStyle? pickerStyle, + MultipleLinkCallback? onChanged, + MultipleLinkCallback? onConfirm, + Function(bool isCancel)? onCancel, + bool overlapTabBar = false}) { + assert(data is Map, 'params : data must Map'); + + if (selectData == null) { + selectData = []; + } + + if (pickerStyle == null) { + pickerStyle = DefaultPickerStyle(); + } + if (pickerStyle.context == null) { + pickerStyle.context = context; + } + + Navigator.of(context, rootNavigator: overlapTabBar) + .push(MultipleLinkPickerRoute( + data: data, + selectData: selectData, + columeNum: columeNum, + suffix: suffix, + pickerStyle: pickerStyle, + onChanged: onChanged, + onConfirm: onConfirm, + onCancel: onCancel, + // theme: Theme.of(context, shadowThemeOnly: true), + theme: Theme.of(context), + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + )); + } + + /// 自定义 地区选择器 + /// [initProvince] 初始化 省 + /// [initCity] 初始化 市 + /// [initTown] 初始化 区 + /// [onChanged] 选择器发生变动 + /// [onConfirm] 选择器提交 + /// [addAllItem] 市、区是否添加 '全部' 选项 默认:true + static void showAddressPicker(BuildContext context, + {PickerStyle? pickerStyle, + String initProvince: '', + String initCity: '', + String? initTown, + bool addAllItem: true, + AddressCallback? onChanged, + AddressCallback? onConfirm, + Function(bool isCancel)? onCancel, + bool overlapTabBar = false}) { + if (pickerStyle == null) { + pickerStyle = DefaultPickerStyle(); + } + if (pickerStyle.context == null) { + pickerStyle.context = context; + } + + Navigator.of(context, rootNavigator: overlapTabBar).push(AddressPickerRoute( + pickerStyle: pickerStyle, + initProvince: initProvince, + initCity: initCity, + initTown: initTown, + onChanged: onChanged, + onConfirm: onConfirm, + onCancel: onCancel, + addAllItem: addAllItem, + theme: Theme.of(context), + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + )); + } + + /// 时间选择器 + /// [Suffix] : 每列时间对应的单位 默认:中文常规 Suffix(years: '年',month: '月'); + /// [selectDate] : 初始化选中时间 默认现在 + /// PDuration.now(); + /// PDuration.parse(DateTime.parse('20210139')); + /// PDuration(year: 2020,month: 2); + /// [maxDate] : 最大时间 用法同上 + /// tip: 当只有单列数据,该限制不产生关联 只针对单列item限制,比如 maxDate>day = 3 minDate>day = 10,那么所有的月份都只显示3-10之间 + /// [minDate] : 最小时间 用法同上 + /// [mode] : 时间选择器所显示样式 16 种时间样式 默认:DateMode.YMD + static void showDatePicker(BuildContext context, + {DateMode mode: DateMode.YMD, + PDuration? selectDate, + PDuration? maxDate, + PDuration? minDate, + Suffix? suffix, + PickerStyle? pickerStyle, + DateCallback? onChanged, + DateCallback? onConfirm, + Function(bool isCancel)? onCancel, + bool overlapTabBar = false}) { + if (pickerStyle == null) { + pickerStyle = DefaultPickerStyle(); + } + if (pickerStyle.context == null) { + pickerStyle.context = context; + } + + if (selectDate == null) selectDate = PDuration.now(); + if (suffix == null) suffix = Suffix.normal(); + + // 解析是否有对应数据 + DateItemModel dateItemModel = DateItemModel.parse(mode); + + if (maxDate == null) maxDate = PDuration(year: 2100); + if (minDate == null) minDate = PDuration(year: 1900); + + if ((dateItemModel.day || dateItemModel.year)) { + if (intEmpty(selectDate.year)) { + print('picker Tip >>> initDate未设置years,默认设置为now().year'); + selectDate.year = DateTime.now().year; + } + + /// 如果有年item ,必须限制 + if (intEmpty(maxDate.year)) maxDate.year = 2100; + if (intEmpty(minDate.year)) minDate.year = 1900; + + // print('longer >>> ${minDate.year}'); + + if (dateItemModel.month || dateItemModel.day) { + assert(minDate.year! > 1582, 'min Date Year must > 1582'); + } + } + + Navigator.of(context, rootNavigator: overlapTabBar).push(DatePickerRoute( + mode: mode, + initDate: selectDate, + maxDate: maxDate, + minDate: minDate, + suffix: suffix, + pickerStyle: pickerStyle, + onChanged: onChanged, + onConfirm: onConfirm, + onCancel: onCancel, + // theme: Theme.of(context, shadowThemeOnly: true), + theme: Theme.of(context), + barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + )); + } +} diff --git a/star_lock/lib/tools/pickers/style/default_style.dart b/star_lock/lib/tools/pickers/style/default_style.dart new file mode 100644 index 00000000..56e43d9b --- /dev/null +++ b/star_lock/lib/tools/pickers/style/default_style.dart @@ -0,0 +1,205 @@ +import 'package:flutter/material.dart'; +import 'package:star_lock/tools/pickers/style/picker_style.dart'; +// import 'package:flutter_pickers/style/picker_style.dart'; + +// 日间圆角 +const headDecorationLight = BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))); + +/// 无标题样式 +class NoTitleStyle extends PickerStyle { + NoTitleStyle() { + showTitleBar = false; + } + + /// 夜间 + NoTitleStyle.dark() { + showTitleBar = false; + backgroundColor = Colors.grey[800]!; + textColor = Colors.white; + } +} + +/// 默认样式 +class DefaultPickerStyle extends PickerStyle { + DefaultPickerStyle({bool haveRadius = false, String? title}) { + if (haveRadius) { + headDecoration = const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))); + } + if (title != null && title != '') { + this.title = Center( + child: Text(title, + style: const TextStyle(color: Colors.grey, fontSize: 14))); + } + } + + /// 夜间 + DefaultPickerStyle.dark({bool haveRadius = false, String? title}) { + commitButton = Container( + alignment: Alignment.center, + padding: const EdgeInsets.only(left: 12, right: 22), + child: const Text('确定', + style: TextStyle(color: Colors.white, fontSize: 16.0)), + ); + + cancelButton = Container( + alignment: Alignment.center, + padding: const EdgeInsets.only(left: 22, right: 12), + child: const Text('取消', + style: TextStyle(color: Colors.white, fontSize: 16.0)), + ); + + headDecoration = BoxDecoration( + color: Colors.grey[800], + borderRadius: !haveRadius + ? null + : const BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))); + + if (title != null && title != '') { + this.title = Center( + child: Text(title, + style: const TextStyle(color: Colors.white, fontSize: 14))); + } + + backgroundColor = Colors.grey[800]!; + textColor = Colors.white; + } +} + +/// 关闭按钮样式 +class ClosePickerStyle extends PickerStyle { + /// 日间 + ClosePickerStyle({bool haveRadius = false, String? title}) { + if (haveRadius) { + headDecoration = const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))); + } + + cancelButton = const SizedBox(); + if (title != null && title != '') { + this.title = Padding( + padding: const EdgeInsets.only(left: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text(title, + style: const TextStyle(color: Colors.grey, fontSize: 14))), + ); + } + commitButton = Container( + // padding: const EdgeInsets.all(4), + margin: const EdgeInsets.only(right: 12), + child: const Icon(Icons.close, color: Colors.grey, size: 28), + ); + } + + /// 夜间 + ClosePickerStyle.dark({bool haveRadius = false, String? title}) { + headDecoration = BoxDecoration( + color: Colors.grey[800], + borderRadius: !haveRadius + ? null + : const BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))); + + cancelButton = const SizedBox(); + commitButton = Container( + margin: const EdgeInsets.only(right: 12), + child: const Icon(Icons.close, color: Colors.white, size: 28), + ); + if (title != null && title != '') { + this.title = Padding( + padding: const EdgeInsets.only(left: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text(title, + style: const TextStyle(color: Colors.white, fontSize: 14))), + ); + } + + backgroundColor = Colors.grey[800]!; + textColor = Colors.white; + } +} + +/// 圆角按钮样式 +class RaisedPickerStyle extends PickerStyle { + RaisedPickerStyle( + {bool haveRadius = false, String? title, Color color = Colors.blue}) { + if (haveRadius) { + headDecoration = const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))); + } + commitButton = Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3), + margin: const EdgeInsets.only(right: 22), + decoration: + BoxDecoration(color: color, borderRadius: BorderRadius.circular(4)), + child: const Text('确定', + style: TextStyle(color: Colors.white, fontSize: 15.0)), + ); + + cancelButton = Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3), + margin: const EdgeInsets.only(left: 22), + decoration: BoxDecoration( + border: Border.all(color: color, width: 1), + borderRadius: BorderRadius.circular(4)), + child: Text('取消', style: TextStyle(color: color, fontSize: 15.0)), + ); + + if (title != null && title != '') { + this.title = Center( + child: Text(title, + style: const TextStyle(color: Colors.grey, fontSize: 14))); + } + } + + /// 夜间 + RaisedPickerStyle.dark( + {bool haveRadius = false, String? title, Color? color}) { + headDecoration = BoxDecoration( + color: Colors.grey[800], + borderRadius: !haveRadius + ? null + : const BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10))); + + commitButton = Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3), + margin: const EdgeInsets.only(right: 22), + decoration: BoxDecoration( + color: color ?? Colors.blue, borderRadius: BorderRadius.circular(4)), + child: const Text('确定', + style: TextStyle(color: Colors.white, fontSize: 15.0)), + ); + + cancelButton = Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3), + margin: const EdgeInsets.only(left: 22), + decoration: BoxDecoration( + border: Border.all(color: Colors.white, width: 1), + borderRadius: BorderRadius.circular(4)), + child: const Text('取消', + style: TextStyle(color: Colors.white, fontSize: 15.0)), + ); + + if (title != null && title != '') { + this.title = Center( + child: Text(title, + style: const TextStyle(color: Colors.white, fontSize: 14))); + } + + backgroundColor = Colors.grey[800]!; + textColor = Colors.white; + } +} diff --git a/star_lock/lib/tools/pickers/style/picker_style.dart b/star_lock/lib/tools/pickers/style/picker_style.dart new file mode 100644 index 00000000..f32c87e8 --- /dev/null +++ b/star_lock/lib/tools/pickers/style/picker_style.dart @@ -0,0 +1,186 @@ +import 'package:flutter/material.dart'; + +/// 基础样式 +/// [showTitleBar] 是否显示头部(选择器以上的控件) 默认:true +/// [menu] 头部和选择器之间的菜单widget,默认null 不显示 +/// [title] 头部 中间的标题 默认SizedBox() 不显示 +/// [pickerHeight] 选择器下面 picker 的整体高度 固定高度:220.0 +/// [pickerTitleHeight] 选择器上面 title 确认、取消的整体高度 固定高度:44.0 +/// [pickerItemHeight] 选择器每个被选中item的高度:40.0 +/// [menuHeight] 头部和选择器之间的菜单高度 固定高度:36.0 +/// [cancelButton] 头部的取消按钮 +/// [commitButton] 头部的确认按钮 +/// [textColor] 选择器的文字颜色 默认黑色 +/// [textSize] 选择器的文字大小 +/// [backgroundColor] 选择器的背景颜色 默认白色 +/// [headDecoration] 头部Container 的Decoration 默认:BoxDecoration(color: Colors.white) +/// +class PickerStyle { + BuildContext? _context; + + bool? _showTitleBar; + Widget? _menu; + double? _pickerHeight; + double? _pickerTitleHeight; + double? _pickerItemHeight; + double? _menuHeight; + + Widget? _cancelButton; + Widget? _commitButton; + Widget? _title; + Decoration? _headDecoration; + Color? _backgroundColor; + Color? _textColor; + double? _textSize; + Widget? _itemOverlay; + + PickerStyle({ + BuildContext? context, + bool? showTitleBar, + Widget? menu, + double? pickerHeight, + double? pickerTitleHeight, + double? pickerItemHeight, + double? menuHeight, + Widget? cancelButton, + Widget? commitButton, + Widget? title, + Decoration? headDecoration, + Color? backgroundColor, + Color? textColor, + double? textSize, + Widget? itemOverlay, + }) { + this._context = context; + this._showTitleBar = showTitleBar; + this._menu = menu; + + this._pickerHeight = pickerHeight; + this._pickerTitleHeight = pickerTitleHeight; + this._pickerItemHeight = pickerItemHeight; + this._menuHeight = menuHeight; + + this._cancelButton = cancelButton; + this._commitButton = commitButton; + this._title = title; + this._headDecoration = headDecoration; + this._backgroundColor = backgroundColor; + this._textColor = textColor; + this._textSize = textSize; + this._itemOverlay = itemOverlay; + } + + set context(BuildContext? value) { + _context = value; + } + + set menuHeight(double value) { + _menuHeight = value; + } + + set menu(Widget? value) { + _menu = value; + } + + set pickerHeight(double value) { + _pickerHeight = value; + } + + set pickerTitleHeight(double value) { + _pickerTitleHeight = value; + } + + set pickerItemHeight(double value) { + _pickerItemHeight = value; + } + + set cancelButton(Widget value) { + _cancelButton = value; + } + + set commitButton(Widget value) { + _commitButton = value; + } + + set itemOverlay(Widget? value) { + _itemOverlay = value; + } + + set title(Widget value) { + _title = value; + } + + set headDecoration(Decoration value) { + _headDecoration = value; + } + + set backgroundColor(Color value) { + _backgroundColor = value; + } + + set textColor(Color value) { + _textColor = value; + } + + set textSize(double? value) { + _textSize = value; + } + + set showTitleBar(bool value) { + _showTitleBar = value; + } + + BuildContext? get context => this._context; + + /// 选择器背景色 默认白色 + Color get backgroundColor => this._backgroundColor ?? Colors.white; + + Decoration get headDecoration => + this._headDecoration ?? BoxDecoration(color: Colors.white); + + Widget? get menu => this._menu; + + double get menuHeight => this._menuHeight ?? 36.0; + + double get pickerHeight => this._pickerHeight ?? 220.0; + + double get pickerItemHeight => this._pickerItemHeight ?? 40.0; + + double get pickerTitleHeight => this._pickerTitleHeight ?? 44.0; + + bool get showTitleBar => this._showTitleBar ?? true; + + Color get textColor => this._textColor ?? Colors.black87; + + double? get textSize => this._textSize; + + Widget get title => this._title ?? SizedBox(); + + Widget get commitButton => getCommitButton(); + + Widget get cancelButton => getCancelButton(); + + Widget? get itemOverlay => this._itemOverlay; + + Widget getCommitButton() { + return this._commitButton ?? + Container( + alignment: Alignment.center, + padding: const EdgeInsets.only(left: 12, right: 22), + child: const Text('确定', + style: TextStyle(color: Colors.blue, fontSize: 16.0)), + ); + } + + Widget getCancelButton() { + return this._cancelButton ?? + Container( + alignment: Alignment.center, + padding: const EdgeInsets.only(left: 22, right: 12), + child: Text('取消', + style: TextStyle( + color: Theme.of(context!).unselectedWidgetColor, + fontSize: 16.0)), + ); + } +} diff --git a/star_lock/lib/tools/pickers/time_picker/model/date_item_model.dart b/star_lock/lib/tools/pickers/time_picker/model/date_item_model.dart new file mode 100644 index 00000000..17f5bbe7 --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/model/date_item_model.dart @@ -0,0 +1,57 @@ +// 是否需要 显示/设置 对应的选项 +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; + +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; + +class DateItemModel { + late bool year; + late bool month; + late bool day; + late bool hour; + late bool minute; + late bool second; + + DateItemModel( + this.year, this.month, this.day, this.hour, this.minute, this.second); + + DateItemModel.parse(DateMode dateMode) { + this.year = DateModeMap[dateMode]!.contains('年'); + this.month = DateModeMap[dateMode]!.contains('月'); + this.day = DateModeMap[dateMode]!.contains('日'); + this.hour = DateModeMap[dateMode]!.contains('时'); + this.minute = DateModeMap[dateMode]!.contains('分'); + this.second = DateModeMap[dateMode]!.contains('秒'); + } + + // 返回需要显示多少个picker + int get length { + int i = 0; + if (this.year) ++i; + if (this.month) ++i; + if (this.day) ++i; + if (this.hour) ++i; + if (this.minute) ++i; + if (this.second) ++i; + + return i; + } +} + +const DateModeMap = { + DateMode.YMDHMS: "年月日时分秒", + DateMode.YMDHM: '年月日时分', + DateMode.YMDH: '年月日时', + DateMode.YMD: '年月日', + DateMode.YM: '年月', + DateMode.Y: '年', + DateMode.MDHMS: '月日时分秒', + DateMode.MDHM: '月日时分', + DateMode.MDH: '月日时', + DateMode.MD: '月日', + DateMode.HMS: '时分秒', + DateMode.HM: '时分', + DateMode.MS: '分秒', + DateMode.S: '秒', + DateMode.M: '月', + DateMode.H: '时' +}; diff --git a/star_lock/lib/tools/pickers/time_picker/model/date_mode.dart b/star_lock/lib/tools/pickers/time_picker/model/date_mode.dart new file mode 100644 index 00000000..b5f7806b --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/model/date_mode.dart @@ -0,0 +1,53 @@ +/// 时间选择器 所显示样式 +/// 16 种时间样式 +/// +enum DateMode { + /// 【yyyy-MM-dd HH:mm:ss】年月日时分秒 + YMDHMS, + + /// 【yyyy-MM-dd HH:mm】年月日时分 + YMDHM, + + /// 【yyyy-MM-dd HH】年月日时 + YMDH, + + /// 【yyyy-MM-dd】年月日 + YMD, + + /// 【yyyy-MM】年月 + YM, + + /// 【yyyy】年 + Y, + + /// 【MM-dd HH:mm:ss】月日时分秒 + MDHMS, + + /// 【MM-dd HH:mm】月日时分 + MDHM, + + /// 【MM-dd HH:mm】月日时 + MDH, + + /// 【MM-dd】月日 + MD, + + /// 【HH:mm:ss】时分秒 + HMS, + + /// 【HH:mm】时分 + HM, + + /// 【mm:ss】分秒 + MS, + + /// 【ss】秒 + S, + + /// 【MM】月 + M, + + /// 【HH】时 + H, +} + diff --git a/star_lock/lib/tools/pickers/time_picker/model/date_time_data.dart b/star_lock/lib/tools/pickers/time_picker/model/date_time_data.dart new file mode 100644 index 00000000..54d41c08 --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/model/date_time_data.dart @@ -0,0 +1,72 @@ +// import 'package:flutter_pickers/time_picker/model/date_type.dart'; + +import 'package:star_lock/tools/pickers/time_picker/model/date_type.dart'; + +/// 时间选择器 item 生成的对应数据 +class DateTimeData { + List _year = []; + List _month = []; + List _day = []; + List _hour = []; + List _minute = []; + List _second = []; + + List getListByName(DateType type) { + switch (type) { + case DateType.Year: + return year; + case DateType.Month: + return month; + case DateType.Day: + return day; + case DateType.Hour: + return hour; + case DateType.Minute: + return minute; + case DateType.Second: + return second; + } + } + + List get year => _year; + + set year(List value) { + _year.clear(); + _year.addAll(value); + } + + List get month => _month; + + set month(List value) { + _month.clear(); + _month.addAll(value); + } + + List get second => _second; + + set second(List value) { + _second.clear(); + _second.addAll(value); + } + + List get minute => _minute; + + set minute(List value) { + _minute.clear(); + _minute.addAll(value); + } + + List get hour => _hour; + + set hour(List value) { + _hour.clear(); + _hour.addAll(value); + } + + List get day => _day; + + set day(List value) { + _day.clear(); + _day.addAll(value); + } +} diff --git a/star_lock/lib/tools/pickers/time_picker/model/date_type.dart b/star_lock/lib/tools/pickers/time_picker/model/date_type.dart new file mode 100644 index 00000000..b07bb7df --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/model/date_type.dart @@ -0,0 +1,10 @@ + + +enum DateType{ + Year, + Month, + Day, + Hour, + Minute, + Second +} \ No newline at end of file diff --git a/star_lock/lib/tools/pickers/time_picker/model/pduration.dart b/star_lock/lib/tools/pickers/time_picker/model/pduration.dart new file mode 100644 index 00000000..bc89c690 --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/model/pduration.dart @@ -0,0 +1,109 @@ +// import 'package:flutter_pickers/time_picker/model/date_type.dart'; + +import 'package:star_lock/tools/pickers/time_picker/model/date_type.dart'; + +/// 时间选择器 默认 时间设置 +/// +/// +/// var s = PDuration.now(); +/// print('longer1 >>> ${s.toString()}'); +/// {year: 2021, month: 1, day: 5, hour: 17, minute: 17, second: 3} +/// +/// var m = PDuration(year: 2011); +/// print('longer2 >>> ${m.toString()}'); +/// {year: 2011, month: 0, day: 0, hour: 0, minute: 0, second: 0} +/// +/// var d = PDuration.parse(DateTime.parse('20200304')); +/// print('longer3 >>> ${d.toString()}'); +/// {year: 2020, month: 3, day: 4, hour: 0, minute: 0, second: 0} + +bool intEmpty(int? value) { + return (value == null || value == 0); +} + +bool intNotEmpty(int? value) { + return (value != null && value != 0); +} + +class PDuration { + int? year; + int? month; + int? day; + int? hour; + int? minute; + int? second; + + PDuration( + {this.year: 0, + this.month: 0, + this.day: 0, + this.hour: 0, + this.minute: 0, + this.second: 0}); + + // 注意默认会设为0 不是null + PDuration.parse(DateTime dateTime) { + this.year = dateTime.year; + this.month = dateTime.month; + this.day = dateTime.day; + this.hour = dateTime.hour; + this.minute = dateTime.minute; + this.second = dateTime.second; + } + + PDuration.now() { + var thisInstant = new DateTime.now(); + this.year = thisInstant.year; + this.month = thisInstant.month; + this.day = thisInstant.day; + this.hour = thisInstant.hour; + this.minute = thisInstant.minute; + this.second = thisInstant.second; + } + + void setSingle(DateType dateType, var value) { + switch (dateType) { + case DateType.Year: + this.year = value; + break; + case DateType.Month: + this.month = value; + break; + case DateType.Day: + this.day = value; + break; + case DateType.Hour: + this.hour = value; + break; + case DateType.Minute: + this.minute = value; + break; + case DateType.Second: + this.second = value; + break; + } + } + + // 若为null 返回0 + int getSingle(DateType dateType) { + switch (dateType) { + case DateType.Year: + return this.year ?? 0; + case DateType.Month: + return this.month ?? 0; + case DateType.Day: + return this.day ?? 0; + case DateType.Hour: + return this.hour ?? 0; + case DateType.Minute: + return this.minute ?? 0; + case DateType.Second: + return this.second ?? 0; + } + } + + @override + String toString() { + return 'PDuration{year: $year, month: $month, day: $day, hour: $hour, minute: $minute, second: $second}'; + } +} diff --git a/star_lock/lib/tools/pickers/time_picker/model/suffix.dart b/star_lock/lib/tools/pickers/time_picker/model/suffix.dart new file mode 100644 index 00000000..b883ce78 --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/model/suffix.dart @@ -0,0 +1,47 @@ +// import 'package:flutter_pickers/time_picker/model/date_type.dart'; + +import 'package:star_lock/tools/pickers/time_picker/model/date_type.dart'; + +/// 后缀标签 +class Suffix { + late String years; + late String month; + late String days; + late String hours; + late String minutes; + late String seconds; + + Suffix.normal() { + this.years = '年'; + this.month = '月'; + this.days = '日'; + this.hours = '时'; + this.minutes = '分'; + this.seconds = '秒'; + } + + Suffix( + {this.years: '', + this.month: '', + this.days: '', + this.hours: '', + this.minutes: '', + this.seconds: ''}); + + String getSingle(DateType dateType) { + switch (dateType) { + case DateType.Year: + return this.years; + case DateType.Month: + return this.month; + case DateType.Day: + return this.days; + case DateType.Hour: + return this.hours; + case DateType.Minute: + return this.minutes; + case DateType.Second: + return this.seconds; + } + } +} diff --git a/star_lock/lib/tools/pickers/time_picker/route/date_picker_route.dart b/star_lock/lib/tools/pickers/time_picker/route/date_picker_route.dart new file mode 100644 index 00000000..ef5f3071 --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/route/date_picker_route.dart @@ -0,0 +1,861 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:star_lock/tools/pickers/style/picker_style.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_item_model.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_time_data.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/date_type.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/pduration.dart'; +import 'package:star_lock/tools/pickers/time_picker/model/suffix.dart'; +// import 'package:flutter_pickers/style/picker_style.dart'; +// import 'package:flutter_pickers/time_picker/model/date_item_model.dart'; +// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; +// import 'package:flutter_pickers/time_picker/model/date_time_data.dart'; +// import 'package:flutter_pickers/time_picker/model/date_type.dart'; +// import 'package:flutter_pickers/time_picker/model/pduration.dart'; +// import 'package:flutter_pickers/time_picker/model/suffix.dart'; + +import '../time_utils.dart'; + +typedef DateCallback(PDuration res); + +class DatePickerRoute extends PopupRoute { + DatePickerRoute({ + this.mode, + required this.initDate, + this.pickerStyle, + required this.maxDate, + required this.minDate, + this.suffix, + this.onChanged, + this.onConfirm, + this.onCancel, + this.theme, + this.barrierLabel, + RouteSettings? settings, + }) : super(settings: settings); + + final DateMode? mode; + late final PDuration initDate; + late final PDuration maxDate; + late final PDuration minDate; + final Suffix? suffix; + final ThemeData? theme; + final DateCallback? onChanged; + final DateCallback? onConfirm; + final Function(bool isCancel)? onCancel; + final PickerStyle? pickerStyle; + + @override + Duration get transitionDuration => const Duration(milliseconds: 200); + + @override + bool get barrierDismissible => true; + + @override + bool didPop(T? result) { + if (onCancel != null) { + if (result == null) { + onCancel!(false); + } else if (!(result as bool)) { + onCancel!(true); + } + } + return super.didPop(result); + } + + @override + final String? barrierLabel; + + @override + Color get barrierColor => Colors.black54; + + AnimationController? _animationController; + + @override + AnimationController createAnimationController() { + assert(_animationController == null); + _animationController = + BottomSheet.createAnimationController(navigator!.overlay!); + return _animationController!; + } + + @override + Widget buildPage(BuildContext context, Animation animation, + Animation secondaryAnimation) { + Widget bottomSheet = MediaQuery.removePadding( + context: context, + removeTop: true, + child: _PickerContentView( + mode: mode, + initData: initDate, + maxDate: maxDate, + minDate: minDate, + pickerStyle: pickerStyle!, + route: this, + ), + ); + if (theme != null) { + bottomSheet = Theme(data: theme!, child: bottomSheet); + } + + return bottomSheet; + } +} + +class _PickerContentView extends StatefulWidget { + _PickerContentView({ + Key? key, + this.mode, + required this.initData, + required this.pickerStyle, + required this.maxDate, + required this.minDate, + required this.route, + }) : super(key: key); + + final DateMode? mode; + late final PDuration initData; + late final DatePickerRoute route; + late final PickerStyle pickerStyle; + + // 限制时间 + late final PDuration maxDate; + late final PDuration minDate; + + @override + State createState() => _PickerState( + this.mode, this.initData, this.maxDate, this.minDate, this.pickerStyle); +} + +class _PickerState extends State<_PickerContentView> { + late final PickerStyle _pickerStyle; + + // 是否显示 [年月日时分秒] + late DateItemModel _dateItemModel; + + // 初始 设置选中的数据 + late final PDuration _initSelectData; + + // 选中的数据 用于回传 + late PDuration _selectData; + + // 所有item 对应的数据 + late DateTimeData _dateTimeData; + + // 限制时间 + late final PDuration maxDate; + late final PDuration minDate; + + Animation? animation; + Map scrollCtrl = {}; + + // 选择器 高度 单独提出来,用来解决修改数据 不及时更新的BUG + late double pickerItemHeight; + + _PickerState(DateMode? mode, this._initSelectData, this.maxDate, this.minDate, + this._pickerStyle) { + this._dateItemModel = DateItemModel.parse(mode!); + this.pickerItemHeight = _pickerStyle.pickerItemHeight; + _init(); + } + + _init() { + scrollCtrl.clear(); + + _dateTimeData = DateTimeData(); + int index = 0; // 初始选中值 Index + _selectData = PDuration(); + + /// minDate 和 maxDate 都初始化了,可以省略很多空判断,直接比较选中值 是否相等 _selectData.month == minDate.month + /// -------年 + if (_dateItemModel.year) { + index = 0; + _dateTimeData.year = + TimeUtils.calcYears(begin: minDate.year!, end: maxDate.year!); + + if (_initSelectData.year != null) { + index = _dateTimeData.year.indexOf(_initSelectData.year); + index = index < 0 ? 0 : index; + } + _selectData.year = _dateTimeData.year[index]; + scrollCtrl[DateType.Year] = + FixedExtentScrollController(initialItem: index); + } + + /// ------月 + // 选中的月 用于之后 day 的计算 + int selectMonth = 1; + if (_dateItemModel.month) { + index = 0; + int begin = 1; + int end = 12; + // 限制区域 + if (intNotEmpty(minDate.month) && _selectData.year == minDate.year) { + begin = minDate.month!; + } + if (intNotEmpty(maxDate.month) && _selectData.year == maxDate.year) { + end = maxDate.month!; + } + + _dateTimeData.month = TimeUtils.calcMonth(begin: begin, end: end); + + if (_initSelectData.month != null) { + index = _dateTimeData.month.indexOf(_initSelectData.month); + index = index < 0 ? 0 : index; + } + selectMonth = _dateTimeData.month[index]; + _selectData.month = selectMonth; + scrollCtrl[DateType.Month] = + FixedExtentScrollController(initialItem: index); + } + + /// -------日 (有日肯定有 年月数据) + if (_dateItemModel.day) { + index = 0; + int begin = 1; + int end = 31; + // 限制区域 + if (intNotEmpty(minDate.day) || intNotEmpty(maxDate.day)) { + if (_selectData.year == minDate.year && + _selectData.month == minDate.month) { + begin = minDate.day!; + } + if (_selectData.year == maxDate.year && + _selectData.month == maxDate.month) { + end = maxDate.day!; + } + } + + _dateTimeData.day = TimeUtils.calcDay(_initSelectData.year!, selectMonth, + begin: begin, end: end); + + if (_initSelectData.day != null) { + index = _dateTimeData.day.indexOf(_initSelectData.day); + index = index < 0 ? 0 : index; + } + _selectData.day = _dateTimeData.day[index]; + scrollCtrl[DateType.Day] = + FixedExtentScrollController(initialItem: index); + } + + /// ---------时 + if (_dateItemModel.hour) { + index = 0; + int begin = 0; + int end = 23; + // 限制区域 + if (intNotEmpty(minDate.hour)) { + begin = minDate.hour!; + } + if (intNotEmpty(maxDate.hour)) { + end = maxDate.hour!; + } + + _dateTimeData.hour = TimeUtils.calcHour(begin: begin, end: end); + + if (_initSelectData.hour != null) { + index = _dateTimeData.hour.indexOf(_initSelectData.hour); + index = index < 0 ? 0 : index; + } + _selectData.hour = _dateTimeData.hour[index]; + scrollCtrl[DateType.Hour] = + FixedExtentScrollController(initialItem: index); + } + + /// ---------分 + if (_dateItemModel.minute) { + index = 0; + int begin = 0; + int end = 59; + // 限制区域 + if (intNotEmpty(minDate.minute) || intNotEmpty(maxDate.minute)) { + if (_dateItemModel.hour) { + // 如果有上级 还有时,要根据时再判断 + if (_selectData.hour == minDate.hour) { + begin = minDate.minute!; + } + if (_selectData.hour == maxDate.hour) { + end = maxDate.minute!; + } + } else { + // 上级没有时间限制 直接取 + if (intNotEmpty(minDate.minute)) { + begin = minDate.minute!; + } + if (intNotEmpty(maxDate.minute)) { + end = maxDate.minute!; + } + } + } + + _dateTimeData.minute = TimeUtils.calcMinAndSecond(begin: begin, end: end); + + if (_initSelectData.minute != null) { + index = _dateTimeData.minute.indexOf(_initSelectData.minute); + index = index < 0 ? 0 : index; + } + _selectData.minute = _dateTimeData.minute[index]; + scrollCtrl[DateType.Minute] = + FixedExtentScrollController(initialItem: index); + } + + /// --------秒 + if (_dateItemModel.second) { + index = 0; + int begin = 0; + int end = 59; + // 限制区域 + if (intNotEmpty(minDate.second) || intNotEmpty(maxDate.second)) { + if (_dateItemModel.hour && _dateItemModel.minute) { + // 如果有上级 还有时 分,要根据时分再判断 + if (_selectData.hour == minDate.hour && + _selectData.minute == minDate.minute) { + begin = minDate.second!; + } + if (_selectData.hour == maxDate.hour && + _selectData.minute == maxDate.minute) { + end = maxDate.second!; + } + } else if (_dateItemModel.minute) { + /// 上级没有时,只有分限制 + if (_selectData.minute == minDate.minute) { + begin = minDate.second!; + } + if (_selectData.minute == maxDate.minute) { + end = maxDate.second!; + } + } else { + /// 上级没有时间限制 直接取 + if (intNotEmpty(minDate.second)) { + begin = minDate.second!; + } + if (intNotEmpty(maxDate.second)) { + end = maxDate.second!; + } + } + } + + _dateTimeData.second = TimeUtils.calcMinAndSecond(begin: begin, end: end); + + if (_initSelectData.second != null) { + index = _dateTimeData.second.indexOf(_initSelectData.second); + index = index < 0 ? 0 : index; + } + _selectData.second = _dateTimeData.second[index]; + scrollCtrl[DateType.Second] = + FixedExtentScrollController(initialItem: index); + } + } + + @override + void dispose() { + scrollCtrl.forEach((key, value) { + value.dispose(); + }); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: AnimatedBuilder( + animation: widget.route.animation!, + builder: (BuildContext context, Widget? child) { + return ClipRect( + child: CustomSingleChildLayout( + delegate: _BottomPickerLayout( + widget.route.animation!.value, _pickerStyle), + child: GestureDetector( + child: Material( + color: Colors.transparent, + child: _renderPickerView(), + ), + ), + ), + ); + }, + ), + ); + } + + void _setPicker(DateType dateType, int selectIndex) { + // 得到新的选中的数据 + var selectValue = _dateTimeData.getListByName(dateType)[selectIndex]; + // 更新选中数据 + _selectData.setSingle(dateType, selectValue); + + switch (dateType) { + case DateType.Year: + _setYear(); + break; + case DateType.Month: + _setMonth(); + break; + case DateType.Day: + break; + case DateType.Hour: + _setHour(); + break; + case DateType.Minute: + _setMinute(); + break; + case DateType.Second: + break; + } + _notifyLocationChanged(); + } + + // -------------------- set begin ------------ + void _setYear() { + // 可能造成 月 日 list的改变 + if (_dateItemModel.month) { + // 月的数据是否需要更新 + bool updateMonth = false; + bool updateDay = false; + + /// 如果只有月 + int beginMonth = 1; + int endMonth = 12; + // 限制区域 + if (intNotEmpty(minDate.month) && _selectData.year == minDate.year) { + beginMonth = minDate.month!; + } + if (intNotEmpty(maxDate.month) && _selectData.year == maxDate.year) { + endMonth = maxDate.month!; + } + + var resultMonth = TimeUtils.calcMonth(begin: beginMonth, end: endMonth); + + int jumpToIndexMonth = 0; + + if (!listEquals(_dateTimeData.month, resultMonth)) { + //可能 选中的月份 由于设置了新数据后没有了 + // 小于不用考虑 会进else + if (_selectData.month! > resultMonth.last) { + jumpToIndexMonth = resultMonth.length - 1; + } else { + jumpToIndexMonth = resultMonth.indexOf(_selectData.month); + } + jumpToIndexMonth = jumpToIndexMonth < 0 ? 0 : jumpToIndexMonth; + _selectData.month = resultMonth[jumpToIndexMonth]; + updateMonth = true; + } + + /// 还有 日 + int jumpToIndexDay = 0; + // 新的day 数据 + var resultDay; + if (_dateItemModel.day) { + int beginDay = 1; + int endDay = 31; + // 限制区域 + if (intNotEmpty(minDate.day) || intNotEmpty(maxDate.day)) { + if (_selectData.year == minDate.year && + _selectData.month == minDate.month) { + beginDay = minDate.day!; + } + if (_selectData.year == maxDate.year && + _selectData.month == maxDate.month) { + endDay = maxDate.day!; + } + } + resultDay = TimeUtils.calcDay(_selectData.year!, _selectData.month!, + begin: beginDay, end: endDay); + + if (!listEquals(_dateTimeData.day, resultDay)) { + //可能 选中的年 月份 由于设置了新数据后没有了 + // 小于不用考虑 会进else + if (_selectData.day! > resultDay.last) { + jumpToIndexDay = resultDay.length - 1; + } else { + jumpToIndexDay = resultDay.indexOf(_selectData.day); + } + jumpToIndexDay = jumpToIndexDay < 0 ? 0 : jumpToIndexDay; + _selectData.day = resultDay[jumpToIndexDay]; + updateDay = true; + } + } + + if (updateMonth || updateDay) { + setState(() { + if (updateMonth) { + _dateTimeData.month = resultMonth; + scrollCtrl[DateType.Month]?.jumpToItem(jumpToIndexMonth); + } + if (updateDay) { + _dateTimeData.day = resultDay; + scrollCtrl[DateType.Day]?.jumpToItem(jumpToIndexDay); + } + + /// FIX:https://github.com/flutter/flutter/issues/22999 + pickerItemHeight = + _pickerStyle.pickerItemHeight - Random().nextDouble() / 100000000; + }); + } + } + } + + void _setMonth() { + // 可能造成 日 list的改变 + bool updateDay = false; + int jumpToIndexDay = 0; + // 新的day 数据 + var resultDay; + if (_dateItemModel.day) { + int beginDay = 1; + int endDay = 31; + // 限制区域 + if (intNotEmpty(minDate.day) || intNotEmpty(maxDate.day)) { + if (_selectData.year == minDate.year && + _selectData.month == minDate.month) { + beginDay = minDate.day!; + } + if (_selectData.year == maxDate.year && + _selectData.month == maxDate.month) { + endDay = maxDate.day!; + } + } + resultDay = TimeUtils.calcDay(_selectData.year!, _selectData.month!, + begin: beginDay, end: endDay); + + if (!listEquals(_dateTimeData.day, resultDay)) { + //可能 选中的年 月份 由于设置了新数据后没有了 + // 小于不用考虑 会进else + if (_selectData.day! > resultDay.last) { + jumpToIndexDay = resultDay.length - 1; + } else { + jumpToIndexDay = resultDay.indexOf(_selectData.day); + } + jumpToIndexDay = jumpToIndexDay < 0 ? 0 : jumpToIndexDay; + _selectData.day = resultDay[jumpToIndexDay]; + updateDay = true; + } + } + if (updateDay) { + setState(() { + _dateTimeData.day = resultDay; + scrollCtrl[DateType.Day]?.jumpToItem(jumpToIndexDay); + + /// FIX:https://github.com/flutter/flutter/issues/22999 + pickerItemHeight = + _pickerStyle.pickerItemHeight - Random().nextDouble() / 100000000; + }); + } + } + + void _setHour() { + // 可能造成 分 秒 list的改变 + if (_dateItemModel.minute) { + // 月的数据是否需要更新 + bool updateMinute = false; + bool updateSecond = false; + + /// 如果只有分 + int beginMinute = 0; + int endMinute = 59; + // 限制区域 + if (intNotEmpty(minDate.minute) && _selectData.hour == minDate.hour) { + beginMinute = minDate.minute!; + } + if (intNotEmpty(maxDate.minute) && _selectData.hour == maxDate.hour) { + endMinute = maxDate.minute!; + } + + var resultMinute = + TimeUtils.calcMinAndSecond(begin: beginMinute, end: endMinute); + + int jumpToIndexMinute = 0; + + if (!listEquals(_dateTimeData.month, resultMinute)) { + //可能 选中的时间 由于设置了新数据后没有了 + // 小于不用考虑 会进else + if (_selectData.minute! > resultMinute.last) { + jumpToIndexMinute = resultMinute.length - 1; + } else { + jumpToIndexMinute = resultMinute.indexOf(_selectData.minute); + } + jumpToIndexMinute = jumpToIndexMinute < 0 ? 0 : jumpToIndexMinute; + _selectData.minute = resultMinute[jumpToIndexMinute]; + updateMinute = true; + } + + /// 还有 秒 + int jumpToIndexSecond = 0; + // 新的day 数据 + var resultSecond; + if (_dateItemModel.second) { + int beginSecond = 0; + int endSecond = 59; + // 限制区域 + if (intNotEmpty(minDate.second) || intNotEmpty(maxDate.second)) { + if (_selectData.hour == minDate.hour && + _selectData.minute == minDate.minute) { + beginSecond = minDate.second!; + } + if (_selectData.hour == maxDate.hour && + _selectData.minute == maxDate.minute) { + endSecond = maxDate.second!; + } + } + resultSecond = + TimeUtils.calcMinAndSecond(begin: beginSecond, end: endSecond); + + if (!listEquals(_dateTimeData.second, resultSecond)) { + //可能 选中的时 分 由于设置了新数据后没有了 + // 小于不用考虑 会进else + if (_selectData.second! > resultSecond.last) { + jumpToIndexSecond = resultSecond.length - 1; + } else { + jumpToIndexSecond = resultSecond.indexOf(_selectData.second); + } + jumpToIndexSecond = jumpToIndexSecond < 0 ? 0 : jumpToIndexSecond; + _selectData.second = resultSecond[jumpToIndexSecond]; + updateSecond = true; + } + } + + if (updateMinute || updateSecond) { + setState(() { + if (updateMinute) { + _dateTimeData.minute = resultMinute; + scrollCtrl[DateType.Minute]?.jumpToItem(jumpToIndexMinute); + } + if (updateSecond) { + _dateTimeData.second = resultSecond; + scrollCtrl[DateType.Second]?.jumpToItem(jumpToIndexSecond); + } + + /// FIX:https://github.com/flutter/flutter/issues/22999 + pickerItemHeight = + _pickerStyle.pickerItemHeight - Random().nextDouble() / 100000000; + }); + } + } + } + + void _setMinute() { + // 可能造成 秒 list的改变 + bool updateSecond = false; + int jumpToIndexSecond = 0; + // 新的day 数据 + var resultSecond; + if (_dateItemModel.second) { + int beginSecond = 0; + int endSecond = 59; + // 限制区域 + if (intNotEmpty(minDate.second) || intNotEmpty(maxDate.second)) { + if (_dateItemModel.hour) { + // 如果上面还有 时 + if (_selectData.hour == minDate.hour && + _selectData.minute == minDate.minute) { + beginSecond = minDate.second!; + } + if (_selectData.hour == maxDate.hour && + _selectData.minute == maxDate.minute) { + endSecond = maxDate.second!; + } + } else { + // 没有时,分秒 + if (_selectData.minute == minDate.minute) { + beginSecond = minDate.second!; + } + if (_selectData.minute == maxDate.minute) { + endSecond = maxDate.second!; + } + } + } + resultSecond = + TimeUtils.calcMinAndSecond(begin: beginSecond, end: endSecond); + + if (!listEquals(_dateTimeData.second, resultSecond)) { + //可能 选中的分 由于设置了新数据后没有了 + // 小于不用考虑 会进else + if (_selectData.second! > resultSecond.last) { + jumpToIndexSecond = resultSecond.length - 1; + } else { + jumpToIndexSecond = resultSecond.indexOf(_selectData.second); + } + jumpToIndexSecond = jumpToIndexSecond < 0 ? 0 : jumpToIndexSecond; + _selectData.second = resultSecond[jumpToIndexSecond]; + updateSecond = true; + } + } + if (updateSecond) { + setState(() { + _dateTimeData.second = resultSecond; + scrollCtrl[DateType.Second]?.jumpToItem(jumpToIndexSecond); + + /// FIX:https://github.com/flutter/flutter/issues/22999 + pickerItemHeight = + _pickerStyle.pickerItemHeight - Random().nextDouble() / 100000000; + }); + } + } + + // -------------------- set end ------------ + + void _notifyLocationChanged() { + if (widget.route.onChanged != null) { + widget.route.onChanged!(_selectData); + } + } + + double _pickerFontSize(String text) { + if (text == '') return 18.0; + + if (_dateItemModel.length == 6 && (text.length > 4 && text.length <= 6)) { + return 16.0; + } + + if (text.length <= 6) { + return 18.0; + } else if (text.length < 9) { + return 16.0; + } else if (text.length < 13) { + return 12.0; + } else { + return 10.0; + } + } + + Widget _renderPickerView() { + Widget itemView = _renderItemView(); + + if (!_pickerStyle.showTitleBar && _pickerStyle.menu == null) { + return itemView; + } + List viewList = []; + if (_pickerStyle.showTitleBar) { + viewList.add(_titleView()); + } + if (_pickerStyle.menu != null) { + viewList.add(_pickerStyle.menu!); + } + viewList.add(itemView); + + return Column(children: viewList); + } + + Widget _renderItemView() { + // 选择器 + List pickerList = []; + if (_dateItemModel.year) pickerList.add(pickerView(DateType.Year)); + if (_dateItemModel.month) pickerList.add(pickerView(DateType.Month)); + if (_dateItemModel.day) pickerList.add(pickerView(DateType.Day)); + if (_dateItemModel.hour) pickerList.add(pickerView(DateType.Hour)); + if (_dateItemModel.minute) pickerList.add(pickerView(DateType.Minute)); + if (_dateItemModel.second) pickerList.add(pickerView(DateType.Second)); + + return Container( + height: _pickerStyle.pickerHeight, + color: _pickerStyle.backgroundColor, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: pickerList, + ), + ); + } + + /// CupertinoPicker.builder + Widget pickerView(DateType dateType) { + return Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: CupertinoPicker.builder( + /// key :年月拼接 就不会重复了 fixme + /// 最好别使用key 会生成新的widget + /// 官方的bug : https://github.com/flutter/flutter/issues/22999 + /// 临时方法 通过修改height + scrollController: scrollCtrl[dateType], + itemExtent: pickerItemHeight, + selectionOverlay: _pickerStyle.itemOverlay, + onSelectedItemChanged: (int selectIndex) => + _setPicker(dateType, selectIndex), + childCount: _dateTimeData.getListByName(dateType).length, + itemBuilder: (_, index) { + String text = + '${_dateTimeData.getListByName(dateType)[index]}${widget.route.suffix?.getSingle(dateType)}'; + return Align( + alignment: Alignment.center, + child: Text(text, + style: TextStyle( + color: _pickerStyle.textColor, + fontSize: _pickerStyle.textSize ?? _pickerFontSize(text), + ), + textAlign: TextAlign.start)); + }, + ), + ), + ); + } + + // 选择器上面的view + Widget _titleView() { + return Container( + height: _pickerStyle.pickerTitleHeight, + decoration: _pickerStyle.headDecoration, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /// 取消按钮 + InkWell( + onTap: () => Navigator.pop(context, false), + child: _pickerStyle.cancelButton), + + /// 标题 + Expanded(child: _pickerStyle.title), + + /// 确认按钮 + InkWell( + onTap: () { + if (widget.route.onConfirm != null) { + widget.route.onConfirm!(_selectData); + } + Navigator.pop(context, true); + }, + child: _pickerStyle.commitButton) + ], + ), + ); + } +} + +class _BottomPickerLayout extends SingleChildLayoutDelegate { + _BottomPickerLayout(this.progress, this.pickerStyle); + + final double progress; + final PickerStyle pickerStyle; + + @override + BoxConstraints getConstraintsForChild(BoxConstraints constraints) { + double maxHeight = pickerStyle.pickerHeight; + if (pickerStyle.showTitleBar) { + maxHeight += pickerStyle.pickerTitleHeight; + } + if (pickerStyle.menu != null) { + maxHeight += pickerStyle.menuHeight; + } + + return BoxConstraints( + minWidth: constraints.maxWidth, + maxWidth: constraints.maxWidth, + minHeight: 0.0, + maxHeight: maxHeight); + } + + @override + Offset getPositionForChild(Size size, Size childSize) { + double height = size.height - childSize.height * progress; + return Offset(0.0, height); + } + + @override + bool shouldRelayout(_BottomPickerLayout oldDelegate) { + return progress != oldDelegate.progress; + } +} diff --git a/star_lock/lib/tools/pickers/time_picker/time_utils.dart b/star_lock/lib/tools/pickers/time_picker/time_utils.dart new file mode 100644 index 00000000..bcb183e7 --- /dev/null +++ b/star_lock/lib/tools/pickers/time_picker/time_utils.dart @@ -0,0 +1,73 @@ +class TimeUtils { + /// 年 + static List calcYears({int begin = 1900, int end = 2100}) => + _calcCount(begin, end); + + /// 月 + static List calcMonth({int begin = 1, int end = 12}) { + begin = begin < 1 ? 1 : begin; + end = end > 12 ? 12 : end; + return _calcCount(begin, end); + } + + /// 日 + static List calcDay(int year, int month, {int begin = 1, int end = 31}) { + begin = begin < 1 ? 1 : begin; + + int days = _calcDateCount(year, month); + if (end > days) { + end = days; + } + return _calcCount(begin, end); + } + + /// 时 + static List calcHour({int begin = 0, int end = 23}) { + begin = begin < 0 ? 0 : begin; + end = end > 23 ? 23 : end; + return _calcCount(begin, end); + } + + /// 分 和 秒 + static List calcMinAndSecond({int begin = 0, int end = 59}) { + begin = begin < 0 ? 0 : begin; + end = end > 59 ? 59 : end; + return _calcCount(begin, end); + } + + static List _calcCount(begin, end) { + int length = end - begin + 1; + if (length == 0) return [begin]; + if (length < 0) return []; + + return List.generate(length, (index) => begin + index); + } + + // 计算月份所对应天数 + static int _calcDateCount(int year, int month) { + switch (month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + case 2: + if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { + return 29; + } + return 28; + } + return 30; + } + + String intToStr(int v) { + return (v < 10) ? "0$v" : "$v"; + } + + // String _checkStr(String v) { + // return v == null ? "" : v; + // } +} diff --git a/star_lock/lib/tools/pickers/utils/check.dart b/star_lock/lib/tools/pickers/utils/check.dart new file mode 100644 index 00000000..ed44592a --- /dev/null +++ b/star_lock/lib/tools/pickers/utils/check.dart @@ -0,0 +1,45 @@ +class PicketUtil { + /// 字符串不为空 + static bool strNoEmpty(String? value) { + if (value == null) return false; + + return value.trim().isNotEmpty; + } + + /// 字符串为空 + static bool strEmpty(String? value) { + if (value == null) return true; + + return value.trim().isEmpty; + } + + /// MAp不为空 + static bool mapNoEmpty(Map? value) { + if (value == null) return false; + return value.isNotEmpty; + } + + /// MAp为空 + static bool mapEmpty(Map? value) { + if (value == null) return true; + return value.isEmpty; + } + + ///判断List是否为空 + static bool listNoEmpty(List? list) { + if (list == null) return false; + + if (list.length == 0) return false; + + return true; + } + + ///判断List是否为空 + static bool listEmpty(List? list) { + if (list == null) return true; + + if (list.length == 0) return true; + + return false; + } +} diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 92daab09..83d3537a 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -64,7 +64,7 @@ dependencies: #生成二维码 qr_flutter: ^4.1.0 #底部选择 - flutter_pickers: ^2.1.9 + #flutter_pickers: ^2.1.9 #万年历 syncfusion_flutter_datepicker: ^22.1.38 #使用相机及相册