@lark-apaas/client-toolkit 0.1.0-alpha.log.10 → 0.1.0-alpha.log.15

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.
@@ -1,4 +1,4 @@
1
- import { batchLogInfo, initBatchLogger } from "../../logger/batch-logger.js";
1
+ import { batchLogInfo, destroyBatchLogger, initBatchLogger } from "../../logger/batch-logger.js";
2
2
  import { postMessage } from "../../utils/postMessage.js";
3
3
  const PROXY_CONSOLE_METHOD = [
4
4
  'log',
@@ -10,6 +10,20 @@ const LOG_FILTER_PREFIX = [
10
10
  '[Dataloom]',
11
11
  '[MiaoDa]'
12
12
  ];
13
+ function formatArg(arg) {
14
+ if (null === arg) return 'null';
15
+ if (void 0 === arg) return 'undefined';
16
+ if ('object' == typeof arg) {
17
+ if (arg instanceof Error) return `${arg.name}: ${arg.message}\n${arg.stack}`;
18
+ try {
19
+ return JSON.stringify(arg, this.getCircularReplacer(), 2);
20
+ } catch (e) {
21
+ return Object.prototype.toString.call(arg);
22
+ }
23
+ }
24
+ if ('function' == typeof arg) return arg.toString();
25
+ return String(arg);
26
+ }
13
27
  const initHandleError = ()=>{
14
28
  window.onerror = (message, source, lineno, colno, error)=>{
15
29
  const errorList = [];
@@ -26,17 +40,22 @@ const initHandleError = ()=>{
26
40
  };
27
41
  const initLogInterceptor = ()=>{
28
42
  initBatchLogger(console);
43
+ window.addEventListener('beforeunload', ()=>{
44
+ destroyBatchLogger();
45
+ });
29
46
  PROXY_CONSOLE_METHOD.forEach((method)=>{
30
47
  const originalMethod = window.console[method];
31
48
  window.console[method] = (...args)=>{
32
49
  originalMethod(...args);
33
- batchLogInfo(method, JSON.stringify(args));
34
50
  const log = args[0];
35
- if ('string' == typeof log && LOG_FILTER_PREFIX.some((prefix)=>log.startsWith(prefix))) postMessage({
36
- type: 'Console',
37
- method,
38
- data: args
39
- });
51
+ if ('string' == typeof log && LOG_FILTER_PREFIX.some((prefix)=>log.startsWith(prefix))) {
52
+ batchLogInfo(method, args.map(formatArg).join(' '));
53
+ postMessage({
54
+ type: 'Console',
55
+ method,
56
+ data: args
57
+ });
58
+ }
40
59
  };
41
60
  });
42
61
  };
@@ -0,0 +1,155 @@
1
+ /**
2
+ * HTTP 请求方法类型
3
+ */
4
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
5
+ /**
6
+ * 请求配置接口
7
+ */
8
+ export interface RequestConfig {
9
+ /** 请求 URL */
10
+ url: string;
11
+ /** 请求方法 */
12
+ method?: HttpMethod;
13
+ /** 请求头 */
14
+ headers?: Record<string, string>;
15
+ /** 请求参数(用于 GET 请求的查询参数) */
16
+ params?: Record<string, any>;
17
+ /** 请求体数据 */
18
+ data?: any;
19
+ /** 超时时间(毫秒) */
20
+ timeout?: number;
21
+ /** 响应类型 */
22
+ responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData';
23
+ /** 是否携带凭证 */
24
+ credentials?: RequestCredentials;
25
+ /** AbortSignal 用于取消请求 */
26
+ signal?: AbortSignal;
27
+ }
28
+ /**
29
+ * 响应数据接口
30
+ */
31
+ export interface ApiResponse<T = any> {
32
+ /** 响应数据 */
33
+ data: T;
34
+ /** HTTP 状态码 */
35
+ status: number;
36
+ /** 状态文本 */
37
+ statusText: string;
38
+ /** 请求是否成功 (2xx 状态码) */
39
+ success: boolean;
40
+ /** 响应头(序列化为普通对象,可通过 postMessage 传递) */
41
+ headers?: Record<string, string>;
42
+ }
43
+ /**
44
+ * API 错误类
45
+ */
46
+ export declare class ApiError extends Error {
47
+ status?: number;
48
+ statusText?: string;
49
+ response?: Response;
50
+ config?: RequestConfig;
51
+ code?: string;
52
+ /** 业务错误响应数据 */
53
+ responseData?: any;
54
+ constructor(message: string, config?: RequestConfig, response?: Response, code?: string, responseData?: any);
55
+ /**
56
+ * 序列化为可传递的 JSON 对象(用于 postMessage 等场景)
57
+ * 移除不可序列化的对象(如 Response、Request 等)
58
+ */
59
+ toJSON(): object;
60
+ }
61
+ /**
62
+ * 通用接口测试 API 代理类
63
+ *
64
+ * 特性:
65
+ * - 支持所有 RESTful 请求方法 (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)
66
+ * - 完善的错误处理和边界检查
67
+ * - 超时控制和请求取消
68
+ * - 支持多种响应类型
69
+ * - 所有响应数据可序列化(可通过 postMessage 传递)
70
+ */
71
+ declare class ApiProxy {
72
+ /** 默认配置 */
73
+ private defaultConfig;
74
+ /** 活跃的请求控制器 Map */
75
+ private activeRequests;
76
+ /**
77
+ * 构造函数
78
+ * @param baseConfig 基础配置
79
+ */
80
+ constructor(baseConfig?: Partial<RequestConfig>);
81
+ /**
82
+ * 验证 URL 格式
83
+ */
84
+ private validateUrl;
85
+ /**
86
+ * 构建完整 URL (包含查询参数)
87
+ */
88
+ private buildUrl;
89
+ /**
90
+ * 序列化请求体
91
+ */
92
+ private serializeData;
93
+ /**
94
+ * 解析响应数据
95
+ */
96
+ private parseResponse;
97
+ /**
98
+ * 将 Headers 对象序列化为普通对象(可通过 postMessage 传递)
99
+ */
100
+ private serializeHeaders;
101
+ /**
102
+ * 生成请求唯一键
103
+ */
104
+ private generateRequestKey;
105
+ /**
106
+ * 核心请求方法
107
+ */
108
+ request<T = any>(config: RequestConfig): Promise<ApiResponse<T>>;
109
+ /**
110
+ * 执行实际请求
111
+ */
112
+ private executeRequest;
113
+ /**
114
+ * GET 请求
115
+ */
116
+ get<T = any>(url: string, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ApiResponse<T>>;
117
+ /**
118
+ * POST 请求
119
+ */
120
+ post<T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ApiResponse<T>>;
121
+ /**
122
+ * PUT 请求
123
+ */
124
+ put<T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ApiResponse<T>>;
125
+ /**
126
+ * DELETE 请求
127
+ */
128
+ delete<T = any>(url: string, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ApiResponse<T>>;
129
+ /**
130
+ * PATCH 请求
131
+ */
132
+ patch<T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ApiResponse<T>>;
133
+ /**
134
+ * HEAD 请求
135
+ */
136
+ head<T = any>(url: string, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ApiResponse<T>>;
137
+ /**
138
+ * OPTIONS 请求
139
+ */
140
+ options<T = any>(url: string, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ApiResponse<T>>;
141
+ /**
142
+ * 取消指定的请求
143
+ */
144
+ cancelRequest(requestKey: string): void;
145
+ /**
146
+ * 取消所有活跃请求
147
+ */
148
+ cancelAllRequests(): void;
149
+ /**
150
+ * 获取活跃请求数量
151
+ */
152
+ getActiveRequestCount(): number;
153
+ }
154
+ declare const apiProxy: ApiProxy;
155
+ export default apiProxy;
@@ -0,0 +1,270 @@
1
+ class ApiError extends Error {
2
+ status;
3
+ statusText;
4
+ response;
5
+ config;
6
+ code;
7
+ responseData;
8
+ constructor(message, config, response, code, responseData){
9
+ super(message);
10
+ this.name = 'ApiError';
11
+ this.config = config;
12
+ this.response = response;
13
+ this.status = response?.status;
14
+ this.statusText = response?.statusText;
15
+ this.code = code;
16
+ this.responseData = responseData;
17
+ Object.setPrototypeOf(this, ApiError.prototype);
18
+ }
19
+ toJSON() {
20
+ return {
21
+ name: this.name,
22
+ message: this.message,
23
+ code: this.code,
24
+ status: this.status,
25
+ statusText: this.statusText,
26
+ responseData: this.responseData,
27
+ config: this.config ? {
28
+ url: this.config.url,
29
+ method: this.config.method,
30
+ headers: this.config.headers,
31
+ params: this.config.params,
32
+ timeout: this.config.timeout,
33
+ responseType: this.config.responseType
34
+ } : void 0
35
+ };
36
+ }
37
+ }
38
+ class ApiProxy {
39
+ defaultConfig = {
40
+ timeout: 30000,
41
+ responseType: 'json',
42
+ credentials: 'same-origin',
43
+ headers: {
44
+ 'Content-Type': 'application/json',
45
+ 'X-Suda-Csrf-Token': window.csrfToken || '',
46
+ 'Cache-Control': 'no-store, no-cache'
47
+ }
48
+ };
49
+ activeRequests = new Map();
50
+ constructor(baseConfig){
51
+ if (baseConfig) this.defaultConfig = {
52
+ ...this.defaultConfig,
53
+ ...baseConfig
54
+ };
55
+ }
56
+ validateUrl(url) {
57
+ if (!url || 'string' != typeof url) return false;
58
+ if (url.startsWith('/') || url.startsWith('./') || url.startsWith('../')) return true;
59
+ try {
60
+ new URL(url);
61
+ return true;
62
+ } catch {
63
+ return false;
64
+ }
65
+ }
66
+ buildUrl(url, params) {
67
+ if (!params || 0 === Object.keys(params).length) return url;
68
+ try {
69
+ const urlObj = new URL(url, window.location.origin);
70
+ Object.entries(params).forEach(([key, value])=>{
71
+ if (null != value) urlObj.searchParams.append(key, String(value));
72
+ });
73
+ return urlObj.toString();
74
+ } catch (error) {
75
+ console.error('Failed to build URL:', error);
76
+ return url;
77
+ }
78
+ }
79
+ serializeData(data, contentType) {
80
+ if (null == data) return null;
81
+ if (data instanceof FormData) return data;
82
+ if (data instanceof Blob || data instanceof File) return data;
83
+ if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) return data;
84
+ if (data instanceof URLSearchParams) return data;
85
+ const type = contentType?.toLowerCase() || '';
86
+ if (type.includes('application/json')) try {
87
+ return JSON.stringify(data);
88
+ } catch (error) {
89
+ throw new ApiError('Failed to serialize JSON data', void 0, void 0, 'SERIALIZATION_ERROR');
90
+ }
91
+ if (type.includes('application/x-www-form-urlencoded')) {
92
+ if ('object' == typeof data) return new URLSearchParams(data).toString();
93
+ return String(data);
94
+ }
95
+ if ('object' == typeof data) try {
96
+ return JSON.stringify(data);
97
+ } catch (error) {
98
+ throw new ApiError('Failed to serialize data', void 0, void 0, 'SERIALIZATION_ERROR');
99
+ }
100
+ return String(data);
101
+ }
102
+ async parseResponse(response, responseType) {
103
+ try {
104
+ switch(responseType){
105
+ case 'json':
106
+ const text = await response.text();
107
+ return text ? JSON.parse(text) : null;
108
+ case 'text':
109
+ return await response.text();
110
+ case 'blob':
111
+ return await response.blob();
112
+ case 'arrayBuffer':
113
+ return await response.arrayBuffer();
114
+ case 'formData':
115
+ return await response.formData();
116
+ default:
117
+ return await response.text();
118
+ }
119
+ } catch (error) {
120
+ throw new ApiError(`Failed to parse response as ${responseType}`, void 0, response, 'PARSE_ERROR');
121
+ }
122
+ }
123
+ serializeHeaders(headers) {
124
+ const serialized = {};
125
+ headers.forEach((value, key)=>{
126
+ serialized[key] = value;
127
+ });
128
+ return serialized;
129
+ }
130
+ generateRequestKey(config) {
131
+ return `${config.method || 'GET'}_${config.url}_${Date.now()}_${Math.random()}`;
132
+ }
133
+ async request(config) {
134
+ if (!config || 'object' != typeof config) throw new ApiError('Request config is required and must be an object', config, void 0, 'INVALID_CONFIG');
135
+ if (!config.url) throw new ApiError('Request URL is required', config, void 0, 'MISSING_URL');
136
+ if (!this.validateUrl(config.url)) throw new ApiError('Invalid URL format', config, void 0, 'INVALID_URL');
137
+ const mergedConfig = {
138
+ ...this.defaultConfig,
139
+ ...config,
140
+ headers: {
141
+ ...this.defaultConfig.headers,
142
+ ...config.headers
143
+ }
144
+ };
145
+ const requestKey = this.generateRequestKey(mergedConfig);
146
+ return await this.executeRequest(mergedConfig, requestKey);
147
+ }
148
+ async executeRequest(config, requestKey) {
149
+ let abortController;
150
+ if (config.signal) {
151
+ abortController = new AbortController();
152
+ config.signal.addEventListener('abort', ()=>abortController.abort());
153
+ } else abortController = new AbortController();
154
+ this.activeRequests.set(requestKey, abortController);
155
+ let timeoutId = null;
156
+ if (config.timeout && config.timeout > 0) timeoutId = setTimeout(()=>{
157
+ abortController.abort();
158
+ }, config.timeout);
159
+ try {
160
+ const fullUrl = this.buildUrl(config.url, config.params);
161
+ const fetchOptions = {
162
+ method: config.method || 'GET',
163
+ headers: config.headers,
164
+ credentials: config.credentials,
165
+ signal: abortController.signal
166
+ };
167
+ const methodsWithoutBody = [
168
+ 'GET',
169
+ 'HEAD'
170
+ ];
171
+ if (config.data && !methodsWithoutBody.includes(config.method || 'GET')) fetchOptions.body = this.serializeData(config.data, config.headers?.['Content-Type']);
172
+ const response = await fetch(fullUrl, fetchOptions);
173
+ if (timeoutId) clearTimeout(timeoutId);
174
+ this.activeRequests.delete(requestKey);
175
+ let data;
176
+ try {
177
+ data = 204 === response.status || 304 === response.status ? null : await this.parseResponse(response, config.responseType || 'json');
178
+ } catch (parseError) {
179
+ console.error('Failed to parse response:', parseError);
180
+ data = null;
181
+ }
182
+ const apiResponse = {
183
+ data,
184
+ status: response.status,
185
+ statusText: response.statusText,
186
+ success: response.ok,
187
+ headers: this.serializeHeaders(response.headers)
188
+ };
189
+ return apiResponse;
190
+ } catch (error) {
191
+ if (timeoutId) clearTimeout(timeoutId);
192
+ this.activeRequests.delete(requestKey);
193
+ if (error instanceof ApiError) throw error;
194
+ if (error instanceof Error && 'AbortError' === error.name) throw new ApiError(config.timeout ? 'Request timeout' : 'Request cancelled', config, void 0, 'ABORT_ERROR');
195
+ if (error instanceof TypeError) throw new ApiError('Network error or CORS issue', config, void 0, 'NETWORK_ERROR');
196
+ throw new ApiError(error instanceof Error ? error.message : 'Unknown error', config, void 0, 'UNKNOWN_ERROR');
197
+ }
198
+ }
199
+ async get(url, config) {
200
+ return this.request({
201
+ ...config,
202
+ url,
203
+ method: 'GET'
204
+ });
205
+ }
206
+ async post(url, data, config) {
207
+ return this.request({
208
+ ...config,
209
+ url,
210
+ method: 'POST',
211
+ data
212
+ });
213
+ }
214
+ async put(url, data, config) {
215
+ return this.request({
216
+ ...config,
217
+ url,
218
+ method: 'PUT',
219
+ data
220
+ });
221
+ }
222
+ async delete(url, config) {
223
+ return this.request({
224
+ ...config,
225
+ url,
226
+ method: 'DELETE'
227
+ });
228
+ }
229
+ async patch(url, data, config) {
230
+ return this.request({
231
+ ...config,
232
+ url,
233
+ method: 'PATCH',
234
+ data
235
+ });
236
+ }
237
+ async head(url, config) {
238
+ return this.request({
239
+ ...config,
240
+ url,
241
+ method: 'HEAD'
242
+ });
243
+ }
244
+ async options(url, config) {
245
+ return this.request({
246
+ ...config,
247
+ url,
248
+ method: 'OPTIONS'
249
+ });
250
+ }
251
+ cancelRequest(requestKey) {
252
+ const controller = this.activeRequests.get(requestKey);
253
+ if (controller) {
254
+ controller.abort();
255
+ this.activeRequests.delete(requestKey);
256
+ }
257
+ }
258
+ cancelAllRequests() {
259
+ this.activeRequests.forEach((controller)=>{
260
+ controller.abort();
261
+ });
262
+ this.activeRequests.clear();
263
+ }
264
+ getActiveRequestCount() {
265
+ return this.activeRequests.size;
266
+ }
267
+ }
268
+ const apiProxy = new ApiProxy();
269
+ const core = apiProxy;
270
+ export { ApiError, core as default };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * GET 请求
3
+ */
4
+ declare function api_get(url: any, config: any): Promise<import("../api-proxy/core").ApiResponse<any>>;
5
+ /**
6
+ * POST 请求
7
+ */
8
+ declare function api_post(url: any, data: any, config: any): Promise<import("../api-proxy/core").ApiResponse<any>>;
9
+ /**
10
+ * PUT 请求
11
+ */
12
+ declare function api_put(url: any, data: any, config: any): Promise<import("../api-proxy/core").ApiResponse<any>>;
13
+ /**
14
+ * DELETE 请求
15
+ */
16
+ declare function api_delete(url: any, config: any): Promise<import("../api-proxy/core").ApiResponse<any>>;
17
+ /**
18
+ * PATCH 请求
19
+ */
20
+ declare function api_patch(url: any, data: any, config: any): Promise<import("../api-proxy/core").ApiResponse<any>>;
21
+ /**
22
+ * HEAD 请求
23
+ */
24
+ declare function api_head(url: any, config: any): Promise<import("../api-proxy/core").ApiResponse<any>>;
25
+ /**
26
+ * OPTIONS 请求
27
+ */
28
+ declare function api_options(url: any, config: any): Promise<import("../api-proxy/core").ApiResponse<any>>;
29
+ export { api_get, api_post, api_put, api_delete, api_patch, api_head, api_options, };
@@ -0,0 +1,66 @@
1
+ import { normalizeBasePath } from "../../../utils/utils.js";
2
+ import core from "../api-proxy/core.js";
3
+ async function api_get(url, config) {
4
+ try {
5
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
6
+ const res = await core.get(`${basePath}${url}`, config);
7
+ return res;
8
+ } catch (error) {
9
+ throw new Error(JSON.stringify(error));
10
+ }
11
+ }
12
+ async function api_post(url, data, config) {
13
+ try {
14
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
15
+ const res = await core.post(`${basePath}${url}`, data, config);
16
+ return res;
17
+ } catch (error) {
18
+ throw new Error(JSON.stringify(error));
19
+ }
20
+ }
21
+ async function api_put(url, data, config) {
22
+ try {
23
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
24
+ const res = await core.put(`${basePath}${url}`, data, config);
25
+ return res;
26
+ } catch (error) {
27
+ throw new Error(JSON.stringify(error));
28
+ }
29
+ }
30
+ async function api_delete(url, config) {
31
+ try {
32
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
33
+ const res = await core["delete"](`${basePath}${url}`, config);
34
+ return res;
35
+ } catch (error) {
36
+ throw new Error(JSON.stringify(error));
37
+ }
38
+ }
39
+ async function api_patch(url, data, config) {
40
+ try {
41
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
42
+ const res = await core.patch(`${basePath}${url}`, data, config);
43
+ return res;
44
+ } catch (error) {
45
+ throw new Error(JSON.stringify(error));
46
+ }
47
+ }
48
+ async function api_head(url, config) {
49
+ try {
50
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
51
+ const res = await core.head(`${basePath}${url}`, config);
52
+ return res;
53
+ } catch (error) {
54
+ throw new Error(JSON.stringify(error));
55
+ }
56
+ }
57
+ async function api_options(url, config) {
58
+ try {
59
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
60
+ const res = await core.options(`${basePath}${url}`, config);
61
+ return res;
62
+ } catch (error) {
63
+ throw new Error(JSON.stringify(error));
64
+ }
65
+ }
66
+ export { api_delete, api_get, api_head, api_options, api_patch, api_post, api_put };
@@ -1,4 +1,5 @@
1
1
  import { normalizeBasePath } from "../../../utils/utils.js";
2
+ import { api_delete, api_get, api_head, api_options, api_patch, api_post, api_put } from "./api-panel.js";
2
3
  async function getRoutes() {
3
4
  let routes = [
4
5
  {
@@ -27,6 +28,15 @@ async function getSourceMap() {
27
28
  }
28
29
  const childApi = {
29
30
  getRoutes,
30
- getSourceMap
31
+ getSourceMap,
32
+ apiProxy: {
33
+ api_get: api_get,
34
+ api_post: api_post,
35
+ api_put: api_put,
36
+ api_delete: api_delete,
37
+ api_patch: api_patch,
38
+ api_head: api_head,
39
+ api_options: api_options
40
+ }
31
41
  };
32
42
  export { childApi };
@@ -1,7 +1,7 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect } from "react";
3
3
  import { useLocation } from "react-router-dom";
4
- import { Button } from "antd";
4
+ import { Button } from "../ui/button.js";
5
5
  import { postMessage } from "../../utils/postMessage.js";
6
6
  import { copyToClipboard } from "../../utils/copyToClipboard.js";
7
7
  const RenderError = (props)=>{
@@ -68,12 +68,12 @@ const RenderError = (props)=>{
68
68
  className: "flex space-x-4",
69
69
  children: [
70
70
  /*#__PURE__*/ jsx(Button, {
71
- className: "bg-white text-gray-600 font-[400] border rounded-[6px] shadow-xs hover:bg-gray-100 active:bg-gray-200 focus:outline-hidden h-[32px] border-[#D0D3D6]",
71
+ className: "bg-white cursor-pointer text-gray-600 font-[400] border rounded-[6px] shadow-xs hover:bg-gray-100 active:bg-gray-200 focus:outline-hidden h-[32px] border-[#D0D3D6]",
72
72
  onClick: onClickCopy,
73
73
  children: "复制错误信息"
74
74
  }),
75
75
  /*#__PURE__*/ jsx(Button, {
76
- className: "h-[32px] text-sm font-medium text-white bg-blue-600 border border-transparent rounded-[6px] shadow-xs hover:bg-blue-600 active:bg-blue-700 focus:outline-hidden ",
76
+ className: "cursor-pointer h-[32px] text-sm font-medium text-white bg-blue-600 border border-transparent rounded-[6px] shadow-xs hover:bg-blue-600 active:bg-blue-700 focus:outline-hidden ",
77
77
  onClick: onClickRepair,
78
78
  children: "告诉妙搭修复"
79
79
  })
@@ -5,5 +5,6 @@ export interface UserDisplayProps {
5
5
  size?: 'small' | 'medium' | 'large';
6
6
  className?: string;
7
7
  style?: React.CSSProperties;
8
+ showLabel?: boolean;
8
9
  }
9
10
  export declare const UserDisplay: React.FC<UserDisplayProps>;
@@ -5,7 +5,7 @@ import { clsxWithTw } from "../../utils/utils.js";
5
5
  import { UserProfile } from "./UserProfile/index.js";
6
6
  import { UserWithAvatar } from "./UserWithAvatar.js";
7
7
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover.js";
8
- const UserDisplay = ({ users, size, className, style })=>{
8
+ const UserDisplay = ({ users, size, className, style, showLabel = true })=>{
9
9
  const normalizedUsers = useMemo(()=>Array.isArray(users) ? users : [
10
10
  users
11
11
  ].filter(Boolean), [
@@ -96,6 +96,7 @@ const UserDisplay = ({ users, size, className, style })=>{
96
96
  children: /*#__PURE__*/ jsx(UserWithAvatar, {
97
97
  data: user,
98
98
  size: size,
99
+ showLabel: showLabel,
99
100
  className: "cursor-pointer hover:bg-[rgba(31,35,41,0.15)] active:bg-[rgba(31,35,41,0.2)]"
100
101
  })
101
102
  })
@@ -1,3 +1,3 @@
1
1
  import * as React from 'react';
2
2
  import type { UserWithAvatarProps } from './type';
3
- export declare function UserWithAvatar({ data, size, mode, className, }: UserWithAvatarProps): React.JSX.Element;
3
+ export declare function UserWithAvatar({ data, size, mode, className, showLabel, }: UserWithAvatarProps): React.JSX.Element;
@@ -23,7 +23,7 @@ const textVariantMap = {
23
23
  medium: 'text-[14px] leading-[20px]',
24
24
  large: 'text-[16px] leading-[24px]'
25
25
  };
26
- function UserWithAvatar({ data, size = 'medium', mode = 'tag', className }) {
26
+ function UserWithAvatar({ data, size = 'medium', mode = 'tag', className, showLabel = true }) {
27
27
  const { avatar, name } = data;
28
28
  const displayName = name?.trim() || '无效人员';
29
29
  const formatSize = [
@@ -48,7 +48,7 @@ function UserWithAvatar({ data, size = 'medium', mode = 'tag', className }) {
48
48
  })
49
49
  ]
50
50
  }),
51
- /*#__PURE__*/ jsx(OverflowTooltipText, {
51
+ showLabel && /*#__PURE__*/ jsx(OverflowTooltipText, {
52
52
  text: displayName,
53
53
  className: clsxWithTw('text-card-foreground', textVariantMap[formatSize])
54
54
  })
@@ -10,4 +10,8 @@ export interface UserWithAvatarProps {
10
10
  */
11
11
  mode?: 'tag' | 'plain';
12
12
  className?: string;
13
+ /**
14
+ * @default true
15
+ */
16
+ showLabel?: boolean;
13
17
  }
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  declare const badgeVariants: (props?: {
4
- variant?: "default" | "secondary" | "destructive" | "outline";
4
+ variant?: "default" | "destructive" | "outline" | "secondary";
5
5
  } & import("class-variance-authority/dist/types").ClassProp) => string;
6
6
  declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
7
7
  asChild?: boolean;
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  declare const buttonVariants: (props?: {
4
- variant?: "default" | "link" | "secondary" | "destructive" | "outline" | "ghost";
4
+ variant?: "default" | "link" | "destructive" | "outline" | "secondary" | "ghost";
5
5
  size?: "default" | "icon" | "sm" | "lg" | "icon-sm" | "icon-lg";
6
6
  } & import("class-variance-authority/dist/types").ClassProp) => string;
7
7
  declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
@@ -4,7 +4,18 @@ const useAppInfo = ()=>{
4
4
  const [appInfo, setAppInfo] = useState({});
5
5
  useEffect(()=>{
6
6
  const handleMetaInfoChanged = async ()=>{
7
- setAppInfo(await getAppInfo());
7
+ const info = await getAppInfo();
8
+ if (info.name) document.title = info.name;
9
+ if (info.avatar) {
10
+ let link = document.querySelector("link[rel~='icon']");
11
+ if (!link) {
12
+ link = document.createElement('link');
13
+ link.rel = 'icon';
14
+ document.head.appendChild(link);
15
+ }
16
+ link.href = info.avatar;
17
+ }
18
+ setAppInfo(info);
8
19
  };
9
20
  handleMetaInfoChanged();
10
21
  window.addEventListener('MiaoDaMetaInfoChanged', handleMetaInfoChanged);
@@ -1,7 +1,7 @@
1
1
  import { getInitialInfo } from "../utils/getInitialInfo.js";
2
2
  import { isSparkRuntime } from "../utils/utils.js";
3
3
  async function getAppInfo() {
4
- let appInfo = window._appInfo;
4
+ let appInfo = 'undefined' != typeof window ? window._appInfo : void 0;
5
5
  if (!appInfo && isSparkRuntime()) {
6
6
  const info = (await getInitialInfo())?.app_info;
7
7
  appInfo = {
@@ -9,15 +9,7 @@ async function getAppInfo() {
9
9
  avatar: info?.app_avatar || ''
10
10
  };
11
11
  if (appInfo.name) appInfo.name = appInfo.name.trim();
12
- if (appInfo.avatar) {
13
- let link = document.querySelector("link[rel~='icon']");
14
- if (!link) {
15
- link = document.createElement('link');
16
- link.rel = 'icon';
17
- document.head.appendChild(link);
18
- }
19
- link.href = appInfo.avatar;
20
- }
12
+ if ('undefined' != typeof window) window._appInfo = appInfo;
21
13
  }
22
14
  return appInfo ?? {};
23
15
  }
@@ -74,4 +74,5 @@ export declare function getBatchLogger(): BatchLogger;
74
74
  export declare function initBatchLogger(oldConsole: Console, config?: BatchLoggerConfig): void;
75
75
  /** 记录日志进行批量同步 */
76
76
  export declare function batchLogInfo(level: string, message: string, source?: string): void;
77
+ export declare function destroyBatchLogger(): void;
77
78
  export {};
@@ -13,7 +13,7 @@ class BatchLogger {
13
13
  userId,
14
14
  tenantId,
15
15
  appId,
16
- endpoint: '/dev/logs/collect-batch',
16
+ endpoint: (process.env.CLIENT_BASE_PATH || '') + '/dev/logs/collect-batch',
17
17
  sizeThreshold: 20,
18
18
  flushInterval: 1000,
19
19
  maxRetries: 3,
@@ -125,7 +125,10 @@ function batchLogInfo(level, message, source) {
125
125
  if (!defaultBatchLogger) return;
126
126
  defaultBatchLogger.batchLog(level, message, source);
127
127
  }
128
- if ('undefined' != typeof window) window.addEventListener('beforeunload', ()=>{
129
- defaultBatchLogger = null;
130
- });
131
- export { BatchLogger, batchLogInfo, getBatchLogger, initBatchLogger };
128
+ function destroyBatchLogger() {
129
+ if (defaultBatchLogger) {
130
+ defaultBatchLogger.destroy();
131
+ defaultBatchLogger = null;
132
+ }
133
+ }
134
+ export { BatchLogger, batchLogInfo, destroyBatchLogger, getBatchLogger, initBatchLogger };
@@ -48,4 +48,13 @@ export interface ParentApi {
48
48
  export interface ChildApi {
49
49
  getRoutes: () => Promise<any[]>;
50
50
  getSourceMap: () => Promise<string>;
51
+ apiProxy: {
52
+ api_get: (url: string, config?: any) => Promise<any>;
53
+ api_post: (url: string, data?: any, config?: any) => Promise<any>;
54
+ api_put: (url: string, data?: any, config?: any) => Promise<any>;
55
+ api_delete: (url: string, config?: any) => Promise<any>;
56
+ api_patch: (url: string, data?: any, config?: any) => Promise<any>;
57
+ api_head: (url: string, config?: any) => Promise<any>;
58
+ api_options: (url: string, config?: any) => Promise<any>;
59
+ };
51
60
  }
@@ -2,10 +2,11 @@ function getAppId(path) {
2
2
  if (window.MIAODA_APP_ID) return window.MIAODA_APP_ID;
3
3
  let prefix;
4
4
  prefix = path.includes('/ai/feida/runtime/') ? '/ai/feida/runtime/' : path.includes('/spark/r/') ? '/spark/r/' : '/ai/miaoda/';
5
- if (!path.startsWith(prefix)) return null;
5
+ const windowAppId = window.appId || null;
6
+ if (!path.startsWith(prefix)) return windowAppId;
6
7
  const remainder = path.substring(prefix.length);
7
8
  const nextSlashIndex = remainder.indexOf('/');
8
- if (-1 === nextSlashIndex) return remainder;
9
- return remainder.substring(0, nextSlashIndex);
9
+ if (-1 === nextSlashIndex) return remainder || windowAppId;
10
+ return remainder.substring(0, nextSlashIndex) || windowAppId;
10
11
  }
11
12
  export { getAppId };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-toolkit",
3
- "version": "0.1.0-alpha.log.10",
3
+ "version": "0.1.0-alpha.log.15",
4
4
  "types": "./lib/index.d.ts",
5
5
  "main": "./lib/index.js",
6
6
  "files": [