h3factory 0.0.0-stage → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +241 -2
- package/bin/h3factory.js +87 -0
- package/cli.py +951 -0
- package/config.example.json +8 -0
- package/docs/platform_gotchas.md +118 -0
- package/docs/requirement_checklist.md +54 -0
- package/docs/schema_doc.md +216 -0
- package/docs/workflow.md +146 -0
- package/h3design/__init__.py +0 -0
- package/h3design/controls.py +414 -0
- package/h3design/dsl.py +553 -0
- package/h3design/newbuilder.py +852 -0
- package/h3platform/__init__.py +0 -0
- package/h3platform/api.py +214 -0
- package/h3platform/h3console.py +99 -0
- package/h3platform/settings.py +74 -0
- package/h3verify/__init__.py +0 -0
- package/h3verify/verify.py +217 -0
- package/package.json +51 -4
- package/projects/demo/dicts.json +10 -0
- package/projects/demo/generated/product.cs +82 -0
- package/projects/demo/groups.json +3 -0
- package/projects/demo/sheets/product.json +24 -0
- package/scripts/postinstall.js +109 -0
- package/skills/h3factory/SKILL.md +137 -0
- package/skills/h3yun-dev-assistant/BACKEND_GUIDELINES.md +120 -0
- package/skills/h3yun-dev-assistant/DEV_DOC_ROUTING.md +39 -0
- package/skills/h3yun-dev-assistant/FORM_ACTIONS_GUIDELINES.md +116 -0
- package/skills/h3yun-dev-assistant/FRONTEND_GUIDELINES.md +47 -0
- package/skills/h3yun-dev-assistant/OPENAPI_GUIDELINES.md +8 -0
- package/skills/h3yun-dev-assistant/PLATFORM_CONSTRAINTS.md +160 -0
- package/skills/h3yun-dev-assistant/POST_GUIDELINES.md +47 -0
- package/skills/h3yun-dev-assistant/PRACTICE_NOTES.md +626 -0
- package/skills/h3yun-dev-assistant/SKILL.md +70 -0
- package/skills/h3yun-dev-assistant/SQL_GUIDELINES.md +9 -0
- package/skills/h3yun-dev-assistant/TOOL_FUNCTIONS.md +96 -0
- package/templates/controller.cs.tpl +78 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""控件构造器 —— 新引擎(Console/SheetDesigner SaveForm)设计态控件列表。
|
|
3
|
+
每个控件 {Key, Type(老枚举), Options, ChildControls};newbuilder 负责转 SchemaStr/BizSheetStr。
|
|
4
|
+
必填/只读在新引擎 SaveForm 载荷中无对应键(UI 侧另存),故 required/readonly 参数仅作定义标注。"""
|
|
5
|
+
import json
|
|
6
|
+
import uuid
|
|
7
|
+
|
|
8
|
+
# FormControlType 数值(老枚举,FormLayout.type 用;已对照 UI 载荷实证):
|
|
9
|
+
# … 9 地址 / 10 位置 / 15 附件 / 16 图片 / 201 流水号 见下方新控件段
|
|
10
|
+
# (2026-09-11 类型试验线上样本 logs/types7_ui_save_payload.json 逐字)
|
|
11
|
+
T_TEXTBOX, T_TEXTAREA, T_DATETIME, T_NUMBER = 1, 2, 3, 4
|
|
12
|
+
T_RADIO, T_CHECKBOX_LIST, T_DROPDOWN, T_SWITCH = 5, 6, 7, 8
|
|
13
|
+
T_AREA, T_MAP = 9, 10
|
|
14
|
+
T_MULTIUSER, T_USER, T_DEPARTMENT, T_MULTIDEPT = 11, 12, 13, 14
|
|
15
|
+
T_ATTACHMENT, T_PHOTO = 15, 16
|
|
16
|
+
T_GROUP_TITLE, T_LAYOUT, T_DESCRIPTION, T_GRID_VIEW, T_TAB = 101, 102, 103, 104, 105
|
|
17
|
+
T_SEQNO = 201
|
|
18
|
+
T_QUERY, T_MULTI_QUERY = 301, 302
|
|
19
|
+
|
|
20
|
+
# ControlKey 字符串(ControlKey/FormLayout.options.ControlKey 用)
|
|
21
|
+
K_TEXTBOX = "FormTextBox"
|
|
22
|
+
K_TEXTAREA = "FormTextArea"
|
|
23
|
+
K_DATETIME = "FormDateTime"
|
|
24
|
+
K_NUMBER = "FormNumber"
|
|
25
|
+
K_RADIO = "FormRadioButtonList"
|
|
26
|
+
K_CHECKBOX_LIST = "FormCheckboxList"
|
|
27
|
+
K_DROPDOWN = "FormDropDownList"
|
|
28
|
+
K_SWITCH = "FormCheckbox"
|
|
29
|
+
K_USER = "FormUser"
|
|
30
|
+
K_DEPARTMENT = "FormDepartment"
|
|
31
|
+
K_MULTIUSER = "FormMultiUser"
|
|
32
|
+
K_MULTIDEPT = "FormMultiDepartment"
|
|
33
|
+
K_ATTACHMENT = "FormAttachment"
|
|
34
|
+
K_PHOTO = "FormPhoto"
|
|
35
|
+
K_AREA = "FormAreaSelect"
|
|
36
|
+
K_MAP = "FormMap"
|
|
37
|
+
K_GROUP_TITLE = "FormGroupTitle"
|
|
38
|
+
K_LAYOUT = "FormLayout"
|
|
39
|
+
K_DESCRIPTION = "FormDescription"
|
|
40
|
+
K_SEQNO = "FormSeqNo"
|
|
41
|
+
K_QUERY = "FormQuery"
|
|
42
|
+
K_GRIDVIEW = "FormGridView" # 子表(明细表);子表行 = 独立 child schema
|
|
43
|
+
|
|
44
|
+
TYPE_OF_KEY = {
|
|
45
|
+
K_TEXTBOX: T_TEXTBOX, K_TEXTAREA: T_TEXTAREA, K_DATETIME: T_DATETIME,
|
|
46
|
+
K_NUMBER: T_NUMBER, K_RADIO: T_RADIO, K_CHECKBOX_LIST: T_CHECKBOX_LIST,
|
|
47
|
+
K_DROPDOWN: T_DROPDOWN, K_SWITCH: T_SWITCH, K_USER: T_USER,
|
|
48
|
+
K_DEPARTMENT: T_DEPARTMENT, K_MULTIUSER: T_MULTIUSER,
|
|
49
|
+
K_MULTIDEPT: T_MULTIDEPT,
|
|
50
|
+
K_ATTACHMENT: T_ATTACHMENT, K_PHOTO: T_PHOTO, K_AREA: T_AREA, K_MAP: T_MAP,
|
|
51
|
+
K_GROUP_TITLE: T_GROUP_TITLE, K_LAYOUT: T_LAYOUT,
|
|
52
|
+
K_DESCRIPTION: T_DESCRIPTION, K_SEQNO: T_SEQNO, K_QUERY: T_QUERY,
|
|
53
|
+
}
|
|
54
|
+
# 只占版面的布局项(不进 SchemaStr.Properties、无 DataField)
|
|
55
|
+
LAYOUT_KEYS = (K_GROUP_TITLE, K_DESCRIPTION)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _common(key, label, ckey, summary=""):
|
|
59
|
+
"""UI 载荷里所有类型都带的基础 Options 键(对照 logs/ui_save_types_payload.json)"""
|
|
60
|
+
opt = {
|
|
61
|
+
"DataField": key,
|
|
62
|
+
"DisplayName": label,
|
|
63
|
+
"Description": "",
|
|
64
|
+
"ControlKey": ckey,
|
|
65
|
+
"Summary": summary or "",
|
|
66
|
+
"DisplayRule": {"Rule": ""},
|
|
67
|
+
"PlaceHolder": "",
|
|
68
|
+
"ComputationRule": {"Rule": ""},
|
|
69
|
+
"DefaultValueRuleType": 2,
|
|
70
|
+
"DataLinkSchemaCode": "",
|
|
71
|
+
"DataLinkSchema": {},
|
|
72
|
+
"DataLinkCondition": [],
|
|
73
|
+
"DataLinkResult": "",
|
|
74
|
+
"DataLinkResultFunction": "",
|
|
75
|
+
}
|
|
76
|
+
return opt
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def control(key, label, ckey, extra=None, summary=""):
|
|
80
|
+
opt = _common(key, label, ckey, summary)
|
|
81
|
+
if extra:
|
|
82
|
+
opt.update(extra)
|
|
83
|
+
return {"Key": key, "Type": TYPE_OF_KEY[ckey], "Options": opt,
|
|
84
|
+
"ChildControls": None}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# ---- 基础控件 ----
|
|
88
|
+
def text(key, label, required=False, readonly=False, placeholder="", summary="", default="",
|
|
89
|
+
rule=""):
|
|
90
|
+
"""单行文本。必填/只读:新引擎另存,参数留作设计稿标注。
|
|
91
|
+
rule: 隐藏条件文本(如 {applytype}=="新料号"),空 = 默认可见。"""
|
|
92
|
+
extra = {"Mode": "Normal",
|
|
93
|
+
"NoRepeatTipMessage": "不允许重复录入信息。",
|
|
94
|
+
"PlaceHolder": placeholder,
|
|
95
|
+
"NoRepeat": False,
|
|
96
|
+
"DefaultValue": default}
|
|
97
|
+
if rule:
|
|
98
|
+
extra["DisplayRule"] = {"Rule": rule}
|
|
99
|
+
return control(key, label, K_TEXTBOX, extra=extra, summary=summary)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def textarea(key, label, required=False, readonly=False, rows=3, default=""):
|
|
103
|
+
extra = {"Rows": rows, "OpenRichText": False, "VoiceInput": False,
|
|
104
|
+
"DefaultValue": default}
|
|
105
|
+
return control(key, label, K_TEXTAREA, extra=extra)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def number(key, label, required=False, readonly=False, decimal=0, default=None,
|
|
109
|
+
rule=""):
|
|
110
|
+
extra = {"DecimalPlaces": decimal, "DataFormatType": "0", "ShowMode": "0",
|
|
111
|
+
"Percentage": False, "ShowBarChart": False, "RollupSettings": []}
|
|
112
|
+
if default is not None:
|
|
113
|
+
extra["DefaultValue"] = default
|
|
114
|
+
if rule:
|
|
115
|
+
extra["DisplayRule"] = {"Rule": rule}
|
|
116
|
+
return control(key, label, K_NUMBER, extra=extra)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def date_field(key, label, required=False, readonly=False, datetime_mode="yyyy-mm-dd",
|
|
120
|
+
rule=""):
|
|
121
|
+
return control(key, label, K_DATETIME,
|
|
122
|
+
extra={"DateTimeMode": datetime_mode, "Width": "100%",
|
|
123
|
+
**({"DisplayRule": {"Rule": rule}} if rule else {})})
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def switch_field(key, label, required=False, readonly=False, checked=False):
|
|
127
|
+
"""开关(是/否)。Options 逐字对照 UI:DefaultItems=[是/否] IsCheckbox="true"。
|
|
128
|
+
DefaultValue: 勾选="true" 否则 "false"(Properties 同款字符串)。"""
|
|
129
|
+
return control(key, label, K_SWITCH,
|
|
130
|
+
extra={"DefaultItems": ["是/否"],
|
|
131
|
+
"DefaultValue": "true" if checked else "false",
|
|
132
|
+
"IsCheckbox": "true",
|
|
133
|
+
"DataDictItemName": "",
|
|
134
|
+
"Checked": bool(checked)})
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def member(key, label, required=False, readonly=False, multi=False,
|
|
138
|
+
rule=""):
|
|
139
|
+
"""成员(单选/多选)。Options 对照 UI 真实载荷(D001599e98... 读回,权威):
|
|
140
|
+
FormUser/FormMultiUser type 12/11;默认取当前用户等规则未配则留空。"""
|
|
141
|
+
ckey = K_MULTIUSER if multi else K_USER
|
|
142
|
+
extra = {
|
|
143
|
+
"DisplayRule": {"Rule": rule},
|
|
144
|
+
"UnitSelectionRange": "", "IsRelatedMember": False,
|
|
145
|
+
"ShowUnActive": False, "UseDataCache": True, "CurrentUserId": False,
|
|
146
|
+
"MappingControls": "", "OrgUnitVisible": False, "UserVisible": True,
|
|
147
|
+
"OwnDepVisible": False, "OwnDepUsersVisble": True,
|
|
148
|
+
"IsMultiple": bool(multi), "ShowCurUser": False,
|
|
149
|
+
"DefaultValueRule": {"value": "", "label": "", "nodes": []},
|
|
150
|
+
}
|
|
151
|
+
return control(key, label, ckey, extra=extra)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def department(key, label, required=False, readonly=False, multi=False,
|
|
155
|
+
rule=""):
|
|
156
|
+
"""部门(单选/多选)。对照 UI 真实载荷:type 13/14;部门无 ShowCurUser。"""
|
|
157
|
+
ckey = K_DEPARTMENT if not multi else K_MULTIDEPT
|
|
158
|
+
extra = {
|
|
159
|
+
"DisplayRule": {"Rule": rule},
|
|
160
|
+
"UnitSelectionRange": "", "IsRelatedMember": False,
|
|
161
|
+
"ShowUnActive": False, "UseDataCache": True, "CurrentUserId": False,
|
|
162
|
+
"MappingControls": "", "OrgUnitVisible": True, "UserVisible": False,
|
|
163
|
+
"OwnDepVisible": True, "OwnDepUsersVisble": False,
|
|
164
|
+
"IsMultiple": bool(multi),
|
|
165
|
+
"DefaultValueRule": {"value": "", "label": "", "nodes": []},
|
|
166
|
+
}
|
|
167
|
+
if multi:
|
|
168
|
+
extra["DefaultValue"] = ""
|
|
169
|
+
return control(key, label, ckey, extra=extra)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# ---- 单选 / 多选 / 下拉(UI 存储值 = 所选文本本身)----
|
|
173
|
+
def radio(key, label, items, required=False, default=""):
|
|
174
|
+
extra = {"SelectShowMode": "0", "TransferItems": K_RADIO,
|
|
175
|
+
"DataDictItemName": "", "ItemColors": [], "ColorSwitch": False,
|
|
176
|
+
"DataSource": "Custom",
|
|
177
|
+
"DefaultItems": list(items), "DefaultValue": default}
|
|
178
|
+
return control(key, label, K_RADIO, extra=extra)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def checkbox_list(key, label, items, required=False, default_items=()):
|
|
182
|
+
"""复选。DefaultValue 用分号连接(与导入数据多值格式一致);无默认=""
|
|
183
|
+
Options 逐字对照 UI(含 IsCheckbox=false)。"""
|
|
184
|
+
dv = ";".join(default_items)
|
|
185
|
+
extra = {"SelectShowMode": "0", "TransferItems": K_CHECKBOX_LIST,
|
|
186
|
+
"DataDictItemName": "", "ItemColors": [], "ColorSwitch": False,
|
|
187
|
+
"DataSource": "Custom",
|
|
188
|
+
"DefaultItems": list(items), "DefaultValue": dv,
|
|
189
|
+
"IsCheckbox": False}
|
|
190
|
+
return control(key, label, K_CHECKBOX_LIST, extra=extra)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def dropdown(key, label, items, required=False, default="", rule=""):
|
|
194
|
+
"""下拉。值即显示文本。rule 同 text()。"""
|
|
195
|
+
extra = {"SelectShowMode": "0", "TransferItems": K_DROPDOWN,
|
|
196
|
+
"DataDictItemName": "", "ItemColors": [], "ColorSwitch": False,
|
|
197
|
+
"DataSource": "Custom",
|
|
198
|
+
"DefaultItems": list(items), "DefaultValue": default}
|
|
199
|
+
if rule:
|
|
200
|
+
extra["DisplayRule"] = {"Rule": rule}
|
|
201
|
+
return control(key, label, K_DROPDOWN, extra=extra)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def assoc_dropdown(key, label, boschema_code, mapping_field, filter_rule="",
|
|
205
|
+
app_package="", rule=""):
|
|
206
|
+
"""联动下拉:选项来自另一张表(DataSource=Association)+ 级联过滤。
|
|
207
|
+
Options 键集逐字对照线上样本(类型试验 F0000021 Association 形态,2026-09-09):
|
|
208
|
+
DataSource/BOSchemaCode/BOSchemaInfo(JSON串)/MappingField(存值列)/
|
|
209
|
+
AssociationFilter{Rule}/AssociationFields(JSON串)/MappingControls/MappingProperties;
|
|
210
|
+
另外剔掉 _common 的 PlaceHolder/DataLink 键(同 query())。
|
|
211
|
+
DefaultItems=[] 不落占位项(UI 从 Custom 改型才残留 选项1/2/3)。
|
|
212
|
+
filter_rule: 规则文本(如 {源表编码.dictcategory}=="特性代码" AND
|
|
213
|
+
CONTAINS({源表编码.applyto},{bigcat}));rule: hideWhen 同 text()。"""
|
|
214
|
+
opt = _common(key, label, K_DROPDOWN)
|
|
215
|
+
opt = {k: v for k, v in opt.items()
|
|
216
|
+
if k not in ("PlaceHolder", "DataLinkSchemaCode", "DataLinkSchema",
|
|
217
|
+
"DataLinkCondition", "DataLinkResult",
|
|
218
|
+
"DataLinkResultFunction")}
|
|
219
|
+
boschema_info = json.dumps(
|
|
220
|
+
{"AppPackage": app_package, "AppGroup": "",
|
|
221
|
+
"AppMenu": boschema_code, "IsChildSchema": False}, ensure_ascii=False,
|
|
222
|
+
separators=(",", ":"))
|
|
223
|
+
assoc_fields = json.dumps({"isDefault": True, "fieldSetting": []},
|
|
224
|
+
ensure_ascii=False, separators=(",", ":"))
|
|
225
|
+
opt.update({
|
|
226
|
+
"DisplayRule": {"Rule": rule},
|
|
227
|
+
"TransferItems": K_DROPDOWN, "SelectShowMode": "0",
|
|
228
|
+
"DataDictItemName": "", "DefaultItems": [], "DefaultValue": None,
|
|
229
|
+
"ColorSwitch": False, "ItemColors": [],
|
|
230
|
+
"DataSource": "Association",
|
|
231
|
+
"BOSchemaCode": boschema_code, "BOSchemaInfo": boschema_info,
|
|
232
|
+
"MappingField": mapping_field,
|
|
233
|
+
"AssociationFilter": {"Rule": filter_rule},
|
|
234
|
+
"MappingControls": "",
|
|
235
|
+
"AssociationFields": assoc_fields, "MappingProperties": "{}",
|
|
236
|
+
})
|
|
237
|
+
return {"Key": key, "Type": T_DROPDOWN, "Options": opt,
|
|
238
|
+
"ChildControls": None}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# ---- 布局项(无 DataField,不进 Properties)----
|
|
242
|
+
_LAYOUT_NS = uuid.UUID("6f1d5a3c-9b2e-4a77-8f10-2c9d4e7b5a31")
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def layout_key(def_key):
|
|
246
|
+
"""布局项(分组标题/描述)在 FormLayout 与 HTML 里的 key:线上是 **GUID**
|
|
247
|
+
(UI 每加一个就发新号),短码当 key 存不住 —— 2026-09-11 线上实证:用定义短码
|
|
248
|
+
保存后回读 key=None、verify 判缺字段。这里用 uuid5(固定命名空间, 短码) 定值:
|
|
249
|
+
同一张表的同一布局项永远同号,verify 才能不靠 registry 复算期望键。
|
|
250
|
+
定义侧短码存控件 Dict 的 DefKey,只供 layout 行引用。"""
|
|
251
|
+
return str(uuid.uuid5(_LAYOUT_NS, str(def_key)))
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _layout_opt(ckey, display_name, extra=None):
|
|
255
|
+
"""布局项(分组标题/描述)的 Options。线上样本只有三四个键,无 Summary/DataField。"""
|
|
256
|
+
opt = {"DisplayName": display_name}
|
|
257
|
+
if extra:
|
|
258
|
+
opt.update(extra)
|
|
259
|
+
if ckey:
|
|
260
|
+
opt["ControlKey"] = ckey # 分组标题线上**不带** ControlKey(2026-09-11 样本)
|
|
261
|
+
return opt
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def group_title(key, title, alignment="left"):
|
|
265
|
+
"""分组标题(type 101)。Options 逐字对照线上样本:{DisplayName, Title, Alignment},
|
|
266
|
+
**没有 ControlKey**(设计器保存的就是这三个键)。
|
|
267
|
+
短码只留在 DefKey(layout 行引用用);Key 是 layout_key 出的 GUID。"""
|
|
268
|
+
return {"Key": layout_key(key), "DefKey": key, "Type": T_GROUP_TITLE,
|
|
269
|
+
"Options": _layout_opt(None, title, {"Title": title,
|
|
270
|
+
"Alignment": alignment}),
|
|
271
|
+
"ChildControls": None}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def description(key, content="", display_name="描述说明", rule=None):
|
|
275
|
+
"""描述/说明文字(type 103,ControlKey FormDescription)。
|
|
276
|
+
content = 富文本 HTML(如 "<p>描述</p>");DisplayRule 线上是空字典 {}。"""
|
|
277
|
+
opt = _layout_opt(K_DESCRIPTION, display_name,
|
|
278
|
+
{"Content": content, "DisplayRule": {}})
|
|
279
|
+
if rule:
|
|
280
|
+
opt["DisplayRule"] = {"Rule": rule}
|
|
281
|
+
return {"Key": layout_key(key), "DefKey": key, "Type": T_DESCRIPTION,
|
|
282
|
+
"Options": opt, "ChildControls": None}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# ---- 新控件(流水号/图片/附件/位置/地址)----
|
|
286
|
+
# 键集对照线上样本:比老控件窄 —— 无 PlaceHolder/ComputationRule/DataLink* 键
|
|
287
|
+
def _plain(key, label, ckey, extra=None, rule=None, summary=""):
|
|
288
|
+
"""新控件 FormLayout Options 基础键。rule=None 表示**不带** DisplayRule 键
|
|
289
|
+
(流水号线上就没有);rule="" 或规则文本 → 落 {"Rule": ...}。"""
|
|
290
|
+
opt = {"DataField": key, "DisplayName": label, "Description": "",
|
|
291
|
+
"ControlKey": ckey, "Summary": summary}
|
|
292
|
+
if rule is not None:
|
|
293
|
+
opt["DisplayRule"] = {"Rule": rule}
|
|
294
|
+
if extra:
|
|
295
|
+
opt.update(extra)
|
|
296
|
+
return opt
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _ctl(key, ckey, opt, extra=None):
|
|
300
|
+
c = {"Key": key, "Type": TYPE_OF_KEY[ckey], "Options": opt,
|
|
301
|
+
"ChildControls": None}
|
|
302
|
+
if extra:
|
|
303
|
+
c.update(extra)
|
|
304
|
+
return c
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def seqno(key="SeqNo", label="流水号", prefix="", datetime_mode="YYYY",
|
|
308
|
+
increment=8):
|
|
309
|
+
"""流水号(type 201)。**表单级**键由 build_schema_str 联动:
|
|
310
|
+
EnableSeqNo=true / SeqNoDateFormat / SeqNoPrefix / SeqNoStructure / SeqNoLength
|
|
311
|
+
(SeqNoLength = 前缀长 + 日期段长 + 序号位数)。
|
|
312
|
+
static: DateTimeMode 支持 YYYY / YYYYMM / YYYYMMDD 等(段长按字符串长度算)。
|
|
313
|
+
prefix 非空只落 Prefix 选项(线上样本 prefix 为空,非空形态未实证)。"""
|
|
314
|
+
opt = _plain(key, label, K_SEQNO, rule=None)
|
|
315
|
+
opt.update({
|
|
316
|
+
"Prefix": prefix,
|
|
317
|
+
"DateTimeMode": datetime_mode,
|
|
318
|
+
"SeqNoStructure": [{"Type": 1, "Value": datetime_mode},
|
|
319
|
+
{"Type": 2, "IncreNum": increment, "Value": "1"}],
|
|
320
|
+
"IncrementNum": increment,
|
|
321
|
+
})
|
|
322
|
+
return _ctl(key, K_SEQNO, opt, {"SeqNoPrefix": prefix,
|
|
323
|
+
"SeqNoDateFormat": datetime_mode})
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def photo(key, label, multiple=False, camera_only=False, watermark=False,
|
|
327
|
+
compression=False, rule=""):
|
|
328
|
+
"""图片(type 16,ControlKey FormPhoto)。multiple=多选上传;
|
|
329
|
+
camera_only=仅拍照;watermark=加水印;compression=压缩。"""
|
|
330
|
+
opt = _plain(key, label, K_PHOTO, rule=rule or "",
|
|
331
|
+
extra={"UploadMultiple": bool(multiple),
|
|
332
|
+
"CameraOnly": bool(camera_only),
|
|
333
|
+
"HasWatermark": bool(watermark),
|
|
334
|
+
"Compression": bool(compression)})
|
|
335
|
+
return _ctl(key, K_PHOTO, opt)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def attachment(key, label, max_upload_size=10, rule=""):
|
|
339
|
+
"""附件(type 15,ControlKey FormAttachment)。max_upload_size 单位 MB(线上默认 10)。
|
|
340
|
+
必填/只读/是否允许多附件等由界面另存。"""
|
|
341
|
+
opt = _plain(key, label, K_ATTACHMENT, rule=rule or "",
|
|
342
|
+
extra={"MaxUploadSize": max_upload_size})
|
|
343
|
+
return _ctl(key, K_ATTACHMENT, opt)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def location(key, label, meters=500, pc_enabled=True, editable=False,
|
|
347
|
+
range_="0", rule=""):
|
|
348
|
+
"""位置(type 10,ControlKey FormMap)。**注意**:Meters/LocationPCEnabled/
|
|
349
|
+
LocationEditable 不在 FormLayout/Properties 里,而走载荷顶层独立的
|
|
350
|
+
ControlSettingsStr(见 newbuilder.build_control_settings)—— 存在返回的
|
|
351
|
+
control["ControlSettings"] 里,由 newbuilder 收集。
|
|
352
|
+
range_: 定位范围选项(线上 "0");data-locationrangelimit 线上写 "undefined"。"""
|
|
353
|
+
opt = _plain(key, label, K_MAP, rule=rule or "", extra={"Range": range_})
|
|
354
|
+
return _ctl(key, K_MAP, opt, {"ControlSettings": {
|
|
355
|
+
"LocationPCEnabled": "true" if pc_enabled else "false",
|
|
356
|
+
"Meters": str(meters),
|
|
357
|
+
"LocationEditable": "true" if editable else "false"}})
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def area(key, label, area_mode="P-C-T", show_detail=True, rule="",
|
|
361
|
+
default=None):
|
|
362
|
+
"""地址(type 9,ControlKey FormAreaSelect)。area_mode 如 "P-C-T"
|
|
363
|
+
(省-市-县;其它档位未实证);show_detail=允许填详细地址;default 为
|
|
364
|
+
{"adcode","adname","Detail"} 三键字典(Properties 侧存 JSON 串)。"""
|
|
365
|
+
dv = default or {"adcode": "", "adname": "", "Detail": ""}
|
|
366
|
+
opt = _plain(key, label, K_AREA, rule=rule or "",
|
|
367
|
+
extra={"AreaMode": area_mode,
|
|
368
|
+
"ShowDetailAddr": bool(show_detail),
|
|
369
|
+
"DefaultValue": dict(dv)})
|
|
370
|
+
return _ctl(key, K_AREA, opt)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def query(key, label, boschema_code, app_package="", required=False, multi=False,
|
|
376
|
+
rule=""):
|
|
377
|
+
"""关联表单控件(FormQuery/FormMultiQuery)。Options 逐字对照 UI 样本 F0000007:
|
|
378
|
+
键集、BOSchemaInfo/AssociationFields 的 JSON 字符串形式完全一致。
|
|
379
|
+
rule: 隐藏条件文本(同 text(),仅 DisplayRule.Rule 变化,其余键位不动)。"""
|
|
380
|
+
ckey = K_QUERY if not multi else "FormMultiQuery"
|
|
381
|
+
boschema_info = json.dumps(
|
|
382
|
+
{"AppPackage": app_package, "AppGroup": "",
|
|
383
|
+
"AppMenu": boschema_code, "IsChildSchema": False}, ensure_ascii=False,
|
|
384
|
+
separators=(",", ":"))
|
|
385
|
+
fields = json.dumps({"isDefault": True, "fieldSetting": []}, ensure_ascii=False,
|
|
386
|
+
separators=(",", ":"))
|
|
387
|
+
extra = {
|
|
388
|
+
"BOSchemaCode": boschema_code,
|
|
389
|
+
"AssociationFilter": {"Rule": ""},
|
|
390
|
+
"BOSchemaName": "",
|
|
391
|
+
"IsListView": "",
|
|
392
|
+
"BOSchemaInfo": boschema_info,
|
|
393
|
+
"BOFilter": "",
|
|
394
|
+
"AssociationFields": fields,
|
|
395
|
+
"InputByScan": False,
|
|
396
|
+
"ScanUpdateEnable": False,
|
|
397
|
+
"DataRule": "",
|
|
398
|
+
"MappingControls": "",
|
|
399
|
+
"MappingProperties": "{}",
|
|
400
|
+
"IsMultiple": False,
|
|
401
|
+
"MappingField": "",
|
|
402
|
+
"Width": "100%",
|
|
403
|
+
}
|
|
404
|
+
opt = _common(key, label, ckey)
|
|
405
|
+
# 规范样本的关联控件不含 PlaceHolder/DataLink 键,替换为规范键集
|
|
406
|
+
opt = {k: v for k, v in opt.items()
|
|
407
|
+
if k not in ("PlaceHolder", "DataLinkSchemaCode", "DataLinkSchema",
|
|
408
|
+
"DataLinkCondition", "DataLinkResult",
|
|
409
|
+
"DataLinkResultFunction")}
|
|
410
|
+
if rule:
|
|
411
|
+
opt["DisplayRule"] = {"Rule": rule}
|
|
412
|
+
opt.update(extra)
|
|
413
|
+
return {"Key": key, "Type": TYPE_OF_KEY[ckey], "Options": opt,
|
|
414
|
+
"ChildControls": None}
|