Browse Source

[feat]亲密度分析,增加分析结果卡片

hezihao 7 tháng trước cách đây
mục cha
commit
559e835105

+ 1 - 0
assets/color/common_color.xml

@@ -37,6 +37,7 @@
     <color name="black55">#8C000000</color>
     <color name="black50">#80000000</color>
     <color name="black45">#73000000</color>
+    <color name="black47">#78000000</color>
     <color name="black40">#66000000</color>
     <color name="black41">#69000000</color>
     <color name="black35">#59000000</color>

BIN
assets/images/icon_ai_model.webp


BIN
assets/images/icon_intimacy_analysis_result_top.webp


+ 4 - 0
assets/string/base/string.xml

@@ -241,6 +241,10 @@
     <string name="intimacy_analyse_step_title_select_prediction_direction">选择预测方向</string>
     <string name="intimacy_analyse_prediction_direction_card_tip">选择不同阶段的标签,可以更精准地分析</string>
     <string name="intimacy_analyse_add_prediction_direction">添加预测方向</string>
+    <string name="intimacy_analyse_prediction_direction">预测方向</string>
+    <string name="intimacy_analyse_model">模型</string>
+
+    <string name="intimacy_analyse_analysis_result">分析结果</string>
 
     <string name="my_self">自己</string>
     <string name="and">与</string>

+ 19 - 0
lib/module/intimacy_analyse/analyse_report/intimacy_analyse_report_view_controller.dart

