feat: UI 系统中心化 + 趋势图重构 + 法律文档 H5 上线
- UI 系统: 新增 design_tokens / module_visuals / app_buttons / app_status_badge / app_toast / ai_content 六个共享模块; 28 个页面接入, SnackBar 全部替换为 AppToast - 趋势图: 直线折线 + 渐变填充 + 阴影; 去网格线; X 轴日+月份分隔; Y 轴整数刻度最多 4 个; 点击数据点/录入记录显示上方浮层, 选中点变实心 - 法律文档 H5: 后端 wwwroot 托管隐私政策/服务协议/关于/个人信息收集清单/第三方 SDK 清单 + 索引页; Program.cs 启用 UseDefaultFiles + UseStaticFiles - 其他: auth_provider 登录流程调整; api_client IP 适配; 主页智能体栏间距优化
This commit is contained in:
@@ -3,9 +3,10 @@ import '../../core/app_colors.dart';
|
||||
import '../../core/app_theme.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../core/navigation_provider.dart';
|
||||
import '../../widgets/ai_content.dart';
|
||||
import 'report_pages.dart';
|
||||
|
||||
/// AI 解读页 — 从服务器获取真实报告数据
|
||||
/// AI 解读页:从服务器获取真实报告数据
|
||||
class AiAnalysisPage extends ConsumerStatefulWidget {
|
||||
final String id;
|
||||
const AiAnalysisPage({super.key, required this.id});
|
||||
@@ -99,7 +100,7 @@ class _AiAnalysisPageState extends ConsumerState<AiAnalysisPage> {
|
||||
_analysisStateCard(
|
||||
isFailed
|
||||
? (analysis.summary.isNotEmpty ? analysis.summary : 'AI 分析失败,请重新上传或稍后重试')
|
||||
: 'AI 正在分析报告,请稍后刷新查看。',
|
||||
: 'AI 正在分析报告,请稍后刷新查看',
|
||||
isFailed: isFailed,
|
||||
onRetry: isFailed
|
||||
? () => ref.read(reportProvider.notifier).reanalyzeReport(widget.id)
|
||||
@@ -107,7 +108,7 @@ class _AiAnalysisPageState extends ConsumerState<AiAnalysisPage> {
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
// ── 1. 指标分析 ──
|
||||
// 指标分析
|
||||
if (!isAnalyzing && !isFailed && analysis.indicators.isNotEmpty) ...[
|
||||
_sectionTitle('指标分析'),
|
||||
const SizedBox(height: 8),
|
||||
@@ -121,7 +122,7 @@ class _AiAnalysisPageState extends ConsumerState<AiAnalysisPage> {
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
// ── 2. 综合解读 ──
|
||||
// 综合解读
|
||||
if (!isAnalyzing && !isFailed) ...[
|
||||
_sectionTitle('综合解读'),
|
||||
const SizedBox(height: 8),
|
||||
@@ -131,35 +132,19 @@ class _AiAnalysisPageState extends ConsumerState<AiAnalysisPage> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
analysis.summary.isNotEmpty
|
||||
AiMarkdownView(
|
||||
data: analysis.summary.isNotEmpty
|
||||
? analysis.summary
|
||||
: 'AI 正在分析中,请稍后刷新查看',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.7,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.cardInner,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: const Text(
|
||||
'以上为AI预解读,不能替代医生诊断和治疗建议',
|
||||
style: TextStyle(fontSize: 13, color: AppColors.textHint),
|
||||
),
|
||||
),
|
||||
const AiGeneratedNote(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
if (!isAnalyzing && !isFailed) ...[
|
||||
// ── 3. 医生审核意见 ──
|
||||
// 医生审核意见
|
||||
_sectionTitle('医生审核意见'),
|
||||
const SizedBox(height: 8),
|
||||
if (isReviewed)
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import '../../core/app_colors.dart';
|
||||
import '../../core/app_module_visuals.dart';
|
||||
import '../../core/app_theme.dart';
|
||||
import '../../core/api_client.dart' show baseUrl;
|
||||
import '../../core/navigation_provider.dart';
|
||||
@@ -17,6 +18,13 @@ final reportProvider = NotifierProvider<ReportNotifier, ReportState>(
|
||||
ReportNotifier.new,
|
||||
);
|
||||
|
||||
Duration? reportAnalysisPollDelay(int attempt) {
|
||||
if (attempt > 15) return null;
|
||||
if (attempt <= 2) return const Duration(seconds: 4);
|
||||
if (attempt <= 5) return const Duration(seconds: 8);
|
||||
return const Duration(seconds: 12);
|
||||
}
|
||||
|
||||
class ReportState {
|
||||
final List<ReportItem> reports;
|
||||
final String? uploadingImage;
|
||||
@@ -132,6 +140,7 @@ class Indicator {
|
||||
|
||||
class ReportNotifier extends Notifier<ReportState> {
|
||||
Timer? _pollTimer;
|
||||
int _pollAttempt = 0;
|
||||
|
||||
@override
|
||||
ReportState build() {
|
||||
@@ -185,12 +194,16 @@ class ReportNotifier extends Notifier<ReportState> {
|
||||
if (!hasAnalyzing) {
|
||||
_pollTimer?.cancel();
|
||||
_pollTimer = null;
|
||||
_pollAttempt = 0;
|
||||
return;
|
||||
}
|
||||
_pollTimer ??= Timer.periodic(
|
||||
const Duration(seconds: 4),
|
||||
(_) => loadReports(),
|
||||
);
|
||||
if (_pollTimer != null) return;
|
||||
final delay = reportAnalysisPollDelay(++_pollAttempt);
|
||||
if (delay == null) return;
|
||||
_pollTimer = Timer(delay, () {
|
||||
_pollTimer = null;
|
||||
loadReports();
|
||||
});
|
||||
}
|
||||
|
||||
void fetchReportDetail(String reportId) async {
|
||||
@@ -354,8 +367,9 @@ class ReportNotifier extends Notifier<ReportState> {
|
||||
class ReportListPage extends ConsumerWidget {
|
||||
const ReportListPage({super.key});
|
||||
|
||||
static const _reportBlue = Color(0xFF8B5CF6);
|
||||
static const _reportCyan = Color(0xFF38BDF8);
|
||||
static const _reportVisual = AppModuleVisuals.report;
|
||||
static const _reportBlue = AppColors.report;
|
||||
static const _reportCyan = Color(0xFF60A5FA);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -407,7 +421,7 @@ class ReportListPage extends ConsumerWidget {
|
||||
EnterpriseHeader(
|
||||
title: '报告处理概览',
|
||||
subtitle: '上传检查报告后自动进行 AI 结构化解读',
|
||||
icon: Icons.description_outlined,
|
||||
icon: _reportVisual.icon,
|
||||
color: _reportBlue,
|
||||
accent: _reportCyan,
|
||||
showIcon: false,
|
||||
@@ -564,11 +578,7 @@ class ReportListPage extends ConsumerWidget {
|
||||
color: _reportBlue.withValues(alpha: 0.08),
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.description_outlined,
|
||||
size: 44,
|
||||
color: _reportBlue,
|
||||
),
|
||||
child: Icon(_reportVisual.icon, size: 44, color: _reportBlue),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Text(
|
||||
@@ -625,11 +635,7 @@ class ReportListPage extends ConsumerWidget {
|
||||
color: _reportBlue.withValues(alpha: 0.10),
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.description_outlined,
|
||||
size: 26,
|
||||
color: _reportBlue,
|
||||
),
|
||||
child: Icon(_reportVisual.icon, size: 26, color: _reportBlue),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
|
||||
Reference in New Issue
Block a user