动态表单字段¶
动态表单字段是 OBPM 表单系统的核心构成单元。一个字段在后端(Java)与前端(PC,Vue 3)各有实现,二者通过**表单模板 JSON** 协同:
- 后端定义字段的存储类型、脚本钩子、权限模型,并输出包含
<o-xxx>标签的表单模板 HTML; - 前端将
<o-xxx>标签渲染为可交互控件,绑定字段值、处理刷新与校验。
本文档分为两部分:后端实现(Java) 与 前端实现(PC)。
后端实现(Java)¶
描述动态表单中的各种字段类型,包含 InputField、SelectField、CheckboxField 等。所有字段位于 obpm-core/src/main/java/cn/myapps/core/runtime/dynaform/form/ejb/,继承自 FormElement。
平台共提供 39 个可实例化字段类,按功能分为:文本、选项、日期/编号、上传、用户/组织、布局/容器、业务集成、多媒体/特殊。
核心机制¶
类继承层次¶
FormElement(接口)
└── FormField(抽象基类,提供公共属性/脚本/权限)
├── ValueStoreField(标记接口)
│ ├── 文本/选项/日期/编号/上传等(存值 → TLK_ 表 ITEM_ 列)
│ └── AbstractUploadField(上传抽象基类)
│ ├── AttachmentUploadField / ImageUploadField / KmsDataField
│ └── ...
└── 纯 UI 字段(不存值)
├── TabField / SplitField / ButtonField / ...
└── ...
ValueStoreField:存值的分水岭¶
实现 ValueStoreField 的字段会持久化值到 TLK_<表单名> 表的 ITEM_<字段名> 列;不实现的就是纯 UI、布局、动作或展示字段。
FormField.shouldStoreValue() 的判定:this instanceof ValueStoreField && !onlyCalculate。
getTagName() 与 HTML 标签¶
getTagName() 默认实现返回类简单名(ObjectUtil.getSimpleName(getClass())):
只有 3 个字段重写了它:
- InputField / NoField —— 当 fieldtype=VALUE_TYPE_NUMBER 时返回 "NumberField"
- TextareaField —— 固定返回 "TextAreaField"(注意 A 大写,类名是 TextareaField)
注意:getTagName()(前端 _fieldType 用)和 toHtmlTemplate() 输出的 <o-xxx> 标签是**两套独立命名**,例如 DateField.getTagName() 返回 DateField,但 HTML 是 <o-date-picker>。
值类型(fieldtype)¶
字段的存储类型由 fieldtype 属性决定,影响动态表列的数据类型。常见取值(定义在 Item 接口):
| 常量 | 说明 | 典型字段 |
|---|---|---|
VALUE_TYPE_VARCHAR |
字符串 | InputField、SelectField、UserField |
VALUE_TYPE_NUMBER |
数值 | InputField(数字模式)、NoField(数字模式) |
VALUE_TYPE_DATE |
日期 | DateField |
VALUE_TYPE_TEXT |
长文本 | TextareaField、HTMLEditorField、附件 JSON |
VALUE_TYPE_BLOB |
二进制 | AttachmentUploadToDataBaseField(已废弃) |
VALUE_TYPE_INCLUDE |
包含视图标记 | IncludeField(不存值) |
FormField 公共属性¶
所有字段共享以下属性,子类只在此基础上添加特有配置:
标识类¶
| 属性 | 类型 | 说明 |
|---|---|---|
id |
String | 字段唯一标识(UUID) |
name |
String | 字段名(决定 TLK_ 表的列名:ITEM_ + name 大写) |
alias |
String | 字段别名 |
discript |
String | 描述说明 |
orderno |
int | 排序号 |
seq |
int | 次序号 |
formid |
String | 所属表单 ID |
attributeId |
String | 属性 ID |
类型类¶
| 属性 | 类型 | 说明 |
|---|---|---|
fieldtype |
String | 字段值类型(VALUE_TYPE_VARCHAR/NUMBER/DATE/TEXT/BLOB/INCLUDE),决定动态表列的数据类型 |
textType |
String | 文本框展现类型:text(普通)/ password(密码)/ readonly(只读)/ hidden(隐藏) |
type |
String | 字段控件类型标记 |
脚本钩子¶
均通过 GraalVM JavaScript 引擎执行。脚本中可用 $CURRDOC(当前文档)、$WEBUSER(当前用户)等内置变量。
| 属性 | 返回值 | 执行时机 | 用途 |
|---|---|---|---|
valueScript |
任意值(String/Number/Date 等) | 表单加载、字段刷新(recalculate)、保存前 |
值计算脚本。计算结果通过 applyValueScriptResult 写入文档 Item,决定字段显示值。支持两种模式:脚本模式直接执行 valueScript;设计模式(editMode=1)按 processDescription 拼接算术表达式 |
hiddenScript |
boolean | 渲染时(getDisplayType,第一优先级) |
隐藏脚本。返回 true 时字段完全隐藏(PermissionType.HIDDEN)。优先级最高,隐藏后字段不可见也不可编辑 |
readonlyScript |
boolean | 渲染时(getDisplayType,第三优先级) |
只读脚本。返回 true 时字段只读(PermissionType.READONLY)。在隐藏、禁用判断之后执行 |
hiddenPrintScript |
boolean | 打印时(getPrintDisplayType) |
打印隐藏脚本。返回 true 时打印不显示该字段,并将 printValue 标记为 HIDDENPRINTVALUE |
validateRule |
String(非空表示失败) | 表单提交前校验 | 校验脚本。返回非空字符串视为校验失败,字符串内容作为错误提示展示给用户;返回空或 null 表示通过 |
validateLibs |
String | 校验时 | 校验依赖库(引入的公共校验函数库) |
hiddenValue |
String | 字段被隐藏时 | 当字段因 hiddenScript 或 textType=hidden 隐藏时,显示此静态值(HTML 解码后) |
printHiddenValue |
String | 打印隐藏时 | 打印时字段被隐藏,显示此替代值 |
显示类型优先级(
getDisplayType方法):HIDDEN(最高)→ DISABLED(文档不可编辑时)→ READONLY → MODIFY(可编辑)。 ButtonField 是唯一豁免 DISABLED 的字段——按钮不受文档编辑状态限制。
行为类¶
| 属性 | 类型 | 说明 |
|---|---|---|
refreshOnChanged |
boolean | 字段值变更时是否触发其它字段刷新 |
calculateOnRefresh |
boolean | 被其它字段刷新时是否重新计算本字段 |
onlyCalculate |
boolean | 仅用于计算(shouldStoreValue 会排除,不落库到 TLK_ 表) |
instantValidate |
boolean | 是否即时校验(输入时即触发,不等提交) |
refreshMode |
int | 刷新模式 |
refreshFields |
String | 本字段变更时需要联动刷新的字段列表 |
editMode |
String | 值脚本编辑模式:0=脚本模式(直接执行 valueScript)/ 1=设计模式(按 processDescription 拼接算术表达式) |
filtercondition |
String | 设计模式下的过滤条件 |
processDescription |
String | 设计模式下的计算过程描述(格式 "[];[]",分号分隔两段:参数列表和运算表达式) |
布局类¶
| 属性 | 类型 | 说明 |
|---|---|---|
width |
String | 字段宽度 |
widthunit |
String | 宽度单位(px/%) |
fieldWidth |
String | 输入框宽度 |
showWidth |
String | 显示宽度 |
layout |
String | 布局方式 |
layoutType |
String | 布局类型 |
mobile |
boolean | 是否在移动端显示 |
borderType |
String | 边框类型 |
权限类¶
| 属性 | 类型 | 说明 |
|---|---|---|
authority |
String | 字段权限配置 |
hideType |
String | 隐藏类型 |
isHideType |
boolean | 是否启用隐藏类型 |
其它¶
| 属性 | 类型 | 说明 |
|---|---|---|
showLog |
boolean | 是否记录字段变更日志(影响 LOG_ 表生成) |
secretText |
String | 密级文本 |
readOnlyShowValOnly |
boolean | 只读时仅显示值(不显示标签) |
文本类字段¶
InputField(单行文本框)¶
- Tag Name:
InputField(数字模式为NumberField) - 存值: 是(
VALUE_TYPE_VARCHAR/VALUE_TYPE_NUMBER) - HTML 标签:
<o-input> - 用途: 单行文本输入,支持普通文本、数字、密码等模式
- 特有属性:
textType- 文本类型(text/number/password/readonly/hidden)numberPattern- 数字显示模式(默认##.#######)fieldkeyevent- 键盘事件(EnterKey/TabKey)dialogView- 弹出对话视图suggest/popToChoice- 联想 / 弹出选择defaultValueIsNull- 数字默认值是否为空
TextareaField(多行文本框)¶
- Tag Name:
TextAreaField(注意 A 大写) - 存值: 是(
VALUE_TYPE_TEXT) - HTML 标签:
<o-textarea> - 特有属性:
textareaHeight(多行框高度)
HTMLEditorField(富文本编辑器)¶
- Tag Name:
HTMLEditorField - 存值: 是(强制
VALUE_TYPE_TEXT) - HTML 标签:
<o-html> - 特有属性:
areaWidth(默认 600px)、areaHeight(默认 200px)
CalctextField(计算文本)¶
- Tag Name:
CalctextField - 存值: 否(纯展示)
- HTML 标签:
<o-calctext> - 用途: 通过
valueScript实时计算显示,不创建数据库字段
CustomField(自定义控件)¶
- Tag Name:
CustomField - 存值: 是(由
fieldtype决定) - HTML 标签:
<o-custom> - 特有属性:
htmlScript(HTML 模板)、initScript、clickScript、changeScript
选项类字段(IOptionsField)¶
均实现 IOptionsField 接口,共享选项配置:optionsScript、optionsEditMode(00 设计/01 脚本)、dialogView、optionsValue、optionsText。
SelectField(下拉选择框)¶
- Tag Name:
SelectField - 存值: 是(
VALUE_TYPE_VARCHAR) - HTML 标签:
<o-select> - 特有属性:
multiSelect(是否多选)
CheckboxField(复选框)¶
- Tag Name:
CheckboxField - 存值: 是(
VALUE_TYPE_VARCHAR,多值以;分隔) - HTML 标签:
<o-checkbox> - 特有属性:
newlineCount(换行个数,默认 3)
RadioField(单选框)¶
- Tag Name:
RadioField - 存值: 是(
VALUE_TYPE_VARCHAR) - HTML 标签:
<o-radio> - 特有属性:
showFieldTitle(是否显示字段标题)
SuggestField(智能选择/自动补全)¶
- Tag Name:
SuggestField - 存值: 是(
VALUE_TYPE_VARCHAR) - HTML 标签:
<o-suggest> - 特有属性:
dataMode(local/remote,查询数据方式)
SelectAboutField(联动选择框)¶
- Tag Name:
SelectAboutField - 存值: 是(
VALUE_TYPE_VARCHAR) - HTML 标签:
<o-select-about> - 用途: 基于其它字段值过滤选项的联动选择
日期/编号字段¶
DateField(日期)¶
- Tag Name:
DateField - 存值: 是(
VALUE_TYPE_DATE) - HTML 标签:
<o-date-picker> - 特有属性:
datePattern- 日期模式(Y/YM/YMD/YMD_HMS/YMD_HM/HMS)prev_Name- 前一个日期字段名(用于区间校验)
NoField(自动编号)¶
- Tag Name:
NoField(数字模式为NumberField) - 存值: 是(
VALUE_TYPE_VARCHAR/VALUE_TYPE_NUMBER) - HTML 标签:
<o-no> - 用途: 自动生成流水号(带前缀,可含年月日)
- 特有属性:
headText(前缀)、isYear/isMonth/isDay、digit(位数)
上传类字段(继承 AbstractUploadField)¶
均通过 AbstractUploadField 间接存值,存为 VALUE_TYPE_TEXT(JSON 字符串存储文件列表)。
AbstractUploadField 公共属性:
- 大小/数量限制:limitsize、limitType、limitNumber
- 类型限制:fileType(00 全部/01 自定义)、customizeType
- 保存路径:fileCatalog、filePattern
- 水印:openWaterMark、waterMarkSupportMode、waterMarkScript
- 在线编辑:previewEdit、showTrackRevisions、selectEditPlug、previewType
- 操作脚本开关:editScript、previewScript、renameScript、deleteScript、downloadScript、versionCompareScript、newVersionScript、restoreScript
AttachmentUploadField(附件上传)¶
- Tag Name:
AttachmentUploadField - HTML 标签:
<o-file-upload> - 特有属性: 继承全部,
imgh/imgw
ImageUploadField(图片上传)¶
- Tag Name:
ImageUploadField - HTML 标签:
<o-image-upload> - 特有属性:
imgh/imgw(图片高/宽)
KmsDataField(KMS 知识库附件)¶
- Tag Name:
KmsDataField - HTML 标签:
<o-file-kms> - 用途: 关联知识管理系统(KMS)文件
GenericWordField(Word 文档在线编辑)¶
- Tag Name:
GenericWordField - 存值: 是(
VALUE_TYPE_TEXT,文件路径) - HTML 标签:
<o-word> - 特有属性:
openType、selectEditPlug(默认 tray)、showTrackRevisions
WordField.java不存在,已被GenericWordField取代。
已废弃¶
- AttachmentUploadToDataBaseField - 文件直接入库(
@Deprecated) - FileManagerField - 文件管理器(
@Deprecated)
用户/组织类字段(IOptionsField)¶
UserField(用户选择)¶
- Tag Name:
UserField - 存值: 是(
VALUE_TYPE_VARCHAR,用户 ID,多值;分隔) - HTML 标签:
<o-user-select> - 特有属性:
filterField(过滤条件)、limitByUser、limitSum(限制数量)、selectMode
DepartmentField(部门选择)¶
- Tag Name:
DepartmentField - 存值: 是(
VALUE_TYPE_VARCHAR,部门 ID) - HTML 标签:
<o-dept-select> - 特有属性:
defaultOptionType- 默认选项类型(如 16=首选项,256=用户所在部门)relatedField- 级联的上级部门 Field IDallowEmpty
TreeDepartmentField(树形部门选择)¶
- Tag Name:
TreeDepartmentField - 存值: 是(
VALUE_TYPE_VARCHAR) - HTML 标签:
<o-dept-tree-select> - 特有属性:
limit(限制选择数量)
布局/容器类字段(不存值)¶
TabField(页签)¶
- Tag Name:
TabField - 存值: 否
- HTML 标签:
<o-tab> - 特有属性:
relStr、showMode、openAll、tabname、selectedScript、tabselwidth、tabselheight、tabs
SplitField(分栏/分割)¶
- Tag Name:
SplitField - 存值: 否
- HTML 标签:
<o-split> - 特有属性:
titleScript(标题脚本)、height
IncludeField(包含视图)¶
- Tag Name:
IncludeField - 存值: 否
- HTML 标签:
<o-include> - 用途: 在表单中嵌入其它视图(父子表/子视图)
- 特有属性:
includeType- 包含类型(INCLUDE_TYPE_VIEW="0")viewId- 嵌入的视图 IDrelate- 是否父子关联fixation、mobileDisplayMode(默认 tile)
ButtonField(按钮)¶
- Tag Name:
ButtonField - 存值: 否
- HTML 标签:
<o-button> - 用途: 表单操作按钮(保存/提交/流程/打印等)
- 特有属性:
actType(动作类型)、actionView、actionForm、actionFlow、actionPrint、colorType、label - 特殊: 在
getDisplayType()中有豁免,按钮不受doc.isEditAble()自动 DISABLED 限制
ViewDialogField(视图对话框)¶
- Tag Name:
ViewDialogField - 存值: 否
- HTML 标签:
<o-view-dialog> - 用途: 弹出视图选择(常与 InputField 配合做选择回填)
- 特有属性:
openType、dialogView、okScript、callbackScript、mapping、eventMapping、mutilSelect
业务集成类字段¶
FlowHistoryField(流程历史)¶
- Tag Name:
FlowHistoryField - 存值: 否
- HTML 标签:
<o-flow-history> - 特有属性:
showMode(text / diagram / textAndDiagram)
FlowReminderHistoryField(催办历史)¶
- Tag Name:
FlowReminderHistoryField - 存值: 否
- HTML 标签:
<o-reminder-history>
CommentField(评论)¶
- Tag Name:
CommentField - 存值: 否
- HTML 标签:
<o-comment> - 特有属性:
title(评论标题)
SurveyField(调查/问卷)¶
- Tag Name:
SurveyField - 存值: 是(
VALUE_TYPE_TEXT,问卷结果 JSON) - HTML 标签:
<o-survey> - 特有属性:
questionScript
ReminderField(提醒/催办)¶
- Tag Name:
ReminderField - 存值: 是(
VALUE_TYPE_VARCHAR) - 特有属性:
reminderid
多媒体/特殊类字段¶
MapField(地图)¶
- Tag Name:
MapField - 存值: 是(
VALUE_TYPE_TEXT,GeoJSON) - HTML 标签:
<o-map> - 特有属性:
openType- 打开地图类型valueType- 数据存储类型:Point/LineString/Bounds/Polygon(字段内自有 valueType,非 Item 值类型)defaultCenterAddress- 默认中心地址level- 默认缩放级别(1–18)
WeixinGpsField(微信 GPS 定位)¶
- Tag Name:
WeixinGpsField - 存值: 是(
VALUE_TYPE_VARCHAR) - HTML 标签:
<o-gps>
WeixinRecordField(微信录音)¶
- Tag Name:
WeixinRecordField - 存值: 是(
VALUE_TYPE_VARCHAR) - HTML 标签:
<o-record>
OnLineTakePhotoField(在线拍照)¶
- Tag Name:
OnLineTakePhotoField - 存值: 是(
VALUE_TYPE_TEXT) - 特有属性:
imgh、imgw、cameraPixelType(0=160×120 / 1=400×300 / 2=800×600)、album
QRCodeField(二维码)¶
- Tag Name:
QRCodeField - 存值: 否
- HTML 标签:
<o-qrcode> - 特有属性:
handleType(text/link/callback_event)、size(默认 200)、codeType(默认 qr_code)、callbackScript
ScancodeField(扫码)¶
- Tag Name:
ScancodeField - 存值: 否
- HTML 标签:
<o-scancode> - 特有属性:
mapping(扫码结果映射的目标字段)
HandwritingField(手写签名 - 已废弃)¶
- Tag Name:
HandwritingField - 存值: 否(
@Deprecated)
NullField(空组件)¶
- Tag Name:
NullField - 存值: 否
- 用途: 空占位组件,name 以
$开头时读取 Document 属性,或显示静态值
字段速查总表¶
| 字段类 | 中文名 | 存值 | HTML 标签 | 值类型 |
|---|---|---|---|---|
| InputField | 单行文本框 | ✓ | <o-input> |
VARCHAR/NUMBER |
| TextareaField | 多行文本框 | ✓ | <o-textarea> |
TEXT |
| HTMLEditorField | 富文本 | ✓ | <o-html> |
TEXT |
| CalctextField | 计算文本 | ✗ | <o-calctext> |
- |
| CustomField | 自定义控件 | ✓ | <o-custom> |
可变 |
| SelectField | 下拉选择 | ✓ | <o-select> |
VARCHAR |
| CheckboxField | 复选框 | ✓ | <o-checkbox> |
VARCHAR |
| RadioField | 单选框 | ✓ | <o-radio> |
VARCHAR |
| SuggestField | 智能选择 | ✓ | <o-suggest> |
VARCHAR |
| SelectAboutField | 联动选择 | ✓ | <o-select-about> |
VARCHAR |
| DateField | 日期 | ✓ | <o-date-picker> |
DATE |
| NoField | 自动编号 | ✓ | <o-no> |
VARCHAR/NUMBER |
| AttachmentUploadField | 附件上传 | ✓ | <o-file-upload> |
TEXT |
| ImageUploadField | 图片上传 | ✓ | <o-image-upload> |
TEXT |
| KmsDataField | KMS 附件 | ✓ | <o-file-kms> |
TEXT |
| GenericWordField | Word 编辑 | ✓ | <o-word> |
TEXT |
| UserField | 用户选择 | ✓ | <o-user-select> |
VARCHAR |
| DepartmentField | 部门选择 | ✓ | <o-dept-select> |
VARCHAR |
| TreeDepartmentField | 树形部门 | ✓ | <o-dept-tree-select> |
VARCHAR |
| TabField | 页签 | ✗ | <o-tab> |
- |
| SplitField | 分栏 | ✗ | <o-split> |
- |
| IncludeField | 包含视图 | ✗ | <o-include> |
- |
| ButtonField | 按钮 | ✗ | <o-button> |
- |
| ViewDialogField | 视图对话框 | ✗ | <o-view-dialog> |
- |
| FlowHistoryField | 流程历史 | ✗ | <o-flow-history> |
- |
| FlowReminderHistoryField | 催办历史 | ✗ | <o-reminder-history> |
- |
| CommentField | 评论 | ✗ | <o-comment> |
- |
| SurveyField | 问卷 | ✓ | <o-survey> |
TEXT |
| ReminderField | 提醒 | ✓ | - | VARCHAR |
| MapField | 地图 | ✓ | <o-map> |
TEXT |
| WeixinGpsField | GPS 定位 | ✓ | <o-gps> |
VARCHAR |
| WeixinRecordField | 录音 | ✓ | <o-record> |
VARCHAR |
| OnLineTakePhotoField | 在线拍照 | ✓ | - | TEXT |
| QRCodeField | 二维码 | ✗ | <o-qrcode> |
- |
| ScancodeField | 扫码 | ✗ | <o-scancode> |
- |
| HandwritingField | 手写签名 | ✗ | - | - |
| NullField | 空占位 | ✗ | - | - |
统计:共 37 个(不含已废弃的 AttachmentUploadToDataBaseField、FileManagerField)。其中存值字段 23 个,不存值字段 14 个。
前端实现(PC)¶
PC 端基于 Vue 3 组合式 API(<script setup>)+ Element Plus 实现。所有 o-* 字段组件位于 src/components/field/,表单容器为 src/components/form/form_normalform.vue。两端约定:后端把字段渲染成带 <o-xxx> 标签的 HTML 模板字符串,前端把这些标签当作全局组件渲染。
组件注册¶
注册入口在 registerFormComponents.ts,由 main.ts 调用 registerFormComponents(app) 把约 36 个 o-* 组件注册为**全局组件**:
export const formComponents = {
'o-input': defineAsyncComponent(() => import('@/components/field/o_input.vue')),
'o-select': defineAsyncComponent(() => import('@/components/field/o_select.vue')),
// ... 其余字段组件
'o-calctext': o_calctext, // 同步注册
'o-include': o_include, // 同步注册
'o-tab': o_tab, // 同步注册
}
- 绝大多数字段用
defineAsyncComponent按需懒加载; o-calctext/o-include/o-tab改为**同步注册**——避免「异步表单组件内再嵌套异步子组件」时,部分 Vue 版本触发onMounted called with no active instance告警;- 另注册了辅助/布局组件:
o-icon、o-title、font。
表单渲染机制(模板编译)¶
后端返回的表单 JSON 包含两块关键字段:
data.formTemplate.template—— 一段 HTML 字符串,内含<o-xxx>标签与布局结构(即后端toHtmlTemplate()的产物);data.fields—— 字段数据对象数组,每个对象携带该字段的id、name、value、displayType、formField(后端类名)、options、脚本结果等。
form_normalform.vue 用一个 _template 计算属性把这段 HTML 包成**动态组件定义**渲染:
const _template = computed(() => ({
methods: { findField, refresh, checkData, getAllFields, addTabs, getStateId },
template: `<div class='formHtml' ref='formHtmlDom'>${data.formTemplate.template}</div>`
}))
// 模板中:<component name="formTemplate" :is="_template" />
<component :is="_template">编译模板字符串,其中的<o-xxx>即解析为上面注册的全局组件;- 表单样式(后端
data.style.content)以<style class="formStyle_<docId>">注入到#formTemplate_<docId>作用域下,实现每份表单独立样式。
字段数据流(initField 模式)¶
字段组件不通过 props 接收完整字段配置,而是只接收 id,再向**父表单**查回字段对象(同一个引用):
const props = defineProps({ id: String, callback: Function, gridOpenType: String })
const refresh = inject('refresh', () => {}) // 触发字段刷新
const findField = inject('findField', () => {}) // 按 id 取字段对象
const checkData = inject('checkData', null) // 取待校验表单数据
const field = ref({ textType: '', fieldtype: '' })
const initField = () => {
const formData = findField(props.id) // 返回 data.fields 中对应对象的同一引用
field.value = formData
}
onMounted(initField)
要点:
findField(id)按 id **尾段**匹配(复制文档时 fieldid 不变,但前缀不同),命中后回填activities;找不到时返回一个displayType=HIDDEN的占位对象;field.value与表单data.fields中的对象是**同一引用**,组件内直接改field.value.value即同步到表单状态,无需$emit回传;- 控件值通常经一个本地
ref(如inputWrapValue)中转,再用watch与field.value.value双向同步(便于做数字格式化、电话截断等本地处理)。
显示类型(displayType)与模板分支¶
displayType 镜像后端 PermissionType,取值定义在 Constant.js:
| 常量 | 值 | 含义 |
|---|---|---|
PermissionType_READONLY |
1 | 只读 |
PermissionType_MODIFY |
2 | 可编辑 |
PermissionType_HIDDEN |
3 | 隐藏 |
PermissionType_DISABLED |
4 | 禁用 |
PermissionType_PRINT |
5 | 打印 |
字段组件模板按 displayType + textType 分支渲染(以 o_input.vue 为例):
HIDDEN或textType=hidden→ 不渲染控件,仅输出hiddenValue(打印时输出printHiddenValue);PRINT→ 纯文本展示(密码显示•••);READONLY/DISABLED→ 禁用态 Element Plus 控件;当readOnlyShowValOnly为真时退化为纯文本;MODIFY→ 可编辑 Element Plus 控件(el-input/el-select/el-tree-select等)。
分支优先级与后端 getDisplayType() 一致:HIDDEN > DISABLED > READONLY > MODIFY。textType(text / password / readonly / hidden / tel)在其上做进一步细分。
字段刷新(refresh)与联动¶
值变化时按需触发服务端重算依赖字段:
watch(() => field.value.value, (newV, oldV) => {
inputWrapValue.value = newV
if (field.value.refreshOnChanged && (refreshMode == 0 || refreshMode == 1)
&& newV != oldV && oldV !== undefined) { // oldV===undefined 跳过初始化
refresh(props.id, newV)
}
if (field.value.instantValidate) handleBlurChange()
}, { deep: true })
refresh(id, value)由form_normalform.vueprovide,最终调用refreshFormAPI让后端按refreshFields重算,再把返回的字段数据**合并回data.fields**——因为是同一引用,被刷新字段的组件会自动响应更新;refreshOnChanged(本字段变更是否触发刷新)、calculateOnRefresh(被刷新时是否重算本字段)、refreshMode共同决定联动行为;- 数字字段(
VALUE_TYPE_NUMBER+numberPattern)在onChange时用NumberFormater.format按模式格式化后再写回。
即时校验(instantValidate)¶
开启 instantValidate 的字段在失焦/值变化时即时校验,无需等提交:
const response = await formValidationAPI(window.$root.appid, formData, {})
if (response.data.errcode == 4001) { // 校验失败
const hit = response.data.errors.find(e => e.field == field.value.name)
if (hit) { isActive.value = true; errorMessage.value = hit.errmsg }
}
失败时在控件下方展示 .tips 错误条(errorMessage)。提交前整表校验同样走 formValidationAPI,对应后端 validateRule / validateLibs。
工作模式(workmode)与 AI 辅助¶
workModeStore.isHuman 区分人工录入与 AI 录入模式,同一字段在两种模式下渲染不同控件:
<template v-if="workModeStore.isHuman"> ...真正的 el-input... </template>
<template v-else>
<o_input_ai :field="field" @change="onAiInputChange" /> <!-- AI 辅助录入 -->
</template>
各基础字段都有对应 AI 变体:o_input_ai.vue、o_select_ai.vue、o_date_picker_ai.vue、o_textarea_ai.vue。
视图选择框回写(field.js)¶
src/components/field/field.js 提供字段值的**兼容回写**与**展示值换算**工具,供视图选择框(o-view-dialog)、SheetView 单元格等场景统一调用:
installFieldSetCompatibleValue(formData, onAfterSet)按formData.formField类型挂载formData.setCompatibleValue(incomingValue, options),把传入的**显示值 / 真实值 / 多值(;分隔)** 统一解析成字段存储格式:TreeDepartmentField→applyTreeDeptCompatibleValue(写value/val/showValue/data)UserField→applyUserCompatibleValue(写value/userName/showValue/data)SelectField/RadioField/CheckboxField→applySelectCompatibleValue(多选判定 + 回写checkShowValue/displayValue)ImageUploadField→applyImageUploadCompatibleValue(JSON 字符串解析为数组 + 同步pathLists)- 展示值换算(存值 → 文案):
buildSelectShowValue、buildUserShowValue、buildTreeDeptShowValue、buildSuggestShowValue、buildSelectAboutShowValue;网格/电子表格单元格统一入口resolveSelectCellDisplay(raw, column)(优先showVal/showValue,否则按value+options/data匹配,受showType==='01'影响显示真实值)。 markFieldRequiredAndDescript(controlEl, fieldValue):当validateLibs含checkEmpty_system时,给字段标题加<span class="field-required-mark">*</span>必填标记。
操作日志(hislogs)¶
字段值被修改(isModified)且开启 showLog 时,控件右侧显示历史图标 o-icon.icon-history;点击经 hisLogs(Pinia)打开 form_operation_log.vue 展示该字段的修改记录。
前端组件 ↔ 后端字段对照表¶
下表为「后端字段类 → 前端组件文件」的对应关系(按 registerFormComponents.ts 注册项核对):
| 后端字段类 | HTML 标签 | 前端组件文件 | 备注 |
|---|---|---|---|
| InputField | <o-input> |
o_input.vue | AI 变体 o_input_ai.vue |
| TextareaField | <o-textarea> |
o_textarea.vue | AI 变体 o_textarea_ai.vue |
| HTMLEditorField | <o-html> |
o_html.vue | 富文本编辑器 |
| CalctextField | <o-calctext> |
o_calctext.vue | 同步注册 |
| SelectField | <o-select> |
o_select.vue | AI 变体 o_select_ai.vue |
| CheckboxField | <o-checkbox> |
o_checkbox.vue | |
| RadioField | <o-radio> |
o_radio.vue | |
| SuggestField | <o-suggest> |
o_suggest.vue | |
| SelectAboutField | <o-select-about> |
o_select_about.vue | |
| DateField | <o-date-picker> |
o_date_picker.vue | AI 变体 o_date_picker_ai.vue |
| NoField | <o-no> |
o_no.vue | 自动编号 |
| AttachmentUploadField | <o-file-upload> |
o_file_upload.vue | |
| ImageUploadField | <o-image-upload> |
o_image_upload.vue | |
| KmsDataField | <o-file-kms> |
o_file_kms.vue | |
| GenericWordField | <o-word> |
o_word.vue | Word 在线编辑 |
| UserField | <o-user-select> |
o_user_select.vue | |
| DepartmentField | <o-dept-select> |
o_dept_select.vue | 另注册有 o_department.vue |
| TreeDepartmentField | <o-dept-tree-select> |
o_dept_tree_select.vue | |
| TabField | <o-tab> |
o_tab.vue | 同步注册 |
| IncludeField | <o-include> |
o_include.vue | 同步注册 |
| ButtonField | <o-button> |
o_button.vue | |
| ViewDialogField | <o-view-dialog> |
o_view_dialog.vue | 配套 viewDialogDoAction.js、viewdialog_event_btn.vue |
| FlowHistoryField | <o-flow-history> |
o_flow_history.vue | 表格子组件 o_flow_history_table.vue |
| FlowReminderHistoryField | <o-reminder-history> |
o_reminder_history.vue | |
| CommentField | <o-comment> |
o_comment.vue | |
| SurveyField | <o-survey> |
o_survey.vue | |
| MapField | <o-map> |
o_map.vue | 配套 o_map_value.js |
| WeixinGpsField | <o-gps> |
o_gps.vue | |
| WeixinRecordField | <o-record> |
o_record.vue | |
| QRCodeField | <o-qrcode> |
o_qrcode.vue |
说明:
SplitField(<o-split>)、ScancodeField(<o-scancode>)、OnLineTakePhotoField、ReminderField、NullField、HandwritingField在 PC 端无独立的全局字段组件,或由布局层/其它机制承载;注册表中另有o-title、o-coding、o-dialog、o-action、font、o-photo、o-icon等辅助/布局组件,不与单一后端字段类一一对应。