feat: 实现用户画像、占卜历史与后端用户管理模块

This commit is contained in:
ZL-Q
2026-04-06 01:28:10 +08:00
parent d87b2e1e3a
commit 8a18b3528b
77 changed files with 5850 additions and 2604 deletions
@@ -4,12 +4,17 @@ import 'package:intl/intl.dart';
import '../../../../l10n/app_localizations.dart';
import '../../../../shared/theme/design_tokens.dart';
import '../../../../shared/widgets/app_modal_dialog.dart';
import '../../../../shared/widgets/divination/divination_shared_widgets.dart';
import '../../../../shared/widgets/divination/divination_terms.dart';
import '../../../../shared/widgets/divination/yao_legend.dart';
import '../../../../shared/widgets/divination/yao_line_row.dart';
import '../../../../shared/widgets/date_time_picker/date_time_picker_bottom_sheet.dart';
import '../../../../shared/widgets/toast/toast.dart';
import '../../../../shared/widgets/toast/toast_type.dart';
import '../../data/models/divination_backend_models.dart';
import '../../data/models/divination_params.dart';
import '../../data/models/divination_result.dart';
import '../../data/services/divination_run_service.dart';
import 'divination_processing_screen.dart';
@@ -18,10 +23,12 @@ class ManualDivinationScreen extends StatefulWidget {
super.key,
required this.params,
required this.runService,
required this.onCompleted,
});
final DivinationParams params;
final DivinationRunService runService;
final Future<void> Function(DivinationResultData result) onCompleted;
@override
State<ManualDivinationScreen> createState() => _ManualDivinationScreenState();
@@ -155,14 +162,16 @@ class _ManualDivinationScreenState extends State<ManualDivinationScreen>
final l10n = AppLocalizations.of(context)!;
await showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: Text(l10n.manualYaoTipTitle),
content: Text(l10n.manualYaoTipContent),
builder: (dialogContext) {
return AppModalDialog(
title: l10n.manualYaoTipTitle,
message: l10n.manualYaoTipContent,
icon: Icons.info_outline_rounded,
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(l10n.divinationIAcknowledge),
AppModalDialogAction(
label: l10n.divinationIAcknowledge,
primary: true,
onPressed: () => Navigator.of(dialogContext).pop(),
),
],
);
@@ -171,6 +180,55 @@ class _ManualDivinationScreenState extends State<ManualDivinationScreen>
}
Future<void> _submitRun() async {
final l10n = AppLocalizations.of(context)!;
PointsBalanceData points;
try {
points = await widget.runService.getPointsBalance();
} catch (_) {
if (!mounted) {
return;
}
Toast.show(context, l10n.errorRequestGeneric, type: ToastType.error);
return;
}
if (!points.canRun || points.availableBalance < points.runCost) {
if (!mounted) {
return;
}
Toast.show(context, l10n.toastCoinInsufficient, type: ToastType.warning);
return;
}
if (!mounted) {
return;
}
final shouldStart = await showDialog<bool>(
context: context,
builder: (dialogContext) {
return AppModalDialog(
title: l10n.divinationCostDialogTitle,
message: l10n.divinationCostDialogBody(
points.runCost,
points.availableBalance,
),
icon: Icons.auto_awesome_rounded,
actions: [
AppModalDialogAction(
label: l10n.cancel,
onPressed: () => Navigator.of(dialogContext).pop(false),
),
AppModalDialogAction(
label: l10n.divinationCostDialogConfirm,
primary: true,
onPressed: () => Navigator.of(dialogContext).pop(true),
),
],
);
},
);
if (shouldStart != true) {
return;
}
setState(() {
_submitting = true;
});
@@ -184,6 +242,7 @@ class _ManualDivinationScreenState extends State<ManualDivinationScreen>
params: widget.params.copyWith(divinationTime: _selectedTime),
yaoStates: _selectedYaos.cast<YaoType>(),
runService: widget.runService,
onCompleted: widget.onCompleted,
),
),
);