@@ -11,6 +11,25 @@ import '../intimacy_analyse_upload/intimacy_analyse_upload_page.dart';
 /// 亲密度分析-分析报告Tab-Controller
 @injectable
 class IntimacyAnalyseReportController extends BaseController {
+  RxString reportPreviewMarkdownData = '''
+  **性格匹配度**
+
+  ● 互补型:一方外向活泼,另一方沉稳内敛,形成动态平衡。
+  ● 相似型:三观一致,兴趣重叠,减少摩擦但需警惕新鲜感流失。
+  ● 关键结论:差异是火花的来源,但核心价值观需一致(如家庭观、金钱观)。
+  
+  **沟通模式分析**
+  
+  ● 语言风格:幽默调侃型 vs 理性分析型 → 需找到共同表达方式。
+  ● 冲突解决:回避型 vs 直面型 → 建议建立“冷静-沟通”机制。
+  ● 情感需求:一方需要高频互动,另一方偏好独立空间 → 需协商平衡点。
+  
+  **爱情语言测试**
+  
+  ● 根据盖瑞·查普曼的“五种爱之语”理论,分析双方的情感表达偏好:
+  ● 你的主要爱语:肯定的言辞(如情话、鼓励)
+  '''.obs;
+
   /// 报告预览数据
   Rx<IntimacyAnalyseReport> reportPreviewData =
       IntimacyAnalyseReport(

+ 159 - 1
lib/module/intimacy_analyse/intimacy_analyse_upload/intimacy_analyse_upload_page.dart

@@ -1,3 +1,4 @@
+import 'package:cached_network_image/cached_network_image.dart';
 import 'package:dotted_border/dotted_border.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
@@ -142,7 +143,7 @@ class IntimacyAnalyseUploadPage
       ),
       contentWidget: Column(
         children: [
-          // 九宫格
+          // 图片九宫格
           Container(
             margin: EdgeInsets.only(left: 12.w, right: 12.w),
             padding: EdgeInsets.only(
@@ -213,6 +214,161 @@ class IntimacyAnalyseUploadPage
     );
   }
 
+  /// 分析结果卡片
+  Widget _buildAnalysisResultCard() {
+    return StepCard(
+      bgImageProvider: Assets.images.bgIntimacyAnalyseUploadCard.provider(),
+      stepLabel: "",
+      stepTitle: StringName.intimacyAnalyseAnalysisResult,
+      stepDesc: "",
+      topIconWidget: Assets.images.iconIntimacyAnalysisResultTop.image(
+        height: 63.h,
+        width: 103.w,
+      ),
+      contentWidget: Column(
+        children: [
+          // 图片九宫格
+          Container(
+            margin: EdgeInsets.only(left: 12.w, right: 12.w),
+            padding: EdgeInsets.only(
+              left: 12.w,
+              top: 12.h,
+              right: 12.w,
+              bottom: 12.h,
+            ),
+            decoration: BoxDecoration(
+              color: ColorName.white,
+              borderRadius: BorderRadius.circular(16.r),
+            ),
+            child: UploadNineGrid(
+              mode: Mode.preview,
+              imageSrcList: ["", "", "", "", "", "", ""],
+              maxCount: 9,
+              spacing: 8.0,
+            ),
+          ),
+          SizedBox(height: 10.h),
+          Container(
+            margin: EdgeInsets.symmetric(horizontal: 12.w),
+            child: Row(
+              children: [
+                // 预测方向
+                _buildDirectionResult(),
+                SizedBox(width: 12.w,),
+                // 模型
+                _buildAiModelResult()
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  /// 预测方向结果
+  Widget _buildDirectionResult() {
+    return Expanded(
+      child: Container(
+        padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 10.w),
+        decoration: BoxDecoration(
+          color: ColorName.white,
+          borderRadius: BorderRadius.circular(14.r),
+        ),
+        child: Row(
+          children: [
+            Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                // 标题
+                Text(
+                  StringName.intimacyAnalysePredictionDirection,
+                  style: TextStyle(
+                    color: ColorName.black47,
+                    fontSize: 12.sp,
+                    fontWeight: FontWeight.w400,
+                  ),
+                ),
+                SizedBox(height: 4.h),
+                // 结果
+                Row(
+                  children: [
+                    // 图标
+                    CachedNetworkImage(imageUrl: "", height: 14.w, width: 14.w),
+                    SizedBox(width: 2.w),
+                    // 结果文字
+                    Text(
+                      "未来",
+                      style: TextStyle(
+                        color: ColorName.black80,
+                        fontSize: 13.sp,
+                        fontWeight: FontWeight.w500,
+                      ),
+                    ),
+                  ],
+                ),
+              ],
+            ),
+            Expanded(child: SizedBox()),
+            // 亲密关系头像
+            IntimacyUserWidget(
+              width: 60.w,
+              height: 30.h,
+              avatarSize: 30.0,
+              avatarUrl1: '',
+              avatarUrl2: '',
+              avatarBorderWidth: 1.w,
+              loveSize: 17.w,
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+
+  /// Ai模型结果
+  Widget _buildAiModelResult() {
+    return Expanded(
+      child: Container(
+        padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 10.w),
+        decoration: BoxDecoration(
+          color: ColorName.white,
+          borderRadius: BorderRadius.circular(14.r),
+        ),
+        child: Row(
+          children: [
+            Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                // 标题
+                Text(
+                  StringName.intimacyAnalyseModel,
+                  style: TextStyle(
+                    color: ColorName.black47,
+                    fontSize: 12.sp,
+                    fontWeight: FontWeight.w400,
+                  ),
+                ),
+                SizedBox(height: 4.h),
+                // 结果文字
+                Text(
+                  "DeepSeek R1",
+                  style: TextStyle(
+                    color: ColorName.black80,
+                    fontSize: 13.sp,
+                    fontWeight: FontWeight.w500,
+                  ),
+                ),
+              ],
+            ),
+            Expanded(child: SizedBox()),
+            // Ai模型图片
+            Assets.images.iconAiModel.image(width: 38, height: 30),
+          ],
+        ),
+      ),
+    );
+  }
+
   /// 添加预测方向按钮
   Widget _buildAddDirectionBtn() {
     return Container(
@@ -504,6 +660,8 @@ class IntimacyAnalyseUploadPage
               children: [
                 // 上传卡片
                 _buildUploadStepCard(),
+                // 分析结果卡片
+                _buildAnalysisResultCard(),
                 // 预测方向卡片
                 _buildPredictionDirectionStepCard(),
                 SizedBox(height: 80.h),

+ 1 - 1
lib/module/intimacy_analyse/intimacy_analyse_upload/widget/upload_nine_grid.dart

@@ -95,7 +95,7 @@ class UploadNineGrid extends StatelessWidget {
   Widget _buildUploadItem(String imageSrc) {
     return UploadItemWidget(
       imageSrc: imageSrc,
-      uploadState: UploadState.uploading,
+      uploadState: UploadState.fail,
       onClickDeleteCallback: () {
         // 删除图片
       },

+ 115 - 0
lib/module/intimacy_analyse/widget/intimacy_analyse_report_widget.dart

@@ -0,0 +1,115 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+
+import '../../../resource/assets.gen.dart';
+import '../../../resource/colors.gen.dart';
+import '../../../widget/markdown/markdown_viewer.dart';
+
+/// 亲密度报告组件
+class IntimacyAnalyseReportWidget extends StatelessWidget {
+  /// 报告内容
+  final String reportContent;
+
+  const IntimacyAnalyseReportWidget({super.key, required this.reportContent});
+
+  @override
+  Widget build(BuildContext context) {
+    // 卡片背景
+    return Stack(
+      // 让大小,撑满父组件
+      fit: StackFit.expand,
+      children: [
+        // 中间内容
+        Container(
+          margin: EdgeInsets.only(left: 12, right: 12, bottom: 0),
+          padding: EdgeInsets.only(bottom: 12),
+          decoration: BoxDecoration(
+            image: DecorationImage(
+              image: Assets.images.bgIntimacyAnalyseReportPreview.provider(),
+              fit: BoxFit.fill,
+            ),
+          ),
+          // 圆角背景
+          child: Stack(
+            children: [
+              // 图标和标题
+              _buildReportPreviewTopLayout(),
+              Container(
+                margin: EdgeInsets.only(
+                  top: 51,
+                  left: 12,
+                  right: 12,
+                  bottom: 5,
+                ),
+                decoration: ShapeDecoration(
+                  color: ColorName.white,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(20.r),
+                  ),
+                ),
+                child: Padding(
+                  padding: const EdgeInsets.only(
+                    left: 14,
+                    right: 14,
+                    top: 20,
+                    bottom: 14,
+                  ),
+                  // 内容
+                  child: Container(
+                    color: Colors.red,
+                    height: 424.h,
+                    child: LayoutBuilder(
+                      builder: (
+                        BuildContext context,
+                        BoxConstraints constraints,
+                      ) {
+                        return SingleChildScrollView(
+                          physics: BouncingScrollPhysics(),
+                          // 渲染Markdown
+                          child: ConstrainedBox(
+                            constraints: BoxConstraints(
+                              // 确保最小高度
+                              minHeight: constraints.maxHeight,
+                            ),
+                            child: MarkdownViewer(content: reportContent),
+                          ),
+                        );
+                      },
+                    ),
+                  ),
+                ),
+              ),
+            ],
+          ),
+        ),
+        // 底部阴影
+        Positioned(
+          left: 0,
+          right: 0,
+          bottom: 0,
+          child: Container(
+            child: Assets.images.bgIntimacyAnalyseReportPreviewMask.image(
+              height: 126,
+            ),
+          ),
+        ),
+      ],
+    );
+  }
+
+  /// 报告预览布局-顶部布局-包含:图标和标题
+  Widget _buildReportPreviewTopLayout() {
+    return Row(
+      children: [
+        Assets.images.iconIntimacyAnalyseReportPreviewLove.image(
+          width: 50,
+          height: 48,
+        ),
+        Assets.images.iconIntimacyAnalyseReportPreviewTitle.image(
+          width: 178,
+          height: 24,
+        ),
+      ],
+    );
+  }
+}

+ 21 - 12
lib/module/intimacy_analyse/widget/step_card.dart

@@ -63,10 +63,11 @@ class StepCard extends StatelessWidget {
                 ),
                 SizedBox(height: 4.h),
                 // 步骤描述
-                _buildStepDesc(stepDesc),
-                SizedBox(height: 16.h),
+                stepDesc.isNotEmpty
+                    ? _buildStepDesc(stepDesc)
+                    : SizedBox(height: 6.h),
                 contentWidget,
-                SizedBox(height: 18.h),
+                SizedBox(height: 12.h),
               ],
             ),
           ),
@@ -106,16 +107,24 @@ class StepCard extends StatelessWidget {
 
   /// 构建步骤描述
   Widget _buildStepDesc(String desc) {
-    return Container(
-      margin: EdgeInsets.only(left: 12.w),
-      child: Text(
-        desc,
-        style: TextStyle(
-          fontSize: 12.sp,
-          fontWeight: FontWeight.w400,
-          color: ColorName.black60,
+    if (desc.isEmpty) {
+      return SizedBox();
+    }
+    return Row(
+      children: [
+        Container(
+          margin: EdgeInsets.only(left: 12.w),
+          child: Text(
+            desc,
+            style: TextStyle(
+              fontSize: 12.sp,
+              fontWeight: FontWeight.w400,
+              color: ColorName.black60,
+            ),
+          ),
         ),
-      ),
+        SizedBox(height: 16.h),
+      ],
     );
   }
 }

+ 11 - 0
lib/resource/assets.gen.dart

@@ -219,6 +219,10 @@ class $AssetsImagesGen {
   AssetGenImage get iconAddPredictionDirection =>
       const AssetGenImage('assets/images/icon_add_prediction_direction.webp');
 
+  /// File path: assets/images/icon_ai_model.webp
+  AssetGenImage get iconAiModel =>
+      const AssetGenImage('assets/images/icon_ai_model.webp');
+
   /// File path: assets/images/icon_alipay_payment.webp
   AssetGenImage get iconAlipayPayment =>
       const AssetGenImage('assets/images/icon_alipay_payment.webp');
@@ -468,6 +472,11 @@ class $AssetsImagesGen {
     'assets/images/icon_intimacy_analyse_upload_top.webp',
   );
 
+  /// File path: assets/images/icon_intimacy_analysis_result_top.webp
+  AssetGenImage get iconIntimacyAnalysisResultTop => const AssetGenImage(
+    'assets/images/icon_intimacy_analysis_result_top.webp',
+  );
+
   /// File path: assets/images/icon_keyboard_banner.webp
   AssetGenImage get iconKeyboardBanner =>
       const AssetGenImage('assets/images/icon_keyboard_banner.webp');
@@ -836,6 +845,7 @@ class $AssetsImagesGen {
     gifDiscountUnlockButton,
     iconAboutArrowLeft,
     iconAddPredictionDirection,
+    iconAiModel,
     iconAlipayPayment,
     iconAlipayScanPayment,
     iconArrowRight,
@@ -894,6 +904,7 @@ class $AssetsImagesGen {
     iconIntimacyAnalyseReportPreviewTitle,
     iconIntimacyAnalyseUnlock,
     iconIntimacyAnalyseUploadTop,
+    iconIntimacyAnalysisResultTop,
     iconKeyboardBanner,
     iconKeyboardBannerClose,
     iconKeyboardCurrentCharacterTitle,

+ 3 - 0
lib/resource/colors.gen.dart

@@ -79,6 +79,9 @@ class ColorName {
   /// Color: #73000000
   static const Color black45 = Color(0x73000000);
 
+  /// Color: #78000000
+  static const Color black47 = Color(0x78000000);
+
   /// Color: #0D000000
   static const Color black5 = Color(0x0D000000);
 

+ 6 - 0
lib/resource/string.gen.dart

@@ -175,6 +175,9 @@ class StringName {
   static final String intimacyAnalyseStepTitleSelectPredictionDirection = 'intimacy_analyse_step_title_select_prediction_direction'.tr; // 选择预测方向
   static final String intimacyAnalysePredictionDirectionCardTip = 'intimacy_analyse_prediction_direction_card_tip'.tr; // 选择不同阶段的标签,可以更精准地分析
   static final String intimacyAnalyseAddPredictionDirection = 'intimacy_analyse_add_prediction_direction'.tr; // 添加预测方向
+  static final String intimacyAnalysePredictionDirection = 'intimacy_analyse_prediction_direction'.tr; // 预测方向
+  static final String intimacyAnalyseModel = 'intimacy_analyse_model'.tr; // 模型
+  static final String intimacyAnalyseAnalysisResult = 'intimacy_analyse_analysis_result'.tr; // 分析结果
   static final String mySelf = 'my_self'.tr; // 自己
   static final String and = 'and'.tr; // 与
   static final String intimacyRelation = 'intimacy_relation'.tr; // 亲密关系
@@ -358,6 +361,9 @@ class StringMultiSource {
       'intimacy_analyse_step_title_select_prediction_direction': '选择预测方向',
       'intimacy_analyse_prediction_direction_card_tip': '选择不同阶段的标签,可以更精准地分析',
       'intimacy_analyse_add_prediction_direction': '添加预测方向',
+      'intimacy_analyse_prediction_direction': '预测方向',
+      'intimacy_analyse_model': '模型',
+      'intimacy_analyse_analysis_result': '分析结果',
       'my_self': '自己',
       'and': '与',
       'intimacy_relation': '亲密关系',

+ 20 - 0
lib/widget/markdown/markdown_viewer.dart

@@ -0,0 +1,20 @@
+import 'package:cached_network_image/cached_network_image.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_markdown/flutter_markdown.dart';
+
+/// Markdown组件
+class MarkdownViewer extends StatelessWidget {
+  /// 内容
+  final String content;
+
+  const MarkdownViewer({super.key, required this.content});
+
+  @override
+  Widget build(BuildContext context) {
+    return Markdown(
+      data: content,
+      imageBuilder:
+          (uri, title, alt) => CachedNetworkImage(imageUrl: uri.toString()),
+    );
+  }
+}

+ 8 - 0
pubspec.lock

@@ -474,6 +474,14 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_markdown:
+    dependency: "direct main"
+    description:
+      name: flutter_markdown
+      sha256: "04c4722cc36ec5af38acc38ece70d22d3c2123c61305d555750a091517bbe504"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.6.23"
   flutter_screenutil:
     dependency: "direct main"
     description:

+ 3 - 0
pubspec.yaml

@@ -73,6 +73,9 @@ dependencies:
   #左滑
   flutter_slidable: ^4.0.0
 
+  # MarkDown文档渲染
+  flutter_markdown: ^0.7.7
+
   #QR
   qr_flutter: ^4.1.0