Commit 0e242fa1 by Administrator

Merge branch 'feature-2601-logoff' into feature-2601

版本合并:审核内容都版本
2 parents ca90354c 35fdb701
...@@ -9,7 +9,7 @@ flutter run -d macos ...@@ -9,7 +9,7 @@ flutter run -d macos
flutter run -d 00008030-001C75810E42402E --release flutter run -d 00008030-001C75810E42402E --release
flutter run -d 00008140-001068C93AB8801C --release flutter run -d 00008140-001068C93AB8801C --release --dart-define=env=pro
gao 00008130-0010788A2E01001C gao 00008130-0010788A2E01001C
yongosng 00008110-000A284C2178801E yongosng 00008110-000A284C2178801E
......
...@@ -514,6 +514,7 @@ ...@@ -514,6 +514,7 @@
DEVELOPMENT_TEAM = 42794B2KBU; DEVELOPMENT_TEAM = 42794B2KBU;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
...@@ -704,6 +705,7 @@ ...@@ -704,6 +705,7 @@
DEVELOPMENT_TEAM = 42794B2KBU; DEVELOPMENT_TEAM = 42794B2KBU;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
...@@ -728,6 +730,7 @@ ...@@ -728,6 +730,7 @@
DEVELOPMENT_TEAM = 42794B2KBU; DEVELOPMENT_TEAM = 42794B2KBU;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
......

68 Bytes | W: | H:

