@litianxiang/portal-core 0.1.11 → 0.1.13
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/dist/index.d.ts +97 -1
- package/dist/index.js +199 -6
- package/package.json +5 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as vue_router from 'vue-router';
|
|
2
2
|
import { RouteRecordRaw } from 'vue-router';
|
|
3
|
+
import { Dayjs } from 'dayjs';
|
|
3
4
|
|
|
4
5
|
interface AppRouterOptions {
|
|
5
6
|
staticRoutes: RouteRecordRaw[];
|
|
@@ -121,5 +122,100 @@ interface MenuHelper {
|
|
|
121
122
|
getBreadcrumb: (path: string) => BreadcrumbItem[];
|
|
122
123
|
}
|
|
123
124
|
declare function createMenuHelper(options: MenuHelperOptions): MenuHelper;
|
|
125
|
+
/**
|
|
126
|
+
* 标准化后的菜单节点结构,供各前端站点复用
|
|
127
|
+
* 不依赖具体项目的 IMenu 类型
|
|
128
|
+
*/
|
|
129
|
+
interface CoreMenuItem {
|
|
130
|
+
id: string | number;
|
|
131
|
+
parent_id?: string | number | null;
|
|
132
|
+
category?: string;
|
|
133
|
+
name?: string;
|
|
134
|
+
path?: string;
|
|
135
|
+
icon?: string;
|
|
136
|
+
order_num?: number;
|
|
137
|
+
site?: string;
|
|
138
|
+
children?: CoreMenuItem[];
|
|
139
|
+
}
|
|
140
|
+
interface TransformMenuOptions {
|
|
141
|
+
/**
|
|
142
|
+
* 当后端未返回 site 字段时使用的默认站点标识
|
|
143
|
+
* 示例:manage、hr-kq 等
|
|
144
|
+
*/
|
|
145
|
+
defaultSite?: string;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 将后端返回的原始菜单数据转换为前端通用的 CoreMenuItem 结构
|
|
149
|
+
* - 主要是结构统一与 children 递归转换
|
|
150
|
+
* - 是否从 snake_case 转 camelCase 由后端约定,这里只做字段透传
|
|
151
|
+
*/
|
|
152
|
+
declare function transformMenuTree(menuList: any[], options?: TransformMenuOptions): CoreMenuItem[];
|
|
153
|
+
/**
|
|
154
|
+
* 生成包含完整 children 的菜单树(包括 page 下的按钮等)
|
|
155
|
+
* 一般用于:
|
|
156
|
+
* - 权限判断(页面 + 按钮)
|
|
157
|
+
* - 侧边菜单折叠前的完整数据源
|
|
158
|
+
*/
|
|
159
|
+
declare function buildAllMenuTree(menuList: CoreMenuItem[]): CoreMenuItem[];
|
|
160
|
+
/**
|
|
161
|
+
* 从完整菜单树中裁剪出 page + button 列表结构
|
|
162
|
+
* - 去掉纯 module 节点
|
|
163
|
+
* - 常用于“页面+按钮权限”一体的菜单视图
|
|
164
|
+
*/
|
|
165
|
+
declare function buildPageMenuList(menuList: CoreMenuItem[]): CoreMenuItem[];
|
|
166
|
+
/**
|
|
167
|
+
* 递归查找菜单树中的第一个 page 页面路径
|
|
168
|
+
* 常用于:登录后或进入某模块时,自动跳转到第一个页面
|
|
169
|
+
*/
|
|
170
|
+
declare function findFirstPagePath(menuList: CoreMenuItem[]): string | null;
|
|
171
|
+
|
|
172
|
+
type TimeInput = string | number | Date | Dayjs;
|
|
173
|
+
interface TimeRange<T = Dayjs> {
|
|
174
|
+
start: T;
|
|
175
|
+
end: T;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 标准时间格式化
|
|
179
|
+
*/
|
|
180
|
+
declare function formatTime(date: TimeInput, format?: string): string;
|
|
181
|
+
/**
|
|
182
|
+
* 人性化相对时间(如:3分钟前)
|
|
183
|
+
*/
|
|
184
|
+
declare function humanizeTime(date: TimeInput): string;
|
|
185
|
+
/**
|
|
186
|
+
* 计算时间差(毫秒)
|
|
187
|
+
*/
|
|
188
|
+
declare function timeDiff(start: TimeInput, end?: TimeInput): number;
|
|
189
|
+
/**
|
|
190
|
+
* 将日期转换为月-日格式
|
|
191
|
+
*/
|
|
192
|
+
declare function formatToMonthDay(date: TimeInput): string;
|
|
193
|
+
/**
|
|
194
|
+
* 生成日期区间对象(Dayjs)
|
|
195
|
+
*/
|
|
196
|
+
declare function createRange(start: TimeInput, end: TimeInput): TimeRange<Dayjs>;
|
|
197
|
+
/**
|
|
198
|
+
* 将日期区间格式化为字符串:2026-02-01 ~ 2026-02-23
|
|
199
|
+
*/
|
|
200
|
+
declare function formatRange(start: TimeInput, end: TimeInput, format?: string): string;
|
|
201
|
+
type PresetRangeKey = 'today' | 'yesterday' | 'last7days' | 'last30days' | 'thisMonth' | 'lastMonth';
|
|
202
|
+
/**
|
|
203
|
+
* 获取常用日期区间(用于统计/筛选快捷选项)
|
|
204
|
+
*/
|
|
205
|
+
declare function getPresetRange(key: PresetRangeKey, now?: TimeInput): TimeRange<Dayjs>;
|
|
206
|
+
/**
|
|
207
|
+
* 判断某个时间是否在区间内(含边界)
|
|
208
|
+
*/
|
|
209
|
+
declare function isInRange(value: TimeInput, range: TimeRange<TimeInput>): boolean;
|
|
210
|
+
declare function useTime(): {
|
|
211
|
+
formatTime: typeof formatTime;
|
|
212
|
+
humanizeTime: typeof humanizeTime;
|
|
213
|
+
timeDiff: typeof timeDiff;
|
|
214
|
+
formatToMonthDay: typeof formatToMonthDay;
|
|
215
|
+
createRange: typeof createRange;
|
|
216
|
+
formatRange: typeof formatRange;
|
|
217
|
+
getPresetRange: typeof getPresetRange;
|
|
218
|
+
isInRange: typeof isInRange;
|
|
219
|
+
};
|
|
124
220
|
|
|
125
|
-
export { type AppRouterOptions, type BreadcrumbItem, type CreateAuthHttpClientOptions, type InactivityConfig, type InactivityResult, type LogoutToAuthOptions, type MenuHelper, type MenuHelperOptions, type PermissionHelper, type PermissionHelperOptions, calcInactivityAction, createAppRouter, createAuthHttpClient, createLogoutToAuth, createMenuHelper, createPermissionHelper };
|
|
221
|
+
export { type AppRouterOptions, type BreadcrumbItem, type CoreMenuItem, type CreateAuthHttpClientOptions, type InactivityConfig, type InactivityResult, type LogoutToAuthOptions, type MenuHelper, type MenuHelperOptions, type PermissionHelper, type PermissionHelperOptions, type PresetRangeKey, type TimeInput, type TimeRange, type TransformMenuOptions, buildAllMenuTree, buildPageMenuList, calcInactivityAction, createAppRouter, createAuthHttpClient, createLogoutToAuth, createMenuHelper, createPermissionHelper, createRange, findFirstPagePath, formatRange, formatTime, formatToMonthDay, getPresetRange, humanizeTime, isInRange, timeDiff, transformMenuTree, useTime };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/router.ts
|
|
1
|
+
// src/router/router.ts
|
|
2
2
|
import { createRouter, createWebHashHistory } from "vue-router";
|
|
3
3
|
function createAppRouter(options) {
|
|
4
4
|
const { staticRoutes, getUserStore, getTabStore, getFirstPage, authLoginUrl } = options;
|
|
@@ -154,7 +154,7 @@ function createAppRouter(options) {
|
|
|
154
154
|
return router;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
// src/auth.ts
|
|
157
|
+
// src/auth/auth.ts
|
|
158
158
|
function createLogoutToAuth(options) {
|
|
159
159
|
const {
|
|
160
160
|
getUserStore,
|
|
@@ -223,7 +223,7 @@ function calcInactivityAction(lastActiveTime, now, config = {}) {
|
|
|
223
223
|
};
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
// src/http.ts
|
|
226
|
+
// src/http/http.ts
|
|
227
227
|
function createAuthHttpClient(options) {
|
|
228
228
|
const {
|
|
229
229
|
axios,
|
|
@@ -371,7 +371,7 @@ function createAuthHttpClient(options) {
|
|
|
371
371
|
return { http, logoutToAuth };
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
-
// src/permission.ts
|
|
374
|
+
// src/permission/permission.ts
|
|
375
375
|
function normalizePath(raw) {
|
|
376
376
|
if (!raw) return "";
|
|
377
377
|
const [base] = raw.split("?");
|
|
@@ -427,7 +427,7 @@ function createPermissionHelper(options) {
|
|
|
427
427
|
};
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
-
// src/menu.ts
|
|
430
|
+
// src/menu/menu.ts
|
|
431
431
|
function normalizePath2(raw) {
|
|
432
432
|
if (!raw) return "";
|
|
433
433
|
const [base] = raw.split("?");
|
|
@@ -513,11 +513,204 @@ function createMenuHelper(options) {
|
|
|
513
513
|
getBreadcrumb
|
|
514
514
|
};
|
|
515
515
|
}
|
|
516
|
+
function transformMenuTree(menuList, options) {
|
|
517
|
+
const defaultSite = options?.defaultSite;
|
|
518
|
+
return (menuList || []).map((item) => {
|
|
519
|
+
const children = Array.isArray(item?.children) ? transformMenuTree(item.children, options) : void 0;
|
|
520
|
+
return {
|
|
521
|
+
id: item?.id,
|
|
522
|
+
parent_id: item?.parent_id ?? null,
|
|
523
|
+
category: item?.category,
|
|
524
|
+
name: item?.name,
|
|
525
|
+
path: item?.path,
|
|
526
|
+
icon: item?.icon,
|
|
527
|
+
order_num: item?.order_num,
|
|
528
|
+
site: item?.site ?? defaultSite,
|
|
529
|
+
children
|
|
530
|
+
};
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
function buildAllMenuTree(menuList) {
|
|
534
|
+
const result = [];
|
|
535
|
+
for (const item of menuList || []) {
|
|
536
|
+
result.push({
|
|
537
|
+
id: item.id,
|
|
538
|
+
parent_id: item.parent_id ?? null,
|
|
539
|
+
category: item.category,
|
|
540
|
+
name: item.name,
|
|
541
|
+
path: item.path,
|
|
542
|
+
icon: item.icon,
|
|
543
|
+
order_num: item.order_num,
|
|
544
|
+
site: item.site,
|
|
545
|
+
children: item.children && item.children.length > 0 ? buildAllMenuTree(item.children) : []
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return result;
|
|
549
|
+
}
|
|
550
|
+
function buildPageMenuList(menuList) {
|
|
551
|
+
const pages = [];
|
|
552
|
+
for (const item of menuList || []) {
|
|
553
|
+
if (item.category !== "module") {
|
|
554
|
+
pages.push({
|
|
555
|
+
id: item.id,
|
|
556
|
+
parent_id: item.parent_id ?? null,
|
|
557
|
+
category: item.category,
|
|
558
|
+
name: item.name,
|
|
559
|
+
path: item.path,
|
|
560
|
+
icon: item.icon,
|
|
561
|
+
order_num: item.order_num,
|
|
562
|
+
site: item.site,
|
|
563
|
+
children: item.children ? buildPageMenuList(item.children) : []
|
|
564
|
+
});
|
|
565
|
+
} else if (item.children && item.children.length > 0) {
|
|
566
|
+
const childMenus = buildPageMenuList(item.children);
|
|
567
|
+
if (childMenus.length > 0) {
|
|
568
|
+
for (const child of childMenus) {
|
|
569
|
+
pages.push({
|
|
570
|
+
id: child.id,
|
|
571
|
+
parent_id: child.parent_id ?? null,
|
|
572
|
+
category: child.category,
|
|
573
|
+
name: child.name,
|
|
574
|
+
path: child.path,
|
|
575
|
+
icon: child.icon,
|
|
576
|
+
order_num: child.order_num,
|
|
577
|
+
site: child.site,
|
|
578
|
+
children: child.children
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return pages;
|
|
585
|
+
}
|
|
586
|
+
function findFirstPagePath(menuList) {
|
|
587
|
+
for (const item of menuList || []) {
|
|
588
|
+
if (item.category === "page" && item.path) {
|
|
589
|
+
return item.path;
|
|
590
|
+
}
|
|
591
|
+
if (item.children && item.children.length > 0) {
|
|
592
|
+
const childFirst = findFirstPagePath(item.children);
|
|
593
|
+
if (childFirst) return childFirst;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// src/time/time.ts
|
|
600
|
+
import dayjs from "dayjs";
|
|
601
|
+
import relativeTime from "dayjs/plugin/relativeTime";
|
|
602
|
+
import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
|
|
603
|
+
import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
|
|
604
|
+
import "dayjs/locale/zh-cn";
|
|
605
|
+
dayjs.extend(relativeTime);
|
|
606
|
+
dayjs.extend(isSameOrAfter);
|
|
607
|
+
dayjs.extend(isSameOrBefore);
|
|
608
|
+
dayjs.locale("zh-cn");
|
|
609
|
+
function formatTime(date, format = "YYYY-MM-DD HH:mm:ss") {
|
|
610
|
+
const d = dayjs(date);
|
|
611
|
+
if (!d.isValid()) return "";
|
|
612
|
+
return d.format(format);
|
|
613
|
+
}
|
|
614
|
+
function humanizeTime(date) {
|
|
615
|
+
return dayjs(date).fromNow();
|
|
616
|
+
}
|
|
617
|
+
function timeDiff(start, end = Date.now()) {
|
|
618
|
+
return dayjs(end).diff(dayjs(start));
|
|
619
|
+
}
|
|
620
|
+
function formatToMonthDay(date) {
|
|
621
|
+
const d = dayjs(date);
|
|
622
|
+
if (!d.isValid()) return "";
|
|
623
|
+
return d.format("MM-DD");
|
|
624
|
+
}
|
|
625
|
+
function createRange(start, end) {
|
|
626
|
+
const s = dayjs(start);
|
|
627
|
+
const e = dayjs(end);
|
|
628
|
+
return s.isBefore(e) ? { start: s, end: e } : { start: e, end: s };
|
|
629
|
+
}
|
|
630
|
+
function formatRange(start, end, format = "YYYY-MM-DD") {
|
|
631
|
+
const { start: s, end: e } = createRange(start, end);
|
|
632
|
+
if (!s.isValid() || !e.isValid()) return "";
|
|
633
|
+
return `${s.format(format)} ~ ${e.format(format)}`;
|
|
634
|
+
}
|
|
635
|
+
function getPresetRange(key, now = dayjs()) {
|
|
636
|
+
const base = dayjs(now);
|
|
637
|
+
switch (key) {
|
|
638
|
+
case "today": {
|
|
639
|
+
const start = base.startOf("day");
|
|
640
|
+
const end = base.endOf("day");
|
|
641
|
+
return { start, end };
|
|
642
|
+
}
|
|
643
|
+
case "yesterday": {
|
|
644
|
+
const start = base.subtract(1, "day").startOf("day");
|
|
645
|
+
const end = base.subtract(1, "day").endOf("day");
|
|
646
|
+
return { start, end };
|
|
647
|
+
}
|
|
648
|
+
case "last7days": {
|
|
649
|
+
const start = base.subtract(6, "day").startOf("day");
|
|
650
|
+
const end = base.endOf("day");
|
|
651
|
+
return { start, end };
|
|
652
|
+
}
|
|
653
|
+
case "last30days": {
|
|
654
|
+
const start = base.subtract(29, "day").startOf("day");
|
|
655
|
+
const end = base.endOf("day");
|
|
656
|
+
return { start, end };
|
|
657
|
+
}
|
|
658
|
+
case "thisMonth": {
|
|
659
|
+
const start = base.startOf("month");
|
|
660
|
+
const end = base.endOf("month");
|
|
661
|
+
return { start, end };
|
|
662
|
+
}
|
|
663
|
+
case "lastMonth": {
|
|
664
|
+
const prev = base.subtract(1, "month");
|
|
665
|
+
const start = prev.startOf("month");
|
|
666
|
+
const end = prev.endOf("month");
|
|
667
|
+
return { start, end };
|
|
668
|
+
}
|
|
669
|
+
default: {
|
|
670
|
+
const start = base.startOf("day");
|
|
671
|
+
const end = base.endOf("day");
|
|
672
|
+
return { start, end };
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
function isInRange(value, range) {
|
|
677
|
+
const v = dayjs(value);
|
|
678
|
+
const s = dayjs(range.start);
|
|
679
|
+
const e = dayjs(range.end);
|
|
680
|
+
if (!v.isValid() || !s.isValid() || !e.isValid()) return false;
|
|
681
|
+
const { start, end } = createRange(s, e);
|
|
682
|
+
return v.isSameOrAfter(start) && v.isSameOrBefore(end);
|
|
683
|
+
}
|
|
684
|
+
function useTime() {
|
|
685
|
+
return {
|
|
686
|
+
formatTime,
|
|
687
|
+
humanizeTime,
|
|
688
|
+
timeDiff,
|
|
689
|
+
formatToMonthDay,
|
|
690
|
+
createRange,
|
|
691
|
+
formatRange,
|
|
692
|
+
getPresetRange,
|
|
693
|
+
isInRange
|
|
694
|
+
};
|
|
695
|
+
}
|
|
516
696
|
export {
|
|
697
|
+
buildAllMenuTree,
|
|
698
|
+
buildPageMenuList,
|
|
517
699
|
calcInactivityAction,
|
|
518
700
|
createAppRouter,
|
|
519
701
|
createAuthHttpClient,
|
|
520
702
|
createLogoutToAuth,
|
|
521
703
|
createMenuHelper,
|
|
522
|
-
createPermissionHelper
|
|
704
|
+
createPermissionHelper,
|
|
705
|
+
createRange,
|
|
706
|
+
findFirstPagePath,
|
|
707
|
+
formatRange,
|
|
708
|
+
formatTime,
|
|
709
|
+
formatToMonthDay,
|
|
710
|
+
getPresetRange,
|
|
711
|
+
humanizeTime,
|
|
712
|
+
isInRange,
|
|
713
|
+
timeDiff,
|
|
714
|
+
transformMenuTree,
|
|
715
|
+
useTime
|
|
523
716
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litianxiang/portal-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"vue": "^3.5.0",
|
|
17
|
-
"vue-router": "^4.5.0"
|
|
17
|
+
"vue-router": "^4.5.0",
|
|
18
|
+
"dayjs": "^1.11.0"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"tsup": "^8.3.0",
|
|
21
|
-
"typescript": "^5.6.3"
|
|
22
|
+
"typescript": "^5.6.3",
|
|
23
|
+
"dayjs": "^1.11.13"
|
|
22
24
|
},
|
|
23
25
|
"license": "UNLICENSED"
|
|
24
26
|
}
|