@pisell/private-materials 3.4.157 → 3.4.158
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/build/lowcode/assets-daily.json +11 -11
- package/build/lowcode/assets-dev.json +2 -2
- package/build/lowcode/assets-prod.json +11 -11
- package/build/lowcode/meta.js +1 -1
- package/build/lowcode/preview.css +1 -1
- package/build/lowcode/preview.js +1 -1
- package/build/lowcode/render/default/view.css +1 -1
- package/build/lowcode/render/default/view.js +13 -13
- package/build/lowcode/view.css +1 -1
- package/build/lowcode/view.js +13 -13
- package/es/components/appointmentBooking/deposit/index.d.ts +2 -1
- package/es/components/appointmentBooking/index.d.ts +2 -1
- package/es/components/booking/dashboard/index.d.ts +1 -1
- package/es/components/booking/deposit/index.d.ts +3 -1
- package/es/components/booking/info/addServiceVariant/index.d.ts +3 -1
- package/es/components/booking/info/index.d.ts +2 -1
- package/es/components/booking/materiels/contacts/index.d.ts +2 -1
- package/es/components/booking/materiels/duration/index.d.ts +2 -1
- package/es/components/booking/materiels/startTime/index.d.ts +2 -1
- package/es/components/ecocup/cupList/index.d.ts +2 -1
- package/es/components/ecocup/cupProject/index.d.ts +2 -2
- package/es/components/ecocup/customerList/index.d.ts +2 -2
- package/es/components/eftpos/index.d.ts +2 -1
- package/es/components/eftposPay/index.d.ts +2 -1
- package/es/components/eventBooking/index.d.ts +2 -1
- package/es/components/kioskSkuDetail/index.d.ts +1 -1
- package/es/components/login/index.d.ts +2 -1
- package/es/components/pisellSelectCustomerModal/index.d.ts +2 -1
- package/es/components/productExtension/index.d.ts +2 -1
- package/es/components/ruleSetting/index.d.ts +2 -1
- package/es/components/scanOrder/index.d.ts +2 -2
- package/es/components/shoppingCart/index.d.ts +2 -1
- package/es/components/subTotal/index.d.ts +1 -1
- package/es/components/taxSelect/index.d.ts +2 -1
- package/es/components/ticketBooking/index.d.ts +2 -1
- package/es/components/venueBooking/index.d.ts +2 -2
- package/es/components/walletList/index.d.ts +2 -1
- package/es/index.d.ts +3 -1
- package/es/index.js +3 -1
- package/es/plus/inventory/InventoryItemManagement.d.ts +2 -2
- package/es/plus/inventory/InventoryLocationManagement.d.ts +2 -2
- package/es/plus/inventory/InventoryUnitManagement.d.ts +2 -2
- package/es/plus/orderList/index.d.ts +1 -1
- package/es/plus/panpacificTask/PanpacificTask.d.ts +2 -2
- package/es/plus/pisellAdyenDashboard/index.d.ts +1 -1
- package/es/plus/pisellProResourcePickerModal/PisellFloorMapPaletteViewAllModal.d.ts +1 -1
- package/es/plus/pisellProResourcePickerModal/PisellProResourcePickerModal.d.ts +2 -2
- package/es/plus/pisellReservation/components/SelectFloorMapResourceDialog.d.ts +1 -1
- package/es/plus/pisellReservation/data/bookingToReservationTables.js +1 -1
- package/es/plus/pisellReservation/floorMap/floorPlanApi.js +1 -1
- package/es/plus/pisellReservation/floorMap/reservationMock.js +1 -1
- package/es/plus/pisellReservation/floorRoomCard/FloorRoomCardFromData.d.ts +1 -1
- package/es/plus/pisellReservation/floorRoomCard/ReservationFloorRoomCard.d.ts +1 -1
- package/es/plus/pisellReservation/floorRoomCard/views/RoomCardHeaderView.d.ts +1 -0
- package/es/plus/pisellReservation/index.js +17 -0
- package/es/plus/pisellSalesManagement/index.d.ts +1 -1
- package/es/plus/pisellSupersetDashboard/README.md +291 -0
- package/es/plus/pisellSupersetDashboard/index.d.ts +15 -0
- package/es/plus/pisellSupersetDashboard/index.js +187 -0
- package/es/plus/pisellSupersetDashboard/index.less +83 -0
- package/es/plus/pisellSupersetDashboard/locales.js +36 -0
- package/es/plus/pisellSupersetDashboard/serve.js +51 -0
- package/es/plus/pisellSupersetDashboard/types.d.ts +17 -0
- package/es/plus/pisellTopology/PisellTopology.d.ts +2 -2
- package/es/plus/pisellTopology/TopologyDeviceCard.d.ts +1 -1
- package/es/plus/saasCreateOrganization/index.d.ts +2 -1
- package/es/plus/saleDetail/index.d.ts +2 -2
- package/es/plus/walletPassGallery/components/passDetail/index.d.ts +2 -1
- package/es/plus/walletPassGallery/index.d.ts +2 -1
- package/es/pro/Login2.0/AuthModal.d.ts +1 -1
- package/es/pro/Login2.0/index.d.ts +2 -1
- package/es/pro/Login2.0/shared/types.d.ts +1 -1
- package/es/pro/Selector/Item.d.ts +1 -1
- package/lib/components/appointmentBooking/deposit/index.d.ts +2 -2
- package/lib/components/appointmentBooking/index.d.ts +2 -2
- package/lib/components/booking/dashboard/index.d.ts +1 -1
- package/lib/components/booking/deposit/index.d.ts +3 -2
- package/lib/components/booking/info/addServiceVariant/index.d.ts +3 -2
- package/lib/components/booking/info/index.d.ts +2 -2
- package/lib/components/booking/materiels/contacts/index.d.ts +2 -2
- package/lib/components/booking/materiels/duration/index.d.ts +2 -2
- package/lib/components/booking/materiels/resources/index.d.ts +1 -1
- package/lib/components/booking/materiels/startTime/index.d.ts +2 -2
- package/lib/components/ecocup/cupList/index.d.ts +2 -2
- package/lib/components/ecocup/cupProject/index.d.ts +2 -2
- package/lib/components/ecocup/customerList/index.d.ts +2 -2
- package/lib/components/eftpos/index.d.ts +2 -2
- package/lib/components/eftposPay/index.d.ts +2 -2
- package/lib/components/eventBooking/index.d.ts +2 -2
- package/lib/components/kioskSkuDetail/index.d.ts +1 -1
- package/lib/components/login/index.d.ts +2 -2
- package/lib/components/pisellCashCounting/types.d.ts +1 -1
- package/lib/components/pisellSelectCustomerModal/index.d.ts +2 -2
- package/lib/components/productExtension/index.d.ts +2 -2
- package/lib/components/ruleSetting/index.d.ts +2 -2
- package/lib/components/scanOrder/index.d.ts +2 -2
- package/lib/components/shoppingCart/index.d.ts +2 -2
- package/lib/components/subTotal/index.d.ts +1 -1
- package/lib/components/taxSelect/index.d.ts +2 -2
- package/lib/components/ticketBooking/index.d.ts +2 -2
- package/lib/components/venueBooking/index.d.ts +2 -2
- package/lib/components/walletList/index.d.ts +2 -2
- package/lib/index.d.ts +3 -1
- package/lib/index.js +128 -126
- package/lib/plus/clinetSearch/index.d.ts +1 -1
- package/lib/plus/inventory/InventoryItemManagement.d.ts +2 -2
- package/lib/plus/inventory/InventoryLocationManagement.d.ts +2 -2
- package/lib/plus/inventory/InventoryUnitManagement.d.ts +2 -2
- package/lib/plus/orderList/index.d.ts +1 -1
- package/lib/plus/panpacificTask/PanpacificTask.d.ts +2 -2
- package/lib/plus/pisellAdyenDashboard/index.d.ts +1 -1
- package/lib/plus/pisellProResourcePickerModal/PisellFloorMapPaletteViewAllModal.d.ts +1 -1
- package/lib/plus/pisellProResourcePickerModal/PisellProResourcePickerModal.d.ts +2 -2
- package/lib/plus/pisellReservation/components/SelectFloorMapResourceDialog.d.ts +1 -1
- package/lib/plus/pisellReservation/floorRoomCard/FloorRoomCardFromData.d.ts +1 -1
- package/lib/plus/pisellReservation/floorRoomCard/ReservationFloorRoomCard.d.ts +1 -1
- package/lib/plus/pisellReservation/floorRoomCard/mapFloorRoomCardViewProps.d.ts +1 -0
- package/lib/plus/pisellReservation/floorRoomCard/views/RoomCardHeaderView.d.ts +1 -0
- package/lib/plus/pisellSalesManagement/index.d.ts +1 -1
- package/lib/plus/pisellSupersetDashboard/README.md +291 -0
- package/lib/plus/pisellSupersetDashboard/index.d.ts +15 -0
- package/lib/plus/pisellSupersetDashboard/index.js +189 -0
- package/lib/plus/pisellSupersetDashboard/index.less +83 -0
- package/lib/plus/pisellSupersetDashboard/locales.js +36 -0
- package/lib/plus/pisellSupersetDashboard/serve.js +52 -0
- package/lib/plus/pisellSupersetDashboard/types.d.ts +17 -0
- package/lib/plus/pisellTopology/PisellTopology.d.ts +2 -2
- package/lib/plus/pisellTopology/TopologyDeviceCard.d.ts +1 -1
- package/lib/plus/saasCreateOrganization/index.d.ts +2 -2
- package/lib/plus/saleDetail/index.d.ts +2 -2
- package/lib/plus/walletPassGallery/components/passDetail/index.d.ts +2 -2
- package/lib/plus/walletPassGallery/index.d.ts +2 -2
- package/lib/pro/Selector/Item.d.ts +1 -1
- package/lowcode/pisell-superset-dashboard/meta.ts +75 -0
- package/package.json +3 -1
- /package/es/{private-materials/lowcode/authmodal/meta.d.ts → plus/pisellReservation/floorRoomCard/mapFloorRoomCardViewProps.d.ts} +0 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# PisellSupersetDashboard
|
|
2
|
+
|
|
3
|
+
用于 SaaS 页面和低代码页面的 Superset 报表组件。宿主提供报表嵌入 UUID、UI 配置和已有请求上下文,组件负责获取会话、初始化 SDK、令牌续期、加载展示、失败重试及资源清理。
|
|
4
|
+
|
|
5
|
+
业务接口固定为 `POST /shop/report/superset/embed`。组件使用 `@superset-ui/embedded-sdk@0.4.0` 创建 iframe,不自行拼接带令牌的报表 URL。
|
|
6
|
+
|
|
7
|
+
## 1. 文件结构与职责
|
|
8
|
+
|
|
9
|
+
| 文件 | 职责 |
|
|
10
|
+
| ---------------------------------------------------- | ---------------------------------------------------- |
|
|
11
|
+
| `index.tsx` | 组件入口、状态管理、SDK 初始化与清理、加载和错误交互 |
|
|
12
|
+
| `types.ts` | 公开 Props,以及内部请求客户端和会话类型 |
|
|
13
|
+
| `serve.ts` | 业务接口调用、响应校验和报表异常类型 |
|
|
14
|
+
| `locales.ts` | 英文、简体中文、繁体中文文案 |
|
|
15
|
+
| `index.less` | 容器尺寸、iframe、加载图标和错误遮罩样式 |
|
|
16
|
+
| `index.test.tsx` | 组件行为、续期、超时和异步竞态测试 |
|
|
17
|
+
| `serve.test.ts` | 请求契约、业务错误和响应字段校验测试 |
|
|
18
|
+
| `../../../lowcode/pisell-superset-dashboard/meta.ts` | 低代码物料描述、属性编辑器及默认片段 |
|
|
19
|
+
|
|
20
|
+
包入口 `packages/private-materials/src/index.ts` 导出 `PisellSupersetDashboard` 和 `PisellSupersetDashboardProps`。组件目录同时提供默认导出与具名导出。
|
|
21
|
+
|
|
22
|
+
## 2. 基础使用
|
|
23
|
+
|
|
24
|
+
以下组件应渲染在宿主已有的引擎上下文 Provider 内:
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import {
|
|
28
|
+
PisellSupersetDashboard,
|
|
29
|
+
type PisellSupersetDashboardProps,
|
|
30
|
+
} from '@pisell/private-materials';
|
|
31
|
+
|
|
32
|
+
/** 宿主页面保存的报表配置;示例 UUID 需在目标环境核实。 */
|
|
33
|
+
const reportConfig: PisellSupersetDashboardProps['proCodeProps'] = {
|
|
34
|
+
dashboardId: '6c442e22-dccf-48bd-b159-7569d497ab56',
|
|
35
|
+
dashboardUiConfig: {
|
|
36
|
+
filters: { visible: true, expanded: false },
|
|
37
|
+
hideTitle: true,
|
|
38
|
+
hideChartControls: true,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** 已位于宿主引擎上下文内的报表页面。 */
|
|
43
|
+
export function ReportPage() {
|
|
44
|
+
return (
|
|
45
|
+
<PisellSupersetDashboard
|
|
46
|
+
proCodeProps={reportConfig}
|
|
47
|
+
style={{ height: 'calc(100vh - 120px)', minHeight: 320 }}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
组件接收的完整页面属性结构:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"proCodeProps": {
|
|
58
|
+
"dashboardId": "6c442e22-dccf-48bd-b159-7569d497ab56",
|
|
59
|
+
"dashboardUiConfig": {
|
|
60
|
+
"filters": { "visible": true, "expanded": false },
|
|
61
|
+
"hideTitle": true,
|
|
62
|
+
"hideChartControls": true
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`dashboardId` 来自 Superset Dashboard 的嵌入配置,必须使用嵌入 UUID。普通数字 Dashboard ID 和完整报表 URL 均不适用。
|
|
69
|
+
|
|
70
|
+
## 3. Props 与类型
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
interface PisellSupersetDashboardProps {
|
|
74
|
+
/** 宿主页面下发的报表配置。 */
|
|
75
|
+
proCodeProps?: {
|
|
76
|
+
/** 报表嵌入 UUID。 */
|
|
77
|
+
dashboardId: string;
|
|
78
|
+
/** 完整透传给 SDK 的 UI 配置。 */
|
|
79
|
+
dashboardUiConfig?: Record<string, any>;
|
|
80
|
+
};
|
|
81
|
+
/** 根容器附加样式类名。 */
|
|
82
|
+
className?: string;
|
|
83
|
+
/** 根容器样式,可覆盖默认宽高。 */
|
|
84
|
+
style?: React.CSSProperties;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| 属性 | 类型 | 行为 |
|
|
89
|
+
| -------------------------------- | --------------------------- | -------------------------------------------- |
|
|
90
|
+
| `proCodeProps` | 对象,可选 | 缺失时显示配置提示,不发请求 |
|
|
91
|
+
| `proCodeProps.dashboardId` | `string` | 非空时请求后端;UUID 格式由后端最终校验 |
|
|
92
|
+
| `proCodeProps.dashboardUiConfig` | `Record<string, any>`,可选 | 原样传给 SDK;未提供时沿用 SDK 默认行为 |
|
|
93
|
+
| `className` | `string`,可选 | 追加到组件根容器 |
|
|
94
|
+
| `style` | `React.CSSProperties`,可选 | 覆盖默认宽 `100%`、高 `75vh`、最小高 `520px` |
|
|
95
|
+
|
|
96
|
+
组件不合并默认 UI 配置、不筛除扩展字段,也不把 UI 配置提交给业务接口。具体字段是否生效取决于当前 SDK 和 Superset 服务端的支持情况。
|
|
97
|
+
|
|
98
|
+
父组件传入内容相同的新配置对象不会重建报表。嵌套字段变化会触发重新初始化;使用深拷贝快照,也能识别原对象被修改后发生重新渲染的情况。仅修改对象而没有触发 React 渲染,不会自动触发更新。
|
|
99
|
+
|
|
100
|
+
当前没有额外的事件 Props、命令式方法、`request`、`token` 或 Superset 域名 Props。点击内置重试按钮即可重新初始化。
|
|
101
|
+
|
|
102
|
+
## 4. 宿主上下文与请求方式
|
|
103
|
+
|
|
104
|
+
组件从以下位置获取已有服务:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
/** 宿主引擎上下文。 */
|
|
108
|
+
const context = useEngineContext();
|
|
109
|
+
/** 宿主请求客户端,需至少提供 post 方法。 */
|
|
110
|
+
const client = context?.appHelper?.utils?.request;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
宿主需要通过现有引擎 Context Provider 提供 `appHelper.utils.request`。普通 proCode 页面也需要该上下文,单独渲染组件不会自动获得业务请求服务。上下文缺失时组件显示提示,不尝试从共享单例或浏览器存储寻找备用客户端。
|
|
114
|
+
|
|
115
|
+
请求客户端负责:
|
|
116
|
+
|
|
117
|
+
- 选择当前环境的业务 API baseURL,并支持 `isShopApi: true`。
|
|
118
|
+
- 注入已选店铺的有效 Bearer Token,处理登录 Token 更新和登录失效。
|
|
119
|
+
- 支持第三个参数中的 `AbortSignal`,以及 `fullResult: true`。
|
|
120
|
+
- 返回已解包的业务响应主体,而非原始 `AxiosResponse`。
|
|
121
|
+
|
|
122
|
+
组件直接将当前客户端传给 `getSupersetSession`,不调用 `request.setRequest()`。这样不会覆盖组件包的共享客户端配置。客户端引用独立不代表内部登录态被固定,切店顺序仍须由宿主保证。
|
|
123
|
+
|
|
124
|
+
直接使用客户端也不会自动注入共享包装层的 `customToast`;本组件通过错误遮罩展示异常,宿主自己的拦截器和错误处理仍会执行。
|
|
125
|
+
|
|
126
|
+
## 5. 接口契约与 SDK 映射
|
|
127
|
+
|
|
128
|
+
每次会话请求均为:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
client.post(
|
|
132
|
+
'/shop/report/superset/embed',
|
|
133
|
+
{ dashboard_id: dashboardId },
|
|
134
|
+
{ isShopApi: true, fullResult: true, signal }
|
|
135
|
+
);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
请求体只提交 `dashboard_id`。店铺身份来自宿主登录态,`shop_id`、RLS、服务账号凭据、UI 配置和 Superset 域名均不由组件提交。
|
|
139
|
+
|
|
140
|
+
成功业务响应示例:
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"status": true,
|
|
145
|
+
"code": 200,
|
|
146
|
+
"message": "",
|
|
147
|
+
"data": {
|
|
148
|
+
"guest_token": "当前店铺的短期访客令牌",
|
|
149
|
+
"superset_domain": "https://bi.mypisell.com",
|
|
150
|
+
"dashboard_id": "6c442e22-dccf-48bd-b159-7569d497ab56"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
| 数据来源 | SDK 参数或用途 |
|
|
156
|
+
| -------------------------------- | --------------------------------------------------- |
|
|
157
|
+
| `data.dashboard_id` | `embedDashboard.id`,采用实际响应值 |
|
|
158
|
+
| `data.superset_domain` | `embedDashboard.supersetDomain` |
|
|
159
|
+
| `data.guest_token` | `fetchGuestToken` 返回的字符串 |
|
|
160
|
+
| `proCodeProps.dashboardUiConfig` | `embedDashboard.dashboardUiConfig` |
|
|
161
|
+
| 本轮独立 DOM 节点 | `embedDashboard.mountPoint` |
|
|
162
|
+
| 固定来源策略 | `referrerPolicy: 'strict-origin-when-cross-origin'` |
|
|
163
|
+
|
|
164
|
+
接口适配层同时要求 `status === true`、`code === 200`,并检查三个会话字段都是非空字符串。HTTP 200 不能单独作为成功依据。业务失败时优先展示 `message`;没有可用消息时使用国际化兜底文案。
|
|
165
|
+
|
|
166
|
+
`SupersetReportError` 是内部异常类型,包含只读 `textKey` 和继承的 `message`。宿主拒绝的请求不会在接口层被改写,组件在上层统一处理其展示。
|
|
167
|
+
|
|
168
|
+
## 6. 初始化与令牌续期
|
|
169
|
+
|
|
170
|
+
```mermaid
|
|
171
|
+
flowchart TD
|
|
172
|
+
A[组件挂载或配置变化] --> B{报表 ID 和客户端可用?}
|
|
173
|
+
B -- 否 --> C[显示配置错误]
|
|
174
|
+
B -- 是 --> D[显示加载状态并申请会话]
|
|
175
|
+
D --> E[使用响应域名和 ID 初始化 SDK]
|
|
176
|
+
E --> F[首次取令牌复用本轮已有令牌]
|
|
177
|
+
F --> G[SDK 初始化完成,隐藏加载状态]
|
|
178
|
+
G --> H[SDK 后续调用取令牌回调]
|
|
179
|
+
H --> I[重新请求业务接口]
|
|
180
|
+
I --> G
|
|
181
|
+
D -- 失败或初始化超时 --> J[清理当前会话并显示错误]
|
|
182
|
+
E -- 初始化失败 --> J
|
|
183
|
+
I -- 续期失败 --> J
|
|
184
|
+
J --> K[用户点击重新加载]
|
|
185
|
+
K --> A
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
每轮初始化维护以下内部状态:
|
|
189
|
+
|
|
190
|
+
| 标识 | 含义 |
|
|
191
|
+
| --------------------------------- | ------------------------------------------ |
|
|
192
|
+
| `INITIALIZATION_TIMEOUT` | 当前为 `60000` 毫秒,即 60 秒初始化超时 |
|
|
193
|
+
| `configSnapshot` / `stableConfig` | 比较 UI 配置内容,避免等值对象触发重复挂载 |
|
|
194
|
+
| `host` / `mountPoint` | React 容器和本轮 SDK 专属节点 |
|
|
195
|
+
| `attempt` | 手动重试序号 |
|
|
196
|
+
| `loading` / `error` | 加载状态及可展示错误 |
|
|
197
|
+
| `controller` | 本轮业务请求的取消控制器 |
|
|
198
|
+
| `stopped` | 本轮会话是否已失效 |
|
|
199
|
+
| `instance` | 已完成初始化的 SDK 实例 |
|
|
200
|
+
| `firstToken` | 仅允许首次回调消费一次的令牌 |
|
|
201
|
+
| `timer` | 首次初始化的超时计时器 |
|
|
202
|
+
|
|
203
|
+
首次业务请求成功后,`firstToken` 供 SDK 第一次调用时返回,随后立即清空。后续每次 SDK 续期回调都重新调用同一业务接口,返回新的 `guest_token` 字符串。组件不自行高频轮询,也不写死 Guest Token 的有效期。
|
|
204
|
+
|
|
205
|
+
60 秒计时覆盖首次业务请求和 SDK 初始化,初始化完成即清除;它不限制图表数据加载时间,也不是令牌有效期或后续所有请求的统一超时时间。请求本身的超时仍由宿主客户端处理,SDK 的内部取令牌超时遵循所用版本的实现。
|
|
206
|
+
|
|
207
|
+
## 7. 清理、竞态与切店
|
|
208
|
+
|
|
209
|
+
| 内部方法 | 职责 |
|
|
210
|
+
| -------------------- | ------------------------------------------------ |
|
|
211
|
+
| `getSupersetSession` | 调用业务接口并校验响应 |
|
|
212
|
+
| `getSession` | 在请求前后检查会话有效性,拒绝迟到响应 |
|
|
213
|
+
| `assertActive` | 阻止失效会话继续请求或返回令牌 |
|
|
214
|
+
| `dispose` | 标记失效、取消请求、清空令牌、卸载实例并移除节点 |
|
|
215
|
+
| `fail` | 清理失败会话,并在当前有效页面显示错误 |
|
|
216
|
+
|
|
217
|
+
组件卸载、报表 ID 变化、UI 配置内容变化、客户端引用变化或手动重试时,都会先结束旧会话。
|
|
218
|
+
|
|
219
|
+
每轮使用独立的 DOM 节点和取消控制器。即便请求客户端未真正中止网络请求,响应返回后也会检查 `stopped`。SDK 创建期间如果发生卸载或超时,迟到的 SDK 实例会立即卸载,不会保存到新会话,也不会清空新报表容器。
|
|
220
|
+
|
|
221
|
+
切店或退出登录必须由宿主按以下顺序执行:
|
|
222
|
+
|
|
223
|
+
1. 先卸载当前报表组件,结束旧实例及续期回调。
|
|
224
|
+
2. 完成店铺登录态切换或退出登录。
|
|
225
|
+
3. 新登录上下文准备好后,再渲染目标报表。
|
|
226
|
+
|
|
227
|
+
宿主可使用 `key={currentShopId}` 区分报表实例,但在登录态更新后才更换 `key` 不能替代上述卸载顺序。不要通过路由保活、隐藏 DOM 或预渲染持续保留旧报表。组件不会主动监听外部存储中的店铺或 Token 变化。
|
|
228
|
+
|
|
229
|
+
Guest Token 只用于当前会话,不写入 URL、日志或浏览器持久存储,不跨店铺或报表复用。
|
|
230
|
+
|
|
231
|
+
## 8. 加载、失败与样式
|
|
232
|
+
|
|
233
|
+
加载状态由 Ant Design `Spin` 和 `LoadingOutlined` 组成,图标为 28px,置于 56px 的浅灰圆角底框内,下方展示加载文案。图标颜色沿用 Ant Design 主题。系统设置减少动画时关闭旋转,保留图标和文案。
|
|
234
|
+
|
|
235
|
+
根容器通过 `aria-busy` 表示初始化状态,加载区使用 `role="status"`,错误区使用 `role="alert"`;装饰图标使用 `aria-hidden` 避免重复播报。
|
|
236
|
+
|
|
237
|
+
默认容器宽度为 `100%`,高度为 `75vh`,最小高度为 `520px`。使用更小高度时,应同时覆盖 `minHeight`。iframe 填满容器,无边框。
|
|
238
|
+
|
|
239
|
+
| 场景 | 组件行为 |
|
|
240
|
+
| ------------------------- | -------------------------------- |
|
|
241
|
+
| 缺少报表 ID 或请求客户端 | 不发请求,显示配置提示 |
|
|
242
|
+
| HTTP 成功但业务失败 | 显示业务消息或兜底文案 |
|
|
243
|
+
| 成功响应缺少会话字段 | 显示报表配置不完整 |
|
|
244
|
+
| 首次请求或 SDK 初始化失败 | 清理本轮资源,显示重新加载按钮 |
|
|
245
|
+
| 初始化超过 60 秒 | 标记超时,取消请求,清理挂载节点 |
|
|
246
|
+
| 续期请求失败 | 停止当前实例,等待手动重新加载 |
|
|
247
|
+
| 主动卸载或被新会话替代 | 静默清理,不展示旧会话错误 |
|
|
248
|
+
|
|
249
|
+
加载提示消失只表示 SDK 初始化完成,不表示每张图表的数据都加载成功。跨域 iframe 中的图表错误不在组件的直接检测范围内。
|
|
250
|
+
|
|
251
|
+
`locales.ts` 提供 `en`、`zh-CN`、`zh-HK` 文案,显示语言来自 `context.engine.props.locale`,未提供时使用 `en`。后端返回的错误消息按原文展示。
|
|
252
|
+
|
|
253
|
+
## 9. 低代码与构建
|
|
254
|
+
|
|
255
|
+
低代码物料名称和包导出名称均为 `PisellSupersetDashboard`。属性面板使用 `ObjectSetter` 编辑 `proCodeProps`,其中 `dashboardId` 使用字符串编辑器,`dashboardUiConfig` 使用 JSON 编辑器。
|
|
256
|
+
|
|
257
|
+
默认物料片段将报表 ID 留空,预置筛选器可见且收起、隐藏标题和图表操作项;这些设置只属于片段默认值,组件运行时不会强制添加。
|
|
258
|
+
|
|
259
|
+
SDK 固定版本为 `0.4.0`,其发布文件包含 Webpack 4 不支持的现代语法。组件包 `build.plugin.js` 已将该 SDK 纳入已有 Babel 转译规则。开发环境建议使用 Node.js 18;现有低代码构建插件在 Node.js 22 下存在类型文件加载兼容问题。
|
|
260
|
+
|
|
261
|
+
在仓库根目录执行:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# 运行组件与接口测试。
|
|
265
|
+
pnpm --filter @pisell/private-materials exec vitest run src/plus/pisellSupersetDashboard --maxWorkers=1 --minWorkers=1
|
|
266
|
+
|
|
267
|
+
# 生成组件包 ESM/CJS 产物和类型声明。
|
|
268
|
+
pnpm --filter @pisell/private-materials build
|
|
269
|
+
|
|
270
|
+
# 使用 Node.js 18 执行现有 Webpack 4 低代码构建。
|
|
271
|
+
NODE_OPTIONS=--openssl-legacy-provider pnpm --filter @pisell/private-materials lowcode:build
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
自动测试覆盖配置透传、响应映射、首次令牌复用、续期失败、手动重试、配置变化、初始化超时、卸载后的迟到响应及多实例隔离。测试使用模拟客户端和 SDK,不会签发真实令牌。
|
|
275
|
+
|
|
276
|
+
## 10. 联调与常见问题
|
|
277
|
+
|
|
278
|
+
| 现象 | 核对事项 |
|
|
279
|
+
| ------------------------ | ----------------------------------------------------------------------- |
|
|
280
|
+
| 提示宿主未提供请求客户端 | 确认当前页面处于引擎 Provider 内,并提供 `appHelper.utils.request.post` |
|
|
281
|
+
| 提示缺少报表嵌入 ID | 检查配置是否放在 `proCodeProps.dashboardId` |
|
|
282
|
+
| 后端提示 UUID 不合法 | 确认使用嵌入配置生成的 UUID |
|
|
283
|
+
| 接口成功但提示配置不完整 | 检查客户端解包层级,以及三个会话字段是否齐全 |
|
|
284
|
+
| iframe 空白或拒绝嵌入 | 检查返回域名、嵌入允许来源、Referer、CSP 和容器尺寸 |
|
|
285
|
+
| 图表显示但无数据 | 检查 Superset 数据集权限、RLS 和目标店铺数据 |
|
|
286
|
+
| 切店后仍看到旧内容 | 检查是否先卸载旧组件,以及路由是否保活 |
|
|
287
|
+
| 重复挂载或重复申请令牌 | 检查报表配置、客户端引用和 React key 是否持续变化 |
|
|
288
|
+
|
|
289
|
+
Superset 需要启用嵌入能力并允许实际前端来源;业务 API 跨域访问还需正确配置 CORS。服务账号、RLS、数据集权限和店铺隔离由后端及 Superset 配置负责。
|
|
290
|
+
|
|
291
|
+
正式接入后仍需验证真实报表展示、长时间打开时的续期、离开页面后的清理,以及 A/B 店铺的数据隔离。组件包导出和物料注册不等于宿主已接通 `superset_dashboard` 页面,该页面映射需要由宿主完成。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PisellSupersetDashboardProps } from "./types.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
//#region src/plus/pisellSupersetDashboard/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Superset 报表组件,负责请求会话、挂载报表、续期、状态展示和资源清理。
|
|
6
|
+
* 切店或退出登录时,宿主必须先卸载旧组件,再更新登录态并重新挂载。
|
|
7
|
+
* @param props 页面报表配置、附加样式类名和根容器样式,详见组件属性类型。
|
|
8
|
+
*/
|
|
9
|
+
declare function PisellSupersetDashboard({
|
|
10
|
+
proCodeProps,
|
|
11
|
+
className,
|
|
12
|
+
style
|
|
13
|
+
}: PisellSupersetDashboardProps): React.JSX.Element;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { PisellSupersetDashboard };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
const require_runtime = require("../../_virtual/_rolldown/runtime.js");
|
|
2
|
+
const require_asyncToGenerator = require("../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js");
|
|
3
|
+
const require_useEngineContext = require("../../hooks/useEngineContext.js");
|
|
4
|
+
const require_serve = require("./serve.js");
|
|
5
|
+
const require_locales = require("./locales.js");
|
|
6
|
+
let react = require("react");
|
|
7
|
+
react = require_runtime.__toESM(react);
|
|
8
|
+
let antd = require("antd");
|
|
9
|
+
let _pisell_utils = require("@pisell/utils");
|
|
10
|
+
let lodash = require("lodash");
|
|
11
|
+
let _ant_design_icons = require("@ant-design/icons");
|
|
12
|
+
let _superset_ui_embedded_sdk = require("@superset-ui/embedded-sdk");
|
|
13
|
+
require("./index.less");
|
|
14
|
+
//#region src/plus/pisellSupersetDashboard/index.tsx
|
|
15
|
+
/** 首次获取会话到 SDK 初始化完成的最长等待时间,单位为毫秒。 */
|
|
16
|
+
const INITIALIZATION_TIMEOUT = 6e4;
|
|
17
|
+
/**
|
|
18
|
+
* Superset 报表组件,负责请求会话、挂载报表、续期、状态展示和资源清理。
|
|
19
|
+
* 切店或退出登录时,宿主必须先卸载旧组件,再更新登录态并重新挂载。
|
|
20
|
+
* @param props 页面报表配置、附加样式类名和根容器样式,详见组件属性类型。
|
|
21
|
+
*/
|
|
22
|
+
function PisellSupersetDashboard({ proCodeProps, className, style }) {
|
|
23
|
+
var _context$appHelper, _context$engine;
|
|
24
|
+
/** 当前宿主引擎上下文,提供请求服务和显示语言。 */
|
|
25
|
+
const context = require_useEngineContext.default();
|
|
26
|
+
/** 当前组件使用的宿主客户端;不写入组件包的共享 request 单例。 */
|
|
27
|
+
const client = context === null || context === void 0 || (_context$appHelper = context.appHelper) === null || _context$appHelper === void 0 || (_context$appHelper = _context$appHelper.utils) === null || _context$appHelper === void 0 ? void 0 : _context$appHelper.request;
|
|
28
|
+
_pisell_utils.locales.init(require_locales.default, (context === null || context === void 0 || (_context$engine = context.engine) === null || _context$engine === void 0 || (_context$engine = _context$engine.props) === null || _context$engine === void 0 ? void 0 : _context$engine.locale) || "en");
|
|
29
|
+
/** 当前报表的嵌入 UUID,用于向业务后端申请会话。 */
|
|
30
|
+
const dashboardId = proCodeProps === null || proCodeProps === void 0 ? void 0 : proCodeProps.dashboardId;
|
|
31
|
+
/** 原始 UI 配置对象,完整透传给 SDK,保留调用方的扩展字段。 */
|
|
32
|
+
const dashboardUiConfig = proCodeProps === null || proCodeProps === void 0 ? void 0 : proCodeProps.dashboardUiConfig;
|
|
33
|
+
/** UI 配置的深拷贝快照,用于识别嵌套字段变化及原对象上的修改。 */
|
|
34
|
+
const configSnapshot = (0, react.useRef)((0, lodash.cloneDeep)(dashboardUiConfig));
|
|
35
|
+
if (!(0, lodash.isEqual)(configSnapshot.current, dashboardUiConfig)) configSnapshot.current = (0, lodash.cloneDeep)(dashboardUiConfig);
|
|
36
|
+
/** 内容不变时保持引用稳定,作为报表初始化副作用的依赖。 */
|
|
37
|
+
const stableConfig = configSnapshot.current;
|
|
38
|
+
/** React 管理的宿主容器;每轮初始化在其中创建独立的 SDK 挂载节点。 */
|
|
39
|
+
const host = (0, react.useRef)(null);
|
|
40
|
+
/** 手动重试序号;递增后触发上一轮清理和新一轮初始化。 */
|
|
41
|
+
const [attempt, setAttempt] = (0, react.useState)(0);
|
|
42
|
+
/** 是否正在获取会话或等待 SDK 初始化,不代表图表数据的加载进度。 */
|
|
43
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
44
|
+
/** 当前可展示错误;有明确错误消息时优先展示,否则使用国际化文案。 */
|
|
45
|
+
const [error, setError] = (0, react.useState)(null);
|
|
46
|
+
(0, react.useEffect)(() => {
|
|
47
|
+
setError(null);
|
|
48
|
+
setLoading(true);
|
|
49
|
+
if (typeof dashboardId !== "string" || !dashboardId.trim()) {
|
|
50
|
+
setError({ key: "pisell-superset.missingDashboard" });
|
|
51
|
+
setLoading(false);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!client || typeof client.post !== "function") {
|
|
55
|
+
setError({ key: "pisell-superset.missingRequest" });
|
|
56
|
+
setLoading(false);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
/** 本轮初始化和续期共用的取消控制器,与其他组件实例相互独立。 */
|
|
60
|
+
const controller = new AbortController();
|
|
61
|
+
/** 本轮专属挂载节点,防止旧异步任务清空新报表的 iframe。 */
|
|
62
|
+
const mountPoint = document.createElement("div");
|
|
63
|
+
mountPoint.className = "pisell-superset-dashboard-mount";
|
|
64
|
+
host.current.appendChild(mountPoint);
|
|
65
|
+
/** 本轮会话是否失效;失效后禁止继续请求或更新组件状态。 */
|
|
66
|
+
let stopped = false;
|
|
67
|
+
/** 已完成初始化的 SDK 实例,用于卸载 iframe 并停止 SDK 续期计时。 */
|
|
68
|
+
let instance;
|
|
69
|
+
/** 首次接口返回的令牌,仅供 SDK 第一次取令牌时消费。 */
|
|
70
|
+
let firstToken;
|
|
71
|
+
/** 初始化超时计时器;初始化完成或会话结束时清除。 */
|
|
72
|
+
let timer;
|
|
73
|
+
/** 使当前会话失效,取消请求并清理令牌、SDK 实例和专属挂载节点。 */
|
|
74
|
+
const dispose = () => {
|
|
75
|
+
stopped = true;
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
controller.abort();
|
|
78
|
+
firstToken = void 0;
|
|
79
|
+
instance === null || instance === void 0 || instance.unmount();
|
|
80
|
+
instance = void 0;
|
|
81
|
+
mountPoint.replaceChildren();
|
|
82
|
+
mountPoint.remove();
|
|
83
|
+
};
|
|
84
|
+
/** 校验会话仍然有效,阻止旧回调继续执行或返回迟到的令牌。 */
|
|
85
|
+
const assertActive = () => {
|
|
86
|
+
if (stopped) throw new Error("Superset session disposed");
|
|
87
|
+
};
|
|
88
|
+
/** 统一处理初始化和续期异常;已失效会话的异常不再影响界面。 */
|
|
89
|
+
const fail = (cause) => {
|
|
90
|
+
if (stopped) return;
|
|
91
|
+
dispose();
|
|
92
|
+
/** 从未知异常中提取消息,兼容 Error 及宿主抛出的业务响应对象。 */
|
|
93
|
+
const message = cause === null || cause === void 0 ? void 0 : cause.message;
|
|
94
|
+
setError({
|
|
95
|
+
key: cause instanceof require_serve.SupersetReportError ? cause.textKey : "pisell-superset.loadFailed",
|
|
96
|
+
message: typeof message === "string" ? message : void 0
|
|
97
|
+
});
|
|
98
|
+
setLoading(false);
|
|
99
|
+
};
|
|
100
|
+
/** 请求新的报表会话,并在请求前后校验生命周期,拒绝过期响应。 */
|
|
101
|
+
const getSession = function() {
|
|
102
|
+
var _ref = require_asyncToGenerator._asyncToGenerator(function* () {
|
|
103
|
+
assertActive();
|
|
104
|
+
/** 经业务成功状态及必填字段校验后的报表会话。 */
|
|
105
|
+
const session = yield require_serve.getSupersetSession(client, dashboardId, controller.signal);
|
|
106
|
+
assertActive();
|
|
107
|
+
return session;
|
|
108
|
+
});
|
|
109
|
+
return function getSession() {
|
|
110
|
+
return _ref.apply(this, arguments);
|
|
111
|
+
};
|
|
112
|
+
}();
|
|
113
|
+
timer = setTimeout(() => {
|
|
114
|
+
fail(new require_serve.SupersetReportError("pisell-superset.timeout"));
|
|
115
|
+
}, INITIALIZATION_TIMEOUT);
|
|
116
|
+
require_asyncToGenerator._asyncToGenerator(function* () {
|
|
117
|
+
/** 首次会话,包含实际嵌入域名、报表 ID 和当前店铺的访客令牌。 */
|
|
118
|
+
const session = yield getSession();
|
|
119
|
+
firstToken = session.guest_token;
|
|
120
|
+
/** SDK 异步创建的实例,确认会话仍有效后才保存到当前作用域。 */
|
|
121
|
+
const embedded = yield (0, _superset_ui_embedded_sdk.embedDashboard)({
|
|
122
|
+
id: session.dashboard_id,
|
|
123
|
+
supersetDomain: session.superset_domain,
|
|
124
|
+
mountPoint,
|
|
125
|
+
dashboardUiConfig,
|
|
126
|
+
referrerPolicy: "strict-origin-when-cross-origin",
|
|
127
|
+
fetchGuestToken: function() {
|
|
128
|
+
var _ref2 = require_asyncToGenerator._asyncToGenerator(function* () {
|
|
129
|
+
assertActive();
|
|
130
|
+
if (firstToken !== void 0) {
|
|
131
|
+
/** 本次要返回的首次令牌;返回前清空缓存,确保只复用一次。 */
|
|
132
|
+
const token = firstToken;
|
|
133
|
+
firstToken = void 0;
|
|
134
|
+
return token;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
return (yield getSession()).guest_token;
|
|
138
|
+
} catch (cause) {
|
|
139
|
+
fail(cause);
|
|
140
|
+
throw cause;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
return function fetchGuestToken() {
|
|
144
|
+
return _ref2.apply(this, arguments);
|
|
145
|
+
};
|
|
146
|
+
}()
|
|
147
|
+
});
|
|
148
|
+
if (stopped) {
|
|
149
|
+
embedded.unmount();
|
|
150
|
+
mountPoint.replaceChildren();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
instance = embedded;
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
setLoading(false);
|
|
156
|
+
})().catch(fail);
|
|
157
|
+
return dispose;
|
|
158
|
+
}, [
|
|
159
|
+
dashboardId,
|
|
160
|
+
stableConfig,
|
|
161
|
+
client,
|
|
162
|
+
attempt
|
|
163
|
+
]);
|
|
164
|
+
return /* @__PURE__ */ react.default.createElement("div", {
|
|
165
|
+
className: ["pisell-superset-dashboard", className].filter(Boolean).join(" "),
|
|
166
|
+
style,
|
|
167
|
+
"aria-busy": loading
|
|
168
|
+
}, loading && /* @__PURE__ */ react.default.createElement("div", {
|
|
169
|
+
className: "pisell-superset-dashboard-status pisell-superset-dashboard-loading",
|
|
170
|
+
role: "status"
|
|
171
|
+
}, /* @__PURE__ */ react.default.createElement("div", {
|
|
172
|
+
className: "pisell-superset-dashboard-loading-icon",
|
|
173
|
+
"aria-hidden": "true"
|
|
174
|
+
}, /* @__PURE__ */ react.default.createElement(antd.Spin, { indicator: /* @__PURE__ */ react.default.createElement(_ant_design_icons.LoadingOutlined, {
|
|
175
|
+
spin: true,
|
|
176
|
+
style: { fontSize: 36 }
|
|
177
|
+
}) })), /* @__PURE__ */ react.default.createElement("p", { className: "pisell-superset-dashboard-loading-text" }, _pisell_utils.locales.getText("pisell-superset.loading"))), error && /* @__PURE__ */ react.default.createElement("div", {
|
|
178
|
+
className: "pisell-superset-dashboard-status",
|
|
179
|
+
role: "alert"
|
|
180
|
+
}, /* @__PURE__ */ react.default.createElement("p", null, error.message || _pisell_utils.locales.getText(error.key)), /* @__PURE__ */ react.default.createElement("button", {
|
|
181
|
+
type: "button",
|
|
182
|
+
onClick: () => setAttempt((value) => value + 1)
|
|
183
|
+
}, _pisell_utils.locales.getText("pisell-superset.retry"))), /* @__PURE__ */ react.default.createElement("div", {
|
|
184
|
+
ref: host,
|
|
185
|
+
className: "pisell-superset-dashboard-host"
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
exports.default = PisellSupersetDashboard;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// 报表根容器提供默认占位高度,宿主可以通过 style 覆盖尺寸。
|
|
2
|
+
.pisell-superset-dashboard {
|
|
3
|
+
position: relative;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 75vh;
|
|
6
|
+
min-height: 520px;
|
|
7
|
+
|
|
8
|
+
// React 容器、当前会话挂载节点和 SDK iframe 逐层填满可用空间。
|
|
9
|
+
&-host,
|
|
10
|
+
&-mount,
|
|
11
|
+
iframe {
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 去掉 iframe 默认边框与行内元素基线留白。
|
|
17
|
+
iframe {
|
|
18
|
+
display: block;
|
|
19
|
+
border: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 加载图标的浅灰圆角底框;图标自身沿用 Ant Design 主题色。
|
|
23
|
+
&-loading-icon {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
width: 56px;
|
|
28
|
+
height: 56px;
|
|
29
|
+
border: 1px solid #eaecf0;
|
|
30
|
+
border-radius: 16px;
|
|
31
|
+
background: #f9fafb;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 加载文案使用次级文字颜色,与组件其他状态提示保持一致。
|
|
35
|
+
&-loading-text {
|
|
36
|
+
color: #667085;
|
|
37
|
+
font-size: 18px;
|
|
38
|
+
font-weight: 500;
|
|
39
|
+
line-height: 22px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 加载与失败状态共用遮罩,覆盖未完成初始化或已清理的报表区域。
|
|
43
|
+
&-status {
|
|
44
|
+
position: absolute;
|
|
45
|
+
inset: 0;
|
|
46
|
+
z-index: 1;
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
gap: 12px;
|
|
52
|
+
padding: 24px;
|
|
53
|
+
text-align: center;
|
|
54
|
+
background: #fff;
|
|
55
|
+
color: #475467;
|
|
56
|
+
|
|
57
|
+
p {
|
|
58
|
+
margin: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 错误状态的手动重试按钮。
|
|
62
|
+
button {
|
|
63
|
+
padding: 8px 16px;
|
|
64
|
+
border: 1px solid #d0d5dd;
|
|
65
|
+
border-radius: 6px;
|
|
66
|
+
background: #fff;
|
|
67
|
+
color: inherit;
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 加载状态的图标与文案采用稍大的垂直间距。
|
|
73
|
+
&-loading {
|
|
74
|
+
gap: 16px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 尊重系统减少动画偏好,保留图标和文字,只关闭旋转动画。
|
|
78
|
+
@media (prefers-reduced-motion: reduce) {
|
|
79
|
+
&-loading-icon .anticon-spin {
|
|
80
|
+
animation: none;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/plus/pisellSupersetDashboard/locales.ts
|
|
2
|
+
/** 报表加载、配置缺失、接口失败和重试相关的国际化文案。 */
|
|
3
|
+
var locales_default = {
|
|
4
|
+
en: {
|
|
5
|
+
"pisell-superset.loading": "Loading report…",
|
|
6
|
+
"pisell-superset.retry": "Reload report",
|
|
7
|
+
"pisell-superset.missingDashboard": "Configure a dashboard embedding ID first.",
|
|
8
|
+
"pisell-superset.missingRequest": "The host has not provided a report request client.",
|
|
9
|
+
"pisell-superset.requestFailed": "Unable to retrieve the report configuration.",
|
|
10
|
+
"pisell-superset.invalidResponse": "The report configuration is incomplete.",
|
|
11
|
+
"pisell-superset.loadFailed": "Report loading or renewal failed. Please reload.",
|
|
12
|
+
"pisell-superset.timeout": "Report initialization timed out. Please reload."
|
|
13
|
+
},
|
|
14
|
+
"zh-CN": {
|
|
15
|
+
"pisell-superset.loading": "正在加载报表…",
|
|
16
|
+
"pisell-superset.retry": "重新加载报表",
|
|
17
|
+
"pisell-superset.missingDashboard": "请先配置报表嵌入 ID。",
|
|
18
|
+
"pisell-superset.missingRequest": "宿主未提供报表请求客户端。",
|
|
19
|
+
"pisell-superset.requestFailed": "获取报表配置失败。",
|
|
20
|
+
"pisell-superset.invalidResponse": "报表配置返回不完整。",
|
|
21
|
+
"pisell-superset.loadFailed": "报表加载或续期失败,请重新加载。",
|
|
22
|
+
"pisell-superset.timeout": "报表初始化超时,请重新加载。"
|
|
23
|
+
},
|
|
24
|
+
"zh-HK": {
|
|
25
|
+
"pisell-superset.loading": "正在載入報表…",
|
|
26
|
+
"pisell-superset.retry": "重新載入報表",
|
|
27
|
+
"pisell-superset.missingDashboard": "請先設定報表嵌入 ID。",
|
|
28
|
+
"pisell-superset.missingRequest": "宿主未提供報表請求客戶端。",
|
|
29
|
+
"pisell-superset.requestFailed": "取得報表設定失敗。",
|
|
30
|
+
"pisell-superset.invalidResponse": "報表設定回傳不完整。",
|
|
31
|
+
"pisell-superset.loadFailed": "報表載入或續期失敗,請重新載入。",
|
|
32
|
+
"pisell-superset.timeout": "報表初始化逾時,請重新載入。"
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
exports.default = locales_default;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const require_asyncToGenerator = require("../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js");
|
|
2
|
+
//#region src/plus/pisellSupersetDashboard/serve.ts
|
|
3
|
+
/** 带有国际化兜底文案键的报表异常,可附带后端返回的可读消息。 */
|
|
4
|
+
var SupersetReportError = class extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* @param textKey 错误消息缺省时使用的国际化文案键,同时保存为只读属性。
|
|
7
|
+
* @param message 优先展示的错误消息;省略时由组件根据 textKey 取文案。
|
|
8
|
+
*/
|
|
9
|
+
constructor(textKey, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.textKey = textKey;
|
|
12
|
+
this.name = "SupersetReportError";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* 获取指定报表的店铺嵌入会话;每次调用都由后端重新申请 Guest Token。
|
|
17
|
+
* @param client 从当前组件宿主上下文取得的请求客户端。
|
|
18
|
+
* @param dashboardId Superset 报表嵌入 UUID。
|
|
19
|
+
* @param signal 当前会话的取消信号。
|
|
20
|
+
* @returns 已校验必填字段的报表会话。
|
|
21
|
+
* @throws 业务失败或响应不完整时抛出报表异常;宿主请求异常保持原样抛出。
|
|
22
|
+
*/
|
|
23
|
+
function getSupersetSession(_x, _x2, _x3) {
|
|
24
|
+
return _getSupersetSession.apply(this, arguments);
|
|
25
|
+
}
|
|
26
|
+
function _getSupersetSession() {
|
|
27
|
+
_getSupersetSession = require_asyncToGenerator._asyncToGenerator(function* (client, dashboardId, signal) {
|
|
28
|
+
/** 宿主已解包的业务响应;此处类型断言仅描述结构,后续仍需运行时校验。 */
|
|
29
|
+
const response = yield client.post("/shop/report/superset/embed", { dashboard_id: dashboardId }, {
|
|
30
|
+
isShopApi: true,
|
|
31
|
+
fullResult: true,
|
|
32
|
+
signal
|
|
33
|
+
});
|
|
34
|
+
if ((response === null || response === void 0 ? void 0 : response.status) !== true || response.code !== 200) throw new SupersetReportError("pisell-superset.requestFailed", typeof (response === null || response === void 0 ? void 0 : response.message) === "string" ? response.message : void 0);
|
|
35
|
+
/** 待校验的会话主体;不能假定业务成功就一定包含完整 SDK 参数。 */
|
|
36
|
+
const session = response.data;
|
|
37
|
+
if (!session || ![
|
|
38
|
+
"guest_token",
|
|
39
|
+
"superset_domain",
|
|
40
|
+
"dashboard_id"
|
|
41
|
+
].every((key) => {
|
|
42
|
+
/** 当前必填字段的原始值,只校验、不改写后端返回内容。 */
|
|
43
|
+
const value = session[key];
|
|
44
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
45
|
+
})) throw new SupersetReportError("pisell-superset.invalidResponse");
|
|
46
|
+
return session;
|
|
47
|
+
});
|
|
48
|
+
return _getSupersetSession.apply(this, arguments);
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
exports.SupersetReportError = SupersetReportError;
|
|
52
|
+
exports.getSupersetSession = getSupersetSession;
|