소스 검색

加入图片的预览引擎,部分页面加入图片预览的功能

liukai 6 달 전
부모
커밋
c200cb8046

+ 24 - 15
packages/cpt_job/lib/modules/applied_staff_detail/staff_detail_widget.dart

@@ -4,12 +4,14 @@ import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
+import 'package:plugin_platform/engine/image/image_preview.dart';
+import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
-/**
- * 员工的做工记录
+/*
+ * 员工的信息
  */
 class StaffDetailWidget extends StatelessWidget {
   final StaffDetailEntity? detail;
@@ -23,9 +25,9 @@ class StaffDetailWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return Container(
-      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 10),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 10),
       decoration: BoxDecoration(
-        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
         borderRadius: BorderRadius.circular(5), // 设置圆角
       ),
       child: Column(
@@ -33,18 +35,25 @@ class StaffDetailWidget extends StatelessWidget {
         children: [
           //头像
           Center(
-              child: MyLoadImage(
-            detail?.avatar,
-            width: 100,
-            height: 100,
-          )).marginOnly(top: 25, bottom: 15),
+              child: Hero(
+            tag: '112cc8a34e13',
+            child: MyLoadImage(
+              detail?.avatar,
+              width: 100,
+              height: 100,
+            ),
+          )).onTap(() {
+            if (Utils.isNotEmpty(detail?.avatar)) {
+              ImagePreviewEngine.singleImagePreview(context, detail!.avatar!, heroTag: '112cc8a34e13');
+            }
+          }).marginOnly(top: 25, bottom: 15),
 
           //姓名
           Row(
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Name:",
+                "Name:".tr,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -64,7 +73,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Gender:",
+                "${"Gender".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -104,7 +113,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "NRIC:",
+                "${"NRIC".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -124,7 +133,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Reviews:",
+                "${"Reviews".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -145,7 +154,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Mobile:",
+                "${"Mobile".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -165,7 +174,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Email:",
+                "${"Email".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,

+ 1 - 1
packages/cpt_job_sg/lib/modules/applied_staff_detail/applied_staff_detail_page.dart

@@ -17,7 +17,7 @@ import 'applied_staff_detail_state.dart';
 import 'staff_detail_widget.dart';
 import 'staff_labour_history_item.dart';
 
-/**
+/*
  * 员工的详情(新加坡)
  */
 class AppliedStaffDetailPage extends BaseStatefulPage<AppliedStaffDetailController> {

+ 27 - 15
packages/cpt_job_sg/lib/modules/applied_staff_detail/staff_detail_widget.dart

@@ -4,18 +4,23 @@ import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
+import 'package:plugin_platform/engine/directory/directory_util.dart';
+import 'package:plugin_platform/engine/image/image_preview.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
-/**
- * 员工的做工记录
+/*
+ * 员工的信息
  */
 class StaffDetailWidget extends StatelessWidget {
   final StaffDetailSGEntity? detail;
   final void Function() onRemarkAction;
 
-  StaffDetailWidget({
+  const StaffDetailWidget({
+    super.key,
     required this.detail,
     required this.onRemarkAction,
   });
@@ -23,9 +28,9 @@ class StaffDetailWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return Container(
-      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 10),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 10),
       decoration: BoxDecoration(
-        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
         borderRadius: BorderRadius.circular(5), // 设置圆角
       ),
       child: Column(
@@ -33,11 +38,18 @@ class StaffDetailWidget extends StatelessWidget {
         children: [
           //头像
           Center(
-              child: MyLoadImage(
-            detail?.icon,
-            width: 100,
-            height: 100,
-          )).marginOnly(top: 25, bottom: 15),
+              child: Hero(
+            tag: '112cc8a34e13',
+            child: MyLoadImage(
+              detail?.icon,
+              width: 100,
+              height: 100,
+            ),
+          )).onTap(() {
+            if (Utils.isNotEmpty(detail?.icon)) {
+              ImagePreviewEngine.singleImagePreview(context, detail!.icon!, heroTag: '112cc8a34e13');
+            }
+          }).marginOnly(top: 25, bottom: 15),
 
           //姓名
           Row(
@@ -64,7 +76,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Gender".tr+":",
+                "${"Gender".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -84,7 +96,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Mobile".tr + ":",
+                "${"Mobile".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -104,7 +116,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Nric".tr + ":",
+                "${"Nric".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -124,7 +136,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Reviews".tr + ":",
+                "${"Reviews".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,
@@ -149,7 +161,7 @@ class StaffDetailWidget extends StatelessWidget {
             mainAxisSize: MainAxisSize.max,
             children: [
               MyTextView(
-                "Hourly Rate".tr + ":",
+                "${"Hourly Rate".tr}:",
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,
                 isFontRegular: true,

+ 16 - 3
packages/cpt_job_sg/lib/modules/job_applied/applied_staff_item.dart

@@ -11,7 +11,7 @@ import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/shatter/border_select_widget.dart';
 
-/**
+/*
  * 已申请的员工列表Item
  */
 class AppliedStaffItem extends StatelessWidget {
@@ -24,6 +24,7 @@ class AppliedStaffItem extends StatelessWidget {
   final VoidCallback? onReviseAction;
   final VoidCallback? onMemberAction;
   final void Function(BuildContext targetContext)? onStatusAction;
+  final void Function(String? img)? onImagePreviewAction;
 
   AppliedStaffItem({
     required this.index,
@@ -35,6 +36,7 @@ class AppliedStaffItem extends StatelessWidget {
     this.onReviseAction,
     this.onMemberAction,
     this.onStatusAction,
+    this.onImagePreviewAction,
   });
 
   @override
@@ -213,8 +215,13 @@ class AppliedStaffItem extends StatelessWidget {
                 item.workIn?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.workIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item.workIn?.color == null ? Colors.white : hexToColor(item.workIn!.color!),
                 fontSize: 14,
+                decorationStyle: item.workIn?.image == null ? null : TextDecorationStyle.solid,
+                decorationColor: item.workIn?.color == null ? Colors.white : hexToColor(item.workIn!.color!),
+                onClick: (){
+                  onImagePreviewAction?.call(item.workIn?.image);
+                },
               ).expanded(),
             ],
           ).marginOnly(top: 12),
@@ -259,8 +266,14 @@ class AppliedStaffItem extends StatelessWidget {
                 item.workOut?.time ?? "-",
                 marginLeft: 5,
                 isFontRegular: true,
-                textColor: item.workOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                textColor: item.workOut?.color == null ? Colors.white : hexToColor(item.workOut!.color!),
                 fontSize: 14,
+                decorationStyle: item.workOut?.image == null ? null : TextDecorationStyle.solid,
+                decorationColor: item.workOut?.color == null ? Colors.white : hexToColor(item.workOut!.color!),
+                decorationThickness: 2.0,
+                onClick: (){
+                  onImagePreviewAction?.call(item.workOut?.image);
+                },
               ).expanded(),
             ],
           ).marginOnly(top: 12),

+ 17 - 0
packages/cpt_job_sg/lib/modules/job_applied/job_applied_page.dart

@@ -1,8 +1,14 @@
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
+import 'package:plugin_platform/engine/directory/directory_util.dart';
+import 'package:plugin_platform/engine/image/image_preview.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_button.dart';
@@ -44,6 +50,7 @@ class JobAppliedPage extends BaseStatefulPage<JobAppliedController> {
 
 class _JobAppliedState extends BaseState<JobAppliedPage, JobAppliedController> {
   late JobAppliedState state;
+  String path = "";
 
   @override
   void initState() {
@@ -51,6 +58,11 @@ class _JobAppliedState extends BaseState<JobAppliedPage, JobAppliedController> {
     state = controller.state;
     state.jobId = Get.arguments['jobId'];
     state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+
+    if (!kIsWeb) {
+      path = DirectoryUtil.getTempPath() ?? "";
+      Log.e("path:$path");
+    }
   }
 
   @override
@@ -220,6 +232,11 @@ class _JobAppliedState extends BaseState<JobAppliedPage, JobAppliedController> {
                           onStatusAction: (targetContext) {
                             controller.dropDownStatus(index, targetContext);
                           },
+                          onImagePreviewAction: (imageUrl) {
+                            if (Utils.isNotEmpty(imageUrl)) {
+                              ImagePreviewEngine.singleImagePreview(context, imageUrl!);
+                            }
+                          },
                         );
                       },
                       childCount: state.datas.length,

+ 5 - 7
packages/cpt_report/lib/modules/report_finance/report_finance_item.dart

@@ -1,4 +1,3 @@
-import 'package:cpt_report/modules/device_list/device_list_controller.dart';
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/fiance_report_entity.dart';
@@ -6,7 +5,6 @@ import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
-import 'package:plugin_platform/engine/loading/loading_engine.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
@@ -64,7 +62,7 @@ class ReportFinanceItem extends StatelessWidget {
                   MyTextView(
                     item.request.toString(),
                     textColor: ColorConstants.textYellowF8AE00,
-                    fontSize: 11.7,
+                    fontSize: 11,
                     isFontRegular: true,
                   ),
                 ],
@@ -82,11 +80,11 @@ class ReportFinanceItem extends StatelessWidget {
                   MyTextView(
                     item.actual.toString(),
                     textColor: ColorConstants.textGreen00FB92,
-                    fontSize: 13.5,
+                    fontSize: 13,
                     isFontBold: true,
                   ),
                 ],
-              ).marginOnly(left: 9,right: 9),
+              ).marginOnly(left: 5,right: 5),
 
               Column(
                 children: [
@@ -99,13 +97,13 @@ class ReportFinanceItem extends StatelessWidget {
                   MyTextView(
                     item.ratio ?? "-",
                     textColor: ColorConstants.textPurpleFF35EE,
-                    fontSize: 13.5,
+                    fontSize: 13,
                     isFontBold: true,
                   ),
                 ],
               ).expanded(),
             ],
-          ).paddingOnly(left: 12,right: 12).expanded(),
+          ).paddingOnly(left: 10,right: 10).expanded(),
         ],
       ),
     );

+ 0 - 1
packages/cpt_report/lib/modules/report_finance/report_finance_page.dart

@@ -7,7 +7,6 @@ import 'package:shared/utils/screen_util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_appbar.dart';
-import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
 import 'report_finance_controller.dart';

+ 59 - 44
packages/cpt_report/lib/modules/report_labour/report_labour_item.dart

@@ -21,7 +21,7 @@ class ReportLabourItem extends StatelessWidget {
   Widget build(BuildContext context) {
     return Container(
       width: double.infinity,
-      padding: const EdgeInsets.only(top: 16,bottom: 20),
+      padding: const EdgeInsets.only(top: 16, bottom: 20),
       margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
       decoration: BoxDecoration(
         color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
@@ -31,17 +31,26 @@ class ReportLabourItem extends StatelessWidget {
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
           MyTextView(
-            type == 0 ? "Completed".tr : type == 1 ? "Incomplete".tr : "Completed + Incomplete".tr,
+            type == 0
+                ? "Completed".tr
+                : type == 1
+                    ? "Incomplete".tr
+                    : "Completed + Incomplete".tr,
             fontSize: 14,
             isFontBold: true,
             marginBottom: 15,
             marginLeft: 20,
             marginRight: 20,
-            textColor: type == 0 ? ColorConstants.textGreen0AC074 : type == 1 ? ColorConstants.textBlue06D9FF : ColorConstants.textRedFF6262,
+            textColor: type == 0
+                ? ColorConstants.textGreen0AC074
+                : type == 1
+                    ? ColorConstants.textBlue06D9FF
+                    : ColorConstants.textRedFF6262,
           ),
           const Divider(height: 0.5, color: ColorConstants.dividerBar),
 
           Row(
+            crossAxisAlignment: CrossAxisAlignment.start,
             children: [
               MyTextView(
                 "Outlet".tr,
@@ -49,49 +58,58 @@ class ReportLabourItem extends StatelessWidget {
                 textColor: Colors.white,
                 isFontRegular: true,
               ).expanded(),
-
-              RichText(
-                text: TextSpan(
-                  children: [
-                    TextSpan(
-                      text: "Hours".tr,
-                      style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w400),
-                    ),
-                    TextSpan(
-                      text: "(${entity?.total?.hrs})",
-                      style: const TextStyle(color: ColorConstants.textGreen0AC074, fontSize: 14, fontWeight: FontWeight.w400),
-                    ),
-                  ],
-                ),
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  MyTextView("Hours".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                  MyTextView(
+                    "(${entity?.total?.hrs})",
+                    textColor: type == 0
+                        ? ColorConstants.textGreen0AC074
+                        : type == 1
+                            ? ColorConstants.textBlue06D9FF
+                            : ColorConstants.textRedFF6262,
+                    fontSize: 14,
+                    isFontRegular: true,
+                  ),
+                ],
               ).expanded(),
-
-              RichText(
-                text: TextSpan(
-                  children: [
-                    TextSpan(
-                      text: "TotalAmt".tr,
-                      style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w400),
-                    ),
-                    TextSpan(
-                      text: "(${entity?.total?.agAmt})",
-                      style: const TextStyle(color: ColorConstants.textGreen0AC074, fontSize: 14, fontWeight: FontWeight.w400),
-                    ),
-                  ],
-                ),
+              Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  MyTextView("TotalAmt".tr, textColor: Colors.white, fontSize: 14, isFontRegular: true),
+                  MyTextView(
+                    "(${entity?.total?.agAmt})",
+                    textColor: type == 0
+                        ? ColorConstants.textGreen0AC074
+                        : type == 1
+                            ? ColorConstants.textBlue06D9FF
+                            : ColorConstants.textRedFF6262,
+                    fontSize: 14,
+                    isFontRegular: true,
+                  ),
+                ],
               ).expanded(),
-
             ],
-          ).marginOnly(left: 20,right:20,top: 18,bottom: 2),
+          ).marginOnly(left: 20, right: 20, top: 18, bottom: 2),
 
           //底部的实际数据
           ...(entity?.rows.map((item) {
-            return _childItem(
-              item.outletName,
-              type == 0 ? item.hrs : type == 1 ? item.inHrs : item.totHrs,
-              type == 0 ? item.agAmt : type == 1 ? item.inAgAmt : item.totAgAmt,
-            );
-          }).toList() ?? []),
-
+                return _childItem(
+                  item.outletName,
+                  type == 0
+                      ? item.hrs
+                      : type == 1
+                          ? item.inHrs
+                          : item.totHrs,
+                  type == 0
+                      ? item.agAmt
+                      : type == 1
+                          ? item.inAgAmt
+                          : item.totAgAmt,
+                );
+              }).toList() ??
+              []),
         ],
       ),
     );
@@ -106,22 +124,19 @@ class ReportLabourItem extends StatelessWidget {
           textColor: Colors.white,
           isFontRegular: true,
         ).expanded(),
-
         MyTextView(
           "$hours H",
           fontSize: 14,
           textColor: Colors.white,
           isFontRegular: true,
         ).expanded(),
-
         MyTextView(
           "\$ $agAmt",
           fontSize: 14,
           textColor: Colors.white,
           isFontRegular: true,
         ).expanded(),
-
       ],
-    ).marginOnly(top: 16,left: 20,right: 20);
+    ).marginOnly(top: 16, left: 20, right: 20);
   }
 }

