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,246 @@
|
|
|
1
|
+
# OpenXiangda 常见问题排查指南
|
|
2
|
+
|
|
3
|
+
> 本文档面向 AI Agent,收录在实际低代码项目(如 zjnu-dxyq-lowcode)开发中遇到的典型问题及解决方案。遇到报错或异常现象时,请优先在此查找匹配项;若无匹配,再结合源码与日志分析。
|
|
4
|
+
|
|
5
|
+
## 快速索引
|
|
6
|
+
|
|
7
|
+
| # | 问题 | 关键报错 / 现象 |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| 1 | antd/antd-mobile 弹层样式丢失 | Select/Modal 弹层无样式或跑到屏幕外 |
|
|
10
|
+
| 2 | SelectField options 为 undefined 导致 .map 报错 | `Cannot read properties of undefined (reading 'map')` |
|
|
11
|
+
| 3 | ESM 模块动态导入路径错误 | `ERR_UNSUPPORTED_ESM_URL_SCHEME` / `Cannot find module` |
|
|
12
|
+
| 4 | Windows 环境 OSS 上传路径错误 | 发布后资源 404,URL 含 `\` |
|
|
13
|
+
| 5 | 构建时表单 API 常量替换失败 | formApi.ts 中环境变量未替换 |
|
|
14
|
+
| 6 | Tailwind 样式被清除(PurgeCSS) | 生产构建后样式丢失 |
|
|
15
|
+
| 7 | React 多实例冲突 | `Invalid hook call` |
|
|
16
|
+
| 8 | 移动端 antd-mobile 组件样式不生效 | 组件渲染但无样式 |
|
|
17
|
+
| 9 | 数据格式理解错误导致展示异常 | 页面显示 `[object Object]` |
|
|
18
|
+
| 10 | workspace publish 环境变量缺失 | `OPENXIANGDA_ACCESS_TOKEN is not set` |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 问题:antd/antd-mobile 弹层样式丢失
|
|
23
|
+
|
|
24
|
+
**症状**:Select / Dropdown / Popup / Modal 等组件的弹出层没有样式,直接跑到屏幕外,或呈现为无样式的裸 HTML。
|
|
25
|
+
|
|
26
|
+
**根因**:当页面启用了 Shadow DOM 样式隔离(`cssIsolation: "shadow"`)时,antd 组件的弹出层默认会渲染到 `document.body`,从而脱离 Shadow DOM 的样式作用域;即使未使用 Shadow DOM,如果没有正确配置弹层容器,antd-mobile 的 Popup 也可能因 namespace 未被继承而失去样式。
|
|
27
|
+
|
|
28
|
+
**解决方案**:
|
|
29
|
+
1. 推荐使用 CSS Namespace 隔离(`cssIsolation: "namespace"`)替代 Shadow DOM。
|
|
30
|
+
2. 为 antd `ConfigProvider` 配置 `getPopupContainer` 指向页面根容器。
|
|
31
|
+
3. 对于 antd-mobile,确保 `Popup` / `Modal` 的 `getContainer` 指向正确容器。
|
|
32
|
+
4. 确保弹层的 `className` 中包含 namespace class(如 `sy-app-workspace`)。
|
|
33
|
+
|
|
34
|
+
**示例**:
|
|
35
|
+
```tsx
|
|
36
|
+
import { useRef } from 'react';
|
|
37
|
+
import { ConfigProvider } from 'antd';
|
|
38
|
+
|
|
39
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
40
|
+
|
|
41
|
+
<div ref={rootRef} className="sy-app-workspace">
|
|
42
|
+
<ConfigProvider getPopupContainer={() => rootRef.current!}>
|
|
43
|
+
<App />
|
|
44
|
+
</ConfigProvider>
|
|
45
|
+
</div>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**预防措施**:在 workspace 初始化阶段就统一约定弹层容器策略,避免后续逐个组件修复。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 问题:SelectField options 为 undefined 导致 .map 报错
|
|
53
|
+
|
|
54
|
+
**症状**:渲染 `SelectField` / `RadioField` / `CheckboxField` 时抛出 `Cannot read properties of undefined (reading 'map')`。
|
|
55
|
+
|
|
56
|
+
**根因**:这些需要枚举值的字段组件在 schema 中未提供 `options` 属性,组件内部直接调用 `options.map(...)`。
|
|
57
|
+
|
|
58
|
+
**解决方案**:
|
|
59
|
+
- 确保所有选择类字段在 schema 中至少包含 `options: []`。
|
|
60
|
+
- 使用 `createFormSchema` 工厂函数,它会自动为缺失的 options 字段补齐空数组。
|
|
61
|
+
|
|
62
|
+
**预防措施**:
|
|
63
|
+
```typescript
|
|
64
|
+
// form-schema.ts 中的保护逻辑
|
|
65
|
+
const NEEDS_OPTIONS = ['SelectField', 'RadioField', 'CheckboxField'];
|
|
66
|
+
|
|
67
|
+
for (const field of schema.fields) {
|
|
68
|
+
if (NEEDS_OPTIONS.includes(field.componentName) && !Array.isArray(field.options)) {
|
|
69
|
+
field.options = [];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 问题:ESM 模块动态导入路径错误
|
|
77
|
+
|
|
78
|
+
**症状**:执行 `sync-schema` 等脚本时报 `ERR_UNSUPPORTED_ESM_URL_SCHEME` 或 `Cannot find module`。
|
|
79
|
+
|
|
80
|
+
**根因**:Node.js 的 `import()` 在部分环境下(尤其是 Windows)不接受纯文件路径,必须使用 `file://` URL 形式。
|
|
81
|
+
|
|
82
|
+
**解决方案**:
|
|
83
|
+
```javascript
|
|
84
|
+
import { pathToFileURL } from 'url';
|
|
85
|
+
|
|
86
|
+
// 错误写法(可能在 Windows 下报错)
|
|
87
|
+
const module = await import(tmpFile);
|
|
88
|
+
|
|
89
|
+
// 正确写法
|
|
90
|
+
const module = await import(pathToFileURL(tmpFile).href);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**预防措施**:所有动态 `import()` 文件路径统一通过 `pathToFileURL().href` 转换,CI 中加入 Windows 平台冒烟测试。
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 问题:Windows 环境 OSS 上传路径错误
|
|
98
|
+
|
|
99
|
+
**症状**:发布完成后访问页面,CSS / JS 资源返回 404,浏览器 Network 面板中可见 URL 内出现反斜杠 `\`。
|
|
100
|
+
|
|
101
|
+
**根因**:Windows 文件系统使用 `\` 作为路径分隔符,而 OSS 对象 key 必须使用 `/`,未做归一化时直接拼接路径会导致非法 key。
|
|
102
|
+
|
|
103
|
+
**解决方案**:
|
|
104
|
+
```javascript
|
|
105
|
+
function toOssKeyPath(file) {
|
|
106
|
+
return String(file).replace(/\\/g, '/');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const ossKey = toOssKeyPath(path.relative(distDir, absFile));
|
|
110
|
+
await ossClient.put(ossKey, absFile);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**预防措施**:在上传函数入口处统一调用 `toOssKeyPath`,禁止直接拼接原始路径。
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 问题:构建时表单 API 常量替换失败
|
|
118
|
+
|
|
119
|
+
**症状**:生成的 `formApi.ts` 中,环境变量(如 `APP_ID`、`BASE_URL`)等常量值没有被正确替换为目标 profile 的真实值。
|
|
120
|
+
|
|
121
|
+
**根因**:旧的替换正则只覆盖了简单字符串字面量,无法匹配对象字面量、函数调用、模板字符串等复杂初始化表达式。
|
|
122
|
+
|
|
123
|
+
**解决方案**:使用更宽松的正则匹配 `=` 到 `;` 之间的任意表达式:
|
|
124
|
+
```javascript
|
|
125
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
126
|
+
const regex = new RegExp(
|
|
127
|
+
`((?:export\\s+)?const\\s+${escaped}\\s*=\\s*)([^;]+);`
|
|
128
|
+
);
|
|
129
|
+
source = source.replace(regex, (_, prefix) => `${prefix}${JSON.stringify(value)};`);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**预防措施**:替换后立即写一个 sanity check,比较替换前后的 AST 是否仅常量值发生变化。
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 问题:Tailwind 样式被清除(PurgeCSS 问题)
|
|
137
|
+
|
|
138
|
+
**症状**:开发环境(`vite dev`)下页面样式正常,但 `vite build` 生产产物中部分组件样式丢失。
|
|
139
|
+
|
|
140
|
+
**根因**:Tailwind v3+ 的 `content` 配置未包含来自 SDK / 组件库的源文件,组件库内使用的类名在编译期被 PurgeCSS 误删。
|
|
141
|
+
|
|
142
|
+
**解决方案**:
|
|
143
|
+
```javascript
|
|
144
|
+
// tailwind.config.cjs
|
|
145
|
+
module.exports = {
|
|
146
|
+
content: [
|
|
147
|
+
'./src/**/*.{ts,tsx}',
|
|
148
|
+
'./node_modules/openxiangda/packages/sdk/dist/**/*.{mjs,cjs}', // 关键:包含 SDK 分发文件
|
|
149
|
+
],
|
|
150
|
+
presets: [require('openxiangda/tailwind-preset')],
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**预防措施**:每次新增第三方组件库时,同步将其分发产物路径加入 `content` 数组;将 `pnpm build` 纳入 CI,对比构建产物体积异常增减。
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 问题:React 多实例冲突
|
|
159
|
+
|
|
160
|
+
**症状**:运行时抛出 `Invalid hook call. Hooks can only be called inside of the body of a function component.`,组件中所有 hooks 失效。
|
|
161
|
+
|
|
162
|
+
**根因**:项目最终打包产物中存在多个 React 实例,通常是因为组件库与宿主项目各自引入了不同版本的 `react` / `react-dom`。
|
|
163
|
+
|
|
164
|
+
**解决方案**:
|
|
165
|
+
```typescript
|
|
166
|
+
// vite.config.ts
|
|
167
|
+
import { defineConfig } from 'vite';
|
|
168
|
+
|
|
169
|
+
export default defineConfig({
|
|
170
|
+
resolve: {
|
|
171
|
+
dedupe: ['react', 'react-dom', 'antd'],
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**预防措施**:
|
|
177
|
+
- 在 `package.json` 中将 `react` / `react-dom` 设为 SDK 的 `peerDependencies`。
|
|
178
|
+
- 使用 `pnpm why react` 排查重复依赖。
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 问题:移动端 antd-mobile 组件样式不生效
|
|
183
|
+
|
|
184
|
+
**症状**:antd-mobile 组件 DOM 已渲染,但样式全部丢失,呈现裸 HTML。
|
|
185
|
+
|
|
186
|
+
**根因**:antd-mobile 使用 CSS-in-JS / 预编译样式,可能被 Tailwind 的 preflight 重置覆盖,或受 namespace 隔离影响。
|
|
187
|
+
|
|
188
|
+
**解决方案**:
|
|
189
|
+
1. 在 `vite.config.ts` 的 `optimizeDeps.include` 中显式添加 `antd-mobile`,避免运行时多次预构建。
|
|
190
|
+
2. 调整 Tailwind preflight 策略,确保不会覆盖 antd-mobile 的基础样式(必要时关闭 preflight 或使用 `important` 选择器)。
|
|
191
|
+
3. 确保 antd-mobile 组件渲染在 `sy-app-workspace` namespace 容器内,弹层 `getContainer` 指向该容器。
|
|
192
|
+
|
|
193
|
+
**示例**:
|
|
194
|
+
```typescript
|
|
195
|
+
// vite.config.ts
|
|
196
|
+
export default defineConfig({
|
|
197
|
+
optimizeDeps: {
|
|
198
|
+
include: ['antd-mobile', 'antd-mobile/es/locales/zh-CN'],
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**预防措施**:移动端项目模板中预置好 antd-mobile 的 vite 与 Tailwind 配置,禁止业务方随意修改 preflight。
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 问题:数据格式理解错误导致展示异常
|
|
208
|
+
|
|
209
|
+
**症状**:页面显示 `[object Object]`、空白,或筛选条件无法命中数据。
|
|
210
|
+
|
|
211
|
+
**根因**:AI 将平台返回的 `{label, value}` 结构字段当作纯字符串处理,直接渲染对象到 JSX。
|
|
212
|
+
|
|
213
|
+
**解决方案**:参考 `platform-data-model.md`,选择类字段在平台中存储为对象(单选为对象,多选为对象数组),渲染时需取 `label` 字段:
|
|
214
|
+
```tsx
|
|
215
|
+
// 错误:直接展示对象
|
|
216
|
+
<span>{record.department}</span> // 显示 [object Object]
|
|
217
|
+
|
|
218
|
+
// 正确:取 label
|
|
219
|
+
<span>{record.department?.label}</span>
|
|
220
|
+
|
|
221
|
+
// 多选字段
|
|
222
|
+
<span>{record.tags?.map(t => t.label).join(', ')}</span>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**预防措施**:
|
|
226
|
+
- 编辑器中为选择类字段统一定义 `OptionValue = { label: string; value: string }` 类型。
|
|
227
|
+
- 列表 / 详情页渲染前,封装 `formatOption(value)` 工具函数。
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 问题:workspace publish 环境变量缺失
|
|
232
|
+
|
|
233
|
+
**症状**:执行发布命令时报错 `OPENXIANGDA_ACCESS_TOKEN is not set` 或类似缺少配置项的错误。
|
|
234
|
+
|
|
235
|
+
**根因**:没有通过 `openxiangda` CLI 触发发布,CLI 负责从安全存储读取 profile 配置并注入到子进程的环境变量中;直接运行 `pnpm` 脚本会绕过这一步骤。
|
|
236
|
+
|
|
237
|
+
**解决方案**:
|
|
238
|
+
- 始终通过 CLI 发布:
|
|
239
|
+
```bash
|
|
240
|
+
openxiangda workspace publish --profile <profile-name>
|
|
241
|
+
```
|
|
242
|
+
- **不要**直接执行 `pnpm run publish:all` / `node scripts/publish.js`,这些命令缺少 token 注入。
|
|
243
|
+
|
|
244
|
+
**预防措施**:
|
|
245
|
+
- 在 workspace 的 `package.json` 中将真正的发布脚本设为内部脚本(前缀 `_`),README 与 SKILL 文档统一引导走 CLI 入口。
|
|
246
|
+
- 必要时在脚本入口处增加守卫,检测到 `OPENXIANGDA_ACCESS_TOKEN` 缺失时输出明确指引:`请通过 openxiangda workspace publish 发布`。
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Workflow V3 Reference
|
|
2
|
+
|
|
3
|
+
Workflow definitions are JSON objects saved by `openxiangda workflow create`.
|
|
4
|
+
|
|
5
|
+
Minimum shape:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"version": "v3",
|
|
10
|
+
"nodes": [
|
|
11
|
+
{ "id": "start", "type": "start", "data": { "label": "开始" } },
|
|
12
|
+
{ "id": "approve", "type": "approval", "data": { "label": "审批" } },
|
|
13
|
+
{ "id": "end", "type": "end", "data": { "label": "结束" } }
|
|
14
|
+
],
|
|
15
|
+
"edges": [
|
|
16
|
+
{ "id": "e1", "source": "start", "target": "approve" },
|
|
17
|
+
{ "id": "e2", "source": "approve", "target": "end" }
|
|
18
|
+
],
|
|
19
|
+
"flowConfig": {}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Rules:
|
|
24
|
+
|
|
25
|
+
- `nodes` and `edges` must be arrays.
|
|
26
|
+
- `version` must be `v3`.
|
|
27
|
+
- Publishing requires one `start` node and at least one `end` node.
|
|
28
|
+
- Each node needs `id`, `type`, and object `data`.
|
|
29
|
+
- Edges must reference existing node IDs.
|
|
30
|
+
- Keep live platform IDs out of the JSON when possible. Resolve `formUuid` and `workflowId` through CLI state.
|
|
31
|
+
- JS_CODE V2 supports trusted Node execution. For AI/admin logic use `runtimeMode: "trusted_node"`.
|
|
32
|
+
|
|
33
|
+
Supported node types:
|
|
34
|
+
|
|
35
|
+
- `start`
|
|
36
|
+
- `approval`
|
|
37
|
+
- `condition`
|
|
38
|
+
- `condition_branch`
|
|
39
|
+
- `end`
|
|
40
|
+
- `copy`
|
|
41
|
+
- `js_code`
|
|
42
|
+
- `branch`
|
|
43
|
+
- `data_retrieve_single`
|
|
44
|
+
- `data_retrieve_batch`
|
|
45
|
+
- `data_create`
|
|
46
|
+
- `data_update`
|
|
47
|
+
- `loop_container`
|
|
48
|
+
- `connector_call`
|
|
49
|
+
- `callback_wait`
|
|
50
|
+
- `work_notification`
|
|
51
|
+
- `dingtalk_card`
|
|
52
|
+
|
|
53
|
+
## JS_CODE V2
|
|
54
|
+
|
|
55
|
+
Inline:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"id": "calc",
|
|
60
|
+
"type": "js_code",
|
|
61
|
+
"data": {
|
|
62
|
+
"label": "计算",
|
|
63
|
+
"runtimeMode": "trusted_node",
|
|
64
|
+
"sourceType": "inline",
|
|
65
|
+
"code": "const crypto = require('crypto'); variables.hash = crypto.createHash('sha256').update('x').digest('hex'); return variables.hash;",
|
|
66
|
+
"timeout": 30000
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
File snapshot:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"id": "sync_customer",
|
|
76
|
+
"type": "js_code",
|
|
77
|
+
"data": {
|
|
78
|
+
"label": "同步客户",
|
|
79
|
+
"runtimeMode": "trusted_node",
|
|
80
|
+
"sourceType": "file_snapshot",
|
|
81
|
+
"scriptCode": "sync_customer",
|
|
82
|
+
"sourceFile": {
|
|
83
|
+
"localPath": "src/js-code-nodes/sync_customer/index.ts"
|
|
84
|
+
},
|
|
85
|
+
"timeout": 30000
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
AI-authored JS_CODE source must be TypeScript under `sy-lowcode-app-workspace/src/js-code-nodes/<scriptCode>/index.ts`. When validating or creating, the CLI runs `pnpm build-js-code --script <scriptCode>`, which runs TypeScript validation first, bundles to `dist/js-code-nodes/<scriptCode>/index.cjs`, uploads the bundle, and replaces `sourceFile.localPath` with immutable snapshot metadata. Scripts can export `export default async function (ctx) {}` or `module.exports = async (ctx) => {}` and call `ctx.platform.api` or global `platform.api`; the default API namespace is `/openxiangda-api/v1`.
|
|
91
|
+
|
|
92
|
+
Field permission config lives in `flowConfig` by node ID:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"flowConfig": {
|
|
97
|
+
"approve": [
|
|
98
|
+
{ "fieldId": "amount", "fieldBehavior": "READONLY" },
|
|
99
|
+
{ "fieldId": "remark", "fieldBehavior": "NORMAL" }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Allowed `fieldBehavior` values: `NORMAL`, `READONLY`, `HIDDEN`.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Workspace State
|
|
2
|
+
|
|
3
|
+
OpenXiangda project state lives in `.openxiangda/state.json`.
|
|
4
|
+
|
|
5
|
+
Tokens never belong in the project. User tokens live in `~/.openxiangda/profiles.json`.
|
|
6
|
+
|
|
7
|
+
## Shape
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"version": 1,
|
|
12
|
+
"profiles": {
|
|
13
|
+
"dev": {
|
|
14
|
+
"baseUrl": "https://dev-lowcode.example.com/service",
|
|
15
|
+
"appType": "APP_DEV",
|
|
16
|
+
"resources": {
|
|
17
|
+
"forms": {
|
|
18
|
+
"customer": {
|
|
19
|
+
"formUuid": "FORM_XXX"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"pages": {
|
|
23
|
+
"dashboard": {
|
|
24
|
+
"pageId": "PAGE_XXX",
|
|
25
|
+
"routeKey": "dashboard",
|
|
26
|
+
"legacyFormUuid": "FORM_LEGACY_PAGE"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"workflows": {},
|
|
30
|
+
"automations": {},
|
|
31
|
+
"menus": {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Rules
|
|
39
|
+
|
|
40
|
+
- Profile is the deployment boundary.
|
|
41
|
+
- `baseUrl` is the backend API base. On standard private deployments it is `<origin>/service`; management pages use `/platform`, and app runtime pages use `/view`.
|
|
42
|
+
- Local resource keys are logical codes.
|
|
43
|
+
- Live IDs are nested under the profile that produced them.
|
|
44
|
+
- A prod publish must not read dev IDs.
|
|
45
|
+
- Before publishing to another platform, run `openxiangda workspace bind --profile <name> --app-type <APP_XXX>`.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openxiangda-app
|
|
3
|
+
description: Manage OpenXiangda low-code apps, profiles, workspace initialization, workspace binding, app snapshots, menus, and profile-isolated resource state through the openxiangda CLI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenXiangda App
|
|
7
|
+
|
|
8
|
+
Use this when the user needs to create, bind, inspect, or publish an app on a private OpenXiangda platform.
|
|
9
|
+
|
|
10
|
+
## Required Context
|
|
11
|
+
|
|
12
|
+
Always start from the current profile and workspace binding:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
openxiangda env --profile <name>
|
|
16
|
+
openxiangda auth status --profile <name>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If the workspace is not bound:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
openxiangda app list --profile <name>
|
|
23
|
+
openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If there is no local app workspace yet:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-type APP_XXX
|
|
30
|
+
cd ./my-app-workspace
|
|
31
|
+
pnpm install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For menu work:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
openxiangda menu list --profile <name>
|
|
38
|
+
openxiangda menu create main --name "主菜单" --type nav --profile <name>
|
|
39
|
+
openxiangda menu create customer-entry --name "客户信息" --type receipt --form-code customer --profile <name>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If the app does not exist:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
openxiangda app create "应用名称" --profile <name>
|
|
46
|
+
openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Rules
|
|
50
|
+
|
|
51
|
+
- Never ask for AK/SK.
|
|
52
|
+
- Always pass `--profile` for publish or cross-platform operations.
|
|
53
|
+
- Use `openxiangda workspace init <dir>` before page/form work when the user starts from a new empty directory.
|
|
54
|
+
- Store platform-specific IDs only in `.openxiangda/state.json`.
|
|
55
|
+
- Use logical local codes for forms, pages, workflows, automations, and menus.
|
|
56
|
+
- Use `openxiangda app snapshot <APP_XXX> --profile <name> --json` before changing an existing app.
|
|
57
|
+
|
|
58
|
+
## Resource State
|
|
59
|
+
|
|
60
|
+
Read `../../references/workspace-state.md` when changing `.openxiangda/state.json`.
|
|
61
|
+
|
|
62
|
+
Read `../../references/openxiangda-api.md` when exact endpoint fields are needed.
|
|
63
|
+
|
|
64
|
+
Read `../../references/architecture-patterns.md` to understand the overall app structure (how forms, pages, menus, workflows, and permissions compose into an app, and the recommended `src/forms` / `src/pages` layout) before scaffolding or restructuring an app workspace.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openxiangda-core
|
|
3
|
+
description: Core OpenXiangda CLI workflow for normal-user token login, platform profiles, workspace initialization, workspace binding, multi-platform publishing, and lightweight app inspection.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenXiangda Core
|
|
7
|
+
|
|
8
|
+
## Login
|
|
9
|
+
|
|
10
|
+
Use ordinary platform login:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
openxiangda login https://lowcode.example.com --profile dev
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The CLI creates a one-time login session, opens the platform authorization page, polls the backend, and stores the returned `accessToken` and `refreshToken` in `~/.openxiangda/profiles.json` with file mode `0600`.
|
|
17
|
+
|
|
18
|
+
Do not request or generate AK/SK credentials.
|
|
19
|
+
|
|
20
|
+
## Private Routing
|
|
21
|
+
|
|
22
|
+
OpenXiangda private deployments use fixed public paths:
|
|
23
|
+
|
|
24
|
+
- `/service` for backend APIs.
|
|
25
|
+
- `/platform` for platform management pages and login redirects.
|
|
26
|
+
- `/view` for app runtime pages.
|
|
27
|
+
|
|
28
|
+
The CLI profile stores the API base. If the user enters a root domain, `/platform` URL, or `/view` URL, normalize it to `<origin>/service` before calling OpenXiangda APIs. Never call `/openxiangda-api/v1` directly at the root domain.
|
|
29
|
+
|
|
30
|
+
## Profiles
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
openxiangda platform add dev https://dev-lowcode.example.com
|
|
34
|
+
openxiangda platform add prod https://lowcode.example.com/platform
|
|
35
|
+
openxiangda platform list
|
|
36
|
+
openxiangda platform use dev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Use `--profile` for every destructive or publishing action. Treat the profile as the deployment boundary.
|
|
40
|
+
|
|
41
|
+
Run write commands sequentially in the same workspace because they update `.openxiangda/state.json`. Read-only commands such as list, pull, snapshot, and inspect may run in parallel.
|
|
42
|
+
|
|
43
|
+
## Workspace State
|
|
44
|
+
|
|
45
|
+
Create a workspace when the current project does not already contain a `sy-lowcode-app-workspace`:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
openxiangda workspace init ./my-app-workspace --profile dev --app-type APP_DEV
|
|
49
|
+
cd ./my-app-workspace
|
|
50
|
+
pnpm install
|
|
51
|
+
openxiangda env --profile dev
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If the workspace already exists, bind each platform to its own app, then publish from `sy-lowcode-app-workspace`:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
openxiangda app list --profile dev
|
|
58
|
+
openxiangda app create "测试应用" --profile dev
|
|
59
|
+
openxiangda workspace bind --profile dev --app-type APP_DEV
|
|
60
|
+
openxiangda workspace bind --profile prod --app-type APP_PROD
|
|
61
|
+
cd /path/to/sy-lowcode-app-workspace
|
|
62
|
+
openxiangda workspace publish --profile dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Read-only diagnosis can use resource commands:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
openxiangda form list --profile dev
|
|
69
|
+
openxiangda form pull customer --profile dev
|
|
70
|
+
openxiangda page list --profile dev
|
|
71
|
+
openxiangda workflow list --form-code customer --profile dev
|
|
72
|
+
openxiangda automation list --form-code customer --profile dev
|
|
73
|
+
openxiangda permission role-list --profile dev
|
|
74
|
+
openxiangda settings get customer --profile dev
|
|
75
|
+
openxiangda inspect app --profile dev --json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`openxiangda form create`, `form publish`, and `page publish` are low-level repair commands. Do not use them as the normal AI page generation path.
|
|
79
|
+
|
|
80
|
+
Project state is stored in `.openxiangda/state.json`:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"version": 1,
|
|
85
|
+
"profiles": {
|
|
86
|
+
"dev": {
|
|
87
|
+
"baseUrl": "https://dev-lowcode.example.com/service",
|
|
88
|
+
"appType": "APP_DEV",
|
|
89
|
+
"resources": {
|
|
90
|
+
"forms": {},
|
|
91
|
+
"pages": {},
|
|
92
|
+
"workflows": {},
|
|
93
|
+
"automations": {},
|
|
94
|
+
"menus": {},
|
|
95
|
+
"roles": {},
|
|
96
|
+
"pagePermissionGroups": {},
|
|
97
|
+
"formPermissionGroups": {}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The CLI reads `.openxiangda/state.json` from the current working directory. Run workspace commands from the workspace root unless the CLI has explicit parent-directory discovery in the current version.
|
|
105
|
+
|
|
106
|
+
## Inspection
|
|
107
|
+
|
|
108
|
+
Use snapshots to understand an app before editing:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
openxiangda app snapshot APP_XXX --profile dev --json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The snapshot endpoint aggregates app metadata, forms, menus, code pages, release summaries, and permission hints using the logged-in user's permissions.
|
|
115
|
+
|
|
116
|
+
## Publishing
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
openxiangda workspace publish --profile prod
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The CLI checks that the target profile is logged in and bound to an app. It then runs the workspace publish script with these environment variables:
|
|
123
|
+
|
|
124
|
+
- `OPENXIANGDA_PROFILE`
|
|
125
|
+
- `OPENXIANGDA_BASE_URL`
|
|
126
|
+
- `OPENXIANGDA_ACCESS_TOKEN`
|
|
127
|
+
- `OPENXIANGDA_APP_TYPE`
|
|
128
|
+
|
|
129
|
+
Publishing scripts must read these values instead of AK/SK.
|
|
130
|
+
|
|
131
|
+
The publish script is responsible for:
|
|
132
|
+
|
|
133
|
+
1. Scanning `src/forms/*/schema.ts` and `page.tsx` for normal and workflow form pages.
|
|
134
|
+
2. Creating or binding platform form shells only as needed.
|
|
135
|
+
3. Building form runtime, form bundles, and code page bundles.
|
|
136
|
+
4. Uploading assets to OSS.
|
|
137
|
+
5. Registering bundles through `/openxiangda-api/v1` with `OPENXIANGDA_ACCESS_TOKEN`.
|
|
138
|
+
|
|
139
|
+
## References
|
|
140
|
+
|
|
141
|
+
- `../../references/openxiangda-api.md` — exact endpoint contracts.
|
|
142
|
+
- `../../references/workspace-state.md` — `.openxiangda/state.json` shape and profile-scoped resource maps.
|
|
143
|
+
- `../../references/architecture-patterns.md` — overall architecture of an OpenXiangda app workspace (CRUD data flow, page/form layering, recommended directory organization). Read this when you need to understand how forms, pages, workflows, and platform state fit together end-to-end.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openxiangda-form
|
|
3
|
+
description: Create, bind, generate, sync, and publish OpenXiangda normal form pages and workflow form pages through sy-lowcode-app-workspace bundles, profile state, and token-based workspace publish.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenXiangda Form
|
|
7
|
+
|
|
8
|
+
Use this when the user asks to create or update normal forms, workflow forms, form page source, form bundles, or form runtime publishing.
|
|
9
|
+
|
|
10
|
+
## Required Workspace Flow
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
openxiangda env --profile <name>
|
|
14
|
+
openxiangda form list --profile <name>
|
|
15
|
+
cd /path/to/sy-lowcode-app-workspace
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If the workspace does not exist yet, create it before writing form source:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-type APP_XXX
|
|
22
|
+
cd ./my-app-workspace
|
|
23
|
+
pnpm install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Create or edit workspace source:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
src/forms/<formCode>/
|
|
30
|
+
├── schema.ts
|
|
31
|
+
└── page.tsx
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then publish:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
openxiangda workspace publish --profile <name>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The workspace publish script receives `OPENXIANGDA_BASE_URL`, `OPENXIANGDA_ACCESS_TOKEN`, and `OPENXIANGDA_APP_TYPE` from the CLI. It creates/binds the platform form shell only when needed, syncs form metadata, builds the React form page bundle, uploads assets, and registers the bundle.
|
|
41
|
+
|
|
42
|
+
## Low-level Commands
|
|
43
|
+
|
|
44
|
+
Use these only for diagnosis, binding existing resources, or repairing a broken publish state:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
openxiangda form bind customer --form-uuid FORM_XXX --profile <name>
|
|
48
|
+
openxiangda form pull customer --profile <name> --json
|
|
49
|
+
openxiangda form create customer --name "客户信息" --profile <name>
|
|
50
|
+
openxiangda form publish customer --bundle-url <url> --profile <name>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Do not use `openxiangda form create` as the normal way to generate a user-facing page. It creates the old platform form shell and will show the legacy default schema until a workspace bundle is published.
|
|
54
|
+
|
|
55
|
+
## Workspace Form Rules
|
|
56
|
+
|
|
57
|
+
Read these references only when writing or reviewing schema:
|
|
58
|
+
|
|
59
|
+
- `../../references/forms/form-schema.md`
|
|
60
|
+
- `../../references/forms/component-registry.md`
|
|
61
|
+
- `../../references/forms/layout-and-rules.md`
|
|
62
|
+
- `../../references/platform-data-model.md` — how each field type is persisted (JSONB, `{label, value}` for option fields, attachment shape). Consult before designing schema or wiring values.
|
|
63
|
+
- `../../references/component-guide.md` — when to pick platform form components vs. custom widgets, and the option-component rules.
|
|
64
|
+
|
|
65
|
+
## Rules
|
|
66
|
+
|
|
67
|
+
- Prefer deterministic `formCode` as local key; bind live `formUuid` under the active profile.
|
|
68
|
+
- For multi-platform publishing, create or bind the form separately for each profile.
|
|
69
|
+
- Do not copy `formUuid` from dev to prod unless the target platform explicitly already uses that ID.
|
|
70
|
+
- Keep `schema.ts` and `page.tsx` as the source for fields/layout/rules and presentation; generated build output is not the source of truth.
|
|
71
|
+
- In `schema.ts`, import `defineFormSchema` from `openxiangda` and default-export the schema.
|
|
72
|
+
- Put validation on field-level `rules`; never generate old top-level validation arrays under `schema.rules`. Top-level `rules` is only for `FormEffect[]` with `when` and `then`.
|
|
73
|
+
- Always provide `options` for option components. `SelectField`, `MultiSelectField`, `RadioField`, `CheckboxField`, and `CascadeSelectField` must not be emitted with `options` undefined. See `../../references/component-guide.md` for the full list and `../../references/platform-data-model.md` for the `{label, value}` storage contract.
|
|
74
|
+
- Workflow form pages use the same workspace form structure plus workflow v3 configuration; publish the form page bundle through workspace publish before treating it as complete.
|
|
75
|
+
- Use `openxiangda form pull` or app snapshot before overwriting an existing form.
|
|
76
|
+
- Before assuming a value shape (e.g. dates, attachments, member fields, option fields), verify against `../../references/platform-data-model.md` instead of guessing.
|