EdonSoft Development Framework

Access 开发框架帮助中心

当前版本v202606.01
更新日期2026-06-19
适用对象用户 / 开发者

快速开始

系统要求

操作系统Windows 7 / 10 / 11
Access 版本2010 / 2013 / 2016 / 2019 / 2021 / Microsoft 365
Office 位数32 位 ↔ 32 位,64 位 ↔ 64 位
后端数据库Access .accdb,专业版支持 SQL Server / MySQL
多用户网络建议稳定局域网共享后端

首次部署

  1. 打开 Access,进入“文件 → 账户 → 关于 Access”,确认 Office 位数。
  2. 下载对应位数版本,避免 32/64 位混用。
  3. 准备前端 .accdb / .accde、后端 Data.accdbassetsTheme 目录。
  4. 首次打开前端时,如出现安全警告,请点击“启用内容”。
  5. 如提示找不到后端数据,请进入链接表设置重新选择 Data.accdb
MyProject\
  MyProject.accdb
  Data.accdb
  assets\
  Theme\
初始账号:admin / admin。首次登录后请立即修改管理员密码。

日常使用

左侧菜单由数据库表驱动,只显示当前用户有权限的功能。
顶部栏系统名称、版本、当前用户、头像、消息、退出。
主工作区用于打开业务窗体、列表、报表或查询。

账号与头像

在登录界面输入用户名密码或按 Enter 登录。修改密码需输入当前密码、新密码并再次确认,两次输入必须一致。

头像默认存放于 assets/images/user/{UserName}.ext。未上传头像时使用 default.jpg

版本更新

v202606.01 2026-06-19 最新 后端连接、链接表管理、数据库升迁、待办提醒与单据选择

新增

  • 新增 后端连接抽象:分别支持 Access、SQL Server、MySQL 的 ADO 与 ODBC 链接字符串生成和连接测试。
  • 新增 链接表管理器:可测试后端连接、读取远程对象并批量重新链接表。
  • 新增 数据库升迁向导:支持将 Access 后端表结构和数据迁移到 SQL Server,并自动处理主键、索引和链接表刷新。
  • 新增 提醒 / 待办中心:业务模块可投递提醒,顶部栏显示未读数量,用户可从提醒跳转到对应业务窗体。
  • 新增 单据选择弹窗:用于从子窗体或业务窗体中选择来源单据并回填数据。

改进

  • 初始化设置支持从 appsettings.json 读取和同步后端配置,兼容旧版本窗体属性保存方式。
  • 后端类型模型扩展为 Access、SQL Server、MySQL,并支持 MySQL 端口和 ODBC 驱动名配置。
  • ADO 通用执行模块可根据当前后端类型生成默认连接字符串,便于业务代码连接 SQL Server 或 MySQL。
  • 主界面顶部栏增加待办未读数刷新,用户关闭待办窗口后可自动更新徽标。

修复

  • 修复重新生成设置窗体后部分数据库属性为空导致初始化异常的问题。
  • 修复链接表切换后端类型时直接刷新链接可能失败的问题,改为必要时使用临时链接表重建本地链接。
  • 修复部分中文配置在跨模块校验时可能不一致的问题。
v202605.01 2026-05-13 历史 代码生成器全面升级、ADO 通用模块、密码哈希

新增

  • 全新升级 代码生成器:支持单表 / 主子表自动生成,可视化勾选按钮、列表字段、编辑字段、必填字段。
  • 代码生成器增加 自动编号 配置:前缀、日期格式、流水位数一次设置完成。
  • 新增 ADO 通用执行模块ADOExecuteSQL / ADOExecuteScalar / ADOOpenRecordset,统一支持 SQL Server。
  • 新增 存储过程执行系列ADOExecuteProcedure / ADOExecuteProcedureScalar / ADOOpenProcedureSnapshot
  • 新增 参数包装函数ADOParams / ADOInputParam / ADOOutputParam
  • 新增 密码安全函数HashPassword / VerifyPassword / NeedsPasswordRehash

改进

  • 统一按钮样式 StyleButton 增加多种 outline 风格。
  • 主界面菜单样式
  • 参数设置增加菜单的字体

修复

  • 数据库配置已知问题
  • 修正主子表代码生成器在非自增主键时按钮事件挂载失败。
  • 修正登录时自动引用edonsoftCore问题
  • 修正第一次登录数据库配置的问题
  • 修正测试版本中已知的一些问题

代码生成

代码生成器用于根据数据表快速生成 F_ 风格业务窗体套件,适合搭建标准的单表或主子表业务模块。

打开代码生成器

在框架主界面进入开发或系统工具相关菜单,打开代码生成器。生成前建议先确认数据表结构、主键字段和命名规则,避免后续重复调整。

支持生成内容

内容 说明
主窗体 业务入口,包含工具栏和列表子窗体
列表窗体 Datasheet 方式展示数据
编辑窗体 新增和编辑记录
主子表窗体 支持主表和明细表组合维护
菜单项 可选,生成后自动写入菜单表