+ 1 - 1
packages/cs_domain/lib/entity/response/job_applied_list_s_g_entity.dart

@@ -100,7 +100,7 @@ class JobAppliedListSGRowsCheck {
 	String? temp = null;
 	String? image;
 	int? changed = 0;
-	String? key = null;
+	String? color;
 
 	JobAppliedListSGRowsCheck();
 

+ 6 - 6
packages/cs_domain/lib/generated/json/job_applied_list_s_g_entity.g.dart

@@ -273,9 +273,9 @@ JobAppliedListSGRowsCheck $JobAppliedListSGRowsCheckFromJson(Map<String, dynamic
   if (changed != null) {
     jobAppliedListSGRowsCheck.changed = changed;
   }
-  final String? key = jsonConvert.convert<String>(json['key']);
-  if (key != null) {
-    jobAppliedListSGRowsCheck.key = key;
+  final String? color = jsonConvert.convert<String>(json['color']);
+  if (color != null) {
+    jobAppliedListSGRowsCheck.color = color;
   }
   return jobAppliedListSGRowsCheck;
 }
@@ -286,7 +286,7 @@ Map<String, dynamic> $JobAppliedListSGRowsCheckToJson(JobAppliedListSGRowsCheck
   data['temp'] = entity.temp;
   data['image'] = entity.image;
   data['changed'] = entity.changed;
-  data['key'] = entity.key;
+  data['color'] = entity.color;
   return data;
 }
 
@@ -296,14 +296,14 @@ extension JobAppliedListSGRowsCheckExtension on JobAppliedListSGRowsCheck {
     String? temp,
     String? image,
     int? changed,
-    String? key,
+    String? color,
   }) {
     return JobAppliedListSGRowsCheck()
       ..time = time ?? this.time
       ..temp = temp ?? this.temp
       ..image = image ?? this.image
       ..changed = changed ?? this.changed
-      ..key = key ?? this.key;
+      ..color = color ?? this.color;
   }
 }
 

