feat: 添加设置页、关于页与账号注销功能,开启网络日志
1. 新增账号注销API接口与设置页菜单,实现完整注销流程 2. 新增关于APP页面,展示隐私政策、用户协议与版本信息 3. 在我的页面添加设置入口,跳转设置页 4. 优化头像上传逻辑,移除预览弹窗步骤并简化流程 5. 开启网络日志打印,方便调试网络请求
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:new_learn/core/api/auth/api.dart';
|
||||
import 'package:new_learn/core/components/app_update_dialog.dart';
|
||||
import 'package:new_learn/core/components/confirm_box.dart';
|
||||
import 'package:new_learn/core/network/dio_client.dart';
|
||||
import 'package:new_learn/core/providers/user_provider.dart';
|
||||
import 'package:new_learn/core/storage/user_storage.dart';
|
||||
import 'package:new_learn/core/version/app_version_service.dart';
|
||||
|
||||
/// ============================================================
|
||||
/// 【SettingsPage】设置页 —— 对齐 Vue pages/myPackage/settings/index.vue
|
||||
///
|
||||
/// 三栏菜单:
|
||||
/// 检查更新(右侧显示当前版本号,手动触发版本比对弹窗)
|
||||
/// 关于APP (TODO: 跳转关于页)
|
||||
/// 注销账号 (Vue 端受 isAuditMode 控制,Flutter 暂先显示)
|
||||
///
|
||||
/// 样式:白色圆角卡片 + 分隔线,和 my_page 的 _MenuCard 风格一致
|
||||
/// ============================================================
|
||||
class SettingsPage extends ConsumerStatefulWidget {
|
||||
const SettingsPage({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<SettingsPage> createState() => _SettingsPageState();
|
||||
}
|
||||
|
||||
class _SettingsPageState extends ConsumerState<SettingsPage> {
|
||||
String _version = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadVersion();
|
||||
}
|
||||
|
||||
Future<void> _loadVersion() async {
|
||||
final service = AppVersionService.instance;
|
||||
if (service.versionName.isEmpty) {
|
||||
await service.init();
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() => _version = service.versionName);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleCheckUpdate() async {
|
||||
// 手动检查更新:复用 AppVersionService + AppUpdateDialog
|
||||
try {
|
||||
final service = AppVersionService.instance;
|
||||
await service.init();
|
||||
final update = await service.checkForUpdate();
|
||||
if (!mounted) return;
|
||||
if (update == null) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('已是最新版本')));
|
||||
return;
|
||||
}
|
||||
await AppUpdateDialog.show(
|
||||
context,
|
||||
update,
|
||||
isForce: service.isForceUpdate(),
|
||||
);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('检查更新失败:$e')));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleCloseAccount() async {
|
||||
final ok = await showConfirmBox(
|
||||
context,
|
||||
title: '注销提醒',
|
||||
content: '账号注销后,将会删除账号的全部数据,不可恢复。请确认是否注销账号?',
|
||||
confirmText: '确定注销',
|
||||
cancelText: '我再想想',
|
||||
);
|
||||
if (!ok) return;
|
||||
try {
|
||||
await UserApi.closeAccount();
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('注销失败:$e')));
|
||||
return;
|
||||
}
|
||||
// 清理本地登录态 → 路由守卫自动踢回登录页
|
||||
DioClient.instance.accessToken = null;
|
||||
await UserStorage.instance.clearAll();
|
||||
if (!mounted) return;
|
||||
ref.read(currentUserProvider.notifier).set(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F8FA),
|
||||
appBar: AppBar(
|
||||
title: const Text('设置'),
|
||||
backgroundColor: Colors.white,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => context.canPop() ? context.pop() : context.go('/my'),
|
||||
),
|
||||
),
|
||||
body: ListView(
|
||||
padding: EdgeInsets.all(12.w),
|
||||
children: [
|
||||
// 检查更新
|
||||
_buildRow(
|
||||
title: '检查更新',
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (_version.isNotEmpty)
|
||||
Text(
|
||||
'v$_version',
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: const Color(0xFF687FAD),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 4.w),
|
||||
const Icon(
|
||||
Icons.chevron_right,
|
||||
size: 22,
|
||||
color: Color(0xFF7FB0F2),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: _handleCheckUpdate,
|
||||
),
|
||||
_buildDivider(),
|
||||
// 关于APP
|
||||
_buildRow(
|
||||
title: '关于APP',
|
||||
trailing: const Icon(
|
||||
Icons.chevron_right,
|
||||
size: 22,
|
||||
color: Color(0xFF7FB0F2),
|
||||
),
|
||||
onTap: () => context.push('/about-app'),
|
||||
),
|
||||
_buildDivider(),
|
||||
// 注销账号
|
||||
_buildRow(
|
||||
title: '注销账号',
|
||||
trailing: const Icon(
|
||||
Icons.chevron_right,
|
||||
size: 22,
|
||||
color: Color(0xFF7FB0F2),
|
||||
),
|
||||
onTap: _handleCloseAccount,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDivider() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Container(height: 1, color: const Color(0xFFEDF3F7)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRow({
|
||||
required String title,
|
||||
required Widget trailing,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: 52.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
color: Colors.white,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(fontSize: 16.sp, color: const Color(0xFF1D2B47)),
|
||||
),
|
||||
const Spacer(),
|
||||
trailing,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user