生成流程

  1. 选择主表。
  2. 选择窗体类型:单表或主子表。
  3. 确认主键字段。
  4. 确认模块名和窗体名称。
  5. 选择要生成的按钮。
  6. 选择列表字段、编辑字段和必填字段。
  7. 如需自动编号,填写编号字段、前缀、位数和日期格式。
  8. 如需菜单,勾选创建导航菜单并填写菜单文本。
  9. 点击“创建”。
生成后建议在 Access VBA 编辑器中执行“调试 → 编译”,并手动测试新增、编辑、删除、查询、导出等按钮。

通用查询

通用查询功能用于给业务窗体快速接入统一的查询弹窗,不需要每个窗体都单独设计一套查询区域。

功能说明

通用查询适合列表窗体、主窗体中的子窗体,以及需要在基础 SQL 上动态追加查询条件的业务页面。

列表筛选按关键字、日期、状态等条件快速筛选记录。
子窗体筛选给主窗体中的列表子窗体增加统一查询入口。
复杂 RecordSource在基础 SQL 上追加查询条件和排序。
查询记忆系统可记住上一次实际执行过的查询值。
模块 作用
basCommonQuery 负责拼接查询条件、应用窗体筛选、应用记录源。
basCommonQueryDialog 负责弹出通用查询窗体、解析配置、保存历史条件。

用户看到的效果

通用查询窗体默认标题为“通用查询”,支持最多 8 行条件。

  • 留空的条件会自动忽略。
  • 多个条件默认按 AND 组合。
  • 布尔类型显示为“是 / 否”下拉框。
  • 日期类型按日期格式输入。
  • 系统会自动记住上次实际执行过的查询条件。
  • 查询窗体不存在或版本过旧时,系统可自动重建 USysFrmCommonQuery

直接用于当前窗体或子窗体

函数 用途
CommonQuery_ShowForForm() 对当前窗体直接应用 Filter
CommonQuery_ShowForSubform() 对当前主窗体中的子窗体应用 Filter
CommonQuery_ShowForRecordSourceForm() 基于基础 SQL 重建当前窗体 RecordSource
CommonQuery_ShowForRecordSourceSubform() 基于基础 SQL 重建子窗体 RecordSource

当前窗体筛选示例:

Private Sub btnQuery_Click()
    Dim strConfig As String

    strConfig = Join(Array( _
        "关键字|ANYLIKE|FUserCode,FUserName,FRealName", _
        "状态|BOOLEAN|FEnabled", _
        "开始日期|DATEFROM|FCreateTime", _
        "结束日期|DATETO|FCreateTime" _
    ), vbCrLf)

    Call CommonQuery_ShowForForm(Me, strConfig, "用户查询")
End Sub

子窗体筛选示例:

Private Sub btnQueryDetail_Click()
    Dim strConfig As String

    strConfig = Join(Array( _
        "产品名称|TEXTCONTAINS|FProductName", _
        "最小数量|NUMBERMIN|FQty", _
        "最大数量|NUMBERMAX|FQty" _
    ), vbCrLf)

    Call CommonQuery_ShowForSubform(Me, "sfrDetail", strConfig, "明细查询")
End Sub

基于基础 SQL 重建记录源

如果列表窗体本身是较长 SQL,或需要在基础 SQL 上附加排序和查询条件,建议使用 RecordSource 模式。

Private Sub btnQuery_Click()
    Dim strBaseSql As String
    Dim strConfig As String

    strBaseSql = "SELECT FID, FOrderNo, FCustomerName, FCreateTime FROM TS_SaleOrder"
    strConfig = Join(Array( _
        "单号|TEXTCONTAINS|FOrderNo", _
        "客户|TEXTCONTAINS|FCustomerName", _
        "开始日期|DATEFROM|FCreateTime", _
        "结束日期|DATETO|FCreateTime" _
    ), vbCrLf)

    Call CommonQuery_ShowForRecordSourceForm(Me, strBaseSql, strConfig, "FID DESC", "销售订单查询")
End Sub

查询配置格式

配置字符串按“每行一个条件”编写,行与行之间用换行分隔。

简写格式:

显示名称|字段名

这种写法默认按 TEXTCONTAINS 处理,也就是模糊包含查询。

完整格式:

显示名称|查询模式|字段名|默认值

示例:

关键字|ANYLIKE|FUserCode,FUserName,FRealName
状态|BOOLEAN|FEnabled
开始日期|DATEFROM|FCreateTime
结束日期|DATETO|FCreateTime

支持的查询模式

模式 说明
TEXTCONTAINS文本包含,等价于 LIKE '*值*'
TEXTEQUALS文本精确匹配。
ANYLIKE多字段模糊匹配,字段之间按 OR 组合。
NUMBER数字等于。
NUMBERMIN数字大于等于。
NUMBERMAX数字小于等于。
DATEFROM日期起始。
DATETO日期截止。
BOOLEAN布尔条件,界面显示为“是 / 否”。
ANYLIKE 的字段名可以写成 FCode,FName,FRemark 这种逗号分隔形式;DATETO 内部按“小于次日”处理,适合整天范围查询。