+ 116 - 0
packages/cs_plugin_platform/lib/engine/image/image_preview.dart

@@ -0,0 +1,116 @@
+import 'package:flutter/material.dart';
+import 'package:image_preview/preview.dart';
+import 'package:image_preview/preview_data.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/util.dart';
+
+import '../directory/directory_util.dart';
+
+class ImagePreviewEngine {
+  /// 单图的预览
+  static void singleImagePreview(
+    BuildContext context,
+    String url, {
+    String? heroTag,
+    void Function(String? url)? onLongPressAction,
+    Widget? Function(int index)? tipWidget,
+  }) {
+    String path;
+
+    // 根据URL类型处理路径
+    if (isNetworkUrl(url)) {
+      // 从URL中提取文件名
+      String fileName = extractFileName(url);
+      // 生成保存路径
+      path = DirectoryUtil.getTempPath(category: 'Pictures', fileName: fileName) ?? "";
+    } else {
+      // 如果是本地路径,直接使用URL作为路径
+      path = url;
+    }
+
+    // 调用预览页面
+    openPreviewPage(
+      Navigator.of(context),
+      data: PreviewData(
+        type: Type.image,
+        heroTag: heroTag ?? '',
+        image: ImageData(
+          url: url,
+          path: path,
+        ),
+      ),
+      tipWidget: tipWidget,
+      onLongPressHandler: (context, data) {
+        onLongPressAction?.call(data.image?.url);
+      },
+    );
+  }
+
+  /// 多图的预览
+  static void multipleImagePreview(
+    BuildContext context,
+    List<String?> urls, {
+    List<String>? heroes,
+    void Function(String? url)? onLongPressAction,
+    void Function(int index)? onPageChanged,
+    Widget? Function(int index)? tipWidget,
+  }) {
+    // 过滤掉 null 值的 URL
+    List<String> filteredUrls = urls.where((url) => url != null).cast<String>().toList();
+
+    List<PreviewData> previewDataList = filteredUrls.asMap().entries.map((entry) {
+      int index = entry.key;
+      String url = entry.value;
+
+      String path;
+      if (isNetworkUrl(url)) {
+        String fileName = extractFileName(url);
+        path = DirectoryUtil.getTempPath(category: 'Pictures', fileName: fileName) ?? "";
+      } else {
+        path = url;
+      }
+
+      return PreviewData(
+        type: Type.image,
+        heroTag: heroes != null && heroes.length > index ? heroes[index] : index.toString(),
+        image: ImageData(
+          url: url,
+          path: path,
+        ),
+      );
+    }).toList();
+
+    // 调用预览页面
+    openPreviewPages(
+      Navigator.of(context),
+      data: previewDataList,
+      tipWidget: tipWidget,
+      onPageChanged: onPageChanged,
+      onLongPressHandler: (context, data) {
+        onLongPressAction?.call(data.image?.url);
+      },
+    );
+  }
+
+  /// 工具函数:从URL提取文件名
+  static String extractFileName(String url) {
+    // 检查是否包含 '/'
+    if (!url.contains('/')) {
+      return DateTimeUtils.getNowDateMs().toString();
+    }
+
+    // 获取最后一个 '/' 后的部分
+    String fileName = url.split('/').last;
+
+    // 检查是否包含 '.'
+    if (Utils.isEmpty(fileName)) {
+      return DateTimeUtils.getNowDateMs().toString();
+    }
+    return fileName;
+  }
+
+  /// 工具函数:判断是否为网络URL
+  static bool isNetworkUrl(String url) {
+    return url.startsWith('http://') || url.startsWith('https://');
+  }
+}

+ 3 - 0
packages/cs_plugin_platform/pubspec.yaml

@@ -57,6 +57,9 @@ dependencies:
   # 内部包含吐司气泡 弹窗 下拉选等
   flutter_smart_dialog: ^4.9.6
 
+  # 图片预览(单图与多图) https://github.com/xia-weiyang/image_preview
+  image_preview: ^1.2.4
+  
   # SD卡管理,缓存管理
   path_provider: 2.1.4
   synchronized: ^3.1.0+1

+ 1 - 1
packages/cs_widgets/lib/my_text_view.dart

@@ -91,7 +91,7 @@ class MyTextView extends StatelessWidget {
     this.fontSize,
     this.textDecoration,
     this.decorationColor,
-    this.decorationThickness,
+    this.decorationThickness,  //下划线
     this.decorationStyle,
     this.isTextEllipsis,
     this.isFontLight,