ecp_widget

ecp_widget 是翼协云底座公共组件库

此库专为内部项目需求设计,若不符合您的使用场景,敬请谅解。

安装

在 pubspec.yaml 中添加依赖:

dependencies:
  ecp_widget: ^2.2.0

组件总览

分类 组件
弹窗 EcpAlertDialog、EcpBottomSheetDialog、EcpBottomSinglePicker、EcpCenterDialog、EcpTipsDialog
基础组件 EcpAvatar(头像)、EcpCachedNetImage(网络图缓存)、EcpCommonBtn(通用按钮)、EcpCornerMark(角标)、EcpIcon、EcpNavBarView(导航栏)、EcpSimpleCard(卡片)、EcpSimpleFormListView(表单列表)、EcpCommonOpinion(意见填写)、EcpGallery(图片预览)
日期时间 EcpDatePicker、EcpDateRangePicker、EcpDateTimePicker、EcpTimePicker
筛选 EcpFilterWidget、EcpFilterDialog、DateRangeFilterItem
选人/选部门 DepartmentUserPicker、EcpDepartmentPicker、EcpDepartmentUserPicker、EcpRolePicker、EcpUnitPicker、EcpUserPicker
搜索 SearchWithBtn、SearchWithDel
页面 LoginPage(登录页,2.2.0 起自 ecp_common_app 迁入:账号记忆、RSA 加密提交)
扫码 EcpScanManager(扫码分发:内容 URI 去掉 query 作为 key 分发;2.2.0 起自 ecp_scan_manager 迁入,底层 EcpScanPage 基于 mobile_scanner,内部页面不对外导出)
其他 IndexedTabScrollView、IndexedWidget、CrumbItem(面包屑)、UserPickerItem、字符串扩展、EcpHtml(富文本展示)

搜索

  • 带删除按钮的搜索框
SearchWithDel(
  onSearchClick: (text) => SmartDialog.showToast(text),///搜索时回调
);
  • 带按钮的搜索框
SearchWithBtn(
  onSearchClick: (text) => SmartDialog.showToast(text),///搜索时回调
);

Screenshot_20221123-175224.png

选人

  • 按部门选人
DepartmentUserPicker(
      {Key? key,
      this.limitNum = noLimited, ///限制数
      this.allowEmpty = false, ///是否允许不选人
      required this.userSelectorBuilder, ///选择人员列表Item样式
      required this.userSelectedBuilder, ///已选择人员列表Item样式
      required this.departmentBuilder, ///部门列表Item样式
      required this.crumbBuilder, ///面包屑列表Item样式
      this.departmentRepo, ///部门列表数据来源,包含子部门列表数据
      this.userRepo, /// 用户列表数据来源
      this.userSearchRepo, // 用户列表搜索数据来源
      });

或者直接使用翼协云公共样式

EcpDepartmentUserPicker({
    super.key,
    super.limitNum,///限制数
    super.allowEmpty,///是否允许不选人
  });
  • 选人控件 继承DepartmentUserPicker时,不传入departmentRepo即可
DepartmentUserPicker(
      {Key? key,
      this.limitNum = noLimited, ///限制数
      this.allowEmpty = false, ///是否允许不选人
      required this.userSelectorBuilder, ///选择人员列表Item样式
      required this.userSelectedBuilder, ///已选择人员列表Item样式
      required this.departmentBuilder, ///部门列表Item样式
      required this.crumbBuilder, ///面包屑列表Item样式
      this.departmentRepo, ///部门列表数据来源,包含子部门列表数据
      this.userRepo, /// 用户列表数据来源
      this.userSearchRepo, // 用户列表搜索数据来源
      });

默认翼协云公共样式

EcpUserPicker({
    super.key,
    super.limitNum,///限制数
    super.allowEmpty,///是否允许不选人
  });

登录页

LoginPage 为开箱即用的登录页(2.2.0 起自 ecp_common_app 迁入本库)。最典型的用法是作为 home:

import 'package:ecp_widget/ecp_widget.dart';

MaterialApp(
  home: LoginPage(
    ip: "http://135.0.123.110:8700/api", /// 可选:调试用登录地址
    nextPage: const MyHomePage(), /// 登录成功后跳转的页面
    onLoginSuccess: () async {
      /// 登录成功回调(先于 nextPage 跳转执行)
    },
  ),
);

在页面中跳转用法:

forwardPage(context, LoginPage(nextPage: const DemoPage()));

行为说明:

  • 账号密码自动记忆:登录成功后写入 SharedPreferences(keyLoginUser / keyLoginPassword),下次进入自动填充;debug 模式预填开发账号 tanantSuperAdmin / 123@Admin
  • 密码提交前经 rsaEncode RSA 加密,非明文传输;请求走 EcpGlobalApi.loginSimple,过程由 toDialogRequest 包裹(带弹窗反馈)
  • 登录成功顺序:RuntimeUtils.setRuntimeEntity + EcpGlobalDebugUtils.fillUserInfo() → onLoginSuccess → 跳转 nextPage
  • 隐藏交互:点击顶部图标,密码自动补全为「用户名@Sys」