不弹窗时,直接在代码中拼条件

如果不想弹出统一查询窗体,也可以直接使用 basCommonQuery 中的条件函数和应用函数。

Private Sub btnQuickQuery_Click()
    Dim strWhere As String

    strWhere = Query_Join( _
        Query_AnyLike(Array("FUserCode", "FUserName"), Me!txtKeyword), _
        Query_NumberEquals("FDeptID", Me!cboDeptID), _
        Query_DateRange("FCreateTime", Me!txtDateFrom, Me!txtDateTo), _
        Query_BooleanEquals("FEnabled", Me!chkEnabled) _
    )

    Call Query_ApplySubformFilter(Me, "sfrList", strWhere)
End Sub
函数 用途
Query_TextContains()文本包含条件。
Query_AnyLike()多字段模糊匹配。
Query_NumberRange()数字范围。
Query_DateRange()日期范围。
Query_Join()AND 拼接多个条件。
Query_JoinOr()OR 拼接多个条件。
Query_ApplyFilter()对当前窗体应用 Filter
Query_ApplySubformFilter()对子窗体应用 Filter
Query_ApplyRecordSource()重建窗体记录源。
简单列表筛选优先用 CommonQuery_ShowForForm() / CommonQuery_ShowForSubform();基础 SQL 较复杂时优先用 CommonQuery_ShowForRecordSourceForm();需要完全自定义查询界面时再直接使用 Query_* 函数。

后端部署

后端部署用于说明 Access、SQL Server、MySQL 三类后端的适用场景和连接方式。需要专业版的后端能力会在对应功能块末尾单独说明。

Access 后端

Access .accdb 是框架默认后端,适合中小型局域网应用、单机应用和快速交付项目。前端数据库通过链接表访问 Data.accdb 中的数据表。

部署方式前端放在用户本机,后端 Data.accdb 放在共享目录。
路径支持NormalizeBackendPath 可处理相对路径和当前项目目录下的后端文件。
连接字符串BuildAccessAdoConnectionStringBuildAccessTableConnectString 用于生成 ADO / 链接表连接字符串。
适用版本社区版和专业版均支持。

SQL Server 后端

SQL Server 后端适合多人并发、集中备份、统一权限管理和数据量较大的业务系统。框架可生成 SQL Server ADO 连接字符串和 ODBC 链接表连接字符串,供链接表管理器和 ADO 通用执行模块使用。

连接测试TestAdoConnection 可在保存配置前验证服务器、数据库和账号是否可用。
ADO 调用ADOExecuteSQLADOExecuteScalarADOOpenRecordset 可执行 SQL Server 查询和操作语句。
存储过程ADOExecuteProcedureADOExecuteProcedureScalarADOOpenProcedureSnapshot 可调用 SQL Server 存储过程。
适用版本SQL Server 完整后端支持为专业版功能。

MySQL 后端

MySQL 后端适合已有 MySQL 数据库环境、跨系统共享数据或需要使用 MySQL 统一维护数据的项目。框架支持 MySQL 服务器、端口、数据库、用户名、密码和 ODBC 驱动名配置。

驱动要求需要安装 MySQL ODBC 驱动,默认驱动名为 MySQL ODBC 8.0 Unicode Driver
连接字符串BuildMySqlAdoConnectionStringBuildMySqlOdbcConnectString 用于生成 ADO / ODBC 连接字符串。
驱动安装FindMySqlOdbcInstallerInstallMySqlOdbcDriverFromLocalPackage 可用于检测或安装本地驱动包。
适用版本MySQL 后端为专业版专属功能。

链接表管理器

链接表管理器用于维护前端 Access 与后端数据库之间的表链接,适合后端文件迁移、服务器地址变更、远程表重新链接等场景。

功能说明

链接表管理器把连接测试、远程对象读取、本地表名设置和链接创建集中在一个界面中,减少手工维护链接表时的路径错误和连接字符串错误。

Access 后端用于重新选择或修复 Data.accdb 链接。
SQL Server用于读取远程表或视图,并创建 ODBC 链接表。
MySQL用于读取 MySQL 表对象,并通过 MySQL ODBC 驱动创建链接表。
批量处理支持选择单个对象链接,也支持一次链接全部对象。

用户看到的效果

  • 先选择后端类型,再填写后端文件路径或服务器连接信息。
  • 点击“测试连接”后,系统会提示连接是否成功。
  • 点击“读取对象”后,列表显示可链接的数据表或视图。
  • 用户可修改本地链接表名称,再执行单个链接或批量链接。
  • 后端类型切换时,界面会显示对应的服务器、数据库、端口、驱动等字段。

操作流程

  1. 打开链接表管理器。
  2. 选择后端类型:Access、SQL Server 或 MySQL。
  3. 填写后端路径或服务器连接信息。
  4. 点击“测试连接”,确认账号、驱动和网络正常。
  5. 点击“读取对象”,加载可链接的数据表或视图。
  6. 选择对象并确认本地表名。
  7. 点击“链接选中”或“链接全部”。