77.1 KB | W: | H:

ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -103,5 +103,19 @@ ...@@ -103,5 +103,19 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<true/> <true/>
<!-- 持续定位权限:用于后台持续获取位置(如导航、运动追踪) -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>为了在您针对老师布置信息反馈或作业消息提交时,可能需要涉及位置信息的提交要求,我们需要访问您的位置信息</string>
<!-- 蓝牙权限:用于连接蓝牙设备 -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>为了搜索、连接并管理您的智能蓝牙设备(如手环、传感器),我们需要使用蓝牙功能</string>
<!-- 在使用时定位权限:用于应用在前台时获取位置 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>为了在您针对老师布置信息反馈或作业消息提交时,可能需要涉及位置信息的提交要求,我们需要在使用应用时获取您的位置信息。</string>
<key>App Uses Non-Exempt Encryption</key>
<false/>
</dict> </dict>
</plist> </plist>
...@@ -79,6 +79,22 @@ class AccountCubit extends Cubit<AccountState> { ...@@ -79,6 +79,22 @@ class AccountCubit extends Cubit<AccountState> {
} }
} }
Future<void> goSetUserInfo() async {
dynamic result = await router.push(
'/account/user',
extra: {
'name': state.name,
'nickname': state.nickname,
'avatar': state.imgIcon,
},
);
if (result != null && result.isNotEmpty) {
Map<String, dynamic> resultMap = Map<String, dynamic>.from(result);
emit(state.copyWith(imgIcon: resultMap['avatar'], name: resultMap['name'], nickname: resultMap['nickname']));
}
}
Future<void> goBind() async { Future<void> goBind() async {
String? result = await router.push( String? result = await router.push(
'/account/phone', '/account/phone',
...@@ -90,4 +106,36 @@ class AccountCubit extends Cubit<AccountState> { ...@@ -90,4 +106,36 @@ class AccountCubit extends Cubit<AccountState> {
emit(state.copyWith(phone: result)); emit(state.copyWith(phone: result));
} }
} }
void goLogoff() {
router.push(
'/account/logoff',
extra: {
'phone': state.phone,
},
);
}
Future<void> unbind() async {
// var sharedPreferences = getIt.get<SharedPreferences>();
// var userCode = sharedPreferences.getString('auth_userCode') ?? '';
// _phoneAuthRepository.unbind(userCode);
// 当前只会成功,不会失败
// 解绑成功,跳转登录界面
// router.go('/loginMain');
// emit(state.copyWith(showSnackBar: true, snackBarMsg: '操作成功'));
// emit(state.copyWith(showSnackBar: false));
// await Future.delayed(Duration(seconds: 1));
var sharedPreferences = getIt.get<SharedPreferences>();
sharedPreferences.getKeys().forEach((key) {
if (key.startsWith('auth_')) {
sharedPreferences.remove(key);
}
});
router.go('/loginMain');
}
} }
import 'dart:async';
import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart';
import 'package:appframe/data/repositories/phone_auth_repository.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AccountLogoffState extends Equatable {
final String phone;
final bool showSnackBar;
final String snackBarMsg;
final bool allowSend;
final int seconds;
final bool isLoading;
const AccountLogoffState({
this.phone = '',
this.showSnackBar = false,
this.snackBarMsg = '',
this.allowSend = true,
this.seconds = 0,
this.isLoading = false,
});
AccountLogoffState copyWith({
String? phone,
bool? showSnackBar,
String? snackBarMsg,
bool? allowSend,
int? seconds,
bool? isLoading,
}) {
return AccountLogoffState(
phone: phone ?? this.phone,
showSnackBar: showSnackBar ?? this.showSnackBar,
snackBarMsg: snackBarMsg ?? this.snackBarMsg,
allowSend: allowSend ?? this.allowSend,
seconds: seconds ?? this.seconds,
isLoading: isLoading ?? this.isLoading,
);
}
@override
List<Object?> get props => [
phone,
showSnackBar,
snackBarMsg,
allowSend,
seconds,
isLoading,
];
}
class AccountLogoffCubit extends Cubit<AccountLogoffState> {
late TextEditingController _codeController;
Timer? _timer;
int countdown = 60;
late final PhoneAuthRepository _phoneAuthRepository;
TextEditingController get codeController => _codeController;
AccountLogoffCubit(super.initialState) {
_codeController = TextEditingController();
_codeController.text = '';
_phoneAuthRepository = getIt.get<PhoneAuthRepository>();
}
/// 开始倒计时
void startCountdown() {
countdown = 60;
emit(state.copyWith(allowSend: false, seconds: countdown));
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
countdown--;
if (countdown <= 0) {
_timer?.cancel();
emit(state.copyWith(allowSend: true, seconds: 60));
} else {
emit(state.copyWith(seconds: countdown));
}
});
}
/// 发送验证码
Future<void> sendVerificationCode() async {
if (state.allowSend) {
if (!RegExp(r'^1[3-9][0-9]{9}$').hasMatch(state.phone)) {
emit(state.copyWith(showSnackBar: true, snackBarMsg: '手机号码信息错误'));
emit(state.copyWith(showSnackBar: false));
return;
}
var result = await _phoneAuthRepository.verifyCode(state.phone, 1);
if (result['code'] != 0) {
emit(state.copyWith(showSnackBar: true, snackBarMsg: result['error']));
emit(state.copyWith(showSnackBar: false));
return;
}
emit(state.copyWith(allowSend: false, seconds: 60));
startCountdown();
}
}
/// 注销账户
Future<void> logoff() async {
// String verifyCode = _codeController.text;
if (!RegExp(r'^1[3-9][0-9]{9}$').hasMatch(state.phone)) {
emit(state.copyWith(showSnackBar: true, snackBarMsg: '手机号码信息错误'));
emit(state.copyWith(showSnackBar: false));
return;
}
// if (!RegExp(r'^\d{4}$').hasMatch(verifyCode)) {
// emit(state.copyWith(showSnackBar: true, snackBarMsg: '请输入正确的验证码'));
// emit(state.copyWith(showSnackBar: false));
// return;
// }
emit(state.copyWith(isLoading: true));
// var sharedPreferences = getIt.get<SharedPreferences>();
// var userCode = sharedPreferences.getString('auth_userCode') ?? '';
// var result = await _phoneAuthRepository.unbindWithVerifyCode(userCode, verifyCode);
var result = await _phoneAuthRepository.unbindPhone(state.phone);
emit(state.copyWith(isLoading: false));
if (result['code'] != 0) {
emit(state.copyWith(showSnackBar: true, snackBarMsg: result['error']));
emit(state.copyWith(showSnackBar: false));
return;
}
emit(state.copyWith(showSnackBar: true, snackBarMsg: '操作成功'));
emit(state.copyWith(showSnackBar: false));
await Future.delayed(Duration(seconds: 1));
var sharedPreferences = getIt.get<SharedPreferences>();
sharedPreferences.getKeys().forEach((key) {
if (key.startsWith('auth_')) {
sharedPreferences.remove(key);
}
});
router.go('/loginMain');
}
@override
Future<void> close() async {
_timer?.cancel();
try {
_codeController.dispose();
} catch (e) {
print(e);
}
await super.close();
}
}
...@@ -17,6 +17,7 @@ import 'package:dio/dio.dart'; ...@@ -17,6 +17,7 @@ import 'package:dio/dio.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluwx/fluwx.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
...@@ -199,6 +200,7 @@ class WebState extends Equatable { ...@@ -199,6 +200,7 @@ class WebState extends Equatable {
class WebCubit extends Cubit<WebState> with WidgetsBindingObserver { class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
late final MessageDispatcher _dispatcher; late final MessageDispatcher _dispatcher;
late final WebViewController _controller; late final WebViewController _controller;
late final Fluwx _fluwx;
HttpServer? _server; HttpServer? _server;
PlayerService? _playerService; PlayerService? _playerService;
RecorderService? _recorderService; RecorderService? _recorderService;
...@@ -272,6 +274,7 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver { ...@@ -272,6 +274,7 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
_readH5ShowVersion(); _readH5ShowVersion();
// 初始化其它一些属性 // 初始化其它一些属性
_fluwx = getIt.get<Fluwx>();
_playerService = getIt.get<PlayerService>(); _playerService = getIt.get<PlayerService>();
_playerService?.sendResponse = _sendResponse; _playerService?.sendResponse = _sendResponse;
_recorderService = getIt.get<RecorderService>(); _recorderService = getIt.get<RecorderService>();
...@@ -483,6 +486,19 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver { ...@@ -483,6 +486,19 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
emit(state.copyWith(loaded: true)); emit(state.copyWith(loaded: true));
} }
///
/// 跳转客服(微信小程序)
///
void goCs() {
_fluwx.open(
target: MiniProgram(
username: 'gh_0ed02e873abc',
path: '/pages/agentChat/index?showAuthDirectly=1&agentId=eiXH0MAJmjgl',
miniProgramType: WXMiniProgramType.release,
),
);
}
void goLogin() { void goLogin() {
router.go('/loginMain'); router.go('/loginMain');
} }
......
...@@ -53,7 +53,7 @@ class Constant { ...@@ -53,7 +53,7 @@ class Constant {
static const String appVersion = EnvConfig.version; static const String appVersion = EnvConfig.version;
/// H5的起始终最低版本号规则 /// H5的起始终最低版本号规则
static String h5Version = '0.0.0'; static String h5Version = '0.1.6';
/// H5的版本号存储的key /// H5的版本号存储的key
static const String h5VersionKey = 'h5_version'; static const String h5VersionKey = 'h5_version';
......
...@@ -9,8 +9,10 @@ import 'package:appframe/ui/pages/login_phone_page.dart'; ...@@ -9,8 +9,10 @@ import 'package:appframe/ui/pages/login_phone_page.dart';
import 'package:appframe/ui/pages/login_qr_page.dart'; import 'package:appframe/ui/pages/login_qr_page.dart';
import 'package:appframe/ui/pages/reload_page.dart'; import 'package:appframe/ui/pages/reload_page.dart';
import 'package:appframe/ui/pages/scan_code_page.dart'; import 'package:appframe/ui/pages/scan_code_page.dart';
import 'package:appframe/ui/pages/setting/account_logoff_page.dart';
import 'package:appframe/ui/pages/setting/account_page.dart'; import 'package:appframe/ui/pages/setting/account_page.dart';
import 'package:appframe/ui/pages/setting/account_phone_page.dart'; import 'package:appframe/ui/pages/setting/account_phone_page.dart';
import 'package:appframe/ui/pages/setting/account_user_page.dart';
import 'package:appframe/ui/pages/web_page.dart'; import 'package:appframe/ui/pages/web_page.dart';
import 'package:appframe/ui/widgets/ios_edge_swipe_detector.dart'; import 'package:appframe/ui/widgets/ios_edge_swipe_detector.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
...@@ -69,6 +71,18 @@ final GoRouter router = GoRouter( ...@@ -69,6 +71,18 @@ final GoRouter router = GoRouter(
}, },
), ),
GoRoute( GoRoute(
path: '/account/user',
builder: (BuildContext context, GoRouterState state) {
return const AccountUserPage();
},
),
GoRoute(
path: '/account/logoff',
builder: (BuildContext context, GoRouterState state) {
return const AccountLogoffPage();
},
),
GoRoute(
path: '/adv', path: '/adv',
builder: (BuildContext context, GoRouterState state) { builder: (BuildContext context, GoRouterState state) {
return const AdvPage(); return const AdvPage();
......
...@@ -86,4 +86,49 @@ class PhoneAuthRepository { ...@@ -86,4 +86,49 @@ class PhoneAuthRepository {
); );
return resp.statusCode == 200 ? resp.data : null; return resp.statusCode == 200 ? resp.data : null;
} }
///
/// {
/// "code": 0,
/// "error": "操作成功"
/// }
///
Future<dynamic> unbind(String userid) async {
Response resp = await _appService.post(
'/api/v1/comm/phone/unbind',
{
"userid": userid,
},
);
return resp.data;
}
Future<dynamic> unbindPhone(String phone) async {
Response resp = await _appService.post(
'/api/v1/comm/phone/unbind',
{
"phone": phone,
},
);
return resp.data;
}
///
/// {
/// "code": 0,
/// "error": "操作成功"
/// }
///
Future<dynamic> updateUser(String userid, String name, String nickName, String avatar) async {
Response resp = await _appService.post(
'/api/v1/comm/user/update',
{
"userid": userid,
"name": name,
"nickName": nickName,
"avatar": avatar,
},
);
return resp.data;
}
} }
import 'package:appframe/bloc/setting/account_logoff_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
class AccountLogoffPage extends StatelessWidget {
const AccountLogoffPage({super.key});
@override
Widget build(BuildContext context) {
final Map<String, dynamic>? extraData = GoRouterState.of(context).extra as Map<String, dynamic>?;
var phone = extraData?['phone'] ?? '';
return BlocProvider(
create: (context) => AccountLogoffCubit(AccountLogoffState(phone: phone)),
child: BlocConsumer<AccountLogoffCubit, AccountLogoffState>(
builder: (context, state) {
final accountLogoffCubit = context.read<AccountLogoffCubit>();
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('注销用户', style: TextStyle(color: Colors.white, fontSize: 18)),
centerTitle: true,
backgroundColor: Color(0xFF7691FA),
iconTheme: IconThemeData(
color: Colors.white,
),
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(60),
child: Column(
children: [
SizedBox(height: 60),
Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFFFFF3F3),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Color(0xFFFFCDD2)),
),
child: Row(
children: [
Icon(
Icons.warning_amber_rounded,
color: Color(0xFFE74C3C),
size: 24,
),
SizedBox(width: 12),
Expanded(
child: Text(
'注销后,您的所有数据将被永久删除且无法恢复,请谨慎操作!',
style: TextStyle(
fontSize: 14,
color: Color(0xFFE74C3C),
height: 1.5,
),
),
),
],
),
),
SizedBox(height: 20),
SizedBox(
width: double.infinity,
height: 47,
child: ElevatedButton(
onPressed: state.isLoading
? null
: () {
accountLogoffCubit.logoff();
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFFE74C3C),
foregroundColor: Colors.white,
textStyle: TextStyle(fontSize: 19),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(23.5),
),
disabledBackgroundColor: Color(0xFFCCCCCC),
),
child: state.isLoading
? SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'确认注销',
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.w400,
color: Color(0xFFFFFFFF),
),
strutStyle: StrutStyle(height: 22 / 19),
),
),
),
],
),
),
),
);
},
listener: (context, state) {
if (state.showSnackBar) {
_showTip(context, state.snackBarMsg);
}
},
),
);
}
void _showTip(BuildContext context, String tip) {
OverlayEntry overlayEntry = OverlayEntry(
builder: (context) => Positioned(
top: 200,
left: 20,
right: 20,
child: Material(
color: Colors.transparent,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.circular(8),
),
child: Text(
tip,
style: TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
),
),
),
);
Overlay.of(context).insert(overlayEntry);
Future.delayed(Duration(seconds: 2), () {
overlayEntry.remove();
});
}
}
...@@ -60,6 +60,27 @@ class AccountPage extends StatelessWidget { ...@@ -60,6 +60,27 @@ class AccountPage extends StatelessWidget {
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
child: ListTile( child: ListTile(
leading: Icon(Icons.person),
title: Text('用户信息设置'),
subtitle: Text(
'点击设置用户信息',
style: TextStyle(
fontSize: 14.0,
color: Colors.grey,
),
),
trailing: Icon(Icons.arrow_forward_ios, size: 14),
onTap: () {
context.read<AccountCubit>().goSetUserInfo();
},
),
),
Card(
color: Color(0xFFF7F9FF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: ListTile(
leading: Icon(Icons.mobile_friendly), leading: Icon(Icons.mobile_friendly),
title: Text('手机号绑定'), title: Text('手机号绑定'),
subtitle: Text( subtitle: Text(
...@@ -77,7 +98,75 @@ class AccountPage extends StatelessWidget { ...@@ -77,7 +98,75 @@ class AccountPage extends StatelessWidget {
}, },
), ),
), ),
// Divider(), SizedBox(height: 16),
Padding(
padding: EdgeInsets.all(80),
child: SizedBox(
width: double.infinity,
height: 47,
child: ElevatedButton(
onPressed: () async {
// 判断是否有绑定手机号
if (state.phone != '') {
context.read<AccountCubit>().goLogoff();
return;
}
final accountCubit = context.read<AccountCubit>();
bool? confirm = await showDialog<bool>(
context: context,
builder: (BuildContext ctx) {
return AlertDialog(
title: Text('确认注销'),
content: Text('您确定要注销当前用户吗?'),
actions: [
TextButton(
onPressed: () {
Navigator.of(ctx).pop(false);
},
child: Text('取消'),
),
TextButton(
onPressed: () {
Navigator.of(ctx).pop(true);
},
child: Text('确认'),
),
],
);
},
);
if (confirm == true) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('已申请注销,等待流程处理'),
backgroundColor: Colors.green,
),
);
accountCubit.unbind();
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFFE74C3C),
foregroundColor: Colors.white,
textStyle: TextStyle(fontSize: 19),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(23.5),
),
),
child: Text(
'注销用户',
style: TextStyle(
fontSize: 19,
fontWeight: FontWeight.w400,
color: Color(0xFFFFFFFF),
),
strutStyle: StrutStyle(height: 22 / 19),
),
),
),
),
], ],
), ),
), ),
......
...@@ -70,7 +70,8 @@ class AccountPhonePage extends StatelessWidget { ...@@ -70,7 +70,8 @@ class AccountPhonePage extends StatelessWidget {
)), )),
]), ]),
) )
: Padding( : SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(60), padding: EdgeInsets.all(60),
child: Column( child: Column(
children: [ children: [
...@@ -221,6 +222,7 @@ class AccountPhonePage extends StatelessWidget { ...@@ -221,6 +222,7 @@ class AccountPhonePage extends StatelessWidget {
], ],
), ),
), ),
),
); );
}, },
listener: (context, state) { listener: (context, state) {
......
...@@ -316,6 +316,29 @@ class WebPage extends StatelessWidget { ...@@ -316,6 +316,29 @@ class WebPage extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
ListTile( ListTile(
leading: const Icon(Icons.headset_mic, size: 20),
title: const Text('在线客服', style: TextStyle(fontSize: 14)),
onTap: () {
Navigator.pop(ctx);
ctx.read<WebCubit>().goCs();
},
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
trailing: Icon(Icons.arrow_forward_ios, size: 14),
dense: true,
visualDensity: VisualDensity.compact,
),
],
),
),
SizedBox(height: 8),
Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 2),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: Column(
children: [
ListTile(
leading: const Icon(Icons.cleaning_services, size: 20), leading: const Icon(Icons.cleaning_services, size: 20),
title: const Text('清理缓存', style: TextStyle(fontSize: 14)), title: const Text('清理缓存', style: TextStyle(fontSize: 14)),
onTap: () { onTap: () {
...@@ -342,7 +365,8 @@ class WebPage extends StatelessWidget { ...@@ -342,7 +365,8 @@ class WebPage extends StatelessWidget {
), ),
), ),
SizedBox(height: 8), SizedBox(height: 8),
Card( EnvConfig.isDev()
? Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 2), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 2),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
...@@ -363,7 +387,8 @@ class WebPage extends StatelessWidget { ...@@ -363,7 +387,8 @@ class WebPage extends StatelessWidget {
), ),
], ],
), ),
), )
: SizedBox(),
], ],
), ),
), ),
......
name: appframe name: appframe
description: "app frame project." description: "app frame project."
publish_to: 'none' publish_to: 'none'
version: 1.0.0+1 version: 1.0.3
environment: environment:
sdk: ">=3.5.0 <4.0.0" sdk: ">=3.5.0 <4.0.0"
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!