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:go_router/go_router.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:city_pickers/city_pickers.dart';
|
||||
import '../../../../core/di/injection_container.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 locationInfo;
|
||||
String? additionalField;
|
||||
|
||||
switch (type) {
|
||||
case AuthorizationType.community:
|
||||
title = '申请社区授权';
|
||||
locationInfo = '请输入您的社区名称';
|
||||
additionalField = 'community';
|
||||
break;
|
||||
case AuthorizationType.cityTeam:
|
||||
title = '申请市团队授权';
|
||||
if (_savedCityName == null || _savedCityCode == null) {
|
||||
_showErrorSnackBar('未找到认种时保存的城市信息,请先完成认种');
|
||||
return Future.value(false);
|
||||
}
|
||||
locationInfo = '城市: $_savedCityName';
|
||||
break;
|
||||
case AuthorizationType.provinceTeam:
|
||||
title = '申请省团队授权';
|
||||
if (_savedProvinceName == null || _savedProvinceCode == null) {
|
||||
_showErrorSnackBar('未找到认种时保存的省份信息,请先完成认种');
|
||||
return Future.value(false);
|
||||
}
|
||||
locationInfo = '省份: $_savedProvinceName';
|
||||
break;
|
||||
}
|
||||
|
||||
return showDialog<bool>(
|
||||
// 初始化弹窗内的临时变量(使用本地存储的值作为默认值)
|
||||
String? tempProvinceName = _savedProvinceName;
|
||||
String? tempProvinceCode = _savedProvinceCode;
|
||||
String? tempCityName = _savedCityName;
|
||||
String? tempCityCode = _savedCityCode;
|
||||
|
||||
return showDialog<Map<String, dynamic>>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (context) => AlertDialog(
|
||||
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 (additionalField == 'community') ...[
|
||||
const Text(
|
||||
'社区名称',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF745D43),
|
||||
),
|
||||
builder: (dialogContext) => StatefulBuilder(
|
||||
builder: (context, setDialogState) {
|
||||
// 显示省市选择器
|
||||
Future<void> showLocationPicker() async {
|
||||
final result = await CityPickers.showCityPicker(
|
||||
context: context,
|
||||
cancelWidget: const Text(
|
||||
'取消',
|
||||
style: TextStyle(color: Color(0xFF745D43), fontSize: 16),
|
||||
),
|
||||
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),
|
||||
),
|
||||
confirmWidget: const Text(
|
||||
'确定',
|
||||
style: TextStyle(color: Color(0xFFD4AF37), fontSize: 16, fontWeight: FontWeight.w600),
|
||||
),
|
||||
] else ...[
|
||||
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(0x33D4AF37)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
locationInfo,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF5D4037),
|
||||
height: 300,
|
||||
showType: ShowType.pc, // 只显示省市两级
|
||||
barrierDismissible: true,
|
||||
locationCode: tempCityCode ?? tempProvinceCode, // 默认选中保存的位置
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
setDialogState(() {
|
||||
tempProvinceName = result.provinceName;
|
||||
tempProvinceCode = result.provinceId;
|
||||
tempCityName = result.cityName;
|
||||
tempCityCode = result.cityId;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return AlertDialog(
|
||||
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(
|
||||
'此信息来自您认种时的选择,不可修改',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: const Color(0xFF745D43).withOpacity(0.7),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'点击可重新选择省市',
|
||||
style: TextStyle(
|
||||
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!);
|
||||
if (confirmed != true) {
|
||||
final dialogResult = await _showAuthorizationConfirmDialog(_selectedType!);
|
||||
if (dialogResult == null || dialogResult['confirmed'] != true) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -419,6 +521,7 @@ class _AuthorizationApplyPageState
|
|||
}
|
||||
|
||||
// 2. 将 AuthorizationType 转换为 SelfApplyAuthorizationType
|
||||
// 从弹窗返回结果中获取省市信息
|
||||
SelfApplyAuthorizationType selfApplyType;
|
||||
String? communityName;
|
||||
String? provinceCode;
|
||||
|
|
@ -433,13 +536,13 @@ class _AuthorizationApplyPageState
|
|||
break;
|
||||
case AuthorizationType.cityTeam:
|
||||
selfApplyType = SelfApplyAuthorizationType.cityTeam;
|
||||
cityCode = _savedCityCode;
|
||||
cityName = _savedCityName;
|
||||
cityCode = dialogResult['cityCode'] as String?;
|
||||
cityName = dialogResult['cityName'] as String?;
|
||||
break;
|
||||
case AuthorizationType.provinceTeam:
|
||||
selfApplyType = SelfApplyAuthorizationType.provinceTeam;
|
||||
provinceCode = _savedProvinceCode;
|
||||
provinceName = _savedProvinceName;
|
||||
provinceCode = dialogResult['provinceCode'] as String?;
|
||||
provinceName = dialogResult['provinceName'] as String?;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue