openxiangda 1.0.0
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 +58 -0
- package/bin/openxiangda.js +11 -0
- package/lib/cli.js +2423 -0
- package/lib/config.js +121 -0
- package/lib/http.js +47 -0
- package/lib/skills.js +371 -0
- package/lib/utils.js +87 -0
- package/lib/workspace-init.js +139 -0
- package/openxiangda-skills/SKILL.md +128 -0
- package/openxiangda-skills/references/architecture-patterns.md +242 -0
- package/openxiangda-skills/references/automation-v3.md +129 -0
- package/openxiangda-skills/references/component-guide.md +198 -0
- package/openxiangda-skills/references/forms/component-registry.md +53 -0
- package/openxiangda-skills/references/forms/form-schema.md +109 -0
- package/openxiangda-skills/references/forms/layout-and-rules.md +24 -0
- package/openxiangda-skills/references/openxiangda-api.md +466 -0
- package/openxiangda-skills/references/pages/page-sdk.md +13 -0
- package/openxiangda-skills/references/pages/publish-flow.md +36 -0
- package/openxiangda-skills/references/pages/workspace-structure.md +38 -0
- package/openxiangda-skills/references/permissions-settings.md +147 -0
- package/openxiangda-skills/references/platform-data-model.md +305 -0
- package/openxiangda-skills/references/style-system.md +492 -0
- package/openxiangda-skills/references/troubleshooting.md +246 -0
- package/openxiangda-skills/references/workflow-v3.md +105 -0
- package/openxiangda-skills/references/workspace-state.md +45 -0
- package/openxiangda-skills/skills/openxiangda-app/SKILL.md +64 -0
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +143 -0
- package/openxiangda-skills/skills/openxiangda-form/SKILL.md +76 -0
- package/openxiangda-skills/skills/openxiangda-inspect/SKILL.md +40 -0
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +62 -0
- package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +95 -0
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +97 -0
- package/package.json +126 -0
- package/packages/sdk/bin/lowcode-workspace.mjs +4 -0
- package/packages/sdk/dist/build/index.cjs +33 -0
- package/packages/sdk/dist/build/index.cjs.map +1 -0
- package/packages/sdk/dist/build/index.d.mts +40 -0
- package/packages/sdk/dist/build/index.d.ts +40 -0
- package/packages/sdk/dist/build/index.mjs +8 -0
- package/packages/sdk/dist/build/index.mjs.map +1 -0
- package/packages/sdk/dist/components/index.cjs +18700 -0
- package/packages/sdk/dist/components/index.cjs.map +1 -0
- package/packages/sdk/dist/components/index.d.mts +2094 -0
- package/packages/sdk/dist/components/index.d.ts +2094 -0
- package/packages/sdk/dist/components/index.mjs +18649 -0
- package/packages/sdk/dist/components/index.mjs.map +1 -0
- package/packages/sdk/dist/runtime/index.cjs +1469 -0
- package/packages/sdk/dist/runtime/index.cjs.map +1 -0
- package/packages/sdk/dist/runtime/index.d.mts +831 -0
- package/packages/sdk/dist/runtime/index.d.ts +831 -0
- package/packages/sdk/dist/runtime/index.mjs +1420 -0
- package/packages/sdk/dist/runtime/index.mjs.map +1 -0
- package/packages/sdk/dist/styles/antd-theme.cjs +60 -0
- package/packages/sdk/dist/styles/antd-theme.cjs.map +1 -0
- package/packages/sdk/dist/styles/antd-theme.d.mts +5 -0
- package/packages/sdk/dist/styles/antd-theme.d.ts +5 -0
- package/packages/sdk/dist/styles/antd-theme.mjs +35 -0
- package/packages/sdk/dist/styles/antd-theme.mjs.map +1 -0
- package/packages/sdk/dist/styles/tailwind-preset.cjs +2641 -0
- package/packages/sdk/dist/styles/tailwind-preset.cjs.map +1 -0
- package/packages/sdk/dist/styles/tailwind-preset.d.mts +75 -0
- package/packages/sdk/dist/styles/tailwind-preset.d.ts +75 -0
- package/packages/sdk/dist/styles/tailwind-preset.mjs +2618 -0
- package/packages/sdk/dist/styles/tailwind-preset.mjs.map +1 -0
- package/packages/sdk/dist/styles/tokens.css +73 -0
- package/packages/sdk/src/build-source/README.md +9 -0
- package/packages/sdk/src/build-source/bin/lowcode-workspace.mjs +7 -0
- package/packages/sdk/src/build-source/package.json +34 -0
- package/packages/sdk/src/build-source/scripts/build-forms.mjs +824 -0
- package/packages/sdk/src/build-source/scripts/build-forms.runtime-entry.test.ts +18 -0
- package/packages/sdk/src/build-source/scripts/build-pages.mjs +793 -0
- package/packages/sdk/src/build-source/scripts/build-workspace.mjs +64 -0
- package/packages/sdk/src/build-source/scripts/publish-all.mjs +127 -0
- package/packages/sdk/src/build-source/scripts/publish-oss.mjs +149 -0
- package/packages/sdk/src/build-source/scripts/register-bundle.mjs +1 -0
- package/packages/sdk/src/build-source/scripts/register.mjs +329 -0
- package/packages/sdk/src/build-source/scripts/sync-schema.mjs +301 -0
- package/packages/sdk/src/build-source/scripts/utils/form-api.mjs +639 -0
- package/packages/sdk/src/build-source/scripts/utils/form-api.test.ts +244 -0
- package/packages/sdk/src/build-source/scripts/utils/form-runtime-assets.mjs +57 -0
- package/packages/sdk/src/build-source/scripts/utils/form-runtime-assets.test.ts +135 -0
- package/packages/sdk/src/build-source/scripts/utils/incremental.mjs +210 -0
- package/packages/sdk/src/build-source/scripts/utils/load-config.mjs +257 -0
- package/packages/sdk/src/build-source/scripts/utils/load-config.test.ts +44 -0
- package/packages/sdk/src/build-source/scripts/utils/mime-types.mjs +70 -0
- package/packages/sdk/src/build-source/scripts/utils/namespace-css.mjs +61 -0
- package/packages/sdk/src/build-source/scripts/utils/oss-client.mjs +128 -0
- package/packages/sdk/src/build-source/scripts/utils/pages.mjs +80 -0
- package/packages/sdk/src/build-source/scripts/utils/progress.mjs +57 -0
- package/packages/sdk/src/build-source/scripts/utils/register-payload.mjs +89 -0
- package/packages/sdk/src/build-source/scripts/utils/register-payload.test.ts +76 -0
- package/packages/sdk/src/build-source/scripts/utils/runtime-css-check.mjs +44 -0
- package/packages/sdk/src/build-source/scripts/utils/runtime-css-check.test.ts +54 -0
- package/packages/sdk/src/build-source/scripts/utils/schema-transform.mjs +130 -0
- package/packages/sdk/src/build-source/scripts/utils/schema-transform.test.ts +141 -0
- package/packages/sdk/src/build-source/scripts/utils/tailwind-config.mjs +227 -0
- package/packages/sdk/src/build-source/scripts/utils/tailwind-config.test.ts +187 -0
- package/packages/sdk/src/build-source/src/cli.mjs +679 -0
- package/templates/sy-lowcode-app-workspace/app-workspace.config.ts +34 -0
- package/templates/sy-lowcode-app-workspace/examples/forms/customer/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/forms/customer/schema.ts +35 -0
- package/templates/sy-lowcode-app-workspace/index.html +12 -0
- package/templates/sy-lowcode-app-workspace/package.json +49 -0
- package/templates/sy-lowcode-app-workspace/postcss.config.cjs +6 -0
- package/templates/sy-lowcode-app-workspace/scripts/build-js-code.mjs +100 -0
- package/templates/sy-lowcode-app-workspace/src/dev/App.tsx +26 -0
- package/templates/sy-lowcode-app-workspace/src/forms/.gitkeep +1 -0
- package/templates/sy-lowcode-app-workspace/src/forms/README.md +48 -0
- package/templates/sy-lowcode-app-workspace/src/index.css +28 -0
- package/templates/sy-lowcode-app-workspace/src/js-code-nodes/.gitkeep +1 -0
- package/templates/sy-lowcode-app-workspace/src/js-code-nodes/types.d.ts +3 -0
- package/templates/sy-lowcode-app-workspace/src/main.tsx +36 -0
- package/templates/sy-lowcode-app-workspace/src/pages/.gitkeep +1 -0
- package/templates/sy-lowcode-app-workspace/src/shared/form-schema.ts +128 -0
- package/templates/sy-lowcode-app-workspace/src/types/app-workspace.types.ts +31 -0
- package/templates/sy-lowcode-app-workspace/tailwind.config.cjs +30 -0
- package/templates/sy-lowcode-app-workspace/tsconfig.app.json +24 -0
- package/templates/sy-lowcode-app-workspace/tsconfig.js-code-nodes.json +15 -0
- package/templates/sy-lowcode-app-workspace/tsconfig.json +7 -0
- package/templates/sy-lowcode-app-workspace/tsconfig.node.json +10 -0
- package/templates/sy-lowcode-app-workspace/vite.config.ts +32 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Component Guide
|
|
2
|
+
|
|
3
|
+
> 面向 AI Agent 的组件使用策略:优先复用平台组件,按需基于 antd / antd-mobile 包装,绝不重造已存在的平台能力。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. 核心原则
|
|
8
|
+
|
|
9
|
+
1. **平台组件优先**:所有平台组件已经接入了组织架构、文件存储、权限、多端适配等平台能力,重写一遍 = 丢能力 + 后续无法维护。
|
|
10
|
+
2. **基于 antd / antd-mobile 包装**:自定义组件必须站在 antd 之上,保证 PC 和移动端的基础体验一致。
|
|
11
|
+
3. **样式走变量与语义类**:使用 CSS 变量、Tailwind 语义类,**禁止**在 JSX 中硬编码颜色、间距、字号、圆角。
|
|
12
|
+
4. **不覆盖组件内部 class**:组件库内部类名(`ant-select-selector` 等)是私有 API,下个版本就可能变。
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 2. 必须使用平台组件(重做即丢能力)
|
|
17
|
+
|
|
18
|
+
| 场景 | 平台组件 | 不重做的原因 | 自动接入的能力 |
|
|
19
|
+
| --- | --- | --- | --- |
|
|
20
|
+
| 选择人员 | `UserSelectField` | 直接接入组织架构 | 人员列表、搜索、按部门筛选、层级树 |
|
|
21
|
+
| 选择部门 | `DepartmentSelectField` | 直接接入组织架构 | 部门树、搜索、多选 |
|
|
22
|
+
| 上传附件 | `AttachmentField` | 接入平台存储 | 上传、预览、下载、鉴权 URL |
|
|
23
|
+
| 上传图片 | `ImageField` | 接入平台存储 | 上传、压缩、缩略图、预览 |
|
|
24
|
+
| 富文本编辑 | `EditorField` | 含图片上传集成 | 完整工具栏、平台图床、粘贴清洗 |
|
|
25
|
+
| 数字签名 | `DigitalSignatureField` | 平台级签名 | 签名采集、验证、归档 |
|
|
26
|
+
| 地理位置 | `LocationField` | 接入地图服务 | 定位、地图选点、地址解析 |
|
|
27
|
+
| 数据管理列表 | `DataManagementList` | 接入数据查询 API | 分页、筛选、导出、批量操作、字段权限 |
|
|
28
|
+
|
|
29
|
+
### 示例
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import {
|
|
33
|
+
UserSelectField,
|
|
34
|
+
DepartmentSelectField,
|
|
35
|
+
AttachmentField,
|
|
36
|
+
} from 'openxiangda';
|
|
37
|
+
|
|
38
|
+
<UserSelectField name="owner" label="负责人" multiple={false} />
|
|
39
|
+
<DepartmentSelectField name="dept" label="所属部门" />
|
|
40
|
+
<AttachmentField name="files" label="附件" maxCount={5} />
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> ✅ 一句话原则:**这些场景看到了,直接抄上表,不要自己写。**
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. 推荐使用平台组件(可自定义但不建议从零重做)
|
|
48
|
+
|
|
49
|
+
| 场景 | 平台组件 | 何时考虑自定义 |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| 下拉选择 | `SelectField` | 需要复杂远程搜索、级联、虚拟滚动时,包装而非重写 |
|
|
52
|
+
| 日期选择 | `DateField` | 特殊日期范围联动、节假日高亮 |
|
|
53
|
+
| 表单容器 | `FormProvider` + `FormRenderer` | 需要极度定制布局(分栏、Tab 嵌套表单) |
|
|
54
|
+
| 审批时间线 | `ApprovalTimeline` | 需要自定义节点渲染(增加业务标签、跳转链接) |
|
|
55
|
+
| 摘要卡片 | `FormSummaryCard` | 需要高度自定义字段展示样式 |
|
|
56
|
+
|
|
57
|
+
自定义时仍应**包装**这些组件,而不是从 antd 从零实现一遍。
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 4. 自定义组件开发规范
|
|
62
|
+
|
|
63
|
+
### 4.1 正确:基于 antd 包装 + CSS 变量 + 语义类
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { Select, SelectProps } from 'antd';
|
|
67
|
+
import clsx from 'clsx';
|
|
68
|
+
|
|
69
|
+
type Option = { label: string; value: string };
|
|
70
|
+
|
|
71
|
+
interface CustomSelectProps extends Omit<SelectProps, 'options'> {
|
|
72
|
+
options: Option[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function CustomSelect({ options, className, ...rest }: CustomSelectProps) {
|
|
76
|
+
return (
|
|
77
|
+
<Select
|
|
78
|
+
className={clsx('w-full rounded-form', className)}
|
|
79
|
+
popupClassName="sy-app-workspace"
|
|
80
|
+
getPopupContainer={(trigger) => trigger.parentElement ?? document.body}
|
|
81
|
+
options={options}
|
|
82
|
+
{...rest}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
要点:
|
|
89
|
+
- 透传 `...rest`,保留 antd 全部 API。
|
|
90
|
+
- `popupClassName="sy-app-workspace"` 确保弹层应用平台样式作用域。
|
|
91
|
+
- `getPopupContainer` 解决弹层被裁切问题(详见第 7 节常见错误)。
|
|
92
|
+
- 使用 `w-full`、`rounded-form` 等语义类,不写 `style={{ width: '100%' }}`。
|
|
93
|
+
|
|
94
|
+
### 4.2 错误:从头实现选择器
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
// ❌ 反例:丢失键盘导航、可访问性、移动端体验、平台主题
|
|
98
|
+
function BadSelect({ options }) {
|
|
99
|
+
return (
|
|
100
|
+
<div style={{ border: '1px solid #d9d9d9', borderRadius: '4px', padding: '4px 11px' }}>
|
|
101
|
+
{options.map((opt) => (
|
|
102
|
+
<div key={opt.value} onClick={() => /* ... */}>
|
|
103
|
+
{opt.label}
|
|
104
|
+
</div>
|
|
105
|
+
))}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
问题清单:
|
|
112
|
+
- 硬编码颜色 `#d9d9d9` → 切主题失效。
|
|
113
|
+
- 丢失 antd 的键盘 / a11y / 输入法行为。
|
|
114
|
+
- 移动端无适配。
|
|
115
|
+
- 平台主题升级时不会跟随。
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 5. 平台组件的样式自定义
|
|
120
|
+
|
|
121
|
+
按推荐顺序由轻到重:
|
|
122
|
+
|
|
123
|
+
1. **className 注入 Tailwind 语义类**
|
|
124
|
+
```tsx
|
|
125
|
+
<UserSelectField className="w-full max-w-md" />
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
2. **CSS 变量覆盖**
|
|
129
|
+
```css
|
|
130
|
+
/* src/index.css */
|
|
131
|
+
:root,
|
|
132
|
+
.sy-app-workspace {
|
|
133
|
+
/* 调整表单控件圆角和品牌色 */
|
|
134
|
+
--sy-radius-md: 8px;
|
|
135
|
+
--sy-color-primary: #2563eb;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> 覆盖时只能使用 `style-system.md` 中定义的 `--sy-color-*`、`--sy-radius-*`、`--sy-spacing-*` 等变量名,自创变量不会生效。
|
|
140
|
+
|
|
141
|
+
3. **antd `ConfigProvider` 主题**
|
|
142
|
+
```tsx
|
|
143
|
+
<ConfigProvider theme={{ token: { colorPrimary: '#2563eb', borderRadius: 8 } }}>
|
|
144
|
+
<App />
|
|
145
|
+
</ConfigProvider>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
4. **禁止**:直接覆盖组件内部 class(`.ant-select-selector { ... }`)—— fragile,升级即坏。
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 6. 移动端组件策略
|
|
153
|
+
|
|
154
|
+
| 场景 | PC | Mobile |
|
|
155
|
+
| --- | --- | --- |
|
|
156
|
+
| 基础组件库 | `antd` | `antd-mobile` |
|
|
157
|
+
| 平台业务组件(如 `UserSelectField`) | ✅ 内置多端适配,**直接用** | ✅ 同左 |
|
|
158
|
+
| 自定义组件 | 自行 `useDeviceDetect` 分支或拆两份实现 | 同左 |
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
import { useDeviceDetect } from 'openxiangda';
|
|
162
|
+
import { Button as PcButton } from 'antd';
|
|
163
|
+
import { Button as MobileButton } from 'antd-mobile';
|
|
164
|
+
|
|
165
|
+
export function ActionButton(props) {
|
|
166
|
+
const { isMobile } = useDeviceDetect();
|
|
167
|
+
return isMobile ? <MobileButton {...props} /> : <PcButton {...props} />;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
> 推荐:能用平台组件就别自己写多端分支;自定义组件且双端差异大时,按 `src/pages/pc` 与 `src/pages/mobile` 整体拆分(详见 `architecture-patterns.md`)。
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 7. 常见错误(AI Agent 高频踩坑)
|
|
176
|
+
|
|
177
|
+
| 错误 | 正确做法 |
|
|
178
|
+
| --- | --- |
|
|
179
|
+
| 自己写人员选择器(搜员工 + 列表) | 用 `UserSelectField` |
|
|
180
|
+
| 自己实现部门树 | 用 `DepartmentSelectField` |
|
|
181
|
+
| 用 `<input type="file">` 上传 | 用 `AttachmentField` / `ImageField` |
|
|
182
|
+
| 用第三方富文本(TinyMCE 等) | 用 `EditorField` |
|
|
183
|
+
| 自己写列表 + 分页 + 导出 | 用 `DataManagementList` |
|
|
184
|
+
| `style={{ color: '#333', padding: 16 }}` 硬编码 | Tailwind 语义类或 CSS 变量 |
|
|
185
|
+
| Select / Date / Modal 弹层错位、被滚动容器裁切 | 加 `getPopupContainer={(trigger) => trigger.parentElement}`,并在弹层 `popupClassName` 上加 `sy-app-workspace` |
|
|
186
|
+
| 不分端,PC 组件直接放移动端 | 按端拆页 + 端内用对应 UI 库 |
|
|
187
|
+
| 覆盖 `.ant-xxx` 内部 class | 用 `className`、CSS 变量或 `ConfigProvider` 主题 |
|
|
188
|
+
| 在自定义组件中不透传 `...rest` / `ref` | 透传 props 与 `forwardRef`,保留底层组件全部能力 |
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 速查 Checklist(提交前自检)
|
|
193
|
+
|
|
194
|
+
- [ ] 涉及人员 / 部门 / 文件 / 图片 / 富文本 / 签名 / 地图 / 列表 → 用了平台组件?
|
|
195
|
+
- [ ] 自定义组件 → 基于 antd / antd-mobile 包装并透传 props?
|
|
196
|
+
- [ ] 样式 → 全部走 Tailwind 语义类 / CSS 变量 / ConfigProvider,无硬编码?
|
|
197
|
+
- [ ] 弹层 → 设置了 `getPopupContainer` 与 `sy-app-workspace` 弹层样式作用域?
|
|
198
|
+
- [ ] 多端 → PC 用 antd、Mobile 用 antd-mobile,业务逻辑共享?
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Form Component Registry
|
|
2
|
+
|
|
3
|
+
Use platform-supported component names in FormSchema.
|
|
4
|
+
|
|
5
|
+
Common field components:
|
|
6
|
+
|
|
7
|
+
| Component | Use |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `TextField` | Short text |
|
|
10
|
+
| `TextAreaField` | Long text |
|
|
11
|
+
| `NumberField` | Numeric value |
|
|
12
|
+
| `DateField` | Date or datetime |
|
|
13
|
+
| `CascadeDateField` | Date range |
|
|
14
|
+
| `SelectField` | Single select |
|
|
15
|
+
| `MultiSelectField` | Multi select |
|
|
16
|
+
| `RadioField` | Radio group |
|
|
17
|
+
| `CheckboxField` | Checkbox group |
|
|
18
|
+
| `UserSelectField` | User picker |
|
|
19
|
+
| `DepartmentSelectField` | Department picker |
|
|
20
|
+
| `AttachmentField` | File upload |
|
|
21
|
+
| `ImageField` | Image upload |
|
|
22
|
+
| `AddressField` | Address |
|
|
23
|
+
| `CascadeSelectField` | Cascading select |
|
|
24
|
+
| `AssociationFormField` | Select records from another form when a linked-form picker is required |
|
|
25
|
+
| `LocationField` | Location |
|
|
26
|
+
| `EditorField` | Rich text |
|
|
27
|
+
| `JSONField` | Structured JSON |
|
|
28
|
+
| `SubFormField` | Child table; do not recursively flatten child fields unless the runtime requires it |
|
|
29
|
+
|
|
30
|
+
Rules:
|
|
31
|
+
|
|
32
|
+
- Prefer simple field types first.
|
|
33
|
+
- Do not use a code page where a normal form can solve the workflow.
|
|
34
|
+
- Keep option values stable; labels may be user-facing.
|
|
35
|
+
- Avoid generated random field IDs after initial creation.
|
|
36
|
+
- Use field-level `rules` for validation. Required fields should set both `required: true` and `rules: [{ required: true, message: "..." }]` when a custom message is needed.
|
|
37
|
+
- For option components (`SelectField`, `MultiSelectField`, `RadioField`, `CheckboxField`, `CascadeSelectField`), always provide an `options` array. Use `options: [{ value: "stable_code", label: "显示名" }]`; if options will be loaded elsewhere later, still emit `options: []` so the runtime does not crash on `options.map(...)`.
|
|
38
|
+
- Do not rely on custom `relation` metadata alone for normal form pages. A `SelectField` with `relation` but no `options` can white-screen with `Cannot read properties of undefined (reading 'map')`. Use static `options`, `AssociationFormField`, or a custom code page that resolves linked records.
|
|
39
|
+
- For `NumberField`, prefer explicit `min`, `max`, `precision`, and `unit` when the business meaning is constrained.
|
|
40
|
+
- For `DateField`, use `mode: "date"` or `mode: "datetime"` and a stable `format` such as `YYYY-MM-DD` or `YYYY-MM-DD HH:mm`.
|
|
41
|
+
- For `CascadeDateField`, store a date range and document whether the value is inclusive.
|
|
42
|
+
- For `UserSelectField` and `DepartmentSelectField`, do not invent user or department IDs. Use runtime/platform selection.
|
|
43
|
+
- For `AttachmentField` and `ImageField`, do not hardcode OSS URLs in defaults unless the file has already been uploaded by platform tooling.
|
|
44
|
+
- For `SubFormField`, use `columns` for child fields and keep child `fieldId` values stable within the subform.
|
|
45
|
+
- `TextAreaField` is accepted by workspace tools and normalized to runtime `TextareaField`; prefer `TextAreaField` in OpenXiangda docs for readability.
|
|
46
|
+
|
|
47
|
+
Common validation rule examples:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
rules: [{ required: true, message: "请填写名称" }]
|
|
51
|
+
rules: [{ preset: "phone", message: "请输入有效手机号" }]
|
|
52
|
+
rules: [{ min: 0, message: "不能小于 0" }]
|
|
53
|
+
```
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# FormSchema
|
|
2
|
+
|
|
3
|
+
Form source lives in `sy-lowcode-app-workspace`. `schema.ts` describes fields, persistence, and rules; `page.tsx` renders the actual form page using platform components. The generated platform page must come from the workspace bundle, not the legacy default platform schema page.
|
|
4
|
+
|
|
5
|
+
Typical file:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
src/forms/<formCode>/schema.ts
|
|
9
|
+
src/forms/<formCode>/page.tsx
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The schema must default-export a `defineFormSchema(...)` result from `openxiangda`.
|
|
13
|
+
|
|
14
|
+
Minimal schema:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { defineFormSchema } from "openxiangda";
|
|
18
|
+
|
|
19
|
+
export default defineFormSchema({
|
|
20
|
+
formMeta: {
|
|
21
|
+
formUuid: "",
|
|
22
|
+
appType: process.env.OPENXIANGDA_APP_TYPE || "APP_XXXX",
|
|
23
|
+
title: "客户信息",
|
|
24
|
+
},
|
|
25
|
+
fields: [
|
|
26
|
+
{
|
|
27
|
+
fieldId: "customer_name",
|
|
28
|
+
componentName: "TextField",
|
|
29
|
+
label: "客户名称",
|
|
30
|
+
required: true,
|
|
31
|
+
rules: [{ required: true, message: "请填写客户名称" }],
|
|
32
|
+
placeholder: "请输入客户名称",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
fieldId: "customer_type",
|
|
36
|
+
componentName: "SelectField",
|
|
37
|
+
label: "客户类型",
|
|
38
|
+
options: [
|
|
39
|
+
{ value: "enterprise", label: "企业客户" },
|
|
40
|
+
{ value: "individual", label: "个人客户" },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Required Metadata
|
|
48
|
+
|
|
49
|
+
- `formMeta.formUuid`: live form ID. It may start empty during local authoring; publish tools can create and write it back.
|
|
50
|
+
- `formMeta.appType`: target app. In OpenXiangda mode, `OPENXIANGDA_APP_TYPE` may override local config.
|
|
51
|
+
- `formMeta.title`: user-facing form name.
|
|
52
|
+
- Do not require `formMeta.formType`; the current `openxiangda` schema type only requires `formUuid`, `appType`, and `title`.
|
|
53
|
+
|
|
54
|
+
## Field Rules
|
|
55
|
+
|
|
56
|
+
- Each persisted field needs a stable `fieldId`.
|
|
57
|
+
- Field labels should be user-facing Chinese names when the app is Chinese.
|
|
58
|
+
- Use platform-supported field components from `component-registry.md`.
|
|
59
|
+
- Do not generate fields that are only visual layout containers.
|
|
60
|
+
- Put validation rules on fields as `field.rules`. Do not put validation objects in top-level `schema.rules`.
|
|
61
|
+
- For option components (`SelectField`, `MultiSelectField`, `RadioField`, `CheckboxField`, `CascadeSelectField`), always include `options`. If a linked lookup is not ready, use `options: []` instead of omitting it.
|
|
62
|
+
|
|
63
|
+
## Effects vs Validation
|
|
64
|
+
|
|
65
|
+
Top-level `schema.rules` is reserved for `FormEffect[]`, not validation. A `FormEffect` must have both `when` and `then`:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
rules: [
|
|
69
|
+
{
|
|
70
|
+
id: "show_invoice_title",
|
|
71
|
+
when: { field: "need_invoice", operator: "eq", value: "yes" },
|
|
72
|
+
then: [{ action: "show", target: "invoice_title" }],
|
|
73
|
+
},
|
|
74
|
+
]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Do not generate old-style top-level validation rules like this:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// Wrong: this causes runtime white screens because `when` is missing.
|
|
81
|
+
rules: [
|
|
82
|
+
{ id: "rule_required_name", type: "validation", field: "name", required: true },
|
|
83
|
+
]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Use field-level validation instead:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
{
|
|
90
|
+
fieldId: "name",
|
|
91
|
+
componentName: "TextField",
|
|
92
|
+
label: "姓名",
|
|
93
|
+
required: true,
|
|
94
|
+
rules: [{ required: true, message: "请填写姓名" }],
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Layout
|
|
99
|
+
|
|
100
|
+
`layout` is optional. If omitted, the standard runtime renders fields in declaration order. When using `layout`, only use `FormLayoutNode` structures supported by `openxiangda` (`field`, `section`, `grid`, `tabs`, `steps`).
|
|
101
|
+
|
|
102
|
+
## Publish Rules
|
|
103
|
+
|
|
104
|
+
- Build output is registered through `openxiangda workspace publish --profile <name>`.
|
|
105
|
+
- The publish path uses `/openxiangda-api/v1` with `OPENXIANGDA_ACCESS_TOKEN`.
|
|
106
|
+
- Do not use AK/SK for new OpenXiangda work.
|
|
107
|
+
- Do not stop after `openxiangda form create`; that only creates the platform form shell. A form page is complete only after workspace publish builds and registers the bundle.
|
|
108
|
+
- If a published form page is blank and the browser console says `Cannot use 'in' operator to search for 'all' in undefined`, check for invalid top-level `schema.rules` entries missing `when`.
|
|
109
|
+
- If a published form page is blank and the browser console says `Cannot read properties of undefined (reading 'map')` near `SelectField`, check for option components missing `options`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Form Layout And Rules
|
|
2
|
+
|
|
3
|
+
## Layout
|
|
4
|
+
|
|
5
|
+
- Keep forms scan-friendly: sections, rows, and field order should follow the user's real workflow.
|
|
6
|
+
- Use groups for semantic sections, not for decoration.
|
|
7
|
+
- Required fields should be limited to data that is actually needed to submit.
|
|
8
|
+
- A process form should put approval-relevant fields near the top.
|
|
9
|
+
|
|
10
|
+
## Rules
|
|
11
|
+
|
|
12
|
+
Use declarative rules when possible:
|
|
13
|
+
|
|
14
|
+
- Required validation
|
|
15
|
+
- Numeric range validation
|
|
16
|
+
- Option visibility
|
|
17
|
+
- Field visibility
|
|
18
|
+
- Computed/default values
|
|
19
|
+
|
|
20
|
+
Avoid hidden custom script unless the behavior cannot be expressed declaratively.
|
|
21
|
+
|
|
22
|
+
## Data Management
|
|
23
|
+
|
|
24
|
+
Data management views are settings/resources around a form, not separate source forms. Store their live IDs under the current profile when they are created.
|