feat(mobile-app): 授权申请弹窗支持省市选择器
- 市团队和省团队申请弹窗使用 city_pickers 选择省市 - 默认选中本地存储的省市(来自认种时的选择) - 允许用户重新选择省市 - 社区申请保持只输入社区名称(无省市选择) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4daee6a650
commit
3f34b11181
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:city_pickers/city_pickers.dart';
|
||||||
import '../../../../core/di/injection_container.dart';
|
import '../../../../core/di/injection_container.dart';
|
||||||
import '../../../../core/services/authorization_service.dart';
|
import '../../../../core/services/authorization_service.dart';
|
||||||
|
|
||||||
|
|
@ -207,159 +208,260 @@ class _AuthorizationApplyPageState
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 显示授权确认弹窗
|
/// 显示授权确认弹窗
|
||||||
Future<bool?> _showAuthorizationConfirmDialog(AuthorizationType type) {
|
/// 返回 Map 包含确认状态和选择的省市信息
|
||||||
|
Future<Map<String, dynamic>?> _showAuthorizationConfirmDialog(AuthorizationType type) {
|
||||||
String title;
|
String title;
|
||||||
String locationInfo;
|
|
||||||
String? additionalField;
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AuthorizationType.community:
|
case AuthorizationType.community:
|
||||||
title = '申请社区授权';
|
title = '申请社区授权';
|
||||||
locationInfo = '请输入您的社区名称';
|
|
||||||
additionalField = 'community';
|
|
||||||
break;
|
break;
|
||||||
case AuthorizationType.cityTeam:
|
case AuthorizationType.cityTeam:
|
||||||
title = '申请市团队授权';
|
title = '申请市团队授权';
|
||||||
if (_savedCityName == null || _savedCityCode == null) {
|
|
||||||
_showErrorSnackBar('未找到认种时保存的城市信息,请先完成认种');
|
|
||||||
return Future.value(false);
|
|
||||||
}
|
|
||||||
locationInfo = '城市: $_savedCityName';
|
|
||||||
break;
|
break;
|
||||||
case AuthorizationType.provinceTeam:
|
case AuthorizationType.provinceTeam:
|
||||||
title = '申请省团队授权';
|
title = '申请省团队授权';
|
||||||
if (_savedProvinceName == null || _savedProvinceCode == null) {
|
|
||||||
_showErrorSnackBar('未找到认种时保存的省份信息,请先完成认种');
|
|
||||||
return Future.value(false);
|
|
||||||
}
|
|
||||||
locationInfo = '省份: $_savedProvinceName';
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return showDialog<bool>(
|
// 初始化弹窗内的临时变量(使用本地存储的值作为默认值)
|
||||||
|
String? tempProvinceName = _savedProvinceName;
|
||||||
|
String? tempProvinceCode = _savedProvinceCode;
|
||||||
|
String? tempCityName = _savedCityName;
|
||||||
|
String? tempCityCode = _savedCityCode;
|
||||||
|
|
||||||
|
return showDialog<Map<String, dynamic>>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (context) => AlertDialog(
|
builder: (dialogContext) => StatefulBuilder(
|
||||||
shape: RoundedRectangleBorder(
|
builder: (context, setDialogState) {
|
||||||
borderRadius: BorderRadius.circular(16),
|
// 显示省市选择器
|
||||||
),
|
Future<void> showLocationPicker() async {
|
||||||
title: Text(
|
final result = await CityPickers.showCityPicker(
|
||||||
title,
|
context: context,
|
||||||
style: const TextStyle(
|
cancelWidget: const Text(
|
||||||
fontSize: 18,
|
'取消',
|
||||||
fontWeight: FontWeight.w600,
|
style: TextStyle(color: Color(0xFF745D43), fontSize: 16),
|
||||||
color: Color(0xFF5D4037),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (additionalField == 'community') ...[
|
|
||||||
const Text(
|
|
||||||
'社区名称',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Color(0xFF745D43),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
confirmWidget: const Text(
|
||||||
TextField(
|
'确定',
|
||||||
controller: _communityNameController,
|
style: TextStyle(color: Color(0xFFD4AF37), fontSize: 16, fontWeight: FontWeight.w600),
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: '请输入社区名称',
|
|
||||||
hintStyle: TextStyle(
|
|
||||||
color: const Color(0xFF745D43).withOpacity(0.5),
|
|
||||||
),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: const BorderSide(color: Color(0x4D8B5A2B)),
|
|
||||||
),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide: const BorderSide(color: Color(0xFFD4AF37), width: 2),
|
|
||||||
),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
] else ...[
|
height: 300,
|
||||||
Container(
|
showType: ShowType.pc, // 只显示省市两级
|
||||||
width: double.infinity,
|
barrierDismissible: true,
|
||||||
padding: const EdgeInsets.all(16),
|
locationCode: tempCityCode ?? tempProvinceCode, // 默认选中保存的位置
|
||||||
decoration: BoxDecoration(
|
);
|
||||||
color: const Color(0xFFFFF5E6),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
if (result != null) {
|
||||||
border: Border.all(color: const Color(0x33D4AF37)),
|
setDialogState(() {
|
||||||
),
|
tempProvinceName = result.provinceName;
|
||||||
child: Column(
|
tempProvinceCode = result.provinceId;
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
tempCityName = result.cityName;
|
||||||
children: [
|
tempCityCode = result.cityId;
|
||||||
Text(
|
});
|
||||||
locationInfo,
|
}
|
||||||
style: const TextStyle(
|
}
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w600,
|
return AlertDialog(
|
||||||
color: Color(0xFF5D4037),
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF5D4037),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (type == AuthorizationType.community) ...[
|
||||||
|
const Text(
|
||||||
|
'社区名称',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Color(0xFF745D43),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
TextField(
|
||||||
|
controller: _communityNameController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: '请输入社区名称',
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
color: const Color(0xFF745D43).withOpacity(0.5),
|
||||||
|
),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: const BorderSide(color: Color(0x4D8B5A2B)),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: const BorderSide(color: Color(0xFFD4AF37), width: 2),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
|
// 省市选择区域
|
||||||
|
Text(
|
||||||
|
type == AuthorizationType.cityTeam ? '选择城市' : '选择省份',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Color(0xFF745D43),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: showLocationPicker,
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFFFF5E6),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: const Color(0x4DD4AF37)),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (type == AuthorizationType.cityTeam) ...[
|
||||||
|
Text(
|
||||||
|
tempCityName ?? '请选择城市',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: tempCityName != null
|
||||||
|
? const Color(0xFF5D4037)
|
||||||
|
: const Color(0xFF5D4037).withOpacity(0.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (tempProvinceName != null) ...[
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
tempProvinceName!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: const Color(0xFF745D43).withOpacity(0.7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
] else ...[
|
||||||
|
Text(
|
||||||
|
tempProvinceName ?? '请选择省份',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: tempProvinceName != null
|
||||||
|
? const Color(0xFF5D4037)
|
||||||
|
: const Color(0xFF5D4037).withOpacity(0.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
color: Color(0xFFD4AF37),
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
),
|
||||||
Text(
|
const SizedBox(height: 8),
|
||||||
'此信息来自您认种时的选择,不可修改',
|
Text(
|
||||||
style: TextStyle(
|
'点击可重新选择省市',
|
||||||
fontSize: 12,
|
style: TextStyle(
|
||||||
color: const Color(0xFF745D43).withOpacity(0.7),
|
fontSize: 12,
|
||||||
),
|
color: const Color(0xFF745D43).withOpacity(0.6),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'确认申请后将使用以上信息提交授权申请',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: const Color(0xFF745D43).withOpacity(0.8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(dialogContext).pop(null),
|
||||||
|
child: const Text(
|
||||||
|
'取消',
|
||||||
|
style: TextStyle(color: Color(0xFF745D43)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (type == AuthorizationType.community) {
|
||||||
|
if (_communityNameController.text.trim().isEmpty) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('请输入社区名称'),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (type == AuthorizationType.cityTeam) {
|
||||||
|
if (tempCityCode == null || tempCityName == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('请选择城市'),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (type == AuthorizationType.provinceTeam) {
|
||||||
|
if (tempProvinceCode == null || tempProvinceName == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('请选择省份'),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.of(dialogContext).pop({
|
||||||
|
'confirmed': true,
|
||||||
|
'provinceName': tempProvinceName,
|
||||||
|
'provinceCode': tempProvinceCode,
|
||||||
|
'cityName': tempCityName,
|
||||||
|
'cityCode': tempCityCode,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFFD4AF37),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'确认申请',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(height: 16),
|
);
|
||||||
Text(
|
},
|
||||||
'确认申请后将使用以上信息提交授权申请',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: const Color(0xFF745D43).withOpacity(0.8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(false),
|
|
||||||
child: const Text(
|
|
||||||
'取消',
|
|
||||||
style: TextStyle(color: Color(0xFF745D43)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (additionalField == 'community') {
|
|
||||||
if (_communityNameController.text.trim().isEmpty) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('请输入社区名称'),
|
|
||||||
backgroundColor: Colors.red,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Navigator.of(context).pop(true);
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: const Color(0xFFD4AF37),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
'确认申请',
|
|
||||||
style: TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -395,8 +497,8 @@ class _AuthorizationApplyPageState
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示确认弹窗
|
// 显示确认弹窗
|
||||||
final confirmed = await _showAuthorizationConfirmDialog(_selectedType!);
|
final dialogResult = await _showAuthorizationConfirmDialog(_selectedType!);
|
||||||
if (confirmed != true) {
|
if (dialogResult == null || dialogResult['confirmed'] != true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -419,6 +521,7 @@ class _AuthorizationApplyPageState
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 将 AuthorizationType 转换为 SelfApplyAuthorizationType
|
// 2. 将 AuthorizationType 转换为 SelfApplyAuthorizationType
|
||||||
|
// 从弹窗返回结果中获取省市信息
|
||||||
SelfApplyAuthorizationType selfApplyType;
|
SelfApplyAuthorizationType selfApplyType;
|
||||||
String? communityName;
|
String? communityName;
|
||||||
String? provinceCode;
|
String? provinceCode;
|
||||||
|
|
@ -433,13 +536,13 @@ class _AuthorizationApplyPageState
|
||||||
break;
|
break;
|
||||||
case AuthorizationType.cityTeam:
|
case AuthorizationType.cityTeam:
|
||||||
selfApplyType = SelfApplyAuthorizationType.cityTeam;
|
selfApplyType = SelfApplyAuthorizationType.cityTeam;
|
||||||
cityCode = _savedCityCode;
|
cityCode = dialogResult['cityCode'] as String?;
|
||||||
cityName = _savedCityName;
|
cityName = dialogResult['cityName'] as String?;
|
||||||
break;
|
break;
|
||||||
case AuthorizationType.provinceTeam:
|
case AuthorizationType.provinceTeam:
|
||||||
selfApplyType = SelfApplyAuthorizationType.provinceTeam;
|
selfApplyType = SelfApplyAuthorizationType.provinceTeam;
|
||||||
provinceCode = _savedProvinceCode;
|
provinceCode = dialogResult['provinceCode'] as String?;
|
||||||
provinceName = _savedProvinceName;
|
provinceName = dialogResult['provinceName'] as String?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue