define-form.md 4.62 KB

How to define a form

A recipe for the metadata rows that produce a working module + form in BACK and FROUNT. Use this when you want to add a new screen without writing Java.

What you'll insert

Three rows, in order, in three tables. Plus optional rows for fields, permissions, and document numbering.

1. The module — gdsmodule

One row registers the module's existence. Required columns:

Column Value
sId unique ID — use the IdGen next-id helper, or any 32-char string not already taken
sName the URL fragment, e.g. /indexPage/commonList (use a shared page-template URL — see Slice 3)
sChinese / sEnglish / sBig5 display name in three languages
sParentId parent module's sId — places this module in the menu tree
sBrandsId / sSubsidiaryId tenant scope — should be your tenant's IDs (or '1111111111' if standard / system-level)
sVersionFlowId the product edition this module belongs to (look up in sisversionflow)
bVisible 1 to show in the menu
bInvalid 0 for active

Leave sSaveProName, sDeleteProName, sCalcProName, sProcName, sSaveProNameBefore empty unless you need custom CRUD (see the runtime reference).

2. The form-master — gdsconfigformmaster

One row per form per module. Required:

Column Value
sId unique form ID
sParentId the module's sId from step 1
sTbName the backing object's name — a real table, view, or proc
sType 'table', 'view', or 'proc'
sSqlStr the read SQL skeleton; usually SELECT ... FROM {sTbName} WHERE ...
sWhere default WHERE predicates (the runtime adds tenant filters automatically)
sOrder default ORDER BY
iPageSize rows per page in the grid
bGrd 1 if a grid layout, 0 if a single-record form
sBrandsId / sSubsidiaryId tenant scope

For a read-only report, use sType = 'view' and point sTbName at a viw_* view. The framework will not render save/delete buttons.

3. The fields — gdsconfigformslave, one row per field

Most-used columns (the table has 60+, most have sane defaults):

Column Value
sId unique field ID
sParentId the form's sId from step 2
iOrder sort order in the grid
sName the column name on the backing object
sChinese / sEnglish / sBig5 display label
sControlName UI control type — 文本框 (textbox), 下拉框 (dropdown), 日期 (date), 数字 (number), …
bVisible 1 to show
bNotEmpty 1 to require
bReadonly 1 for display-only
bCanInput 1 for editable
iColValue column-span in form layout
sDefault default value
sChineseDropDown dropdown SQL (if applicable) — SELECT sId AS sValue, sChinese AS sText FROM …
sActiveId / sActiveKey for popup-lookup controls — refers to another module

Optional layers

Document numbering — sysbillnosettings

If the module's records need auto-generated bill numbers (work-order numbers, quotation numbers, etc.), add a row here keyed by the form's sId. The runtime returns this in the getModelBysId response under billnosetting.

Permissions — gdsjurisdiction

See How to set permissions. One row per (module, button-or-data, role) tuple.

Tenant overrides

A tenant who wants a different view of this form inserts rows into gdsconfigformpersonalize (form-level override) or gdsconfigformcustomslave (field-level override). See Slice 4.

Verifying

Once all rows are inserted, the SPA's next request to getModelBysId/{your-module-sId} should return your form's metadata. Click the new sidebar item — the form should render. If it doesn't:

  1. Check bVisible = 1 on gdsmodule.
  2. Check that gdsroute has an entry for the URL (one is auto-added in most deployments).
  3. Check sBrandsId/sSubsidiaryId on every row match the user's tenant.
  4. Check that the form's sParentId matches the module's sId exactly — semantic FK, no cross-row check at write time.

Cache invalidation

After inserting, the runtime's cache holds the previous (empty) state until a JMS message fires. xly's cache-invalidation listener (ConsumerChangeGdsModuleThread) handles this when the BACK builder saves changes; if you're inserting via raw SQL, you may need to bounce the running services or wait for the TTL to expire. See Cache invalidation on metadata change.