openxiangda 1.0.154 → 1.0.156
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/openxiangda-skills/SKILL.md +1 -0
- package/openxiangda-skills/references/component-guide.md +2 -0
- package/openxiangda-skills/references/pages/page-sdk.md +19 -0
- package/openxiangda-skills/references/troubleshooting.md +17 -5
- package/openxiangda-skills/skills/openxiangda-form/SKILL.md +1 -0
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +1 -0
- package/package.json +1 -1
- package/packages/sdk/dist/components/index.cjs +2 -1
- package/packages/sdk/dist/components/index.cjs.map +1 -1
- package/packages/sdk/dist/components/index.mjs +2 -1
- package/packages/sdk/dist/components/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/index.cjs +846 -796
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +1 -1
- package/packages/sdk/dist/runtime/index.d.ts +1 -1
- package/packages/sdk/dist/runtime/index.mjs +232 -182
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/react.cjs +274 -224
- package/packages/sdk/dist/runtime/react.cjs.map +1 -1
- package/packages/sdk/dist/runtime/react.d.mts +10 -2
- package/packages/sdk/dist/runtime/react.d.ts +10 -2
- package/packages/sdk/dist/runtime/react.mjs +146 -96
- package/packages/sdk/dist/runtime/react.mjs.map +1 -1
- package/templates/openxiangda-react-spa/AGENTS.md +1 -0
|
@@ -59,6 +59,7 @@ OpenXiangda supports two workspace modes. Classic `sy-lowcode-app-workspace` pub
|
|
|
59
59
|
- ✅ In React SPA apps, keep imports on public package entrypoints such as `openxiangda`, `openxiangda/runtime`, and `openxiangda/runtime/react`. The default template already groups large vendor chunks; if a bundle is too large, use route-level lazy loading and Vite `manualChunks`, not `openxiangda/packages/sdk/dist/...` internal paths.
|
|
60
60
|
- ✅ For image thumbnails or lightweight previews, use `imageCompression` on `ImageField` or `AttachmentField`. Keep the original `url` for the source file and use `thumbUrl` / `previewUrl` / `variants` for smaller images.
|
|
61
61
|
- ✅ In form context, let `ImageField` and `AttachmentField` own preview UX. In standalone React SPA pages, use `AttachmentPreviewList`, `ImagePreviewGrid`, or `useFilePreview` from `openxiangda/runtime/react`; do not create a fake form context or import internal `FilePreviewContent` / `useFilePreviewController`. All paths must honor platform capability checks, and apps must not maintain local previewable-extension allowlists.
|
|
62
|
+
- ✅ When a custom editable React SPA surface genuinely needs `FormProvider`, set `config.api` from `usePageFormRuntimeApi()`; use `createPageFormRuntimeApi(sdk)` outside hooks. Never implement the bridge as `api.request: config => sdk.request(...)`, because JSON transport drops `responseType: "blob"` and breaks binary attachment previews.
|
|
62
63
|
- ✅ For data delivery with files, use `openxiangda form export <formCode> --mode xlsx|xlsx-images|package --profile <name>`. `package` writes a zip with `data.xlsx`, `attachments/`, and `manifest.json`; do not hand-write export URLs or stream binary content to stdout.
|
|
63
64
|
- ✅ List pages, linked options, remote selectors, and report drill-downs must use paginated server-side queries with explicit searchable fields. Do not fetch a large page and filter in local state.
|
|
64
65
|
- ✅ Treat workflow forms as an exception. Ordinary ticket/order/task/asset lifecycles use status fields, state machines, action logs, permissions, and automations; workflows are for real approval tasks.
|
|
@@ -89,6 +89,8 @@ OSS 浏览器直传所需的 CORS 规则在 `src/resources/storage/<code>.json`
|
|
|
89
89
|
|
|
90
90
|
预览能力也由运行时统一接管:表单上下文使用 `ImageField` / `AttachmentField`;自定义 React SPA 页面展示任意业务数据中的只读附件时,从 `openxiangda/runtime/react` 使用 `ImagePreviewGrid` / `AttachmentPreviewList`,或使用 `useFilePreview({ items })` 接入自定义卡片、表格和详情操作。不要为只读附件伪造 `FormProvider`。
|
|
91
91
|
|
|
92
|
+
自定义编辑页确需嵌入平台字段时,使用 `usePageFormRuntimeApi()` 生成 `FormProvider` 的 `config.api`;非 Hook 场景使用 `createPageFormRuntimeApi(sdk)`。不要把所有请求手工转给 `sdk.request()`,因为附件预览的 `responseType: "blob"` 必须走 PageSdk 二进制下载通道。
|
|
93
|
+
|
|
92
94
|
```tsx
|
|
93
95
|
import { AttachmentPreviewList, ImagePreviewGrid } from "openxiangda/runtime/react"
|
|
94
96
|
|
|
@@ -134,6 +134,25 @@ export function RecordFiles({ record }) {
|
|
|
134
134
|
|
|
135
135
|
These APIs must render below `OpenXiangdaProvider` and `OpenXiangdaPageProvider`. `useFilePreview` returns `canPreview`, `getCapability`, `open`, `download`, `isOpening`, and `host`. Render `host` once in the component tree. Do not import the internal `FilePreviewContent` or `useFilePreviewController`, create a fake `FormProvider`, or keep a local previewable-extension list.
|
|
136
136
|
|
|
137
|
+
For a real custom edit surface that embeds platform form fields, adapt PageSdk with the public form runtime API instead of hand-writing a request bridge:
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { AttachmentField, FormProvider } from "openxiangda"
|
|
141
|
+
import { usePageFormRuntimeApi } from "openxiangda/runtime/react"
|
|
142
|
+
|
|
143
|
+
const api = usePageFormRuntimeApi()
|
|
144
|
+
|
|
145
|
+
<FormProvider
|
|
146
|
+
config={{ api, appType, formUuid: "training_lesson", mode: "edit" }}
|
|
147
|
+
schema={schema}
|
|
148
|
+
initialValues={values}
|
|
149
|
+
>
|
|
150
|
+
<AttachmentField fieldId="materials" label="Materials" />
|
|
151
|
+
</FormProvider>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Use `createPageFormRuntimeApi(sdk)` when hooks are unavailable. Both APIs preserve JSON envelopes, route `responseType: "blob"` through `sdk.transport.download`, and normalize ticket content URLs such as `/file/download-by-ticket/*` with the current PageSdk `servicePrefix`. They do not rewrite `/view/*` page URLs or absolute storage URLs. Never forward every form request to `sdk.request`, and never prepend `/service` in application code.
|
|
155
|
+
|
|
137
156
|
Shareable file preview ticket:
|
|
138
157
|
|
|
139
158
|
```ts
|
|
@@ -16,19 +16,31 @@
|
|
|
16
16
|
| 8 | 移动端 antd-mobile 组件样式不生效 | 组件渲染但无样式 |
|
|
17
17
|
| 9 | 数据格式理解错误导致展示异常 | 页面显示 `[object Object]` |
|
|
18
18
|
| 10 | workspace publish 环境变量缺失 | `OPENXIANGDA_ACCESS_TOKEN is not set` |
|
|
19
|
-
| 11 | DOCX
|
|
19
|
+
| 11 | DOCX 二进制契约异常 | 真实字节不是 `PK`,或自定义 FormProvider 把 Blob 请求错误转给 JSON 通道 |
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
## 问题:DOCX 响应是 Base64 文本
|
|
24
24
|
|
|
25
|
-
**症状**:ticket metadata 正常返回 `renderMode: "docx-html"` 和 `canPreview: true`,`/service/file/preview-by-ticket/:ticket` 也是 HTTP 200
|
|
25
|
+
**症状**:ticket metadata 正常返回 `renderMode: "docx-html"` 和 `canPreview: true`,`/service/file/preview-by-ticket/:ticket` 也是 HTTP 200,但 Word 预览仍然解析失败或提示“文件内容响应不是二进制数据”。
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
**判定**:DOCX 本质是 ZIP,真实原始字节应以 `PK`(十六进制 `50 4B 03 04`)开头。Chrome DevTools 可能把二进制响应显示成 `UEsDB...`,这只是展示形式;使用 `response.arrayBuffer()`、下载文件或服务端探针检查真实前四字节。只有真实字节是 ASCII `UEsDB` 时,才是 Base64 包装对象。
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**解决方案**:若真实字节是 `UEsDB`,升级平台服务端和 OpenXiangda SDK,使用严格 ZIP 校验后的兼容解码。若真实字节已经是 `PK`,检查自定义编辑页的 `FormProvider`:`config.api` 必须来自 `usePageFormRuntimeApi()`,非 Hook 场景使用 `createPageFormRuntimeApi(sdk)`。不要手写 `api.request: config => sdk.request(...)`,也不要在业务页面自行调用 `atob`。
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
**验证方式**:真实响应字节以 `PK` 开头;组件的 Blob 请求进入 `sdk.transport.download`,并最终向 DOCX 渲染器传入 `Blob`。若下载后的文件真实字节仍是 ASCII `UEsDB`,再检查服务端版本和多节点部署一致性。
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 问题:附件下载打开站点根 `/file/` 并返回 404
|
|
36
|
+
|
|
37
|
+
**症状**:附件下载 ticket 创建成功,但浏览器打开 `https://host/file/...`,实际平台文件接口位于 `https://host/service/file/...`。
|
|
38
|
+
|
|
39
|
+
**原因**:应用手写了 PageSdk 到 `FormProvider` 的不完整适配,或使用了未归一化的 ticket payload,绕过了当前 runtime 的 `servicePrefix`。
|
|
40
|
+
|
|
41
|
+
**解决方案**:升级 OpenXiangda,并让 `FormProvider.config.api` 来自 `usePageFormRuntimeApi()` 或 `createPageFormRuntimeApi(sdk)`。SDK 会把 ticket payload 中的 `/file/*` 内容地址补成当前 `servicePrefix`,同时保留 `/view/*` 页面地址和绝对 OSS URL。业务代码不要直接 `window.open(ticket.downloadUrl)` 后再自行猜测前缀。
|
|
42
|
+
|
|
43
|
+
**验证方式**:点击下载后地址应为 `/service/file/download-by-ticket/:ticket` 或服务端返回的绝对存储 URL,不应是站点根 `/file/*`。
|
|
32
44
|
|
|
33
45
|
---
|
|
34
46
|
|
|
@@ -164,6 +164,7 @@ Read these references only when writing or reviewing schema:
|
|
|
164
164
|
- 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.
|
|
165
165
|
- Do not emit raw native form controls in app/workspace source. For basic entry use `TextField`, `TextAreaField`, `NumberField`, `DateField`, `SelectField`, `RadioField`, etc.; for platform-specific entry use `UserSelectField`, `DepartmentSelectField`, `AttachmentField`, `ImageField`, `EditorField`, `DigitalSignatureField`, and `LocationField`.
|
|
166
166
|
- For image thumbnails or lightweight detail previews, configure `imageCompression` on `ImageField` or `AttachmentField`. The submitted value still keeps the original `url`; compressed variants are written to `thumbUrl`, `previewUrl`, and `variants`.
|
|
167
|
+
- React SPA custom edit surfaces that render `FormProvider` must set `config.api` from `usePageFormRuntimeApi()` or `createPageFormRuntimeApi(sdk)`. Do not map all field requests to `sdk.request`, because attachment and image preview require the PageSdk Blob download channel.
|
|
167
168
|
- For OSS-backed image or attachment fields, declare a storage resource first, then set `uploadProvider: "oss"` and `storageCode`. Do not hardcode OSS URLs or credentials in schema/page source; if compressed output uses `webp`, storage `allowedExtensions` must include `webp`.
|
|
168
169
|
- Workflow form pages use the same workspace form structure plus workflow v3 configuration. In legacy workspaces, publish the form page bundle through workspace publish before treating it as complete. In React SPA workspaces, `workspace publish --form` syncs schema only, and the SPA default process pages render through `runtime deploy`.
|
|
169
170
|
- After editing one form, use `workspace publish --form <formCode>` or preview `--changed --dry-run`; do not run full workspace publish by default.
|
|
@@ -128,5 +128,6 @@ Read these references only when editing page code:
|
|
|
128
128
|
- Pick components per `references/component-guide.md`: prefer the platform component, fall back to Ant Design / antd-mobile wrappers, and only build a custom component when neither fits. In app/workspace page code, do not emit raw `<input>`, `<select>`, `<textarea>`, file inputs, hand-written pickers, or hand-written uploaders.
|
|
129
129
|
- When a page misbehaves (lost styles, `options is undefined`, option labels showing raw values, etc.), consult `references/troubleshooting.md` before patching symptoms.
|
|
130
130
|
- For custom portal pages and business modals, do not temporarily embed a single `FormProvider` field component from the standard form runtime. If a standard component is required, navigate to a full standard form page or render a complete `StandardFormPage` inside a dedicated carrier route.
|
|
131
|
+
- If a complete custom edit surface intentionally embeds platform fields in `FormProvider`, set `config.api` from `usePageFormRuntimeApi()` (or `createPageFormRuntimeApi(sdk)` outside hooks). Never hand-write a JSON-only `sdk.request` bridge; it breaks Blob preview and download contracts.
|
|
131
132
|
- Keep PC and mobile portal styles separate. Do not share one form UI implementation across both viewports unless the surrounding shell, modal layer, date picker, and bottom-sheet behavior have been tested in both contexts.
|
|
132
133
|
- After introducing Ant Design overlays, date/datetime fields, or mobile bottom-sheet selectors, verify that global button, modal, picker, and sheet styles do not leak into the host business page.
|
package/package.json
CHANGED
|
@@ -4659,7 +4659,8 @@ var useFilePreviewController = ({
|
|
|
4659
4659
|
);
|
|
4660
4660
|
url = typeof ticket === "string" ? ticket : ticket?.downloadUrl || ticket?.relayUrl || ticket?.url || url;
|
|
4661
4661
|
}
|
|
4662
|
-
|
|
4662
|
+
const resolvedUrl = resolvePreviewServiceUrl(url);
|
|
4663
|
+
if (resolvedUrl && typeof window !== "undefined") window.location.assign(resolvedUrl);
|
|
4663
4664
|
},
|
|
4664
4665
|
[api, bucketName]
|
|
4665
4666
|
);
|