切换后端类型时,如果直接刷新链接失败,系统会在必要时使用临时链接表重建本地链接。

开发者入口

函数用途
LinkedTableMgr_Open打开链接表管理器。
LinkedTableMgr_ListRemoteObjects读取远程数据库中可链接的表或视图。
LinkedTableMgr_LinkObject按指定连接信息链接单个远程对象。
LinkedTableMgr_IsAvailable判断当前版本是否可使用对应链接能力。
Access 后端链接维护可用于社区版;SQL Server / MySQL 链接表管理为专业版功能。

数据库升迁

数据库升迁向导用于把本地 Access 后端表结构和数据迁移到 SQL Server,适合项目从单机或小型局域网部署升级到企业级数据库部署。

功能说明

升迁向导会扫描 Access 后端表结构,检查字段类型、主键和索引,再把可迁移的数据表创建到目标 SQL Server 数据库中。

结构扫描读取表、字段、主键、普通索引和唯一索引。
类型映射把 Access 字段类型转换为 SQL Server 可用字段类型。
数据迁移按表写入数据,并保留主键和索引。
链接刷新升迁后可把前端链接表切换到 SQL Server 后端。

用户看到的效果

  • 向导界面显示目标服务器、数据库、账号和连接测试按钮。
  • 表列表中显示可升迁的 Access 后端数据表。
  • 检查阶段提示字段类型、主键、索引和不适合自动迁移的字段。
  • 执行阶段显示迁移进度和结果信息。
  • 完成后可重新链接到目标 SQL Server 数据库。

升迁流程

步骤说明
测试连接输入目标服务器、数据库、账号和密码,确认 ADO 连接可用。
扫描表结构读取 Access 后端中的业务表、字段、主键和索引信息。
检查兼容性预览字段类型映射,提前发现附件、多值字段、OLE 等不建议自动迁移的字段。
执行升迁创建远程表、迁移数据、创建主键和索引。
重新链接升迁完成后可将前端链接表切换到新的 SQL Server 后端。

注意事项

  • 正式升迁前请备份前端、后端和目标数据库。
  • 附件字段、多值字段、复杂查阅字段和 OLE 对象不建议自动迁移。
  • 升迁完成后,需要在测试环境验证新增、编辑、删除、查询、导出等关键流程。
  • 开发者入口包括 Upsize_OpenUpsize_CheckTableUpsize_MigrateTableUpsize_BuildConnectionFromForm
数据库升迁向导为专业版专属功能。

提醒与待办

提醒与待办用于把业务消息投递给指定用户或所有用户,并在主界面顶部栏显示未读数量。

功能说明

业务模块可以通过公共 API 投递提醒,提醒中可保存标题、内容、类别、目标用户、优先级、过期时间和跳转参数。

目标用户可投递给指定用户名,也可以留空表示所有用户可见。
优先级支持普通、重要、紧急等优先级。
未读数量顶部栏可显示当前用户未读提醒数量。
业务跳转提醒可保存菜单同款 FArguments,用于打开对应业务窗体。

用户看到的效果

  • 主界面顶部栏显示当前用户未读提醒数量。
  • 点击提醒入口后打开待办列表窗口。
  • 用户可查看提醒标题、内容、类别、优先级和创建时间。
  • 用户可标记单条已读、全部已读或删除提醒。
  • 带跳转参数的提醒可打开对应业务窗体。

公共 API

函数用途
AddReminder投递一条提醒,可设置标题、内容、类别、目标用户、优先级、过期时间和跳转参数。
GetUnreadCount读取当前用户未读数量,供主界面顶部栏徽标显示。
MarkReminderRead标记单条提醒为已读。
MarkAllRead将当前用户可见提醒全部标记为已读。
DeleteReminder删除指定提醒。

跳转参数

Call AddReminder( _
    "销售订单待处理", _
    "订单 SO20260619001 需要确认", _
    "销售", _
    "OpenForm|编辑|F_SaleOrder_Edit|||FID=123|||", _
    "admin", _
    1)
FArguments 与菜单表 TS_Menus.FArguments 使用同一套管道分隔格式,便于从提醒直接跳到业务窗体。

单据选择弹窗

单据选择弹窗用于在主子表业务窗体中,从来源表、查询或 SQL 中选择一行或多行记录,并把选中的字段写入目标明细子窗体。

功能说明

单据选择弹窗适合销售订单选商品、采购入库选采购明细、费用单选项目等场景。业务窗体只需要调用 BillSelect_ShowForSubform,传入来源数据、字段映射和目标明细子窗体控件名,即可完成选择和写入。

来源数据支持表名、查询名或 SELECT SQL。
多选写入列表支持多选,可一次追加多条明细。
字段映射支持 目标字段|来源字段目标字段=来源字段
发布准备运行时直接打开宿主窗体 USysFrmBillSelect

用户看到的效果

  • 弹窗标题默认显示“选择信息”,调用方也可以指定为“选择商品”“选择销售订单”等业务标题。
  • 顶部可选择过滤字段、过滤方式并输入关键字;过滤方式支持“包含”“开头是”“等于”。
  • 列表区域显示调用方指定的字段,未指定时默认显示来源数据前 8 个字段。
  • 用户可勾选多行后点击“确定”;如果没有勾选但当前行已定位,也会写入当前行。
  • 双击当前行等同于确定;点击“取消”关闭弹窗,不写入明细。

调用入口

Call BillSelect_ShowForSubform( _
    Me, _
    "sfrDetail", _
    "SELECT FID, FProductCode, FProductName, FSpec, FUnit FROM TS_Product WHERE FEnabled=True", _
    "FProductID|FID;FProductCode|FProductCode;FProductName|FProductName;FSpec|FSpec;FUnit|FUnit", _
    "FProductCode,FProductName,FSpec,FUnit", _
    "FProductCode,FProductName,FSpec", _
    "选择商品", _
    "FQty", _
    1)
参数说明
frmCaller当前主窗体,通常传 Me
strSubformControlName目标明细子窗体控件名,不是子窗体对象名。
strSource来源表名、查询名或 SELECT SQL。
strFieldMap字段映射,决定来源字段如何写入目标明细字段。
strDisplayFields可选,列表显示字段,逗号分隔。
strSearchFields可选,未指定过滤字段时参与搜索的字段,逗号分隔。
strDialogTitle可选,弹窗标题。
strDefaultQtyField可选,默认数量字段,默认 FQty;传空字符串可关闭默认数量写入。
dblDefaultQty可选,数量字段为空时写入的默认值,默认 1
strTargetAppendSource可选,目标明细记录集不可更新时,指定实际写入表或可更新查询。

字段映射

字段映射支持分号或换行分隔,也兼容 |= 两种写法。左侧是目标明细字段,右侧是来源字段。

FProductID|FID
FProductCode|FProductCode
FProductName|FProductName
FQty||1
  • 第 3 段可作为默认值,例如 FQty||1 表示来源中没有数量时写入 1。
  • 来源字段为空但存在默认值时,会按默认值写入。
  • 默认数量字段会在映射写入后再检查,如果该字段为空,会写入 dblDefaultQty

查询与显示字段

strDisplayFields 控制列表中哪些字段可见;未指定时默认显示来源数据前 8 个字段。列宽会根据字段名自动估算,例如名称字段更宽、规格字段次之。

strSearchFields 控制没有指定过滤字段时参与关键字搜索的字段。弹窗加载后会把可显示字段放入过滤字段下拉框,用户也可以在界面中选择单个字段进行查询。

如果来源是复杂 SQL,关键字查询会在外层包装查询后追加 WHERE 条件;如果来源是表名或查询名,则直接按该对象生成筛选 SQL。

发布与维护

当前版本运行时只检查并打开宿主窗体 USysFrmBillSelect,不会在业务运行过程中自动调用窗体生成器。发布前请确认前端 .accdb.accde 中已经包含该窗体。

BuildBillSelectForm True
  • 开发环境或发布准备阶段,可在 VBA 立即窗口执行上面的命令创建或重建宿主窗体。
  • basBillSelectFormBuilder.bas 只用于创建或重建宿主窗体,不应作为业务运行时依赖。
  • 目标明细子窗体应绑定到可新增记录源;如果不可更新,可在 BillSelect_ShowForSubform 最后一个参数指定实际写入表或可更新查询。
单据选择弹窗为专业版专属功能。

函数与接口

编号与数值

AutoNumStr按规则生成下一个编号

语法:AutoNumStr(TableName, FieldName, Digit, [Prefixal], [DateFormat])

返回:编号字符串,例如 SO202605120001

Me.txtOrderNo = AutoNumStr("TS_SaleOrder", "FOrderNo", 4, "SO", "yyyymmdd")

按"当前最大值 + 1"生成,非严格并发安全,高并发场景需要额外防重。

RoundDown向下取值

语法:RoundDown(Number, [NumDigitsAfterDecimal = 0])

Debug.Print RoundDown(12.987, 2)  ' 12.98
RoundUp向上取值

语法:RoundUp(Number, [NumDigitsAfterDecimal = 0])

Debug.Print RoundUp(12.011, 2)  ' 12.02
RoundOff四舍五入

语法:RoundOff(Number, [NumDigitsAfterDecimal = 0])

Debug.Print RoundOff(12.555, 2)  ' 12.56

SQL 与数据读取

SQLText构造安全 SQL 字符串字面量

语法:SQLText(Expression)

返回:带单引号的 SQL 文本;空值返回 Null

strSQL = "SELECT * FROM TS_Users WHERE FUserName=" & SQLText(Me.txtUserName)
SQLDate构造 Access SQL 日期字面量

语法:SQLDate(Expression)

返回:#2026-05-12# 形式;空值返回 Null

strSQL = "SELECT * FROM TS_Log WHERE FLogDate>=" & SQLDate(Me.txtDateFrom)
DoRunSQL执行操作型 SQL

