Form Engine
A homegrown gform-designer Form Designer plus a runtime rendering engine. The form schema is embedded in the process DSL, and a single schema drives three views: initiation form filling, approval display, and field permissions.
Designer Capabilities
Drag-and-drop configuration with a live preview in the properties panel on the right:
- Field types (29 in total): single-line/multi-line text, number, amount, password, single-select/multi-select, dropdown (static/dictionary/API data source), date/date range, switch, upload, image, department/member/multi-member selection, cascade, sub-table (line items), rich text, signature, location, serial number, ID card, phone number, plus layout widgets such as grid/card/tabs/divider/alert
- Validation: required, length, numeric range, regex, cross-field validation, formula computation
- Linkage: show/hide logic (visibleWhen / disabledWhen)
- Formula fields: once a
formulais declared, the field becomes read-only; its value is computed in real time from dependent fields and written into the process variables on submit (e.g. leave daysDATEDIFF(endTime, startTime) + 1). Supports arithmetic/comparison/logical operators and the functionsSUM/AVG/MAX/MIN/COUNT/ROUND/ABS/IF/CONCAT/LEN/UPPER/LOWER/DATEDIFF. Missing dependencies propagate as null (null is never treated as 0 to produce a bogus value) - Layout: grid span, label position, label width
- Default values: static values or expressions
- Template library: common approval forms (leave / expense reimbursement / procurement / seal usage) can be saved as templates and applied to a new process in one click; templates can also be shared via
formKeyreferences
The form schema lives in the process DSL at ruleChain.additionalInfo.form:
json
{
"ruleChain": {
"additionalInfo": {
"formType": "design",
"form": {
"title": "Leave Application Form",
"fields": [
{
"id": "f_leave_type",
"type": "select",
"label": "Leave Type",
"field": "leaveType",
"dataSource": { "type": "static", "options": [ /* … */ ] },
"validate": { "required": true }
},
{
"id": "f_leave_days",
"type": "number",
"label": "Leave Days",
"field": "days",
"validate": { "required": true },
"formula": "DATEDIFF(endTime, startTime) + 1"
}
]
}
}
}
}Runtime Rendering
The same schema serves three scenarios:
- Initiate: renders the fill-in form from the schema; once validation passes, field values are loaded into the process variable
msg - Approval display: the detail page renders a read-only/editable view based on "current node + field permissions", with
msgvalues back-filled automatically - Print/archive: a snapshot of
variablestaken the moment the task ends is kept inwf_hi_task, so historical records remain queryable forever
Integration with Processes
- Conditional routing: the designer's condition drawer autocompletes form fields (
msg.days); see the Process Designer - Field permissions:
userTask'sadditionalInfo.formPermissionscontrols visibility and editability per field key across the three views - Template references:
formKeypoints to a template in theformstable (code / name / schema_json); multiple processes share a single form definition, and one change takes effect everywhere
External Forms
Already have forms in an existing business system? formType: "external" + formUrl hooks the existing page directly, and the approval detail opens it read-only in an iframe — the engine only manages the process and never takes over your forms.