@owocow/saber-ui 0.0.1 → 0.0.3
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 +215 -2
- package/dist/BadgeStatus.types.d.ts +1 -1
- package/dist/BadgeStatus.vue.d.ts +1 -1
- package/dist/SaberConfirmModal.vue_vue_type_script_setup_true_lang-Cqp9krYl.js +86 -0
- package/dist/SaberConfirmProvider.vue_vue_type_script_setup_true_lang-DUJ6ftNJ.js +30 -0
- package/dist/SaberDictCheckbox.vue_vue_type_script_setup_true_lang-DUbzy_C6.js +34 -0
- package/dist/SaberDictRadio.vue_vue_type_script_setup_true_lang-DR6-jSID.js +50 -0
- package/dist/SaberDictSelect.vue_vue_type_script_setup_true_lang-B8PTKNKX.js +35 -0
- package/dist/SaberDistrictSelect.vue_vue_type_script_setup_true_lang-BX8nLC35.js +257 -0
- package/dist/SaberInfo.vue_vue_type_script_setup_true_lang-B3W5VsGR.js +58 -0
- package/dist/SaberInfoProvider.vue_vue_type_script_setup_true_lang-3rF6bSCn.js +28 -0
- package/dist/SaberModal.vue_vue_type_script_setup_true_lang-DJno3jA3.js +71 -0
- package/dist/SaberModalWithMobile.vue_vue_type_script_setup_true_lang-aQlToncY.js +87 -0
- package/dist/SaberNoData.types.d.ts +11 -0
- package/dist/SaberNoData.vue.d.ts +24 -0
- package/dist/SaberPopSelect.vue_vue_type_script_setup_true_lang-BcS27NXI.js +125 -0
- package/dist/SaberStatus.vue_vue_type_script_setup_true_lang-D9aRVCow.js +38 -0
- package/dist/SaberSwitchBar.vue_vue_type_script_setup_true_lang-CDx3Dcas.js +47 -0
- package/dist/SaberUploadImage.vue_vue_type_script_setup_true_lang-CAwci2Vr.js +224 -0
- package/dist/colors.d.ts +1 -1
- package/dist/components/SaberConfirmModal.mjs +4 -0
- package/dist/components/SaberConfirmModal.vue.d.ts +28 -0
- package/dist/components/SaberConfirmProvider.mjs +4 -0
- package/dist/components/SaberConfirmProvider.vue.d.ts +2 -0
- package/dist/components/SaberInfo.mjs +4 -0
- package/dist/components/SaberInfo.types.d.ts +14 -0
- package/dist/components/SaberInfo.vue.d.ts +21 -0
- package/dist/components/SaberInfoProvider.mjs +4 -0
- package/dist/components/SaberInfoProvider.vue.d.ts +20 -0
- package/dist/components/SaberModalWithMobile.mjs +4 -0
- package/dist/components/SaberModalWithMobile.vue.d.ts +36 -0
- package/dist/components/SaberStatus.mjs +4 -0
- package/dist/components/SaberStatus.types.d.ts +1 -0
- package/dist/components/SaberStatus.vue.d.ts +8 -0
- package/dist/components/SaberSwitchBar.mjs +4 -0
- package/dist/components/SaberSwitchBar.types.d.ts +13 -0
- package/dist/components/SaberSwitchBar.vue.d.ts +18 -0
- package/dist/components/info-context.d.ts +3 -0
- package/dist/composables/index.d.ts +12 -0
- package/dist/composables/use-address-parse.d.ts +15 -0
- package/dist/composables/use-address-parse.mjs +20 -0
- package/dist/composables/use-boolean.d.ts +8 -0
- package/dist/composables/use-boolean.mjs +20 -0
- package/dist/composables/use-confirm.d.ts +34 -0
- package/dist/composables/use-confirm.mjs +28 -0
- package/dist/composables/use-delay-unmount.d.ts +7 -0
- package/dist/composables/use-delay-unmount.mjs +26 -0
- package/dist/composables/use-delete.d.ts +13 -0
- package/dist/composables/use-delete.mjs +19 -0
- package/dist/composables/use-loading.d.ts +6 -0
- package/dist/composables/use-loading.mjs +8 -0
- package/dist/composables/use-skeleton.d.ts +5 -0
- package/dist/composables/use-skeleton.mjs +23 -0
- package/dist/composables/use-table.d.ts +57 -0
- package/dist/composables/use-table.mjs +87 -0
- package/dist/composables.mjs +21 -0
- package/dist/district-service-cOu1tbQG.js +147 -0
- package/dist/district.d.ts +3 -0
- package/dist/district.mjs +8 -0
- package/dist/forms/components/SaberFilterBar.vue.d.ts +41 -0
- package/dist/forms/components/SaberFormModal.vue.d.ts +31 -0
- package/dist/forms/components/SaberModal.vue.d.ts +34 -0
- package/dist/forms/components/fields/SaberDictCheckbox.vue.d.ts +24 -0
- package/dist/forms/components/fields/SaberDictRadio.vue.d.ts +24 -0
- package/dist/forms/components/fields/SaberDictSelect.vue.d.ts +28 -0
- package/dist/forms/components/fields/SaberDistrictSelect.vue.d.ts +31 -0
- package/dist/forms/components/fields/SaberInput.vue.d.ts +16 -0
- package/dist/forms/components/fields/SaberInputNumber.vue.d.ts +11 -0
- package/dist/forms/components/fields/SaberPopSelect.vue.d.ts +25 -0
- package/dist/forms/components/fields/SaberRadioGroup.vue.d.ts +11 -0
- package/dist/forms/components/fields/SaberSelect.vue.d.ts +11 -0
- package/dist/forms/components/fields/SaberTextarea.vue.d.ts +11 -0
- package/dist/forms/components/fields/SaberUploadImage.vue.d.ts +113 -0
- package/dist/forms/dict-checkbox.mjs +4 -0
- package/dist/forms/dict-radio.mjs +4 -0
- package/dist/forms/dict-select.mjs +4 -0
- package/dist/forms/dict-source.d.ts +3 -0
- package/dist/forms/district-select.mjs +4 -0
- package/dist/forms/district-service.d.ts +46 -0
- package/dist/forms/filter-state.d.ts +4 -0
- package/dist/forms/index.d.ts +24 -0
- package/dist/forms/plugin.d.ts +20 -0
- package/dist/forms/pop-select.mjs +4 -0
- package/dist/forms/presets/basic.d.ts +5 -0
- package/dist/forms/registry.d.ts +15 -0
- package/dist/forms/types.d.ts +102 -0
- package/dist/forms/upload-image-source.d.ts +3 -0
- package/dist/forms/upload-image.mjs +4 -0
- package/dist/forms/use-dict-options.d.ts +8 -0
- package/dist/forms.mjs +45 -0
- package/dist/index.d.ts +62 -1
- package/dist/index.mjs +122 -33
- package/dist/info-context-MfOfJNDT.js +4 -0
- package/dist/plugin-Dr3z0YFg.js +396 -0
- package/dist/types/api.d.ts +30 -0
- package/dist/types/auth.d.ts +54 -0
- package/dist/types/common.d.ts +14 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.mjs +1 -0
- package/dist/upload-image-source-On8NHgmx.js +4 -0
- package/dist/use-dict-options-DjtbYYIa.js +38 -0
- package/dist/utils/addressParse.d.ts +37 -0
- package/dist/utils/addressParse.mjs +623 -0
- package/dist/utils/crypto.d.ts +11 -0
- package/dist/utils/crypto.mjs +36 -0
- package/dist/utils/filter.d.ts +20 -0
- package/dist/utils/filter.mjs +11 -0
- package/dist/utils/format.d.ts +9 -0
- package/dist/utils/format.mjs +7 -0
- package/dist/utils/http.d.ts +45 -0
- package/dist/utils/http.mjs +147 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.mjs +41 -0
- package/dist/utils/klona.d.ts +2 -0
- package/dist/utils/klona.mjs +4 -0
- package/dist/utils/nanoid.d.ts +2 -0
- package/dist/utils/nanoid.mjs +4 -0
- package/dist/utils/permission.d.ts +45 -0
- package/dist/utils/permission.mjs +38 -0
- package/dist/utils/rsa.d.ts +26 -0
- package/dist/utils/rsa.mjs +2073 -0
- package/dist/utils/storage.d.ts +29 -0
- package/dist/utils/storage.mjs +39 -0
- package/dist/utils/toast.d.ts +26 -0
- package/dist/utils/toast.mjs +17 -0
- package/dist/utils/tree.d.ts +20 -0
- package/dist/utils/tree.mjs +30 -0
- package/dist/vite.d.ts +1 -0
- package/dist/vite.mjs +4 -0
- package/package.json +182 -7
- package/dist/index.cjs +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { default as CryptoJS } from 'crypto-js';
|
|
2
|
+
/** 随机生成 AES 密钥 */
|
|
3
|
+
export declare function generateAesKey(): CryptoJS.lib.WordArray;
|
|
4
|
+
/** 将 WordArray 转为 Base64 字符串 */
|
|
5
|
+
export declare function encryptBase64(str: CryptoJS.lib.WordArray): string;
|
|
6
|
+
/** Base64 字符串转 WordArray */
|
|
7
|
+
export declare function decryptBase64(str: string): CryptoJS.lib.WordArray;
|
|
8
|
+
/** 使用 AES 密钥加密 */
|
|
9
|
+
export declare function encryptWithAes(message: string, aesKey: CryptoJS.lib.WordArray): string;
|
|
10
|
+
/** 使用 AES 密钥解密 */
|
|
11
|
+
export declare function decryptWithAes(message: string, aesKey: CryptoJS.lib.WordArray): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import t from "crypto-js";
|
|
2
|
+
function o() {
|
|
3
|
+
const e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
4
|
+
let n = "";
|
|
5
|
+
for (let r = 0; r < 32; r++)
|
|
6
|
+
n += e.charAt(Math.floor(Math.random() * e.length));
|
|
7
|
+
return n;
|
|
8
|
+
}
|
|
9
|
+
function a() {
|
|
10
|
+
return t.enc.Utf8.parse(o());
|
|
11
|
+
}
|
|
12
|
+
function i(e) {
|
|
13
|
+
return t.enc.Base64.stringify(e);
|
|
14
|
+
}
|
|
15
|
+
function d(e) {
|
|
16
|
+
return t.enc.Base64.parse(e);
|
|
17
|
+
}
|
|
18
|
+
function p(e, n) {
|
|
19
|
+
return t.AES.encrypt(e, n, {
|
|
20
|
+
mode: t.mode.ECB,
|
|
21
|
+
padding: t.pad.Pkcs7
|
|
22
|
+
}).toString();
|
|
23
|
+
}
|
|
24
|
+
function s(e, n) {
|
|
25
|
+
return t.AES.decrypt(e, n, {
|
|
26
|
+
mode: t.mode.ECB,
|
|
27
|
+
padding: t.pad.Pkcs7
|
|
28
|
+
}).toString(t.enc.Utf8);
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
d as decryptBase64,
|
|
32
|
+
s as decryptWithAes,
|
|
33
|
+
i as encryptBase64,
|
|
34
|
+
p as encryptWithAes,
|
|
35
|
+
a as generateAesKey
|
|
36
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface StatusFilterOption {
|
|
2
|
+
label: string;
|
|
3
|
+
value: string | number | boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface FilterOptions {
|
|
6
|
+
/** 筛选选项列表,用于 SaberSelect / USelect 的 items */
|
|
7
|
+
options: StatusFilterOption[];
|
|
8
|
+
/** value → label 映射,用于列表展示时反查文本 */
|
|
9
|
+
optionsMap: Record<string, string>;
|
|
10
|
+
/** value → SaberStatusType 映射,用于 SaberStatus 组件 */
|
|
11
|
+
statusTypeMap: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 从 'label:value[:statusType]' 格式的字符串数组生成筛选选项、反查 Map 与状态类型 Map
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* createFilterOptions(['启用:1:success', '禁用:0:danger'])
|
|
18
|
+
* // { options: [{ label: '启用', value: '1' }, ...], optionsMap: { '1': '启用', ... }, statusTypeMap: { '1': 'success', ... } }
|
|
19
|
+
*/
|
|
20
|
+
export declare function createFilterOptions(map: string[]): FilterOptions;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function r(a) {
|
|
2
|
+
const o = [], n = {}, p = {};
|
|
3
|
+
for (const i of a) {
|
|
4
|
+
const t = i.split(":"), c = t[0], s = t[1], e = t[2];
|
|
5
|
+
o.push({ label: c, value: s }), n[s] = c, e && (p[s] = e);
|
|
6
|
+
}
|
|
7
|
+
return { options: o, optionsMap: n, statusTypeMap: p };
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
r as createFilterOptions
|
|
11
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
function m(i, t) {
|
|
2
|
+
const { prefix: r = "¥", minimumFractionDigits: n = 2, maximumFractionDigits: o = 2 } = t ?? {};
|
|
3
|
+
return i == null ? `${r} 0.00` : `${r} ${i.toLocaleString("zh-CN", { minimumFractionDigits: n, maximumFractionDigits: o })}`;
|
|
4
|
+
}
|
|
5
|
+
export {
|
|
6
|
+
m as formatCurrency
|
|
7
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ApiResponse, ListResponse } from '../types/api';
|
|
2
|
+
export type { ApiResponse, ListResponse } from '../types/api';
|
|
3
|
+
/** @deprecated 请使用 ListResponse。 */
|
|
4
|
+
export type ListResult<T = unknown> = ListResponse<T>;
|
|
5
|
+
export interface HttpConfig {
|
|
6
|
+
/** API 基础路径,如 `/api` */
|
|
7
|
+
baseURL: string;
|
|
8
|
+
/** 客户端标识,放入请求头 Clientid */
|
|
9
|
+
clientId: string;
|
|
10
|
+
/** 鉴权失败(token 无效/过期,code 401)回调,由业务方注入登出逻辑;403/402 视为无权限,仅提示不登出 */
|
|
11
|
+
onAuthError: () => void;
|
|
12
|
+
/** storage 中 token 的 key,默认 `'token'` */
|
|
13
|
+
tokenKey?: string;
|
|
14
|
+
/** 请求超时(毫秒),默认 10000 */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/** 是否启用请求/响应加密 */
|
|
17
|
+
encryptEnabled?: boolean;
|
|
18
|
+
/** 加密响应头的 key,默认 `'encrypt-key'` */
|
|
19
|
+
encryptHeaderKey?: string;
|
|
20
|
+
}
|
|
21
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
22
|
+
interface RequestOptions {
|
|
23
|
+
method?: HttpMethod;
|
|
24
|
+
data?: object;
|
|
25
|
+
params?: object;
|
|
26
|
+
withToken?: boolean;
|
|
27
|
+
encrypt?: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface UploadOptions {
|
|
30
|
+
data?: Record<string, string | Blob>;
|
|
31
|
+
field?: string;
|
|
32
|
+
onProgress?: (percent: number) => void;
|
|
33
|
+
withToken?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function setupHttp(config: HttpConfig): void;
|
|
36
|
+
export declare function request<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
|
|
37
|
+
export declare const http: {
|
|
38
|
+
get<T = unknown, P extends object = object>(url: string, params?: P, withToken?: boolean): Promise<ApiResponse<T>>;
|
|
39
|
+
list<T = unknown, P extends object = object>(url: string, params?: P, withToken?: boolean): Promise<ListResponse<T>>;
|
|
40
|
+
post<T = unknown, D extends object = object>(url: string, data?: D, withToken?: boolean, encrypt?: boolean): Promise<ApiResponse<T>>;
|
|
41
|
+
put<T = unknown, D extends object = object>(url: string, data?: D, withToken?: boolean, encrypt?: boolean): Promise<ApiResponse<T>>;
|
|
42
|
+
patch<T = unknown, D extends object = object>(url: string, data?: D, withToken?: boolean, encrypt?: boolean): Promise<ApiResponse<T>>;
|
|
43
|
+
delete<T = unknown, D extends object = object>(url: string, data?: D, withToken?: boolean): Promise<ApiResponse<T>>;
|
|
44
|
+
upload<T = unknown>(url: string, file: File | File[], options?: UploadOptions): Promise<T>;
|
|
45
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { ofetch as H } from "ofetch";
|
|
2
|
+
import { decryptBase64 as L, decryptWithAes as O, generateAesKey as R, encryptBase64 as I, encryptWithAes as K } from "./crypto.mjs";
|
|
3
|
+
import { rsaDecrypt as B, rsaEncrypt as U } from "./rsa.mjs";
|
|
4
|
+
import { storage as k } from "./storage.mjs";
|
|
5
|
+
import { getToast as T } from "./toast.mjs";
|
|
6
|
+
let $ = "", S = "", _ = "token", y = null, b = !1, P = "encrypt-key", A = null;
|
|
7
|
+
function v() {
|
|
8
|
+
if (!A)
|
|
9
|
+
throw new Error("[http] 尚未初始化,请先调用 setupHttp({ baseURL, clientId, onAuthError })");
|
|
10
|
+
return A;
|
|
11
|
+
}
|
|
12
|
+
function C() {
|
|
13
|
+
return new Headers({ Clientid: S });
|
|
14
|
+
}
|
|
15
|
+
function N(r) {
|
|
16
|
+
$ = r.baseURL, S = r.clientId, y = r.onAuthError, _ = r.tokenKey ?? "token", b = r.encryptEnabled ?? !1, P = r.encryptHeaderKey ?? "encrypt-key", A = H.create({
|
|
17
|
+
baseURL: $,
|
|
18
|
+
timeout: r.timeout ?? 1e4,
|
|
19
|
+
async onResponse({ response: t }) {
|
|
20
|
+
const e = b ? t.headers.get(P) : null;
|
|
21
|
+
if (e) {
|
|
22
|
+
const c = L(String(B(e)));
|
|
23
|
+
t._data = JSON.parse(O(String(t._data), c));
|
|
24
|
+
} else if (typeof t._data == "string")
|
|
25
|
+
try {
|
|
26
|
+
t._data = JSON.parse(t._data);
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
const o = t._data;
|
|
30
|
+
if (!o) return;
|
|
31
|
+
const { code: n, msg: i } = o;
|
|
32
|
+
if (n === 200) return;
|
|
33
|
+
const p = T();
|
|
34
|
+
if (n === 401) {
|
|
35
|
+
p.add({ title: i, color: "error" }), y == null || y();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (n === 402 || n === 403) {
|
|
39
|
+
p.add({ title: i ?? "无权限访问该资源", color: "error" });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (n === 404) {
|
|
43
|
+
p.add({ title: "后端 API 不存在", color: "error" });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
throw p.add({ title: i ?? `请求失败,错误码:${n}`, color: "error" }), new Error(i ?? `请求失败,错误码:${n}`);
|
|
47
|
+
},
|
|
48
|
+
onResponseError({ response: t }) {
|
|
49
|
+
var n;
|
|
50
|
+
const e = t.status, o = (n = t._data) == null ? void 0 : n.msg;
|
|
51
|
+
T().add({
|
|
52
|
+
title: `请求错误 ${e}${o ? `:${o}` : ""}`,
|
|
53
|
+
color: "error"
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function m(r, t = {}) {
|
|
59
|
+
const { method: e = "GET", data: o, params: n, withToken: i = !0, encrypt: p = !1 } = t, c = C();
|
|
60
|
+
if (i) {
|
|
61
|
+
const a = k.get(_);
|
|
62
|
+
a && c.set("Authorization", `Bearer ${a}`);
|
|
63
|
+
}
|
|
64
|
+
let f = e !== "GET" ? o : void 0, E;
|
|
65
|
+
if (b && p && (e === "POST" || e === "PUT" || e === "PATCH") && f) {
|
|
66
|
+
const a = R();
|
|
67
|
+
c.set(P, String(U(I(a)))), f = K(typeof f == "object" ? JSON.stringify(f) : String(f), a), E = "text";
|
|
68
|
+
}
|
|
69
|
+
return v()(r, {
|
|
70
|
+
method: e,
|
|
71
|
+
headers: c,
|
|
72
|
+
body: f,
|
|
73
|
+
query: e === "GET" ? { ...n, _t: Date.now() } : void 0,
|
|
74
|
+
responseType: E
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const z = {
|
|
78
|
+
get(r, t, e = !0) {
|
|
79
|
+
return m(r, { method: "GET", params: t, withToken: e });
|
|
80
|
+
},
|
|
81
|
+
list(r, t, e = !0) {
|
|
82
|
+
return m(r, { method: "GET", params: t, withToken: e });
|
|
83
|
+
},
|
|
84
|
+
post(r, t, e = !0, o = !1) {
|
|
85
|
+
return m(r, { method: "POST", data: t, withToken: e, encrypt: o });
|
|
86
|
+
},
|
|
87
|
+
put(r, t, e = !0, o = !1) {
|
|
88
|
+
return m(r, { method: "PUT", data: t, withToken: e, encrypt: o });
|
|
89
|
+
},
|
|
90
|
+
patch(r, t, e = !0, o = !1) {
|
|
91
|
+
return m(r, { method: "PATCH", data: t, withToken: e, encrypt: o });
|
|
92
|
+
},
|
|
93
|
+
delete(r, t, e = !0) {
|
|
94
|
+
return m(r, { method: "DELETE", data: t, withToken: e });
|
|
95
|
+
},
|
|
96
|
+
upload(r, t, e = {}) {
|
|
97
|
+
const { data: o, field: n = "file", onProgress: i, withToken: p = !0 } = e, c = new FormData();
|
|
98
|
+
(Array.isArray(t) ? t : [t]).forEach((a) => c.append(n, a)), o && Object.entries(o).forEach(([a, l]) => c.append(a, l));
|
|
99
|
+
const E = $, g = { Clientid: S };
|
|
100
|
+
if (p) {
|
|
101
|
+
const a = k.get(_);
|
|
102
|
+
a && (g.Authorization = `Bearer ${a}`);
|
|
103
|
+
}
|
|
104
|
+
return new Promise((a, l) => {
|
|
105
|
+
const s = new XMLHttpRequest();
|
|
106
|
+
s.open("POST", `${E}${r}`), Object.entries(g).forEach(([u, d]) => s.setRequestHeader(u, d)), i && s.upload.addEventListener("progress", (u) => {
|
|
107
|
+
u.lengthComputable && i(Math.round(u.loaded / u.total * 100));
|
|
108
|
+
}), s.addEventListener("load", () => {
|
|
109
|
+
if (s.status < 200 || s.status >= 300) {
|
|
110
|
+
T().add({ title: `请求错误 ${s.status}`, color: "error" }), l(new Error(`请求错误 ${s.status}`));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
let u;
|
|
114
|
+
try {
|
|
115
|
+
u = JSON.parse(s.responseText);
|
|
116
|
+
} catch {
|
|
117
|
+
l(new Error("响应解析失败"));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const { code: d, msg: h } = u;
|
|
121
|
+
if (d === 200) {
|
|
122
|
+
a(u.data);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const w = T();
|
|
126
|
+
if (d === 401) {
|
|
127
|
+
w.add({ title: h, color: "error" }), y == null || y(), l(new Error(h ?? `鉴权失败,错误码:${d}`));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (d === 402 || d === 403) {
|
|
131
|
+
w.add({ title: h ?? "无权限访问该资源", color: "error" }), l(new Error(h ?? `无权限,错误码:${d}`));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (d === 404) {
|
|
135
|
+
w.add({ title: "后端 API 不存在", color: "error" }), l(new Error("后端 API 不存在"));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
w.add({ title: h ?? `上传失败,错误码:${d}`, color: "error" }), l(new Error(h ?? `上传失败,错误码:${d}`));
|
|
139
|
+
}), s.addEventListener("error", () => l(new Error("上传请求失败"))), s.send(c);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
export {
|
|
144
|
+
z as http,
|
|
145
|
+
m as request,
|
|
146
|
+
N as setupHttp
|
|
147
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './permission';
|
|
2
|
+
export * from './format';
|
|
3
|
+
export * from './filter';
|
|
4
|
+
export * from './tree';
|
|
5
|
+
export * from './crypto';
|
|
6
|
+
export * from './toast';
|
|
7
|
+
export * from './storage';
|
|
8
|
+
export * from './rsa';
|
|
9
|
+
export * from './http';
|
|
10
|
+
export { jsonClone } from './klona';
|
|
11
|
+
export { nanoid } from './nanoid';
|
|
12
|
+
export { addressParse, createAddressParser, type AddressParseDistrict, type AddressParseResult, type AddressParser, } from './addressParse';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { canAccess as t, hasPermission as o, hasRole as s, setupPermission as p } from "./permission.mjs";
|
|
2
|
+
import { formatCurrency as m } from "./format.mjs";
|
|
3
|
+
import { createFilterOptions as c } from "./filter.mjs";
|
|
4
|
+
import { createTreeFromList as x } from "./tree.mjs";
|
|
5
|
+
import { decryptBase64 as y, decryptWithAes as d, encryptBase64 as u, encryptWithAes as h, generateAesKey as A } from "./crypto.mjs";
|
|
6
|
+
import { getToast as l, setToast as P, tryGetToast as T } from "./toast.mjs";
|
|
7
|
+
import { setupStorage as C, storage as F } from "./storage.mjs";
|
|
8
|
+
import { rsaDecrypt as W, rsaEncrypt as j, setupRsa as k } from "./rsa.mjs";
|
|
9
|
+
import { http as D, request as E, setupHttp as G } from "./http.mjs";
|
|
10
|
+
import { klona as K } from "klona/json";
|
|
11
|
+
import { nanoid as O } from "nanoid";
|
|
12
|
+
import { addressParse as b, createAddressParser as v } from "./addressParse.mjs";
|
|
13
|
+
export {
|
|
14
|
+
b as addressParse,
|
|
15
|
+
t as canAccess,
|
|
16
|
+
v as createAddressParser,
|
|
17
|
+
c as createFilterOptions,
|
|
18
|
+
x as createTreeFromList,
|
|
19
|
+
y as decryptBase64,
|
|
20
|
+
d as decryptWithAes,
|
|
21
|
+
u as encryptBase64,
|
|
22
|
+
h as encryptWithAes,
|
|
23
|
+
m as formatCurrency,
|
|
24
|
+
A as generateAesKey,
|
|
25
|
+
l as getToast,
|
|
26
|
+
o as hasPermission,
|
|
27
|
+
s as hasRole,
|
|
28
|
+
D as http,
|
|
29
|
+
K as jsonClone,
|
|
30
|
+
O as nanoid,
|
|
31
|
+
E as request,
|
|
32
|
+
W as rsaDecrypt,
|
|
33
|
+
j as rsaEncrypt,
|
|
34
|
+
P as setToast,
|
|
35
|
+
G as setupHttp,
|
|
36
|
+
p as setupPermission,
|
|
37
|
+
k as setupRsa,
|
|
38
|
+
C as setupStorage,
|
|
39
|
+
F as storage,
|
|
40
|
+
T as tryGetToast
|
|
41
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 权限鉴权工具模块
|
|
3
|
+
*
|
|
4
|
+
* 使用前必须在 main.ts 中 await setupPermission() 注入用户信息获取器:
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { setupPermission } from '@owocow/saber-ui/utils/permission'
|
|
8
|
+
* import { useAuthStore } from '@/store/auth'
|
|
9
|
+
* import { SUPER_ADMIN_ROLE, SUPER_PERM } from '@/enums'
|
|
10
|
+
*
|
|
11
|
+
* await setupPermission(() => useAuthStore().userInfo, {
|
|
12
|
+
* superRoles: [SUPER_ADMIN_ROLE],
|
|
13
|
+
* superPerms: [SUPER_PERM],
|
|
14
|
+
* })
|
|
15
|
+
*/
|
|
16
|
+
/** 用户信息最小约定 — 只需 roles 和 permissions 两个字段 */
|
|
17
|
+
export interface UserInfo {
|
|
18
|
+
roles: string[];
|
|
19
|
+
permissions: string[];
|
|
20
|
+
}
|
|
21
|
+
/** 路由/菜单/按钮 meta 中的权限配置 */
|
|
22
|
+
export interface PermissionMeta {
|
|
23
|
+
roles?: string | string[];
|
|
24
|
+
permissions?: string | string[];
|
|
25
|
+
}
|
|
26
|
+
/** setupPermission 可选配置 */
|
|
27
|
+
export interface PermissionOptions {
|
|
28
|
+
/** 超级管理员角色列表,命中任一即跳过所有鉴权;默认 ['admin'] */
|
|
29
|
+
superRoles?: string[];
|
|
30
|
+
/** 超级权限标识列表,命中任一即跳过权限检查;默认 ['*:*:*'] */
|
|
31
|
+
superPerms?: string[];
|
|
32
|
+
}
|
|
33
|
+
type UserInfoGetter = () => UserInfo | Promise<UserInfo>;
|
|
34
|
+
/**
|
|
35
|
+
* 初始化权限模块,注入用户信息获取器。
|
|
36
|
+
* 会立即调用 getter 一次以验证可用性,因此支持 await。
|
|
37
|
+
*/
|
|
38
|
+
export declare function setupPermission(getter: UserInfoGetter, options?: PermissionOptions): Promise<void>;
|
|
39
|
+
/** 是否拥有任一所需角色;required 为空视为通过 */
|
|
40
|
+
export declare function hasRole(required?: string | string[]): boolean;
|
|
41
|
+
/** 是否拥有任一所需权限;required 为空视为通过 */
|
|
42
|
+
export declare function hasPermission(required?: string | string[]): boolean;
|
|
43
|
+
/** 路由/菜单/按钮的统一鉴权入口 */
|
|
44
|
+
export declare function canAccess(meta?: PermissionMeta | null): boolean;
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
let u = null, t = ["admin"], i = ["*:*:*"];
|
|
2
|
+
async function a(r, e) {
|
|
3
|
+
u = r, e != null && e.superRoles && (t = e.superRoles), e != null && e.superPerms && (i = e.superPerms), await r();
|
|
4
|
+
}
|
|
5
|
+
function f() {
|
|
6
|
+
if (!u)
|
|
7
|
+
throw new Error(
|
|
8
|
+
"[permission] 尚未初始化,请在 main.ts 调用 await setupPermission(() => useAuthStore().userInfo)"
|
|
9
|
+
);
|
|
10
|
+
return u();
|
|
11
|
+
}
|
|
12
|
+
function l(r) {
|
|
13
|
+
return Array.isArray(r) ? r : [r];
|
|
14
|
+
}
|
|
15
|
+
function s(r, e) {
|
|
16
|
+
return r.some((n) => e.includes(n));
|
|
17
|
+
}
|
|
18
|
+
function c(r) {
|
|
19
|
+
const e = r != null ? l(r).filter(Boolean) : [];
|
|
20
|
+
if (!e.length) return !0;
|
|
21
|
+
const { roles: n } = f();
|
|
22
|
+
return s(t, n) ? !0 : s(e, n);
|
|
23
|
+
}
|
|
24
|
+
function o(r) {
|
|
25
|
+
const e = r != null ? l(r).filter(Boolean) : [];
|
|
26
|
+
if (!e.length) return !0;
|
|
27
|
+
const { permissions: n } = f();
|
|
28
|
+
return s(i, n) ? !0 : s(e, n);
|
|
29
|
+
}
|
|
30
|
+
function m(r) {
|
|
31
|
+
return r ? c(r.roles) && o(r.permissions) : !0;
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
m as canAccess,
|
|
35
|
+
o as hasPermission,
|
|
36
|
+
c as hasRole,
|
|
37
|
+
a as setupPermission
|
|
38
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSA 加解密模块
|
|
3
|
+
*
|
|
4
|
+
* 使用前需在 main.ts 中调用 setupRsa() 注入密钥:
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { setupRsa } from '@owocow/saber-ui/utils/rsa'
|
|
8
|
+
*
|
|
9
|
+
* setupRsa({
|
|
10
|
+
* publicKey: import.meta.env.VITE_APP_RSA_PUBLIC_KEY,
|
|
11
|
+
* privateKey: import.meta.env.VITE_APP_RSA_PRIVATE_KEY,
|
|
12
|
+
* })
|
|
13
|
+
*
|
|
14
|
+
* // 之后任意位置直接使用
|
|
15
|
+
* import { rsaEncrypt, rsaDecrypt } from '@owocow/saber-ui/utils/rsa'
|
|
16
|
+
*/
|
|
17
|
+
export interface RsaConfig {
|
|
18
|
+
publicKey: string;
|
|
19
|
+
privateKey: string;
|
|
20
|
+
}
|
|
21
|
+
/** 初始化 RSA 模块 */
|
|
22
|
+
export declare function setupRsa(config: RsaConfig): void;
|
|
23
|
+
/** RSA 公钥加密 */
|
|
24
|
+
export declare function rsaEncrypt(txt: string): string | false;
|
|
25
|
+
/** RSA 私钥解密 */
|
|
26
|
+
export declare function rsaDecrypt(txt: string): string | false;
|