语法:DoRunSQL(SQLStatement)

Call DoRunSQL("UPDATE TS_Users SET FIsEnabled=0 WHERE FID=" & Nz(Me.FID, 0))

内部会临时关闭系统警告,不负责事务控制。

AdoScalar读取第一行第一列

语法:AdoScalar(strSQL, [varDefault])

lngCount = Nz(AdoScalar("SELECT Count(*) FROM TS_Users", 0), 0)
AdoExists判断查询是否有记录

语法:AdoExists(strSQL)

If AdoExists("SELECT 1 FROM TS_Users WHERE FUserName=" & SQLText(Me.txtUserName)) Then ...
AdoOpenSnapshot打开只读快照记录集

语法:AdoOpenSnapshot(strSQL)

Set rst = AdoOpenSnapshot("SELECT FUserName FROM TS_Users")
Do Until rst.EOF
    Debug.Print rst!FUserName
    rst.MoveNext
Loop
rst.Close : Set rst = Nothing
ADOExecuteSQLADODB 执行操作型 SQL

语法:ADOExecuteSQL(sql, [UseTransaction=True], [UseProjectConnection=True], [ConnectionString], [CommandTimeout=30])

返回:受影响记录数。

lngRows = ADOExecuteSQL("UPDATE TS_Users SET FOnline=0 WHERE FID=1")

适合连接 SQL Server 或需要超时控制的场景。

ADOExecuteScalarADODB 读取单个值

语法:ADOExecuteScalar(sql, [varDefault], [UseProjectConnection=True], [ConnectionString], [CommandTimeout=30])

lngCount = Nz(ADOExecuteScalar("SELECT Count(*) FROM TS_Users", 0), 0)
ADOOpenRecordsetADODB 打开断开式记录集

语法:ADOOpenRecordset(sql, [UseProjectConnection=True], [ConnectionString], [CommandTimeout=30])

Set rst = ADOOpenRecordset("SELECT FID, FUserName FROM TS_Users ORDER BY FID")
ADOExecuteProcedure执行 SQL Server 存储过程

语法:ADOExecuteProcedure(ProcedureName, [Parameters], [UseTransaction=True], [UseProjectConnection=False], [ConnectionString], [CommandTimeout=30])

Call ADOExecuteProcedure("usp_UpdateUser", ADOParams( _
    ADOInputParam("@UserID", adInteger, 1), _
    ADOInputParam("@UserName", adVarChar, "张三", 50) _
))
ADOExecuteProcedureScalar执行存储过程并取单个值

语法:ADOExecuteProcedureScalar(ProcedureName, [Parameters], [varDefault], ...)

lngCount = ADOExecuteProcedureScalar("usp_GetUserCount", ADOParams(ADOInputParam("@UserGroupID", adInteger, 1)), 0)
ADOOpenProcedureSnapshot执行存储过程并返回记录集

语法:ADOOpenProcedureSnapshot(ProcedureName, [Parameters], ...)

Set rst = ADOOpenProcedureSnapshot("usp_GetUsers", ADOParams(ADOInputParam("@UserGroupID", adInteger, 1)))
ADOParams包装多个 ADO 参数

语法:ADOParams(ParamArray Parameters())

无参数存储过程不需要写 ADOParams()

ADOInputParam创建输入参数

语法:ADOInputParam(Name, DataType, Value, [Size=0])

ADOInputParam "@UserName", adVarChar, "张三", 50
ADOOutputParam创建输出参数

语法:ADOOutputParam(Name, DataType, [Size=0])

ADOOutputParam "@NewID", adInteger
DMerge把查询结果某字段拼接成字符串

语法:DMerge(Exps, Domain, [Criteria], [Separator=";"])

strRoles = DMerge("FRoleName", "TS_UserRole", "FUserID=" & Nz(Me.FUserID, 0), ",")

表单与记录

CheckRequired检查必填控件

语法:CheckRequired(DataForm, [RequiredMark="<Required>"])

If Not CheckRequired(Me) Then Exit Sub

把必填控件的 Tag 属性设为 <Required>

ReadRecord把记录集当前行读取到窗体控件

语法:ReadRecord(DataForm, rst, [ReadMark="<Read>"])

Set rst = CurrentDb.OpenRecordset("SELECT * FROM TS_Users WHERE FID=" & Nz(Me.FID, 0), dbOpenSnapshot)
If Not rst.EOF Then
    Call ReadRecord(Me, rst)
End If

把需要从记录集读取的控件 Tag 设为 <Read>

WriteRecord把窗体控件值写入记录集当前行

语法:WriteRecord(DataForm, rst, [WriteMark="<Write>"])

Set rst = CurrentDb.OpenRecordset("TS_Users", dbOpenDynaset)
rst.AddNew
Call WriteRecord(Me, rst)
rst.Update

把需要写入记录集的控件 Tag 设为 <Write>

ClearInput清空带标记的输入控件

语法:ClearInput(DataForm, [WriteMark="<Clear>"])

Call ClearInput(Me)
Call ClearInput(Me, "<Write>")

