@done-coding/admin-core 0.7.1-alpha.0 → 0.8.1-alpha.0
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 +1 -1
- package/es/bridge/index.mjs +19 -18
- package/es/store/user.mjs +62 -61
- package/package.json +2 -2
- package/types/bridge/index.d.ts +50 -3
- package/types/store/user.d.ts +3 -5
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install @done-coding/admin-core
|
|
|
14
14
|
|
|
15
15
|
### 自定义分页字段(pnpm patch 逃生通道)
|
|
16
16
|
|
|
17
|
-
`@done-coding/admin-core` 的列表分页 KEY 配置(`APP_API_LIST_MODEL_KEY_CONFIG`)在 core
|
|
17
|
+
`@done-coding/admin-core` 的列表分页 KEY 配置(`APP_API_LIST_MODEL_KEY_CONFIG`)在 core 包内**固化为标准级约定**:
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
{
|
package/es/bridge/index.mjs
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import { createStorageWithNamespace as
|
|
2
|
-
import { createUseState as
|
|
3
|
-
import { createGenerateRouteMetaRawTree as
|
|
4
|
-
function
|
|
1
|
+
import { createStorageWithNamespace as a } from "./storage.mjs";
|
|
2
|
+
import { createUseState as c } from "./state.mjs";
|
|
3
|
+
import { createGenerateRouteMetaRawTree as o } from "./route.mjs";
|
|
4
|
+
function l(e) {
|
|
5
5
|
const F = e.APP_CACHE_CONFIG.namespace;
|
|
6
6
|
let _;
|
|
7
7
|
F === "" ? (console.error(
|
|
8
8
|
"[adminBridge] APP_CACHE_CONFIG.namespace 为空,已兜底为 'ADMIN_CORE'"
|
|
9
9
|
), _ = "ADMIN_CORE") : _ = F, Object.freeze(e);
|
|
10
|
-
|
|
11
|
-
const i = a(_), u = G(
|
|
10
|
+
const g = a(_), C = e.routes, u = e.getUserInfoInitFn, N = e.userInfoAccess, i = c(_), R = o(
|
|
12
11
|
e.APP_ROUTER_META_DEFAULT_CONFIG
|
|
13
|
-
),
|
|
12
|
+
), U = Object.freeze({
|
|
14
13
|
header: e.APP_LAYOUT_HEADER_CONFIG,
|
|
15
14
|
footer: e.APP_LAYOUT_FOOTER_CONFIG,
|
|
16
15
|
sidebar: e.APP_LAYOUT_SIDEBAR_CONFIG,
|
|
17
16
|
breadcrumb: e.APP_LAYOUT_BREADCRUMB_CONFIG,
|
|
18
17
|
body: e.APP_LAYOUT_BODY_CONFIG
|
|
19
18
|
});
|
|
20
|
-
let t, P,
|
|
19
|
+
let t, P, n, O, T, I, f, E;
|
|
21
20
|
const A = (r) => `admin bridge: ${r} 未注册`;
|
|
22
21
|
return {
|
|
23
22
|
register(r) {
|
|
24
|
-
r.getToken && (t = r.getToken), r.goToLogin && (P = r.goToLogin), r.refreshToken && (
|
|
23
|
+
r.getToken && (t = r.getToken), r.goToLogin && (P = r.goToLogin), r.refreshToken && (n = r.refreshToken), r.refreshAuth && (O = r.refreshAuth), r.loginApi && (T = r.loginApi), r.logoutApi && (I = r.logoutApi), r.getUserInfoApi && (f = r.getUserInfoApi), r.refreshTokenApi && (E = r.refreshTokenApi);
|
|
25
24
|
},
|
|
26
25
|
// 已注册返回 undefined 是合法业务态不 throw
|
|
27
26
|
// v3 终锁 Δ8b:零参 facade(BR-1 ③ 终裁——core 对 UserInfo 不透明 + 拦截器无 info 源)
|
|
@@ -35,11 +34,11 @@ function L(e) {
|
|
|
35
34
|
},
|
|
36
35
|
// 异步对:未注册才返回 rejected Promise(既有降级语义保留)。
|
|
37
36
|
refreshToken() {
|
|
38
|
-
return
|
|
37
|
+
return n ? n().then(() => {
|
|
39
38
|
}) : Promise.reject(new Error(A("refreshToken")));
|
|
40
39
|
},
|
|
41
40
|
refreshAuth() {
|
|
42
|
-
return
|
|
41
|
+
return O ? O().then(() => {
|
|
43
42
|
}) : Promise.reject(new Error(A("refreshAuth")));
|
|
44
43
|
},
|
|
45
44
|
getStorage() {
|
|
@@ -49,10 +48,10 @@ function L(e) {
|
|
|
49
48
|
return C;
|
|
50
49
|
},
|
|
51
50
|
getUserInfoInitFn() {
|
|
52
|
-
return
|
|
51
|
+
return u;
|
|
53
52
|
},
|
|
54
53
|
useState: i,
|
|
55
|
-
generateRouteMetaRawTree:
|
|
54
|
+
generateRouteMetaRawTree: R,
|
|
56
55
|
// ============ #2.5 期 12 readonly 属性值挂载(per ADR-1 sibling pattern 复用 useState / generateRouteMetaRawTree) ============
|
|
57
56
|
/** 应用基础信息(per #2.5 期 REQ-1 直接挂载形态) */
|
|
58
57
|
APP_BASE_INFO: e.APP_BASE_INFO,
|
|
@@ -71,7 +70,7 @@ function L(e) {
|
|
|
71
70
|
/** 应用布局-页面主体配置(per #2.5 期 REQ-1) */
|
|
72
71
|
APP_LAYOUT_BODY_CONFIG: e.APP_LAYOUT_BODY_CONFIG,
|
|
73
72
|
/** 应用布局聚合配置(per #2.5 期 ADR-3 bridge 内部聚合派生) */
|
|
74
|
-
APP_LAYOUT_CONFIG:
|
|
73
|
+
APP_LAYOUT_CONFIG: U,
|
|
75
74
|
/** 应用路由元信息默认配置(per #2.5 期 REQ-1) */
|
|
76
75
|
APP_ROUTER_META_DEFAULT_CONFIG: e.APP_ROUTER_META_DEFAULT_CONFIG,
|
|
77
76
|
/** 应用路由配置(per #2.5 期 REQ-1) */
|
|
@@ -80,6 +79,8 @@ function L(e) {
|
|
|
80
79
|
APP_ROUTER_PATHS_CONFIG: e.APP_ROUTER_PATHS_CONFIG,
|
|
81
80
|
/** 应用主题配置(per #2.5 期 REQ-1) */
|
|
82
81
|
APP_THEME_CONFIG: e.APP_THEME_CONFIG,
|
|
82
|
+
/** 用户信息字段访问器集(第一宪法:业务注入 get/set 读写 token/refreshToken/permission) */
|
|
83
|
+
userInfoAccess: N,
|
|
83
84
|
// 异步对:未注册返回 rejected 原生 Error(#4a-2 per-method 降级)
|
|
84
85
|
loginApi(r) {
|
|
85
86
|
return T ? T(r) : Promise.reject(new Error(A("loginApi")));
|
|
@@ -96,8 +97,8 @@ function L(e) {
|
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
export {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
l as createAdminBridge,
|
|
101
|
+
o as createGenerateRouteMetaRawTree,
|
|
102
|
+
a as createStorageWithNamespace,
|
|
103
|
+
c as createUseState
|
|
103
104
|
};
|
package/es/store/user.mjs
CHANGED
|
@@ -1,91 +1,92 @@
|
|
|
1
|
-
import { defineStore as
|
|
2
|
-
import { computed as
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return U("USER", () => {
|
|
10
|
-
const k = o.getUserInfoInitFn(), c = (e, t, m) => {
|
|
11
|
-
const g = L(e);
|
|
12
|
-
return _(g, t, m), g;
|
|
13
|
-
}, S = (e) => p(e, "permission"), r = o.useState(
|
|
14
|
-
k(),
|
|
1
|
+
import { defineStore as y } from "pinia";
|
|
2
|
+
import { computed as o, watch as l } from "vue";
|
|
3
|
+
import { flatRouteMetaResolveRaw as P } from "../utils/router.mjs";
|
|
4
|
+
function L(g) {
|
|
5
|
+
const { bridge: t } = g;
|
|
6
|
+
return y("USER", () => {
|
|
7
|
+
const h = t.getUserInfoInitFn(), n = t.useState(
|
|
8
|
+
h(),
|
|
15
9
|
{
|
|
16
10
|
moduleKey: "USER_STORE",
|
|
17
11
|
debug: !1,
|
|
18
12
|
cache: !0
|
|
19
13
|
}
|
|
20
|
-
),
|
|
21
|
-
() =>
|
|
22
|
-
), u =
|
|
23
|
-
() =>
|
|
24
|
-
),
|
|
25
|
-
() =>
|
|
14
|
+
), r = o(() => n.state), a = o(
|
|
15
|
+
() => t.userInfoAccess.token.get(r.value)
|
|
16
|
+
), u = o(() => !!a.value), m = o(
|
|
17
|
+
() => t.userInfoAccess.refreshToken.get(r.value)
|
|
18
|
+
), v = o(
|
|
19
|
+
() => t.userInfoAccess.permission.get(r.value)
|
|
20
|
+
), p = o(
|
|
21
|
+
() => t.generateRouteMetaRawTree(t.getRoutes(), {
|
|
26
22
|
// 配置权限且有权限 或 (未配置权限无子路由(即末端子路由) 或 子路由有权限)
|
|
27
|
-
filterFn: (e,
|
|
28
|
-
sortFn: (e,
|
|
23
|
+
filterFn: (e, s, f) => e.checkPermission ? v.value.includes(e.permissionKey) : !f || s,
|
|
24
|
+
sortFn: (e, s) => e.menuSort - s.menuSort
|
|
29
25
|
})
|
|
30
|
-
),
|
|
31
|
-
|
|
32
|
-
},
|
|
26
|
+
), d = o(() => P(p.value)), k = o(() => d.value.map((e) => e.path)), i = () => {
|
|
27
|
+
n.resetState();
|
|
28
|
+
}, I = async () => {
|
|
33
29
|
try {
|
|
34
|
-
u.value && await
|
|
30
|
+
u.value && await t.logoutApi();
|
|
35
31
|
} catch (e) {
|
|
36
32
|
console.error("退出登录失败", e);
|
|
37
33
|
}
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
},
|
|
44
|
-
const e = await
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
i();
|
|
35
|
+
}, A = async (e) => {
|
|
36
|
+
i();
|
|
37
|
+
const s = await t.loginApi(e);
|
|
38
|
+
n.updateState(s);
|
|
39
|
+
}, c = async () => {
|
|
40
|
+
const e = await t.getUserInfoApi(), s = t.userInfoAccess.token.set(
|
|
41
|
+
e,
|
|
42
|
+
a.value
|
|
43
|
+
), f = t.userInfoAccess.refreshToken.set(
|
|
44
|
+
s,
|
|
45
|
+
m.value
|
|
48
46
|
);
|
|
49
|
-
return
|
|
50
|
-
},
|
|
51
|
-
const e = await
|
|
52
|
-
|
|
47
|
+
return n.updateState(f), e;
|
|
48
|
+
}, S = async () => {
|
|
49
|
+
const e = await t.refreshTokenApi(
|
|
50
|
+
m.value
|
|
53
51
|
);
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
n.updateState(
|
|
53
|
+
t.userInfoAccess.token.set(
|
|
54
|
+
r.value,
|
|
55
|
+
e
|
|
56
|
+
)
|
|
56
57
|
);
|
|
57
58
|
};
|
|
58
|
-
|
|
59
|
+
t.register({
|
|
59
60
|
getToken: () => a.value,
|
|
60
|
-
refreshToken:
|
|
61
|
-
refreshAuth:
|
|
61
|
+
refreshToken: S,
|
|
62
|
+
refreshAuth: c
|
|
62
63
|
});
|
|
63
|
-
const
|
|
64
|
-
return
|
|
64
|
+
const T = (e) => k.value.includes(e), R = (e) => v.value.includes(e);
|
|
65
|
+
return l(
|
|
65
66
|
u,
|
|
66
|
-
(e,
|
|
67
|
-
e && (
|
|
67
|
+
(e, s) => {
|
|
68
|
+
e && (s ?? c());
|
|
68
69
|
},
|
|
69
70
|
{
|
|
70
71
|
immediate: !0
|
|
71
72
|
}
|
|
72
|
-
),
|
|
73
|
-
e && !
|
|
74
|
-
}),
|
|
75
|
-
e &&
|
|
73
|
+
), l(u, (e, s) => {
|
|
74
|
+
e && !s && c();
|
|
75
|
+
}), l(a, (e, s) => {
|
|
76
|
+
e && s && c();
|
|
76
77
|
}), {
|
|
77
|
-
userInfo:
|
|
78
|
+
userInfo: r,
|
|
78
79
|
token: a,
|
|
79
80
|
isLogin: u,
|
|
80
|
-
login:
|
|
81
|
-
logout:
|
|
82
|
-
noApiLogout:
|
|
83
|
-
getInfo:
|
|
84
|
-
havePermissionByPath:
|
|
85
|
-
havePermissionByKey:
|
|
81
|
+
login: A,
|
|
82
|
+
logout: I,
|
|
83
|
+
noApiLogout: i,
|
|
84
|
+
getInfo: c,
|
|
85
|
+
havePermissionByPath: T,
|
|
86
|
+
havePermissionByKey: R
|
|
86
87
|
};
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
90
|
export {
|
|
90
|
-
|
|
91
|
+
L as createUserStore
|
|
91
92
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@done-coding/admin-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1-alpha.0",
|
|
4
4
|
"description": "后台管理核心",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "lib/index.cjs",
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"node": ">=18.0.0",
|
|
82
82
|
"pnpm": ">=9.0.0"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "611bac8c61ae3bafdde1ad22d358c992094b95d5"
|
|
85
85
|
}
|
package/types/bridge/index.d.ts
CHANGED
|
@@ -238,6 +238,49 @@ export type AppThemeConfig = AppConfig["APP_THEME_CONFIG"];
|
|
|
238
238
|
export type AppRouterMetaDefaultConfig = AppConfig["APP_ROUTER_META_DEFAULT_CONFIG"];
|
|
239
239
|
/** 应用缓存配置 type 别名 */
|
|
240
240
|
export type AppCacheConfig = AppConfig["APP_CACHE_CONFIG"];
|
|
241
|
+
/**
|
|
242
|
+
* token / refreshToken 字段访问器(含 get + set)。
|
|
243
|
+
*
|
|
244
|
+
* 第一宪法:core 对业务 `UserInfo` shape 完全不透明——业务自存自取,经本 adapter
|
|
245
|
+
* 注入读写两字段的纯函数,core [MUST NOT] 硬编字面字段名/路径耦合业务字段位置。
|
|
246
|
+
* `set` [MUST] 产新对象([MUST NOT] 原地 mutate,破响应式 + 破不可变)。
|
|
247
|
+
*/
|
|
248
|
+
export interface UserInfoFieldAccessor<UserInfo = unknown> {
|
|
249
|
+
/** 从用户信息读取字段值(未命中返回 undefined) */
|
|
250
|
+
get: (info: Partial<UserInfo>) => string | undefined;
|
|
251
|
+
/**
|
|
252
|
+
* 写入字段值,返回**保留 info 其余全部字段**的新对象。
|
|
253
|
+
*
|
|
254
|
+
* [MUST] 含 info 全字段(如 `{ ...info, <业务字段>: value }`)——createUserStore
|
|
255
|
+
* getInfo 顺势更新全部用户信息时以 data 为基,依赖本契约把 token/refreshToken
|
|
256
|
+
* 贴回而不丢失 data 其余字段;[MUST NOT] 只返回单字段对象,[MUST NOT] 原地 mutate info。
|
|
257
|
+
*/
|
|
258
|
+
set: (info: Partial<UserInfo>, value: string) => Partial<UserInfo>;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* permission 字段访问器(仅 get)。
|
|
262
|
+
*
|
|
263
|
+
* 权限由服务端下发只读,core 不写——仅 get 无 set;返回权限 key 列表(业务侧保底 `[]`)。
|
|
264
|
+
*/
|
|
265
|
+
export interface UserInfoPermissionAccessor<UserInfo = unknown> {
|
|
266
|
+
/** 从用户信息读取权限列表 */
|
|
267
|
+
get: (info: Partial<UserInfo>) => (string | number)[];
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* 用户信息字段访问器集(token / refreshToken / permission 三字段注入)。
|
|
271
|
+
*
|
|
272
|
+
* createUserStore 经 `bridge.userInfoAccess.<字段>.get/set` 读写业务 UserInfo,
|
|
273
|
+
* core 零字段名耦合(第一宪法)。业务 shape 完全自由(嵌套 / 组合 / 任意命名),
|
|
274
|
+
* core 只认 adapter 契约不认数据结构。
|
|
275
|
+
*/
|
|
276
|
+
export interface UserInfoAccess<UserInfo = unknown> {
|
|
277
|
+
/** token 字段访问器 */
|
|
278
|
+
token: UserInfoFieldAccessor<UserInfo>;
|
|
279
|
+
/** refreshToken 字段访问器 */
|
|
280
|
+
refreshToken: UserInfoFieldAccessor<UserInfo>;
|
|
281
|
+
/** permission 字段访问器(仅 get) */
|
|
282
|
+
permission: UserInfoPermissionAccessor<UserInfo>;
|
|
283
|
+
}
|
|
241
284
|
/**
|
|
242
285
|
* `createAdminBridge` 入参类型(#2.5 期 schema 扩张到 14 顶层字段,per ADR-3 / ADR-6)。
|
|
243
286
|
*
|
|
@@ -247,9 +290,9 @@ export type AppCacheConfig = AppConfig["APP_CACHE_CONFIG"];
|
|
|
247
290
|
*
|
|
248
291
|
* `routes`(#4e additive)为 app 嵌套路由树(带 children),createUserStore 经此算权限树;
|
|
249
292
|
* `getUserInfoInitFn` 为 createUserStore 用户信息空保底注入面(core 对 UserInfo 不透明,
|
|
250
|
-
* 业务 shape 不下沉,规则 8
|
|
251
|
-
*
|
|
252
|
-
*
|
|
293
|
+
* 业务 shape 不下沉,规则 8)。`userInfoAccess` 为 token / refreshToken / permission
|
|
294
|
+
* 三字段的业务注入访问器(第一宪法:core 经纯函数 get/set 读写,零字面字段名耦合,
|
|
295
|
+
* 业务 UserInfo shape 完全自由)。
|
|
253
296
|
*/
|
|
254
297
|
export interface AdminBridgeInitOptions<UserInfo = unknown> {
|
|
255
298
|
/** 应用基础信息(store/app 仅取 name) */
|
|
@@ -280,6 +323,8 @@ export interface AdminBridgeInitOptions<UserInfo = unknown> {
|
|
|
280
323
|
routes: RouteRecordRaw[];
|
|
281
324
|
/** 用户信息空保底工厂(v3 终锁 Δ0b;恒返非空业务字段默认值对象,createUserStore useState 经此取初值,core 不锁业务 shape) */
|
|
282
325
|
getUserInfoInitFn: () => UserInfo;
|
|
326
|
+
/** 用户信息字段访问器集(第一宪法:core 经业务注入 get/set 读写 token/refreshToken/permission,零字段名耦合,业务 shape 自由) */
|
|
327
|
+
userInfoAccess: UserInfoAccess<UserInfo>;
|
|
283
328
|
}
|
|
284
329
|
/**
|
|
285
330
|
* 认证桥接实例类型。
|
|
@@ -343,6 +388,8 @@ export interface AdminBridge<UserInfo = unknown, LoginParams = unknown> {
|
|
|
343
388
|
readonly APP_ROUTER_PATHS_CONFIG: AppRouterPathsConfig;
|
|
344
389
|
/** 应用主题配置(per #2.5 期 REQ-1) */
|
|
345
390
|
readonly APP_THEME_CONFIG: AppThemeConfig;
|
|
391
|
+
/** 用户信息字段访问器集(业务注入;createUserStore 经 bridge.userInfoAccess.<字段>.get/set 读写,第一宪法 core 零字段耦合) */
|
|
392
|
+
readonly userInfoAccess: UserInfoAccess<UserInfo>;
|
|
346
393
|
}
|
|
347
394
|
/**
|
|
348
395
|
* 认证桥接无状态纯工厂:接收 init 参数,内部立即初始化,返回可直接使用的
|
package/types/store/user.d.ts
CHANGED
|
@@ -8,10 +8,8 @@ import { RoutePermission } from '../types';
|
|
|
8
8
|
* 运行时配置 + 注入面全部经 `bridge`——`getAppConfig` / `getRoutes` / 4 业务 api /
|
|
9
9
|
* `getUserInfoInitFn()`(用户信息空保底工厂,替代 0fd94cc `userInfoInit` deps 字段)。
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* (与 permission design D-a 同模式),refreshTokenApi 直传 refreshToken string 由
|
|
14
|
-
* 业务方 wrap 内自打包业务 shape。
|
|
11
|
+
* 第一宪法:token / refreshToken / permission 三字段经 `bridge.userInfoAccess.<字段>`
|
|
12
|
+
* 业务注入访问器读写(纯函数 get/set,core 零字面字段名耦合,业务 UserInfo shape 自由)。
|
|
15
13
|
*/
|
|
16
14
|
export interface CreateUserStoreDeps<UserInfo, LoginParams = unknown> {
|
|
17
15
|
/** app 侧 admin bridge 单例(注入而非 core 持单例,守规则 8;getUserInfoInitFn 经 bridge.init 注入,本工厂经 bridge.getUserInfoInitFn() 读) */
|
|
@@ -50,7 +48,7 @@ export declare function createUserStore<UserInfo, LoginParams = unknown>(deps: C
|
|
|
50
48
|
getInfo: () => Promise<Partial<UserInfo>>;
|
|
51
49
|
havePermissionByPath: (path: string) => boolean;
|
|
52
50
|
havePermissionByKey: (key?: RoutePermission["key"]) => boolean;
|
|
53
|
-
}, "
|
|
51
|
+
}, "userInfo" | "token" | "isLogin">, Pick<{
|
|
54
52
|
userInfo: ComputedRef<UserInfo>;
|
|
55
53
|
token: ComputedRef<string | undefined>;
|
|
56
54
|
isLogin: ComputedRef<boolean>;
|