@zxiaosi/sdk 0.5.1 → 1.0.0-beta.1
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 +71 -52
- package/dist/index.d.ts +17 -59
- package/dist/index.js +2 -1
- package/dist/style.css +1 -0
- package/package.json +27 -8
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
## 快速开始
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
+
# 安装 @zxiaosi/sdk 对应的版本 0.5.x
|
|
12
13
|
npm install -g @zxiaosi/create-sdk
|
|
13
14
|
|
|
14
15
|
npx create-sdk
|
|
@@ -18,30 +19,20 @@ npx create-sdk
|
|
|
18
19
|
|
|
19
20
|
- 整个 `SDK` 都是围绕 `getRoutesApi`、`getUserInfoApi` 这两个接口进行设计的,旨在简化微前端应用的开发
|
|
20
21
|
|
|
21
|
-
- `getRoutesApi` 接口用于获取应用路由信息,包括主应用和微应用的路由配置。因为 `Qiankun` 的 `entry`
|
|
22
|
+
- `getRoutesApi` 接口用于获取应用路由信息,包括主应用和微应用的路由配置。因为 `Qiankun` 的 `entry` 配置比较特殊,所以 `主应用` 需要使用 `vite-plugin-mock` 插件 `mock` 接口
|
|
23
|
+
- 在本地开发是本地服务 `"entry": "http://localhost:5174"`
|
|
24
|
+
- 在生产环境是文件路径 `"entry": "/subapp/"`
|
|
22
25
|
|
|
23
|
-
- `getUserInfoApi`
|
|
26
|
+
- `getUserInfoApi` 接口用于获取用户相关数据,以便进行权限控制和个性化设置。
|
|
27
|
+
- `user`:用户信息(必选)
|
|
28
|
+
- `permissions`:权限信息(必选)
|
|
29
|
+
- `role`:角色信息(可选)
|
|
30
|
+
- `setting`:配置信息(可选)
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- 微应用启动服务时需要加上 `--host` 参数,否则可能会出现微应用静态资源访问不到的情况。完整命令 `"dev": "vite --host"`
|
|
28
|
-
|
|
29
|
-
- `SDK` 不能在 `组件外` 进行使用,否则会报 `SDK 未初始化` 错误
|
|
30
|
-
|
|
31
|
-
## 具体使用
|
|
32
|
+
## 核心代码
|
|
32
33
|
|
|
33
34
|
### 主应用
|
|
34
35
|
|
|
35
|
-
- 安装依赖
|
|
36
|
-
|
|
37
|
-
```sh
|
|
38
|
-
// 必须的依赖
|
|
39
|
-
npm install react react-dom react-router-dom@6.30.2 zustand @zxiaosi/sdk
|
|
40
|
-
|
|
41
|
-
// 可选的依赖
|
|
42
|
-
npm install antd dayjs
|
|
43
|
-
```
|
|
44
|
-
|
|
45
36
|
- 在 `main.ts` 中进行 `SDK` 的挂载
|
|
46
37
|
|
|
47
38
|
```js
|
|
@@ -59,23 +50,29 @@ npx create-sdk
|
|
|
59
50
|
import { createRoot } from 'react-dom/client';
|
|
60
51
|
import App from './App';
|
|
61
52
|
|
|
53
|
+
const getRoutesApi = async () => ({
|
|
54
|
+
code: 0,
|
|
55
|
+
data: [
|
|
56
|
+
{ path: '/home', name: '首页', component: 'Home' },
|
|
57
|
+
{ path: '/subapp', name: '微应用', component: 'Microapp',
|
|
58
|
+
routeAttr: `{"name": "subapp", "entry": "http://localhost:5174", "activeRule": "/subapp", "rootId": "sub-app"}`,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const getUserInfoApi = async () => ({
|
|
64
|
+
code: 0,
|
|
65
|
+
data: { user: {}, permissions: ['/home', '/subapp'], roles: [], settings: {} },
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const loginApi = async () => ({ code: 0, data: { token: 'xxxx' } })
|
|
69
|
+
|
|
62
70
|
/** 挂载 SDK */
|
|
63
71
|
sdk
|
|
64
72
|
.use(SdkApiPlugin, {
|
|
65
|
-
getRoutesApi
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{ path: '/home', name: '首页', component: 'Home' },
|
|
69
|
-
{ path: '/subapp', name: '微应用', component: 'Microapp',
|
|
70
|
-
routeAttr: `{"name": "subapp", "entry": "http://localhost:5174", "activeRule": "/subapp", "rootId": "sub-app"}`,
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
}),
|
|
74
|
-
getUserInfoApi: async () => ({
|
|
75
|
-
code: 0,
|
|
76
|
-
data: { user: {}, permissions: ['/home', '/subapp'], roles: [], settings: {} },
|
|
77
|
-
}),
|
|
78
|
-
loginApi: async () => ({ code: 0, data: { token: 'xxxx' } }),
|
|
73
|
+
getRoutesApi,
|
|
74
|
+
getUserInfoApi,
|
|
75
|
+
loginApi,
|
|
79
76
|
})
|
|
80
77
|
.use(SdkAppPlugin)
|
|
81
78
|
.use(SdkClientPlugin)
|
|
@@ -111,17 +108,6 @@ npx create-sdk
|
|
|
111
108
|
|
|
112
109
|
### 微应用
|
|
113
110
|
|
|
114
|
-
- 安装依赖
|
|
115
|
-
|
|
116
|
-
```sh
|
|
117
|
-
// 必须的依赖
|
|
118
|
-
npm install react react-dom react-router-dom@6.30.2 zustand @zxiaosi/sdk
|
|
119
|
-
npm install vite-plugin-qiankun-lite --save-dev
|
|
120
|
-
|
|
121
|
-
// 可选的依赖
|
|
122
|
-
npm install antd dayjs
|
|
123
|
-
```
|
|
124
|
-
|
|
125
111
|
- 在 `vite.config.ts` 中配置 `vite-plugin-qiankun-lite` 插件
|
|
126
112
|
|
|
127
113
|
```js
|
|
@@ -163,10 +149,6 @@ npx create-sdk
|
|
|
163
149
|
render();
|
|
164
150
|
}
|
|
165
151
|
|
|
166
|
-
export async function bootstrap() {
|
|
167
|
-
console.log(`Microapp bootstrap`);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
152
|
export async function mount(props: any) {
|
|
171
153
|
console.log(`Microapp mount`, props);
|
|
172
154
|
sdk.extend('sdk'); // 继承 sdk 功能
|
|
@@ -177,10 +159,47 @@ npx create-sdk
|
|
|
177
159
|
console.log(`Microapp unmount`, props);
|
|
178
160
|
root.unmount();
|
|
179
161
|
}
|
|
180
|
-
|
|
181
|
-
export async function update(props: any) {
|
|
182
|
-
console.log(`Microapp update`, props);
|
|
183
|
-
}
|
|
184
162
|
```
|
|
185
163
|
|
|
186
164
|
- [可参考项目](https://github.com/zxiaosi-team/fontend-sdk/tree/master/packages)
|
|
165
|
+
|
|
166
|
+
## 注意事项
|
|
167
|
+
|
|
168
|
+
- `SDK` 不能在 `组件外` 进行使用,否则会报 `SDK 未初始化` 错误
|
|
169
|
+
|
|
170
|
+
- 微应用使用 `sdk.ui.renderComponent('xxx')` 时,会报 `React 多实例` 的错误,需要使用 `vite-plugin-externals` 插件将 `React` 等依赖排除在打包之外。[更多详情](https://zxiaosi.com/archives/bc84a75a.html)
|
|
171
|
+
- 在主/子应用的 `index.html` 中使用 `cdn` 的方式去加载 `react` 和 `react-dom` 包
|
|
172
|
+
|
|
173
|
+
```html
|
|
174
|
+
<!doctype html>
|
|
175
|
+
<html lang="en">
|
|
176
|
+
<head>
|
|
177
|
+
<title>%VITE_APP_TITLE%</title>
|
|
178
|
+
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js"></script>
|
|
179
|
+
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js"></script>
|
|
180
|
+
</head>
|
|
181
|
+
<body>
|
|
182
|
+
<div id="root"></div>
|
|
183
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
184
|
+
</body>
|
|
185
|
+
</html>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- 在主/子应用中使用 `vite-plugin-externals` 插件去排除 `react` 和 `react-dom` 包
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { viteExternalsPlugin } from 'vite-plugin-externals';
|
|
192
|
+
|
|
193
|
+
export default defineConfig({
|
|
194
|
+
plugins: [
|
|
195
|
+
viteExternalsPlugin({
|
|
196
|
+
react: 'React',
|
|
197
|
+
|
|
198
|
+
// 开发环境不排除 react-dom 依赖, 防止热更新失效
|
|
199
|
+
// 或者 浏览器安装 React Developer Tools 插件
|
|
200
|
+
'react-dom': 'ReactDOM',
|
|
201
|
+
'react-dom/client': 'ReactDOM',
|
|
202
|
+
}),
|
|
203
|
+
],
|
|
204
|
+
});
|
|
205
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import * as zustand from "zustand";
|
|
1
|
+
import * as _$zustand from "zustand";
|
|
2
2
|
import { ComponentType, ReactElement } from "react";
|
|
3
3
|
import { Location, NavigateFunction, RouteObject, UIMatch } from "react-router-dom";
|
|
4
|
-
import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from "axios";
|
|
5
|
-
import { ConfigProviderProps } from "antd";
|
|
6
|
-
import * as react_intl_universal0 from "react-intl-universal";
|
|
7
|
-
import intl from "react-intl-universal";
|
|
8
|
-
import { MenuDataItem, ProLayoutProps } from "@ant-design/pro-layout";
|
|
9
4
|
import { MicroApp, ObjectType, RegistrableApp } from "qiankun";
|
|
5
|
+
import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from "axios";
|
|
10
6
|
|
|
11
7
|
//#region src/plugins/api/http.d.ts
|
|
12
8
|
interface ApiRequestOption extends AxiosRequestConfig {
|
|
@@ -74,7 +70,7 @@ declare const SdkApiPlugin: Plugin<'api'>;
|
|
|
74
70
|
//#region src/plugins/app/index.d.ts
|
|
75
71
|
interface AppOptions {
|
|
76
72
|
/** 菜单数据 */
|
|
77
|
-
menuData?:
|
|
73
|
+
menuData?: any[];
|
|
78
74
|
/** 所有路由信息 */
|
|
79
75
|
allRoutes?: RouteObject[];
|
|
80
76
|
/** 微应用信息 */
|
|
@@ -178,10 +174,7 @@ interface ConfigOptions {
|
|
|
178
174
|
* - 会合并到 sdk.app.allRoutes 中
|
|
179
175
|
*/
|
|
180
176
|
customRoutes?: RouteObject[];
|
|
181
|
-
|
|
182
|
-
antdConfig?: ConfigProviderProps;
|
|
183
|
-
/** ProLayout 配置 */
|
|
184
|
-
proLayoutConfig?: ProLayoutProps;
|
|
177
|
+
[key: string]: any;
|
|
185
178
|
}
|
|
186
179
|
interface ConfigResults extends Required<ConfigOptions> {}
|
|
187
180
|
/**
|
|
@@ -191,19 +184,16 @@ interface ConfigResults extends Required<ConfigOptions> {}
|
|
|
191
184
|
* - 配置 默认主题、语言
|
|
192
185
|
* - 配置 Qiankun 模式
|
|
193
186
|
* - 配置 默认登录路径、跳转路径、自定义路由
|
|
194
|
-
* - 配置 Antd 配置、ProLayout 配置
|
|
195
187
|
*/
|
|
196
188
|
declare const SdkConfigPlugin: Plugin<'config'>;
|
|
197
189
|
//#endregion
|
|
198
190
|
//#region src/plugins/i18n/index.d.ts
|
|
199
191
|
interface I18nOptions {
|
|
200
192
|
/**
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* - 如果项目不使用 React Compiler, 可以直接使用 sdk.i18n.intl
|
|
204
|
-
* @example const intl = useIntl(); intl.get(key).d(defaultValue)
|
|
193
|
+
* Intl 实例
|
|
194
|
+
* @example sdk.i18n.intl?.xxx
|
|
205
195
|
*/
|
|
206
|
-
intl?:
|
|
196
|
+
intl?: any;
|
|
207
197
|
/**
|
|
208
198
|
* 自定义语言包
|
|
209
199
|
* @example
|
|
@@ -217,37 +207,11 @@ interface I18nOptions {
|
|
|
217
207
|
* }
|
|
218
208
|
*/
|
|
219
209
|
intlConfig?: Record<string, any>;
|
|
220
|
-
/**
|
|
221
|
-
* 加载语言包
|
|
222
|
-
* @param locale 语言包名
|
|
223
|
-
* @example
|
|
224
|
-
* import enUS from 'antd/es/locale/en_US';
|
|
225
|
-
* import zhCN from 'antd/es/locale/zh_CN';
|
|
226
|
-
* import dayjs from 'dayjs';
|
|
227
|
-
* import 'dayjs/locale/en';
|
|
228
|
-
* import 'dayjs/locale/zh';
|
|
229
|
-
*
|
|
230
|
-
* const loadLocale = (locale: string) => {
|
|
231
|
-
* switch (locale) {
|
|
232
|
-
* case 'en-US':
|
|
233
|
-
* dayjs.locale('en');
|
|
234
|
-
* return enUS;
|
|
235
|
-
* case 'zh-CN':
|
|
236
|
-
* dayjs.locale('zh');
|
|
237
|
-
* return zhCN;
|
|
238
|
-
* default:
|
|
239
|
-
* return undefined;
|
|
240
|
-
* }
|
|
241
|
-
* }
|
|
242
|
-
*/
|
|
243
|
-
loadLocale?(locale: string): any;
|
|
244
210
|
}
|
|
245
211
|
interface I18nResults extends Required<I18nOptions> {}
|
|
246
212
|
/**
|
|
247
213
|
* 多语言
|
|
248
214
|
* - 详情参考 {@link I18nOptions} {@link I18nResults}
|
|
249
|
-
* - 集成 React Intl Universal 和 Antd 国际化
|
|
250
|
-
* - 需要从外部引入语言包, 详见 intlConfig 和 loadLocale 配置项
|
|
251
215
|
*/
|
|
252
216
|
declare const SdkI18nPlugin: Plugin<'i18n'>;
|
|
253
217
|
//#endregion
|
|
@@ -336,7 +300,7 @@ type StoreResults = typeof globalStore;
|
|
|
336
300
|
* 创建 Store
|
|
337
301
|
* - 这里单独声明变量, 主要是为了使用返回类型 StoreResults 🤔
|
|
338
302
|
*/
|
|
339
|
-
declare const globalStore: Omit<zustand.StoreApi<StoreOptions>, "subscribe"> & {
|
|
303
|
+
declare const globalStore: Omit<_$zustand.StoreApi<StoreOptions>, "subscribe"> & {
|
|
340
304
|
subscribe: {
|
|
341
305
|
(listener: (selectedState: StoreOptions, previousSelectedState: StoreOptions) => void): () => void;
|
|
342
306
|
<U>(selector: (state: StoreOptions) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
|
|
@@ -502,20 +466,7 @@ declare const useUserInfo: () => {
|
|
|
502
466
|
* - 不要解构使用, const { get } = useIntl() 会报错
|
|
503
467
|
* @example const intl = useIntl(); intl.get(key).d(defaultValue)
|
|
504
468
|
*/
|
|
505
|
-
declare const useIntl: () =>
|
|
506
|
-
determineLocale: typeof react_intl_universal0.determineLocale;
|
|
507
|
-
formatHTMLMessage: typeof react_intl_universal0.formatHTMLMessage;
|
|
508
|
-
formatMessage: typeof react_intl_universal0.formatMessage;
|
|
509
|
-
get: typeof react_intl_universal0.get;
|
|
510
|
-
getHTML: typeof react_intl_universal0.getHTML;
|
|
511
|
-
getInitOptions: typeof react_intl_universal0.getInitOptions;
|
|
512
|
-
init: typeof react_intl_universal0.init;
|
|
513
|
-
load: typeof react_intl_universal0.load;
|
|
514
|
-
formatList: typeof react_intl_universal0.formatList;
|
|
515
|
-
formatParentheses: typeof react_intl_universal0.formatParentheses;
|
|
516
|
-
getColon: typeof react_intl_universal0.getColon;
|
|
517
|
-
formatNumber: typeof react_intl_universal0.formatNumber;
|
|
518
|
-
};
|
|
469
|
+
declare const useIntl: () => any;
|
|
519
470
|
//#endregion
|
|
520
471
|
//#region src/hooks/useCrumb.d.ts
|
|
521
472
|
/**
|
|
@@ -531,4 +482,11 @@ declare const useCrumb: () => any[];
|
|
|
531
482
|
*/
|
|
532
483
|
declare const usePermission: (code?: string) => boolean;
|
|
533
484
|
//#endregion
|
|
534
|
-
|
|
485
|
+
//#region src/hooks/useInitData.d.ts
|
|
486
|
+
/** 初始化数据 */
|
|
487
|
+
declare const useInitData: () => {
|
|
488
|
+
loading: boolean;
|
|
489
|
+
routes: RouteObject[];
|
|
490
|
+
};
|
|
491
|
+
//#endregion
|
|
492
|
+
export { type ApiOptions, type ApiResults, type AppOptions, type AppResults, type ClientOptions, type ClientResults, type ConfigOptions, type ConfigResults, type I18nOptions, type I18nResults, SdkApiPlugin, SdkAppPlugin, SdkClientPlugin, SdkConfigPlugin, SdkI18nPlugin, SdkStoragePlugin, SdkStorePlugin, SdkUIPlugin, type StorageOptions, type StorageResults, type StoreOptions, type StoreResults, type UIOptions, type UIResults, sdk, useCrumb, useInitData, useIntl, usePermission, useUserInfo };
|
package/dist/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{createStore as e,useStore as t}from"zustand";import{useShallow as n}from"zustand/shallow";import{Suspense as r,createElement as i,memo as a,useEffect as o,useMemo as s,useState as c}from"react";import{Navigate as ee,Outlet as l,RouterProvider as te,createBrowserRouter as ne,useLocation as u,useMatches as d,useNavigate as f}from"react-router-dom";import{Fragment as p,jsx as m,jsxs as h}from"react/jsx-runtime";import g from"axios";import{Button as _,ConfigProvider as re,Flex as v,Form as y,Input as b,message as x,theme as S}from"antd";import C from"react-intl-universal";import{subscribeWithSelector as w}from"zustand/middleware";import T from"@ant-design/pro-layout";import{loadMicroApp as E,registerMicroApps as ie,start as ae}from"qiankun";const D=new class{name;_plugins;api;app;client;config;i18n;storage;store;ui;constructor(){this.name=``,this._plugins=new Map}mount(e){if(window[e])throw Error(`The SDK already exists - ${e}`);console.log(`%c SDK mounted:`,`color: pink; font-weight: bold;`,e,D),this.name=e;let t=new Proxy(this,{get:(e,t,n)=>e?Reflect.get(e,t,n):null,set:()=>(console.error(`The SDK cannot be modified.`),!1),deleteProperty:()=>(console.error(`The SDK cannot be deleted.`),!1)});window[this.name]=t}extend(e){if(!window[e])throw Error(`The SDK not found - ${e}`);console.log(`%c SDK extended:`,`color: pink; font-weight: bold;`,e),Object.assign(this,window[e])}use(e,t){let{name:n,install:r}=e;if(!n)throw Error(`${n} plugin has no name`);if(typeof r!=`function`)throw Error(`${n} plugin is not a function`);return r(this,t),this._plugins.set(n,{...e,options:t}),this}},O=()=>{let[e,r,i]=t(D.store,n(e=>[e.userInfo,e.setUserInfo,e.resetUserInfo]));return{userInfo:e,setUserInfo:r,resetUserInfo:i}};function k(e){return e==null||typeof e!=`object`&&typeof e!=`function`}function A(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function oe(e){return Object.getOwnPropertySymbols(e).filter(t=>Object.prototype.propertyIsEnumerable.call(e,t))}function se(e){return e==null?e===void 0?`[object Undefined]`:`[object Null]`:Object.prototype.toString.call(e)}function j(e,t,n,r=new Map,i=void 0){let a=i?.(e,t,n,r);if(a!==void 0)return a;if(k(e))return e;if(r.has(e))return r.get(e);if(Array.isArray(e)){let t=Array(e.length);r.set(e,t);for(let a=0;a<e.length;a++)t[a]=j(e[a],a,n,r,i);return Object.hasOwn(e,`index`)&&(t.index=e.index),Object.hasOwn(e,`input`)&&(t.input=e.input),t}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp){let t=new RegExp(e.source,e.flags);return t.lastIndex=e.lastIndex,t}if(e instanceof Map){let t=new Map;r.set(e,t);for(let[a,o]of e)t.set(a,j(o,a,n,r,i));return t}if(e instanceof Set){let t=new Set;r.set(e,t);for(let a of e)t.add(j(a,void 0,n,r,i));return t}if(typeof Buffer<`u`&&Buffer.isBuffer(e))return e.subarray();if(A(e)){let t=new(Object.getPrototypeOf(e)).constructor(e.length);r.set(e,t);for(let a=0;a<e.length;a++)t[a]=j(e[a],a,n,r,i);return t}if(e instanceof ArrayBuffer||typeof SharedArrayBuffer<`u`&&e instanceof SharedArrayBuffer)return e.slice(0);if(e instanceof DataView){let t=new DataView(e.buffer.slice(0),e.byteOffset,e.byteLength);return r.set(e,t),M(t,e,n,r,i),t}if(typeof File<`u`&&e instanceof File){let t=new File([e],e.name,{type:e.type});return r.set(e,t),M(t,e,n,r,i),t}if(typeof Blob<`u`&&e instanceof Blob){let t=new Blob([e],{type:e.type});return r.set(e,t),M(t,e,n,r,i),t}if(e instanceof Error){let t=structuredClone(e);return r.set(e,t),t.message=e.message,t.name=e.name,t.stack=e.stack,t.cause=e.cause,t.constructor=e.constructor,M(t,e,n,r,i),t}if(e instanceof Boolean){let t=new Boolean(e.valueOf());return r.set(e,t),M(t,e,n,r,i),t}if(e instanceof Number){let t=new Number(e.valueOf());return r.set(e,t),M(t,e,n,r,i),t}if(e instanceof String){let t=new String(e.valueOf());return r.set(e,t),M(t,e,n,r,i),t}if(typeof e==`object`&&ce(e)){let t=Object.create(Object.getPrototypeOf(e));return r.set(e,t),M(t,e,n,r,i),t}return e}function M(e,t,n=e,r,i){let a=[...Object.keys(t),...oe(t)];for(let o=0;o<a.length;o++){let s=a[o],c=Object.getOwnPropertyDescriptor(e,s);(c==null||c.writable)&&(e[s]=j(t[s],s,n,r,i))}}function ce(e){switch(se(e)){case`[object Arguments]`:case`[object Array]`:case`[object ArrayBuffer]`:case`[object DataView]`:case`[object Boolean]`:case`[object Date]`:case`[object Float32Array]`:case`[object Float64Array]`:case`[object Int8Array]`:case`[object Int16Array]`:case`[object Int32Array]`:case`[object Map]`:case`[object Number]`:case`[object Object]`:case`[object RegExp]`:case`[object Set]`:case`[object String]`:case`[object Symbol]`:case`[object Uint8Array]`:case`[object Uint8ClampedArray]`:case`[object Uint16Array]`:case`[object Uint32Array]`:return!0;default:return!1}}function N(e){return j(e,void 0,e,new Map,void 0)}function P(e){if(!e||typeof e!=`object`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype||Object.getPrototypeOf(t)===null?Object.prototype.toString.call(e)===`[object Object]`:!1}function le(e){return e===`__proto__`}function F(e,t){let n=Object.keys(t);for(let r=0;r<n.length;r++){let i=n[r];if(le(i))continue;let a=t[i],o=e[i];I(a)&&I(o)?e[i]=F(o,a):Array.isArray(a)?e[i]=F([],a):P(a)?e[i]=F({},a):(o===void 0||a!==void 0)&&(e[i]=a)}return e}function I(e){return P(e)||Array.isArray(e)}const ue=()=>s(()=>N(D.i18n.intl),[t(D.store,e=>e.locale)]),L=()=>s(()=>D.client.matches,[u()]).filter(e=>!!e.handle?.crumb).map(e=>e.handle.crumb(e.data)),R=e=>{let{requestId:t,url:n,method:r,params:i,data:a}=e;return t||`${r}:${n}?${JSON.stringify(i)}&${JSON.stringify(a)}`},z=e=>{let t=R(e),n=D.api.controllers.get(t);n&&(n.abort(),D.api.controllers.delete(t))},B={beforeLoad:[async e=>{console.log(`[LifeCycle] before load %c%s`,`color: green;`,e.name)}],beforeMount:[async e=>{console.log(`[LifeCycle] before mount %c%s`,`color: green;`,e.name)}],afterUnmount:[async e=>{console.log(`[LifeCycle] after unmount %c%s`,`color: green;`,e.name)}]},V=e=>{let t=e.storage.getTheme();if(t)return t;let n=e.config?.theme;if(n)return n;let r=window.matchMedia(`(prefers-color-scheme: dark)`);return r.matches&&r.matches?`dark`:`light`},H=e=>e.storage.getLocale()||e.config?.locale||navigator.language||`zh-CN`,U=e=>D.app.permissions?.includes?.(e),de=e=>{let t=new Map,n=W(e,t);return{microApps:[...t.values()],menuData:n}},W=(e,t)=>!e||e?.length===0?[]:e.map(e=>{let n=null,{locale:r,path:i,icon:a,component:o,routeAttr:s,children:c}=e;if(s){let e={};try{e=JSON.parse(s)}catch(e){console.error(`Sdk: initData - Subapp routeAttr error: `,e)}let{name:r,rootId:i,...a}=e,o={...a,name:r,container:`#${i}`,props:{sdk:D},loader:e=>D.store.getState().setMicroAppLoading(e)};t.set(r,o),n=D.ui.renderComponent(`Microapp`,{name:r,rootId:i})}else if(o===`Microapp`)n=D.ui.renderComponent(`Microapp`);else if(o===`Outlet`)n=m(l,{});else{let e=U(i);n=D.ui.renderComponent(e?o:`NoPermission`)}return{...e,key:`${i}_${a}_${r}`,element:n,children:W(c,t),handle:{crumb:(t={})=>({...e,...t})}}}),G=e=>{let t=`/`;return!e||e.length===0?t:(t=e?.[0]?.path,e?.[0]?.children&&e?.[0]?.children.length>0&&(t=G(e?.[0]?.children)),t)},fe=e=>s(()=>U(e||D.client.location.pathname),[u().pathname,e]);var pe=class{instance;constructor(e={}){this.instance=g.create(e),this.defaultRequestInterceptor(),this.defaultResponseInterceptor()}defaultRequestInterceptor(){this.instance.interceptors.request.use(function(e){if(e?.isCancelRequest){let t=R(e);z(e);let n=new AbortController;D.api.controllers.set(t,n),e.requestId=t,e.signal=n.signal}let t=D.storage.getToken();return e.headers.lang=D.config.locale,e.headers.Authorization=t,F(e.headers,D.api.config.headers||{}),e},function(e){return console.error(`Sdk: defaultRequestInterceptor - 请求错误`),Promise.reject(e)})}defaultResponseInterceptor(){this.instance.interceptors.response.use(function(e){let{data:t,config:n}=e,{isOriginalData:r,isShowFailMsg:i,isCancelRequest:a}=n,{code:o,msg:s}=t;return o!==0&&(i&&x.error(s),console.error(`Sdk: defaultResponseInterceptor - Response error: `,n.url,s),o==20041&&D.app.pageToLogin()),a&&D.api.controllers.delete(n.requestId),r?e:e.data},function(e){let{response:t,config:n}=e,{isShowFailMsg:r}=n;if(g.isCancel(e))return Promise.reject(e);if(t){let{status:e,data:n,statusText:i}=t;r&&x.error(n.msg||i),e==401&&D.app.pageToLogin()}else r&&x.error(`请求超时或服务器异常,请检查网络或联系管理员`),console.error(`Sdk: defaultResponseInterceptor - Request error:`,n.url,e);return Promise.reject(e)})}getInstance(){return this.instance}};const me={name:`api`,install(e,t={}){let n={baseURL:`/`,timeout:0,...t.config},r=t?.instance||new pe(n).getInstance();e.api=F({config:n,controllers:new Map,instance:null,request:(e,t={})=>r.request({url:e,isOriginalData:!1,isShowFailMsg:!0,isCancelRequest:!0,...t}),getUserInfoApi:()=>e.api.request(`/getUserInfo`,{method:`GET`}),getRoutesApi:()=>e.api.request(`/routes`,{method:`GET`}),loginApi:()=>e.api.request(`/login`,{method:`POST`})},t)}},he={name:`app`,install(e,t={}){e.app=F({menuData:[],allRoutes:[],microApps:[],microAppsInstance:new Map,user:null,permissions:[],roles:[],settings:{},initData:null,clearData:()=>{e.app.menuData=[],e.app.allRoutes=e.app.allRoutes.filter(e=>e.path!==`/`),e.app.microApps=[],e.app.microAppsInstance.forEach(e=>e.unmount()),e.app.microAppsInstance.clear(),e.store.getState().resetUserInfo()},pageToLogin:()=>{e.storage.clearToken();let t=window.location.pathname||`/`,n=e.config.loginPath,r=t===n?n:`${n}?redirect=${encodeURIComponent(t)}`;e.config.qiankunMode===`router`?window.location.replace(r):(e.app.clearData(),e.client.navigate(r,{replace:!0}))},getRedirectPath:()=>{let t=e.config.defaultPath;if(t)return t;let n=new URLSearchParams(window.location.search);return decodeURIComponent(n.get(`redirect`)||``)||`/`}},t)}},K=`client`,ge={name:K,install(e,t={}){e[K]=F({location:null,navigate:null,matches:null},t)}},q=`config`,_e={name:q,install(e,t={}){e[q]=F({env:{},qiankunMode:`router`,theme:null,locale:null,loginPath:`/login`,defaultPath:``,customRoutes:[],antdConfig:{},proLayoutConfig:{title:`Demo`}},t)}},J=`i18n`,ve={name:J,install(e,t={}){e[J]=F({intl:C,intlConfig:{},loadLocale:e=>void 0},t)}},Y=`storage`,ye={name:Y,install(e,t={}){e[Y]=F({localeKey:`locale`,themeKey:`theme`,tokenKey:`token`,getLocale:()=>localStorage.getItem(e.storage.localeKey),setLocale:t=>{localStorage.setItem(e.storage.localeKey,t)},clearLocale:()=>{localStorage.removeItem(e.storage.localeKey)},getTheme:()=>localStorage.getItem(e.storage.themeKey),setTheme:t=>{localStorage.setItem(e.storage.themeKey,t)},clearTheme:()=>{localStorage.removeItem(e.storage.themeKey)},getToken:()=>localStorage.getItem(e.storage.tokenKey),setToken:t=>{localStorage.setItem(e.storage.tokenKey,t)},clearToken:()=>{localStorage.removeItem(e.storage.tokenKey)}},t)}},be=(e,t)=>({locale:null,setLocale:t=>{e(()=>({locale:t})),D.config.locale=t,D.storage.setLocale(t),document.documentElement.setAttribute(`lang`,t);let n=D.i18n.intlConfig;C.init({currentLocale:t,locales:n});try{let e=D.i18n.loadLocale?.(t)||void 0;F(D.config.antdConfig,{locale:e})}catch(e){console.error(`Sdk: createLocaleSlice - sdk.i18n.loadLocale error:`,e)}}}),xe=(e,t)=>({microAppLoading:!1,setMicroAppLoading:t=>e(()=>({microAppLoading:t}))}),{defaultAlgorithm:Se,darkAlgorithm:Ce}=S,we=(e,t)=>({theme:null,setTheme:t=>{e(()=>({theme:t})),D.config.theme=t,D.storage.setTheme(t),document.documentElement.setAttribute(`theme`,t);let n=t===`light`?Se:Ce;F(D.config.antdConfig,{theme:{algorithm:n}})}}),X={user:{},permissions:[],roles:[],settings:{}},Te=(e,t)=>({userInfo:X,setUserInfo:t=>{e(()=>({userInfo:t})),D.app={...D.app,...t}},resetUserInfo:()=>{e(()=>({userInfo:X}))}}),Ee=e()(w((...e)=>({...be(...e),...xe(...e),...we(...e),...Te(...e)}))),Z=`store`,De={name:Z,install(e,t={}){e[Z]=Ee}},Oe=()=>{let e=f(),n=u(),i=d(),a=t(D.store,e=>e.locale),o=i[i.length-1]?.handle?.crumb()||{},s=JSON.parse(o?.routeAttr||`{}`)?.noLayout,c=t=>{e(t.path)};return m(T,{locale:a,formatMessage:({id:e,defaultMessage:t})=>D.i18n.intl.get(e).d(t),location:n,menuItemRender:(e,t)=>m(`div`,{onClick:()=>c(e),children:t}),onMenuHeaderClick:()=>{e(`/`)},onPageChange:e=>{if(!D.app.user||Object.keys(D.app.user).length===0)return D.app.pageToLogin()},...s&&{headerRender:!1,footerRender:!1,menuRender:!1},menu:{request:async()=>D.app.menuData||[],...D.config.proLayoutConfig.menu},...D.config.proLayoutConfig,children:m(r,{fallback:D.ui.renderComponent(`Loading`,{isSuspense:!0}),children:m(l,{})})})},{useToken:Q}=S,ke=({isInitData:e=!1,isSuspense:t=!1,isMicroApp:n=!1})=>{let{token:r}=Q();return m(`div`,{style:e?{width:`100%`,height:`100%`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:r.colorBgContainer,color:r.colorText}:{},children:`Loading...`})},{useToken:Ae}=S,je=()=>{let{token:e}=Ae(),[t,n]=c(!1);return m(v,{style:{width:`100%`,height:`100%`,background:e.colorBgContainer},justify:`center`,align:`center`,children:h(y,{labelCol:{span:8},labelAlign:`left`,wrapperCol:{span:16},style:{maxWidth:600},initialValues:{username:`admin`,password:`admin`},onFinish:async e=>{try{n(()=>!0);let t=await D.api.loginApi(e);n(()=>!1);let r=t?.data?.token||``;if(!r)return;D.storage.setToken(r);let i=D.app.getRedirectPath();D.config.qiankunMode===`load`?(D.client.navigate(i,{replace:!0}),D.app.initData?.()):window.location.replace(i)}catch(e){console.log(`Sdk: Login - handleFinish: `,e),n(()=>!1)}},autoComplete:`off`,children:[m(y.Item,{label:`用户名`,name:`username`,rules:[{required:!0,message:`请输入用户名!`}],children:m(b,{})}),m(y.Item,{label:`密码`,name:`password`,rules:[{required:!0,message:`请输入密码!`}],children:m(b.Password,{})}),m(y.Item,{noStyle:!0,children:m(_,{block:!0,type:`primary`,htmlType:`submit`,loading:t,children:`登录`})})]})})},$=({children:e})=>{let t=u(),n=d(),r=f();return D.client.location=t,D.client.matches=n,D.client.navigate=r,e},Me=()=>{let e=D.config.loginPath,i=D.config.customRoutes,a=D.config.qiankunMode===`router`,l=e=>D.ui.renderComponent(`Loading`,e),u=D.ui.renderComponent(`Layout`),d=D.ui.renderComponent(`Login`),f=D.ui.renderComponent(`NotFound`),p=[{path:e,element:d},{path:`*`,element:f},...i].map(e=>({...e,element:m($,{children:e.element})})),[h,g]=c(!1),[_,v]=c(p),[y,b,x,S,C]=t(D.store,n(e=>[e.locale,e.setLocale,e.theme,e.setTheme,e.setUserInfo])),w=s(()=>N(D.config.antdConfig),[y,x]),T=(e,t)=>{S(e||V(D)),b(t||H(D))},E=async()=>{try{g(()=>!0);let[{data:e={}},{data:t=[]}]=await Promise.all([D.api.getUserInfoApi(),D.api.getRoutesApi()]);g(()=>!1),C(e);let{theme:n,locale:r}=e?.settings||{};T(n,r);let{microApps:i=[],menuData:o=[]}=de(t);a&&(ie(i,B),ae());let s=G(o),c=[...p,{path:`/`,element:m(ee,{to:s,replace:!0})},{path:`/`,element:m($,{children:u}),children:o,errorElement:f}];v(c),D.app={...D.app,allRoutes:c,microApps:i,menuData:o}}catch(e){console.error(e),g(()=>!1)}};return o(()=>{D.app.initData=E,D.app.allRoutes=p;let t=D.config.customRoutes?.map(e=>e.path),n=window.location.pathname;[e,...t]?.includes(n)?T():E()},[]),m(re,{...w,children:m(r,{fallback:l({isSuspense:!0}),children:h?l({isInitData:!0}):m(te,{router:ne(_,{basename:`/`}),future:{v7_startTransition:!1}})})})};var Ne=a(({name:e,rootId:r})=>{let[i,a]=t(D.store,n(e=>[e.microAppLoading,e.setMicroAppLoading]));return o(()=>{if(!e||D.config.qiankunMode!==`load`)return;let t=D.app.microAppsInstance.get(e);if(t)t?.mount();else{let n=D.app.microApps.find(t=>t.name===e);if(!n)return;a(!0),t=E(n,{},B),t?.mountPromise?.finally(()=>{a(!1)}),D.app.microAppsInstance.set(e,t)}return()=>{t?.unmount()}},[e]),h(p,{children:[i&&D.ui.renderComponent(`Loading`,{isMicroApp:!0}),m(`main`,{id:r})]})});const Pe=()=>m(`div`,{children:`无权限`}),{useToken:Fe}=S,Ie=()=>{let{token:e}=Fe();return m(`div`,{style:{width:`100%`,height:`100%`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:e.colorBgContainer},children:`找不到页面`})},Le={name:`ui`,install(e,t={}){e.ui=F({Layout:Oe,Loading:ke,Login:je,Mainapp:Me,Microapp:Ne,NotFound:Ie,NoPermission:Pe,setComponent:(t,n)=>{if(!t){console.error(`Sdk: SdkUIPlugin - component cannot be empty`);return}let r=n||t.displayName||t.name;if(!r){console.error(`Sdk: SdkUIPlugin - Component name cannot be empty`);return}e.ui[r]=t},getComponent:t=>t?e.ui[t]:(console.error(`Sdk: SdkUIPlugin - Component name cannot be empty`),null),renderComponent:(t,n={})=>{let r=e.ui.getComponent(t);return r?i(r,n):(console.error(`Sdk: SdkUIPlugin - Component ${t} not found`),null)}},t)}};export{me as SdkApiPlugin,he as SdkAppPlugin,ge as SdkClientPlugin,_e as SdkConfigPlugin,ve as SdkI18nPlugin,ye as SdkStoragePlugin,De as SdkStorePlugin,Le as SdkUIPlugin,D as sdk,L as useCrumb,ue as useIntl,fe as usePermission,O as useUserInfo};
|
|
1
|
+
import './style.css';
|
|
2
|
+
import{createStore as e,useStore as t}from"zustand";import{useShallow as n}from"zustand/shallow";import{Suspense as r,createElement as i,memo as a,useEffect as o,useMemo as s,useState as c}from"react";import{Navigate as l,Outlet as u,useLocation as d,useMatches as f,useNavigate as p}from"react-router-dom";import{loadMicroApp as m,registerMicroApps as ee,start as te}from"qiankun";import{Fragment as h,jsx as g,jsxs as _}from"react/jsx-runtime";import v from"axios";import{subscribeWithSelector as y}from"zustand/middleware";const b=new class{name;_plugins;api;app;client;config;i18n;storage;store;ui;constructor(){this.name=``,this._plugins=new Map}mount(e){if(window[e])throw Error(`The SDK already exists - ${e}`);console.log(`%c SDK mounted:`,`color: pink; font-weight: bold;`,e,b),this.name=e;let t=new Proxy(this,{get:(e,t,n)=>e?Reflect.get(e,t,n):null,set:()=>(console.error(`The SDK cannot be modified.`),!1),deleteProperty:()=>(console.error(`The SDK cannot be deleted.`),!1)});window[this.name]=t}extend(e){if(!window[e])throw Error(`The SDK not found - ${e}`);console.log(`%c SDK extended:`,`color: pink; font-weight: bold;`,e),Object.assign(this,window[e])}use(e,t){let{name:n,install:r}=e;if(!n)throw Error(`${n} plugin has no name`);if(typeof r!=`function`)throw Error(`${n} plugin is not a function`);return r(this,t),this._plugins.set(n,{...e,options:t}),this}},x=()=>{let[e,r,i]=t(b.store,n(e=>[e.userInfo,e.setUserInfo,e.resetUserInfo]));return{userInfo:e,setUserInfo:r,resetUserInfo:i}};function S(e){return e==null||typeof e!=`object`&&typeof e!=`function`}function C(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function w(e){return Object.getOwnPropertySymbols(e).filter(t=>Object.prototype.propertyIsEnumerable.call(e,t))}function ne(e){return e==null?e===void 0?`[object Undefined]`:`[object Null]`:Object.prototype.toString.call(e)}function T(e,t,n,r=new Map,i=void 0){let a=i?.(e,t,n,r);if(a!==void 0)return a;if(S(e))return e;if(r.has(e))return r.get(e);if(Array.isArray(e)){let t=Array(e.length);r.set(e,t);for(let a=0;a<e.length;a++)t[a]=T(e[a],a,n,r,i);return Object.hasOwn(e,`index`)&&(t.index=e.index),Object.hasOwn(e,`input`)&&(t.input=e.input),t}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp){let t=new RegExp(e.source,e.flags);return t.lastIndex=e.lastIndex,t}if(e instanceof Map){let t=new Map;r.set(e,t);for(let[a,o]of e)t.set(a,T(o,a,n,r,i));return t}if(e instanceof Set){let t=new Set;r.set(e,t);for(let a of e)t.add(T(a,void 0,n,r,i));return t}if(typeof Buffer<`u`&&Buffer.isBuffer(e))return e.subarray();if(C(e)){let t=new(Object.getPrototypeOf(e)).constructor(e.length);r.set(e,t);for(let a=0;a<e.length;a++)t[a]=T(e[a],a,n,r,i);return t}if(e instanceof ArrayBuffer||typeof SharedArrayBuffer<`u`&&e instanceof SharedArrayBuffer)return e.slice(0);if(e instanceof DataView){let t=new DataView(e.buffer.slice(0),e.byteOffset,e.byteLength);return r.set(e,t),E(t,e,n,r,i),t}if(typeof File<`u`&&e instanceof File){let t=new File([e],e.name,{type:e.type});return r.set(e,t),E(t,e,n,r,i),t}if(typeof Blob<`u`&&e instanceof Blob){let t=new Blob([e],{type:e.type});return r.set(e,t),E(t,e,n,r,i),t}if(e instanceof Error){let t=structuredClone(e);return r.set(e,t),t.message=e.message,t.name=e.name,t.stack=e.stack,t.cause=e.cause,t.constructor=e.constructor,E(t,e,n,r,i),t}if(e instanceof Boolean){let t=new Boolean(e.valueOf());return r.set(e,t),E(t,e,n,r,i),t}if(e instanceof Number){let t=new Number(e.valueOf());return r.set(e,t),E(t,e,n,r,i),t}if(e instanceof String){let t=new String(e.valueOf());return r.set(e,t),E(t,e,n,r,i),t}if(typeof e==`object`&&D(e)){let t=Object.create(Object.getPrototypeOf(e));return r.set(e,t),E(t,e,n,r,i),t}return e}function E(e,t,n=e,r,i){let a=[...Object.keys(t),...w(t)];for(let o=0;o<a.length;o++){let s=a[o],c=Object.getOwnPropertyDescriptor(e,s);(c==null||c.writable)&&(e[s]=T(t[s],s,n,r,i))}}function D(e){switch(ne(e)){case`[object Arguments]`:case`[object Array]`:case`[object ArrayBuffer]`:case`[object DataView]`:case`[object Boolean]`:case`[object Date]`:case`[object Float32Array]`:case`[object Float64Array]`:case`[object Int8Array]`:case`[object Int16Array]`:case`[object Int32Array]`:case`[object Map]`:case`[object Number]`:case`[object Object]`:case`[object RegExp]`:case`[object Set]`:case`[object String]`:case`[object Symbol]`:case`[object Uint8Array]`:case`[object Uint8ClampedArray]`:case`[object Uint16Array]`:case`[object Uint32Array]`:return!0;default:return!1}}function O(e){return T(e,void 0,e,new Map,void 0)}function k(e){if(!e||typeof e!=`object`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype||Object.getPrototypeOf(t)===null?Object.prototype.toString.call(e)===`[object Object]`:!1}function A(e){return e===`__proto__`}function j(e,t){let n=Object.keys(t);for(let r=0;r<n.length;r++){let i=n[r];if(A(i))continue;let a=t[i],o=e[i];M(a)&&M(o)?e[i]=j(o,a):Array.isArray(a)?e[i]=j([],a):k(a)?e[i]=j({},a):(o===void 0||a!==void 0)&&(e[i]=a)}return e}function M(e){return k(e)||Array.isArray(e)}const re=()=>s(()=>O(b.i18n.intl),[t(b.store,e=>e.locale)]),ie=()=>s(()=>b.client.matches,[d()]).filter(e=>!!e.handle?.crumb).map(e=>e.handle.crumb(e.data)),ae=e=>s(()=>{let t=e||b.client.location.pathname;return b.app.permissions?.includes?.(t)},[d().pathname,e]),N=e=>{let{requestId:t,url:n,method:r,params:i,data:a}=e;return t||`${r}:${n}?${JSON.stringify(i)}&${JSON.stringify(a)}`},oe=e=>{let t=N(e),n=b.api.controllers.get(t);n&&(n.abort(),b.api.controllers.delete(t))},P={beforeLoad:[async e=>{console.log(`[LifeCycle] before load %c%s`,`color: green;`,e.name)}],beforeMount:[async e=>{console.log(`[LifeCycle] before mount %c%s`,`color: green;`,e.name)}],afterUnmount:[async e=>{console.log(`[LifeCycle] after unmount %c%s`,`color: green;`,e.name)}]},F=e=>{let t=e.storage.getTheme();if(t)return t;let n=e.config?.theme;if(n)return n;let r=window.matchMedia(`(prefers-color-scheme: dark)`);return r.matches&&r.matches?`dark`:`light`},I=e=>e.storage.getLocale()||e.config?.locale||navigator.language||`zh-CN`,L=e=>{let t=new Map,n=R(e,t);return{microApps:[...t.values()],menuData:n}},R=(e,t)=>!e||e?.length===0?[]:e.map(e=>{let n=null,{locale:r,path:i,icon:a,component:o,routeAttr:s,children:c}=e;if(s){let e={};try{e=JSON.parse(s)}catch(e){console.error(`Sdk: initData - Subapp routeAttr error: `,e)}let{name:r,rootId:i,...a}=e,o={...a,name:r,container:`#${i}`,props:{sdk:b},loader:e=>b.store.getState().setMicroAppLoading(e)};t.set(r,o),n=b.ui.renderComponent(`Microapp`,{name:r,rootId:i})}else n=o===`Microapp`?b.ui.renderComponent(`Microapp`):o===`Outlet`?g(u,{}):b.ui.renderComponent(o);return{...e,key:`${i}_${a}_${r}`,element:n,children:R(c,t),handle:e}}),z=e=>{let t=`/`;return!e||e.length===0?t:(t=e?.[0]?.path,e?.[0]?.children&&e?.[0]?.children.length>0&&(t=z(e?.[0]?.children)),t)},B=({children:e})=>{let t=d(),n=f(),r=p();return b.client.location=t,b.client.matches=n,b.client.navigate=r,e},V=()=>{let e=b.config.loginPath,r=b.config.customRoutes,i=b.config.qiankunMode===`router`,a=b.ui.renderComponent(`Layout`),s=b.ui.renderComponent(`Login`),u=b.ui.renderComponent(`NotFound`),d=[{path:e,element:s},{path:`*`,element:u},...r].map(e=>({...e,element:g(B,{children:e.element})})),[f,p]=c(!1),[m,h]=c(d),[_,v,y]=t(b.store,n(e=>[e.setLocale,e.setTheme,e.setUserInfo])),x=(e,t)=>{v(e||F(b)),_(t||I(b))},S=async()=>{try{p(()=>!0);let[{data:e={}},{data:t=[]}]=await Promise.all([b.api.getUserInfoApi(),b.api.getRoutesApi()]);p(()=>!1),y(e);let{theme:n,locale:r}=e?.settings||{};x(n,r);let{microApps:o=[],menuData:s=[]}=L(t);i&&(ee(o,P),te());let c=z(s),f=[...d,{path:`/`,element:g(l,{to:c,replace:!0})},{path:`/`,element:g(B,{children:a}),children:s,errorElement:u}];h(f),b.app={...b.app,allRoutes:f,microApps:o,menuData:s}}catch(e){console.error(e),p(()=>!1)}};return o(()=>{b.app.initData=S,b.app.allRoutes=d;let t=b.config.customRoutes?.map(e=>e.path),n=window.location.pathname;[e,...t]?.includes(n)?x():S()},[]),{loading:f,routes:m}};var H=class{instance;constructor(e={}){this.instance=v.create(e),this.defaultRequestInterceptor(),this.defaultResponseInterceptor()}defaultRequestInterceptor(){this.instance.interceptors.request.use(function(e){if(e?.isCancelRequest){let t=N(e);oe(e);let n=new AbortController;b.api.controllers.set(t,n),e.requestId=t,e.signal=n.signal}let t=b.storage.getToken();return e.headers.lang=b.config.locale,e.headers.Authorization=t,j(e.headers,b.api.config.headers||{}),e},function(e){return console.error(`Sdk: defaultRequestInterceptor - 请求错误`),Promise.reject(e)})}defaultResponseInterceptor(){this.instance.interceptors.response.use(function(e){let{data:t,config:n}=e,{isOriginalData:r,isShowFailMsg:i,isCancelRequest:a}=n,{code:o,msg:s}=t;return o!==0&&(console.error(`Sdk: defaultResponseInterceptor - Response error: `,n.url,s),o==20041&&b.app.pageToLogin()),a&&b.api.controllers.delete(n.requestId),r?e:e.data},function(e){let{response:t,config:n}=e,{isShowFailMsg:r}=n;if(v.isCancel(e))return Promise.reject(e);if(t){let{status:e,data:n,statusText:r}=t;e==401&&b.app.pageToLogin()}else console.error(`Sdk: defaultResponseInterceptor - Request error:`,n.url,e);return Promise.reject(e)})}getInstance(){return this.instance}};const U={name:`api`,install(e,t={}){let n={baseURL:`/`,timeout:0,...t.config},r=t?.instance||new H(n).getInstance();e.api=j({config:n,controllers:new Map,instance:null,request:(e,t={})=>r.request({url:e,isOriginalData:!1,isShowFailMsg:!0,isCancelRequest:!0,...t}),getUserInfoApi:()=>e.api.request(`/getUserInfo`,{method:`GET`}),getRoutesApi:()=>e.api.request(`/routes`,{method:`GET`}),loginApi:()=>e.api.request(`/login`,{method:`POST`})},t)}},W={name:`app`,install(e,t={}){e.app=j({menuData:[],allRoutes:[],microApps:[],microAppsInstance:new Map,user:null,permissions:[],roles:[],settings:{},initData:null,clearData:()=>{e.app.menuData=[],e.app.allRoutes=e.app.allRoutes.filter(e=>e.path!==`/`),e.app.microApps=[],e.app.microAppsInstance.forEach(e=>e.unmount()),e.app.microAppsInstance.clear(),e.store.getState().resetUserInfo()},pageToLogin:()=>{e.storage.clearToken();let t=window.location.pathname||`/`,n=e.config.loginPath,r=t===n?n:`${n}?redirect=${encodeURIComponent(t)}`;e.config.qiankunMode===`router`?window.location.replace(r):(e.app.clearData(),e.client.navigate(r,{replace:!0}))},getRedirectPath:()=>{let t=e.config.defaultPath;if(t)return t;let n=new URLSearchParams(window.location.search);return decodeURIComponent(n.get(`redirect`)||``)||`/`}},t)}},G=`client`,K={name:G,install(e,t={}){e[G]=j({location:null,navigate:null,matches:null},t)}},q=`config`,se={name:q,install(e,t={}){e[q]=j({env:{},qiankunMode:`router`,theme:null,locale:null,loginPath:`/login`,defaultPath:``,customRoutes:[]},t)}},J=`i18n`,ce={name:J,install(e,t={}){e[J]=j({intl:{},intlConfig:{}},t)}},Y=`storage`,le={name:Y,install(e,t={}){e[Y]=j({localeKey:`locale`,themeKey:`theme`,tokenKey:`token`,getLocale:()=>localStorage.getItem(e.storage.localeKey),setLocale:t=>{localStorage.setItem(e.storage.localeKey,t)},clearLocale:()=>{localStorage.removeItem(e.storage.localeKey)},getTheme:()=>localStorage.getItem(e.storage.themeKey),setTheme:t=>{localStorage.setItem(e.storage.themeKey,t)},clearTheme:()=>{localStorage.removeItem(e.storage.themeKey)},getToken:()=>localStorage.getItem(e.storage.tokenKey),setToken:t=>{localStorage.setItem(e.storage.tokenKey,t)},clearToken:()=>{localStorage.removeItem(e.storage.tokenKey)}},t)}},ue=(e,t)=>({locale:null,setLocale:t=>{e(()=>({locale:t})),b.config.locale=t,b.storage.setLocale(t),document.documentElement.setAttribute(`lang`,t)}}),de=(e,t)=>({microAppLoading:!1,setMicroAppLoading:t=>e(()=>({microAppLoading:t}))}),fe=(e,t)=>({theme:null,setTheme:t=>{e(()=>({theme:t})),b.config.theme=t,b.storage.setTheme(t),document.documentElement.setAttribute(`theme`,t)}}),X={user:{},permissions:[],roles:[],settings:{}},pe=(e,t)=>({userInfo:X,setUserInfo:t=>{e(()=>({userInfo:t})),b.app={...b.app,...t}},resetUserInfo:()=>{e(()=>({userInfo:X}))}}),me=e()(y((...e)=>({...ue(...e),...de(...e),...fe(...e),...pe(...e)}))),Z=`store`,he={name:Z,install(e,t={}){e[Z]=me}},Q=({items:e=[]})=>{let t=d(),n=p();return!e||e.length===0?null:e.map(e=>{let{key:r,name:i,path:a,locale:o,children:s,hideInMenu:c=!1}=e,l=!0;return s&&s.length>0&&s.filter(e=>!e.hideInMenu).length>0&&(l=!1),_(`li`,{className:`sdk-layout-menu-item`,children:[g(`div`,{className:`sdk-layout-menu-item-title`,style:{...t.pathname===a?{background:`#e6f4ff`,color:`#1677ff`}:{},...c?{display:`none`}:{},cursor:l?`pointer`:`not-allowed`},onClick:()=>l?n(a):{},children:b.i18n.intl?.get?.(o)||i}),g(`ul`,{className:`sdk-layout-menu-sub`,children:g(Q,{items:s})})]},r)})},ge=()=>{let e=p(),t=d();return o(()=>{if(!b.app.user||Object.keys(b.app.user).length===0)return b.app.pageToLogin();e(t.pathname)},[t.pathname]),_(`div`,{className:`sdk-layout`,children:[_(`div`,{className:`sdk-layout-header`,children:[g(`div`,{onClick:()=>{e(`/`)},children:`Logo`}),g(`button`,{onClick:()=>{b.app.pageToLogin()},children:`退出登录`})]}),_(`div`,{className:`sdk-layout-content`,children:[g(`ul`,{className:`sdk-layout-menu`,children:g(Q,{items:b.app.menuData||[]})}),g(`div`,{className:`sdk-layout-outlet`,children:g(r,{fallback:b.ui.renderComponent(`Loading`,{isSuspense:!0}),children:g(u,{})})})]})]})},$=({isInitData:e=!1,isSuspense:t=!1,isMicroApp:n=!1})=>g(`div`,{className:`${e?`sdk-loading-init`:``}`,children:`Loading...`}),_e=()=>{let[e,t]=c(!1),[n,r]=c(`admin`),[i,a]=c(`123456`);return g(`div`,{className:`sdk-login`,children:_(`form`,{className:`sdk-login-form`,children:[_(`div`,{className:`sdk-login-form-group`,children:[g(`label`,{children:`用 户 名`}),_(`div`,{className:`sdk-login-form-group-input`,children:[g(`input`,{type:`text`,value:n,placeholder:`your@email.com 或 昵称`,onChange:e=>r(e.target.value)}),g(`div`,{children:n?``:`请输入用户名`})]})]}),_(`div`,{className:`sdk-login-form-group`,children:[g(`label`,{children:`密 码`}),_(`div`,{className:`sdk-login-form-group-input`,children:[g(`input`,{type:`password`,value:i,placeholder:`请输入密码`,onChange:e=>a(e.target.value)}),g(`div`,{children:i?``:`请输入密码`})]})]}),g(`button`,{className:`sdk-login-form-btn`,onClick:async r=>{if(!e){r.preventDefault();try{t(()=>!0);let e=await b.api.loginApi({userName:n,password:i});t(()=>!1);let r=e?.data?.token||``;if(!r)return;b.storage.setToken(r);let a=b.app.getRedirectPath();b.config.qiankunMode===`load`?(b.client.navigate(a,{replace:!0}),b.app.initData?.()):window.location.replace(a)}catch(e){console.log(`Sdk: Login - handleFinish: `,e),t(()=>!1)}}},children:e?`登录中...`:`登录`})]})})};var ve=a(({name:e,rootId:r})=>{let[i,a]=t(b.store,n(e=>[e.microAppLoading,e.setMicroAppLoading]));return o(()=>{if(!e||b.config.qiankunMode!==`load`)return;let t=b.app.microAppsInstance.get(e);if(t)t?.mount();else{let n=b.app.microApps.find(t=>t.name===e);if(!n)return;a(!0),t=m(n,{},P),t?.mountPromise?.finally(()=>{a(!1)}),b.app.microAppsInstance.set(e,t)}return()=>{t?.unmount()}},[e]),_(h,{children:[i&&b.ui.renderComponent(`Loading`,{isMicroApp:!0}),g(`main`,{id:r})]})});const ye=()=>g(`div`,{children:`无权限`}),be=()=>g(`div`,{className:`sdk-notfound`,children:`找不到页面`}),xe={name:`ui`,install(e,t={}){e.ui=j({Layout:ge,Loading:$,Login:_e,Microapp:ve,NotFound:be,NoPermission:ye,setComponent:(t,n)=>{if(!t){console.error(`Sdk: SdkUIPlugin - component cannot be empty`);return}let r=n||t.displayName||t.name;if(!r){console.error(`Sdk: SdkUIPlugin - Component name cannot be empty`);return}e.ui[r]=t},getComponent:t=>t?e.ui[t]:(console.error(`Sdk: SdkUIPlugin - Component name cannot be empty`),null),renderComponent:(t,n={})=>{let r=e.ui.getComponent(t);return r?i(r,n):(console.error(`Sdk: SdkUIPlugin - Component ${t} not found`),null)}},t)}};export{U as SdkApiPlugin,W as SdkAppPlugin,K as SdkClientPlugin,se as SdkConfigPlugin,ce as SdkI18nPlugin,le as SdkStoragePlugin,he as SdkStorePlugin,xe as SdkUIPlugin,b as sdk,ie as useCrumb,V as useInitData,re as useIntl,ae as usePermission,x as useUserInfo};
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root[theme=dark]{--sdk-bg-color:#141414;--sdk-text-color:#ffffffd9;--sdk-border-color:#ffffff26}:root[theme=light]{--sdk-bg-color:#fff;--sdk-text-color:#000000d9;--sdk-border-color:#00000026}.sdk-layout{height:100vh;color:var(--sdk-text-color);background:var(--sdk-bg-color)}.sdk-layout-header{border-bottom:1px solid var(--sdk-border-color);box-sizing:border-box;justify-content:space-between;align-items:center;height:64px;padding:0 24px;line-height:64px;display:flex}.sdk-layout-content{height:calc(100vh - 64px);display:flex}.sdk-layout-menu{box-sizing:border-box;border-right:1px solid var(--sdk-border-color);width:200px;height:100%;margin:0;padding:8px;list-style:none}.sdk-layout-outlet{flex:1;padding:24px;overflow:auto}.sdk-layout-menu-item{margin-bottom:6px}.sdk-layout-menu-item-title{padding:8px 12px}.sdk-layout-menu-item-title:hover{color:#1677ff;cursor:pointer;background:#e6f4ff}.sdk-layout-menu-sub{margin:0;padding:0;list-style:none}.sdk-layout-menu-sub .sdk-layout-menu-item-title{margin-top:8px;padding-left:24px}.sdk-loading-init{width:100%;height:100%;color:var(--sdk-text-color);background-color:var(--sdk-bg-color);justify-content:center;align-items:center;display:flex}.sdk-login{width:100vw;height:100vh;color:var(--sdk-text-color);background:var(--sdk-bg-color);justify-content:center;align-items:center;display:flex}.sdk-login-form{border-radius:8px;flex-direction:column;width:300px;padding:23px;display:flex;box-shadow:0 0 10px #0000004d}.sdk-login-form-group{align-items:flex-start;margin-bottom:24px;display:flex}.sdk-login-form-group>label{width:70px}.sdk-login-form-group-input{flex:1}.sdk-login-form-group-input>input{box-sizing:border-box;width:230px;padding:4px 11px;font-size:16px}.sdk-login-form-btn{padding:4px 11px}.sdk-notfound{width:100%;height:100%;color:var(--sdk-text-color);background-color:var(--sdk-bg-color);justify-content:center;align-items:center;display:flex}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zxiaosi/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"description": "A micro frontend kit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"micro frontend",
|
|
@@ -18,8 +18,12 @@
|
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
20
|
"type": "module",
|
|
21
|
-
"main": "./dist/index.js",
|
|
22
21
|
"types": "dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": "./dist/index.js",
|
|
24
|
+
"./package.json": "./package.json",
|
|
25
|
+
"./style.css": "./dist/style.css"
|
|
26
|
+
},
|
|
23
27
|
"publishConfig": {
|
|
24
28
|
"access": "public",
|
|
25
29
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -29,23 +33,38 @@
|
|
|
29
33
|
"dev": "tsdown --watch"
|
|
30
34
|
},
|
|
31
35
|
"dependencies": {
|
|
32
|
-
"
|
|
33
|
-
"axios": "^1.13.6",
|
|
34
|
-
"qiankun": "^2.10.16",
|
|
35
|
-
"react-intl-universal": "^2.13.4"
|
|
36
|
+
"axios": "^1.13.6"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
39
|
+
"@tsdown/css": "^0.21.6",
|
|
38
40
|
"@types/react": "^18.3.12",
|
|
39
41
|
"@types/react-dom": "^18.3.1",
|
|
40
42
|
"es-toolkit": "^1.45.1",
|
|
41
|
-
"tsdown": "^0.21.
|
|
43
|
+
"tsdown": "^0.21.6",
|
|
42
44
|
"typescript": "^5.9.3"
|
|
43
45
|
},
|
|
44
46
|
"peerDependencies": {
|
|
45
|
-
"
|
|
47
|
+
"qiankun": "^2.10.16",
|
|
46
48
|
"react": "^18.3.1 || >=19.0.0",
|
|
47
49
|
"react-dom": "^18.3.1 || >=19.0.0",
|
|
48
50
|
"react-router-dom": "^6.30.0",
|
|
49
51
|
"zustand": "^5.0.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"react": {
|
|
55
|
+
"optional": false
|
|
56
|
+
},
|
|
57
|
+
"react-dom": {
|
|
58
|
+
"optional": false
|
|
59
|
+
},
|
|
60
|
+
"react-router-dom": {
|
|
61
|
+
"optional": false
|
|
62
|
+
},
|
|
63
|
+
"qiankun": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"zustand": {
|
|
67
|
+
"optional": true
|
|
68
|
+
}
|
|
50
69
|
}
|
|
51
70
|
}
|