默认清空 Tag 包含 <Clear> 的控件,也可传 <Write> 复用可写字段标记。

DeleteRecord删除当前记录

语法:DeleteRecord(DataForm, SQLArray)

Call DeleteRecord(Me, "DELETE FROM TS_Customer WHERE FID=" & Nz(Me.FID, 0))
RequerySnapshot刷新快照窗体并保留定位

语法:RequerySnapshot(DataForm, [FindWhereCondition])

Call RequerySnapshot(Me, "FID=" & Nz(Me.FID, 0))
AuditData写入审核人、审核时间和审核状态

语法:AuditData(sTable, sUser, lngID, sStatus)

strUser = Nz(AdoScalar("SELECT FValues FROM TS_ParametersLocal WHERE FItem='UserName'", ""), "")
If AuditData("TS_SaleOrder", strUser, Nz(Me.FID, 0), "已审核") Then
    ShowMsg "审核完成", vbInformation, "提示"
End If

目标表需要存在 AuditorAuditTimeAuditStatusid 等字段。

UpdateCreatorModifier回写创建人、修改人和修改时间

语法:UpdateCreatorModifier(strTable, strUser, clngID, IsEdit)

strUser = Nz(AdoScalar("SELECT FValues FROM TS_ParametersLocal WHERE FItem='UserName'", ""), "")
Call UpdateCreatorModifier("TS_Customer", strUser, Nz(Me.FID, 0), True)

IsEdit=True 时会写 FCreatorFModifierFModifyTimeFalse 时只写创建人。

ChildFormClose按菜单配置关闭子窗体

语法:ChildFormClose(strMode, strFrm)

Private Sub btnClose_Click()
    Call ChildFormClose("客户管理", Me)
End Sub

strMode 传的是菜单文本,不是窗体名。找不到菜单配置时会直接关闭当前窗体。

WriteLog向日志表追加操作日志

语法:WriteLog(sModuleCode, sDes, sUser)

strUser = Nz(AdoScalar("SELECT FValues FROM TS_ParametersLocal WHERE FItem='UserCode'", ""), "")
Call WriteLog("F_Customer", "新增客户:" & Nz(Me.txtCustomerName, ""), strUser)

函数会直接向 Ts_Log 表写入 FModuleCodeFLogDesFUserCode 字段。

SwitchRecord用上下方向键切换记录

语法:SwitchRecord(KeyCode, Shift)

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
    Call SwitchRecord(KeyCode, Shift)
End Sub

日期 / 对象 / 设置

FirstOfMonth取月初日期
Me.txtDateFrom = FirstOfMonth(Date)
LastOfMonth取月末日期
Me.txtDateTo = LastOfMonth(Date)
FirstOfWeek取本周第一天
Me.txtWeekFrom = FirstOfWeek(Date, vbMonday)
LastOfWeek取本周最后一天
Me.txtWeekTo = LastOfWeek(Date, vbMonday)
ObjectIsExists判断对象是否存在

语法:ObjectIsExists(ObjectType, ObjectName)

If ObjectIsExists(acForm, "F_Customer") Then DoCmd.OpenForm "F_Customer"
ObjectIsLoaded判断窗体或报表是否已打开
If ObjectIsLoaded(acForm, "USysFrmLogin") Then Forms("USysFrmLogin").Visible = True
SaveDbSetting保存数据库属性

语法:SaveDbSetting([DatabaseName], [PropertyName], DataType, Value)

Call SaveDbSetting("", "SoftwareName", DB_TEXT, "报价管理系统")
GetDbSetting读取数据库属性

语法:GetDbSetting(SettingName, DefaultValue)

Debug.Print GetDbSetting("SoftwareName", "未设置")
LoadString读取多语言字符串

语法:LoadString(Key, [FindText], [ReplaceText])

ShowMsg LoadString("MsgNoPermission"), vbExclamation, LoadString("MsgTitle_Notes")

导出 / 文件 / 系统

ExportToExcel导出数据到 Excel

语法:ExportToExcel(WorkbookName, [SheetName], [FirstRange="A1"])

Call ExportToExcel("销售订单列表", "订单")
GetSaveAsFileName弹出另存为对话框
strFile = GetSaveAsFileName("销售订单.xlsx")
GetLocalIPAddress获取本机 IP 地址
Debug.Print GetLocalIPAddress()
ShellExecute打开文件 / 目录 / 网址
Call ShellExecute("https://www.edonsoft.com")
Call ShellExecute(CurrentProject.Path & "\帮助文档.pdf")
PS_Zip压缩文件或文件夹

语法:PS_Zip(sSrc, sDest, [sCompressionLvl="Optimal"])

Call PS_Zip("C:\Temp\MonthlyStats.xlsx", "C:\Temp\MonthlyStats.zip")
PS_UnZip解压 ZIP 文件
Call PS_UnZip("C:\Temp\MonthlyStats.zip", "C:\Temp\Export")

UI 与交互

ShowMsg统一消息提示框

