openxiangda 1.0.153 → 1.0.154

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.
@@ -14,12 +14,25 @@
14
14
  | 6 | Tailwind 样式被清除(PurgeCSS) | 生产构建后样式丢失 |
15
15
  | 7 | React 多实例冲突 | `Invalid hook call` |
16
16
  | 8 | 移动端 antd-mobile 组件样式不生效 | 组件渲染但无样式 |
17
- | 9 | 数据格式理解错误导致展示异常 | 页面显示 `[object Object]` |
18
- | 10 | workspace publish 环境变量缺失 | `OPENXIANGDA_ACCESS_TOKEN is not set` |
17
+ | 9 | 数据格式理解错误导致展示异常 | 页面显示 `[object Object]` |
18
+ | 10 | workspace publish 环境变量缺失 | `OPENXIANGDA_ACCESS_TOKEN is not set` |
19
+ | 11 | DOCX 响应是 Base64 文本 | 文件流以 `UEsDB` 开头,`docx-preview` 无法解包 |
19
20
 
20
- ---
21
-
22
- ## 问题:antd/antd-mobile 弹层样式丢失
21
+ ---
22
+
23
+ ## 问题:DOCX 响应是 Base64 文本
24
+
25
+ **症状**:ticket metadata 正常返回 `renderMode: "docx-html"` 和 `canPreview: true`,`/service/file/preview-by-ticket/:ticket` 也是 HTTP 200,但响应内容以 `UEsDB` 开头,Word 预览仍然解析失败。
26
+
27
+ **根因**:DOCX 本质是 ZIP。原始二进制应以 `PK`(十六进制 `50 4B 03 04`)开头;`UEsDB` 是这个 ZIP 内容再次经过 Base64 编码后的文本,不能直接交给 `docx-preview`。这不是 MIME、ticket 或 ONLYOFFICE 配置问题。
28
+
29
+ **解决方案**:升级平台服务端和 OpenXiangda SDK 到包含 Base64 Office 兼容解码的版本。服务端会对历史 Base64 DOCX 对象做严格 ZIP 魔数校验后恢复原始二进制,并按解码后的长度返回 Range;SDK 对旧服务端和直连文件流保留同样的浏览器端兜底。不要在业务页面自行调用 `atob` 或复制一套文件类型判断。
30
+
31
+ **验证方式**:修复后的响应字节应以 `PK` 开头,`Content-Length` 应是解码后的二进制长度。若下载后的 DOCX 仍以可见文本 `UEsDB` 开头,说明服务端尚未升级或请求仍命中了旧节点。
32
+
33
+ ---
34
+
35
+ ## 问题:antd/antd-mobile 弹层样式丢失
23
36
 
24
37
  **症状**:Select / Dropdown / Popup / Modal 等组件的弹出层没有样式,直接跑到屏幕外,或呈现为无样式的裸 HTML。