配置注意事项:

  1. 网络初始化:登录请求依赖 ecp_net。宿主 App 需先完成 NetConfig 初始化(convert / initialDio / baseOptions),参照 example/lib/main.dart 的 initNet(),否则请求没有正确的 baseUrl 与转换规则
  2. 登录地址优先级:传入 ip 时直接与路径拼接为 "$ip" + "/km/sso/access/doLogin",必须包含完整前缀(协议+域名+端口+上下文,如 http://host:8700/api);不传则使用 NetConfig 的 baseUrl。ip 仅供调试时临时切换服务器
  3. 依赖版本:需 ecp_global ^2.1.0(提供 loginSimple、RuntimeUtils),登录成功会写入全局运行时供后续业务读取

扫码

扫码功能基于 mobile_scanner ^7.4.2(Android CameraX + MLKit;iOS AVFoundation + Vision)。推荐使用 EcpScanManager 做业务码分发:

// 1. 注册业务码回调。key 为二维码内容去掉 query 后的值:scheme://host + path
//    例如二维码内容 https://app.example.com/demo?from=qrcode → key 为 https://app.example.com/demo
EcpScanManager.register("https://app.example.com/demo", (uri) async {
  print("命中业务码,完整内容:$uri");
});

// 2. 打开扫码页
EcpScanManager.scan(context);

只关心原始内容时,可跳过 Manager 直接打开扫码页:

import 'package:ecp_widget/widgets/ecp_scan_page.dart';

var barcode = await forwardPage(context, const EcpScanPage());
print(barcode?.rawValue); /// 原始文本;barcode.displayValue / format 也可用

分发规则:扫码结果按「内容 URI 去掉 query」查找注册回调——

  • 命中 → 执行对应回调
  • 未命中 → 走 EcpScanManager.onErrorHandle;两者都没有时 toast「无法处理当前二维码」并抛出异常

配置注意事项:

  1. Android 权限:插件的 AndroidManifest 已声明 CAMERA 权限与 uses-feature(camera, required=false),manifest merger 会自动并入宿主,无需重复声明(example 中显式声明同样生效)
  2. 包体积:Android 默认使用 bundled 版 MLKit 条码模型,将增加约 3~10 MB 体积;如需瘦身,在宿主 android/gradle.properties 中添加 dev.steenbakker.mobile_scanner.useUnbundled=true(改用 unbundled 版,首次使用经 Google Play Services 下载,仅增约 600 KB,要求设备具备 GMS)
  3. iOS 权限:Info.plist 必须添加 NSCameraUsageDescription 及用途说明文案(example 已配置);当前实现未用相册识别,无需 NSPhotoLibraryUsageDescription,后续若启用 analyzeImage/相册选码再补
  4. 系统版本:插件要求 Android minSdk 23、最低 iOS 12.0;ecp_widget 2.1.0 已同步 minSdk 23 / iOS 部署目标 15.0(Podfile platform + post_install 强制),满足要求
  5. API 导出:EcpScanManager 从 ecp_widget.dart 主入口导出;EcpScanPage 未导出,需直接 import 'package:ecp_widget/widgets/ecp_scan_page.dart'(与 ecp_scaffold 的导出策略一致)
  6. 注册管理:register 对同 key 重复注册为幂等覆盖,页面重复进入无需清理;取消注册用 EcpScanManager().unRegister(key)

AI生成

Libraries

constants/ecp_widget_constants
constants/sp_key
ecp_widget
entities/ecp_opinion_entity
entities/select_wrapper
exts/ecp_widget_string_ext
exts/html/ecp_html
exts/html/ecp_img_ext
exts/html/ecp_table_ext
exts/select_wrapper_list_ext
network/ecp_widget_api
network/ecp_widget_path
pages/login_page
resources/ecp_widget_colors
resources/ecp_widget_style
utils/reg
utils/segments
utils/typed_func
widgets/default_circle_icon
widgets/dialog/ecp_alert_dialog
widgets/dialog/ecp_bottom_multi_picker
widgets/dialog/ecp_bottom_sheet_dialog
@author lzj
widgets/dialog/ecp_bottom_single_picker
widgets/dialog/ecp_center_dialog
widgets/dialog/ecp_comment_dialog
widgets/dialog/ecp_tips_dialog
widgets/dialog/picker_dialog
widgets/ecp_avatar
widgets/ecp_cached_net_image
widgets/ecp_common_btn
widgets/ecp_common_opinion
widgets/ecp_corner_mark
widgets/ecp_date_picker
widgets/ecp_date_range_picker
widgets/ecp_date_time_picker
widgets/ecp_expandable
widgets/ecp_icon
widgets/ecp_nav_bar_view
widgets/ecp_scaffold
widgets/ecp_scan_manager
widgets/ecp_scan_page
widgets/ecp_simple_card
widgets/ecp_simple_form_list_view
widgets/ecp_time_picker
widgets/filters/date_range_filter_item
widgets/filters/ecp_filter_dialog
widgets/filters/ecp_filter_widget
widgets/fitted_check_box
widgets/indexed_tab_scroll_view
widgets/indexed_widget
widgets/items/crumb_item
widgets/items/ecp_picker_tile_item
widgets/items/unit_picker_item
widgets/items/user_picker_item
widgets/pickers/department_user_picker
widgets/pickers/department_user_repo
widgets/pickers/ecp_department_picker
widgets/pickers/ecp_department_user_picker
widgets/pickers/ecp_role_picker
widgets/pickers/ecp_tile_picker
widgets/pickers/ecp_unit_picker
@author lzj
widgets/pickers/ecp_user_picker
widgets/pickers/selected_list
widgets/round_image
widgets/search/search_with_btn
widgets/search/search_with_del