语法:ShowMsg(Prompt, [Buttons=vbOKOnly], [Title], [lngSeconds])

If ShowMsg("确认删除当前记录?", vbExclamation + vbYesNo + vbDefaultButton2, "删除确认") = vbYes Then ...

支持倒计时自动关闭与字符串表。

StyleButton统一按钮样式

语法:StyleButton(btn, sStyle)

样式名:primary / secondary / add / delete / warning / info / light / dark / outline-primary / outline-secondary / outline-success / outline-danger / outline-warning / outline-info / outline-dark

StyleButton Me.btnSave, "primary"
StyleButton Me.btnDelete, "delete"
StyleButton Me.btnClose, "outline-secondary"
BillSelect_ShowForSubform选择来源数据并追加到明细子窗体

语法:BillSelect_ShowForSubform(frmCaller, strSubformControlName, strSource, strFieldMap, [strDisplayFields], [strSearchFields], [strDialogTitle], [strDefaultQtyField], [dblDefaultQty], [strTargetAppendSource])

返回:成功写入明细时返回 True;取消或未写入时返回 False

If BillSelect_ShowForSubform(Me, "sfrDetail", "TS_Product", "FProductID|FID", "FProductCode,FProductName", "FProductCode,FProductName", "选择商品") Then
    ShowMsg "明细已添加", vbInformation, "提示"
End If

运行时必须已存在宿主窗体 USysFrmBillSelect。开发或发布准备阶段可执行 BuildBillSelectForm True 创建或重建。

GetUserAvatarPath获取当前用户头像路径
Me.imgAvatar.Picture = GetUserAvatarPath()
ChangeUserAvatar更换当前用户头像
If ChangeUserAvatar() Then Me.imgAvatar.Picture = GetUserAvatarPath()

安全与权限

HashPassword生成密码哈希

语法:HashPassword(PlainText, [Salt=""])

strHash = HashPassword(Me.txtPassword)
VerifyPassword校验密码

语法:VerifyPassword(PlainText, StoredHash)

If VerifyPassword(Me.txtPassword, strStoredHash) Then ...
NeedsPasswordRehash判断旧密码是否需要升级哈希
If NeedsPasswordRehash(strStoredHash) Then strStoredHash = HashPassword(Me.txtPassword)
GetPermissions读取当前模块权限集合

语法:GetPermissions(Module, CltPermissions)

Dim cltPermissions As New Collection
If Not GetPermissions("F_Customer", cltPermissions) Then Exit Sub
If cltPermissions("Open/Run") Then DoCmd.OpenForm "F_Customer"
LogOff关闭业务窗体并返回登录界面
Call LogOff

常见问题

打开程序后提示找不到链接表怎么办?

通常是后端 Data.accdb 路径改变。请在登录界面进入链接表设置,重新选择后端文件。

切换 SQL Server 或 MySQL 后端后链接表刷新失败怎么办?

请先在链接表管理器中测试连接,再执行批量重新链接。SQL Server / MySQL 链接表管理属于专业版功能,请确认当前版本已开通专业版。

登录失败怎么办?

先确认用户名和密码,再检查后端链接。如果后端链接失败,登录也会失败。

权限 / 菜单

为什么某个用户看不到菜单?

该用户所属角色没有对应菜单的"查看"权限。请管理员检查角色权限和菜单权限绑定。

权限改了为什么没有立即生效?

建议用户退出并重新登录。权限缓存和菜单显示通常在登录或主界面加载时刷新。

为什么点击某些功能会提示需要专业版?

MySQL 后端、数据库升迁向导、SQL Server / MySQL 完整链接管理、单据选择弹窗等功能为专业版专属。请确认当前版本已开通专业版后再使用。

点击选单按钮提示通用单据选择窗体不存在怎么办?

请确认前端中已经包含 USysFrmBillSelect。开发环境可在 VBA 立即窗口执行 BuildBillSelectForm True 重建该窗体,确认编译通过后再重新发布前端。

选单确定后没有写入明细怎么办?

先检查字段映射中的目标字段和来源字段是否拼写正确,再确认目标明细子窗体记录源是否可新增。如果子窗体基于复杂查询导致记录集不可更新,可在 BillSelect_ShowForSubform 最后一个参数指定实际写入表或可更新查询。

环境 / 资源

32 位和 64 位版本有什么区别?

功能一致,仅适配不同位数的 Office。32 位 Office 必须使用 32 位版本,64 位 Office 必须使用 64 位版本。

菜单图标不显示怎么办?

检查 assets/Theme/font-awesome.css 和字体文件是否存在,资源路径应相对数据库目录可访问。

主题或菜单字体大小保存后没变化?

确认系统设置保存成功。如果仍未变化,请关闭主界面重新登录。

开发相关

代码生成器生成的窗体打不开怎么办?

在 VBA 编辑器中执行"调试 → 编译",根据编译错误定位字段名、主键字段或窗体名冲突等问题。

进度条显示后程序像卡住了怎么办?

在长循环中加入 DoEvents,并确保任务结束后调用进度条对象的 Close 方法。