25
38
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.153",
3
+ "version": "1.0.154",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {
@@ -139,6 +139,7 @@ __export(components_exports, {
139
139
  normalizeDataManagementList: () => normalizeDataManagementList,
140
140
  normalizeFieldBehaviors: () => normalizeFieldBehaviors,
141
141
  normalizeOperation: () => normalizeOperation,
142
+ normalizePreviewBlobContent: () => normalizePreviewBlobContent,
142
143
  normalizePreviewBlobResponse: () => normalizePreviewBlobResponse,
143
144
  normalizeRichTextHtml: () => normalizeRichTextHtml,
144
145
  prepareFilePreview: () => prepareFilePreview,
@@ -3391,6 +3392,45 @@ var normalizePreviewBlobResponse = (response) => {
3391
3392
  if (blob) return blob;
3392
3393
  throw new Error(getBinaryResponseMessage(payload) || "\u6587\u4EF6\u5185\u5BB9\u54CD\u5E94\u4E0D\u662F\u4E8C\u8FDB\u5236\u6570\u636E");
3393
3394
  };
3395
+ var isZipBytes = (bytes) => bytes.length >= 4 && bytes[0] === 80 && bytes[1] === 75 && (bytes[2] === 3 && bytes[3] === 4 || bytes[2] === 5 && bytes[3] === 6 || bytes[2] === 7 && bytes[3] === 8);
3396
+ var decodeBase64ZipBlob = async (blob) => {
3397
+ const prefix = (await blob.slice(0, 96).text()).replace(/^\uFEFF/, "").replace(/\s+/g, "");
3398
+ if (!prefix.startsWith("UEsDB")) return blob;
3399
+ if (blob.size > 32 * 1024 * 1024) {
3400
+ throw new Error("Base64 \u6587\u4EF6\u8D85\u8FC7\u6D4F\u89C8\u5668\u517C\u5BB9\u89E3\u7801\u4E0A\u9650");
3401
+ }
3402
+ const base64 = (await blob.text()).replace(/^\uFEFF/, "").replace(/\s+/g, "");
3403
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(base64)) {
3404
+ throw new Error("\u6587\u4EF6\u5185\u5BB9\u662F\u65E0\u6548\u7684 Base64 \u4E8C\u8FDB\u5236\u6570\u636E");
3405
+ }
3406
+ let binary = "";
3407
+ try {
3408
+ binary = globalThis.atob(base64);
3409
+ } catch {
3410
+ throw new Error("\u6587\u4EF6\u5185\u5BB9\u662F\u65E0\u6548\u7684 Base64 \u4E8C\u8FDB\u5236\u6570\u636E");
3411
+ }
3412
+ const bytes = new Uint8Array(binary.length);
3413
+ for (let index = 0; index < binary.length; index += 1) {
3414
+ bytes[index] = binary.charCodeAt(index);
3415
+ }
3416
+ if (!isZipBytes(bytes)) {
3417
+ throw new Error("Base64 \u6587\u4EF6\u89E3\u7801\u540E\u4E0D\u662F\u6709\u6548\u7684 Office \u6587\u6863");
3418
+ }
3419
+ if (globalThis.btoa(binary).replace(/=+$/, "") !== base64.replace(/=+$/, "")) {
3420
+ throw new Error("\u6587\u4EF6\u5185\u5BB9\u662F\u65E0\u6548\u7684 Base64 \u4E8C\u8FDB\u5236\u6570\u636E");
3421
+ }
3422
+ return new Blob([bytes], { type: blob.type || "application/zip" });
3423
+ };
3424
+ var normalizePreviewBlobContent = async (response) => {
3425
+ const blob = normalizePreviewBlobResponse(response);
3426
+ if (String(blob.type || "").toLowerCase().includes("application/json")) {
3427
+ const payload = await blob.text().then((value) => JSON.parse(value)).catch(() => null);
3428
+ if (payload) {
3429
+ throw new Error(getBinaryResponseMessage(payload) || "\u6587\u4EF6\u5185\u5BB9\u8BF7\u6C42\u5931\u8D25");
3430
+ }
3431
+ }
3432
+ return decodeBase64ZipBlob(blob);
3433
+ };
3394
3434
  var isDirectStorageItem = (item) => item.provider === "oss" || item.uploadProvider === "oss" || item.uploadProvider === "builtin-oss" || Boolean(item.storageCode);
3395
3435
  var getPreviewItemKey = (item, index = 0) => getAttachmentItemIdentity(item) || item.id || item.uid || `${item.name || "file"}-${index}`;
3396
3436
  var getPreviewSourceUrl = (item) => item.previewUrl || item.publicUrl || item.url || "";
@@ -3564,7 +3604,7 @@ var prepareFilePreview = async (options) => {
3564
3604
  };
3565
3605
  var loadPreviewBlob = async (request, url) => {
3566
3606
  const response = await request({ url, method: "get", responseType: "blob" });
3567
- return normalizePreviewBlobResponse(response);
3607
+ return normalizePreviewBlobContent(response);
3568
3608
  };
3569
3609
  var convertHeicPreview = async (request, url) => {
3570
3610
  const source = await loadPreviewBlob(request, url);