@peng_kai/kit 0.2.0-beta.2 → 0.2.0-beta.21
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/admin/adminPlugin.ts +11 -1
- package/admin/components/filter/src/FilterParam.vue +1 -1
- package/admin/components/text/src/Datetime.vue +1 -1
- package/admin/defines/route/index.ts +1 -1
- package/admin/layout/large/Breadcrumb.vue +2 -2
- package/admin/layout/large/Content.vue +2 -2
- package/admin/layout/large/Menu.vue +2 -2
- package/admin/layout/large/PageTab.vue +2 -2
- package/admin/styles/index.scss +14 -12
- package/antd/hooks/useAntdModal.ts +5 -2
- package/libs/dayjs.ts +7 -0
- package/libs/echarts.ts +1 -1
- package/libs/vue-i18n.ts +21 -0
- package/package.json +92 -91
- package/utils/LocaleManager.ts +125 -0
- package/utils/date.ts +1 -9
package/admin/adminPlugin.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { inject } from 'vue';
|
|
1
2
|
import type { App } from 'vue';
|
|
2
3
|
import type { Router } from 'vue-router';
|
|
3
4
|
import type { TUseMenuStore } from './stores/createUseMenuStore';
|
|
@@ -5,7 +6,7 @@ import type { TUsePageStore } from './stores/createUsePageStore';
|
|
|
5
6
|
import type { TUsePageTabStore } from './stores/createUsePageTabStore';
|
|
6
7
|
import type { TRole, TUsePermissionStore } from './stores/createUsePermissionStore';
|
|
7
8
|
|
|
8
|
-
interface IOtions {
|
|
9
|
+
export interface IOtions {
|
|
9
10
|
meta: {
|
|
10
11
|
appId: string
|
|
11
12
|
appName: string
|
|
@@ -20,6 +21,7 @@ interface IOtions {
|
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
const PROVIDE_KEY = 'TT_ADMIN';
|
|
23
25
|
let _meta: IOtions['meta'];
|
|
24
26
|
let _deps: IOtions['deps'];
|
|
25
27
|
|
|
@@ -27,6 +29,10 @@ export const adminPlugin = {
|
|
|
27
29
|
install(_app: App, options: IOtions) {
|
|
28
30
|
_meta = options.meta;
|
|
29
31
|
_deps = options.deps;
|
|
32
|
+
_app.provide(PROVIDE_KEY, {
|
|
33
|
+
meta: this.meta,
|
|
34
|
+
deps: this.deps,
|
|
35
|
+
});
|
|
30
36
|
},
|
|
31
37
|
meta: new Proxy({} as IOtions['meta'], {
|
|
32
38
|
get(_, p) {
|
|
@@ -45,3 +51,7 @@ export const adminPlugin = {
|
|
|
45
51
|
},
|
|
46
52
|
}),
|
|
47
53
|
};
|
|
54
|
+
|
|
55
|
+
export function injectTTAdmin() {
|
|
56
|
+
return inject<IOtions>(PROVIDE_KEY);
|
|
57
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import isNil from 'lodash-es/isNil';
|
|
3
3
|
import isFinite from 'lodash-es/isFinite';
|
|
4
4
|
import bignumber from 'bignumber.js';
|
|
5
|
-
import
|
|
5
|
+
import dayjs from '../../../../libs/dayjs';
|
|
6
6
|
|
|
7
7
|
export const paramTypes = { numberRange, datetimeRange, options };
|
|
8
8
|
|
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|
|
3
3
|
import type { VNode } from 'vue';
|
|
4
4
|
import { Breadcrumb as ABreadcrumb } from 'ant-design-vue';
|
|
5
5
|
import type { Route as AntdBreadcrumbRoute } from 'ant-design-vue/es/breadcrumb/Breadcrumb';
|
|
6
|
-
import {
|
|
6
|
+
import { injectTTAdmin } from '../../adminPlugin';
|
|
7
7
|
import type { IBreadcrumb } from '../../stores/createUsePageStore';
|
|
8
8
|
|
|
9
9
|
interface IBreadcrumbRoute extends AntdBreadcrumbRoute {
|
|
@@ -23,7 +23,7 @@ function _buildRoute(breadcrumb: IBreadcrumb): IBreadcrumbRoute {
|
|
|
23
23
|
</script>
|
|
24
24
|
|
|
25
25
|
<script setup lang="ts">
|
|
26
|
-
const pageStore =
|
|
26
|
+
const pageStore = injectTTAdmin()!.deps.usePageStore();
|
|
27
27
|
const routes = computed(() => {
|
|
28
28
|
let breadcrumbs: IBreadcrumbRoute[] = [];
|
|
29
29
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { injectTTAdmin } from '../../adminPlugin';
|
|
3
3
|
|
|
4
|
-
const pageStore =
|
|
4
|
+
const pageStore = injectTTAdmin()!.deps.usePageStore();
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
7
|
<template>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { computed, ref, watch } from 'vue';
|
|
3
3
|
import { Menu as AMenu } from 'ant-design-vue';
|
|
4
4
|
import type { ItemType } from 'ant-design-vue';
|
|
5
|
-
import {
|
|
5
|
+
import { injectTTAdmin } from '../../adminPlugin';
|
|
6
6
|
import type { TMenu } from '../../stores/createUseMenuStore';
|
|
7
7
|
|
|
8
8
|
function formatMenu(menu: TMenu): ItemType {
|
|
@@ -21,7 +21,7 @@ function formatMenu(menu: TMenu): ItemType {
|
|
|
21
21
|
</script>
|
|
22
22
|
|
|
23
23
|
<script setup lang="ts">
|
|
24
|
-
const { router, useMenuStore } =
|
|
24
|
+
const { router, useMenuStore } = injectTTAdmin()!.deps;
|
|
25
25
|
const menuStore = useMenuStore();
|
|
26
26
|
const items = computed(() => menuStore.menus.map(formatMenu));
|
|
27
27
|
const openKeys = ref<string[]>([]);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { TabPane as ATabPane, Tabs as ATabs } from 'ant-design-vue';
|
|
3
|
-
import {
|
|
3
|
+
import { injectTTAdmin } from '../../adminPlugin';
|
|
4
4
|
|
|
5
|
-
const pageTabStore =
|
|
5
|
+
const pageTabStore = injectTTAdmin()!.deps.usePageTabStore();
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<template>
|
package/admin/styles/index.scss
CHANGED
|
@@ -2,26 +2,28 @@
|
|
|
2
2
|
@import './globalCover.scss';
|
|
3
3
|
|
|
4
4
|
@media (pointer: fine) {
|
|
5
|
-
* {
|
|
6
|
-
scrollbar-color: rgb(0 0 0 / 50%) transparent;
|
|
7
|
-
scrollbar-width: thin;
|
|
8
5
|
|
|
9
|
-
|
|
6
|
+
*::-webkit-scrollbar-thumb {
|
|
7
|
+
border-radius: 10px;
|
|
8
|
+
background-color: rgb(133 133 133 / 20%);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
12
|
+
background-color: rgb(133 133 133 / 60%);
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
*::-webkit-scrollbar {
|
|
13
16
|
width: 6px;
|
|
14
17
|
height: 6px;
|
|
15
18
|
background-color: transparent;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
background-color: rgb(133 133 133 / 60%);
|
|
21
|
+
/* 不支持`::-webkit-scrollbar-*`的浏览器 */
|
|
22
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
23
|
+
* {
|
|
24
|
+
scrollbar-color: rgb(0 0 0 / 50%) transparent;
|
|
25
|
+
scrollbar-width: thin;
|
|
26
|
+
}
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -30,10 +30,13 @@ export function useAntdModal<Comp extends Component>(
|
|
|
30
30
|
const compProps = reactive(_comp.props);
|
|
31
31
|
const compRef = useComponentRef(_comp.is);
|
|
32
32
|
const _modalProps: ModalProps = reactive({
|
|
33
|
-
...defaultModalProps,
|
|
33
|
+
...toRefs(defaultModalProps),
|
|
34
34
|
...isProxy(modalProps) ? toRefs(modalProps) : modalProps,
|
|
35
35
|
confirmLoading: toRef(() => (compRef as any)?.loading),
|
|
36
|
-
onOk: () =>
|
|
36
|
+
onOk: (e: MouseEvent) => {
|
|
37
|
+
(compRef as any)?.confirm?.(e);
|
|
38
|
+
defaultModalProps.onOk?.(e);
|
|
39
|
+
},
|
|
37
40
|
});
|
|
38
41
|
const modalSlotName = _comp.type === 'body' ? 'default' : 'modalRender';
|
|
39
42
|
|
package/libs/dayjs.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
|
|
3
|
+
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
4
|
+
import 'dayjs/locale/zh';
|
|
5
|
+
import 'dayjs/locale/en';
|
|
6
|
+
|
|
3
7
|
export { isDayjs, unix, locale, extend } from 'dayjs';
|
|
4
8
|
export type { Dayjs, PluginFunc, UnitType, UnitTypeLong, UnitTypeLongPlural, UnitTypeShort, QUnitType, ConfigType, ConfigTypeMap, OpUnitType, OptionType, ManipulateType } from 'dayjs';
|
|
5
9
|
export default dayjs;
|
|
10
|
+
|
|
11
|
+
dayjs.locale('zh');
|
|
12
|
+
dayjs.extend(relativeTime);
|
package/libs/echarts.ts
CHANGED
package/libs/vue-i18n.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { I18nOptions } from 'vue-i18n';
|
|
2
|
+
|
|
3
|
+
export * from 'vue-i18n';
|
|
4
|
+
|
|
5
|
+
export type TDatetimeStyles = Record<
|
|
6
|
+
'date' | 'time' | 'full' | 'mdhms' | 'mdhm',
|
|
7
|
+
NonNullable<I18nOptions['datetimeFormats']>[string][string]
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
export const presetDatetimeStyles: TDatetimeStyles = {
|
|
11
|
+
/** 年/月/日 */
|
|
12
|
+
date: { year: 'numeric', month: '2-digit', day: '2-digit' },
|
|
13
|
+
/** 时:分:秒 */
|
|
14
|
+
time: { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false },
|
|
15
|
+
/** 年/月/日 时:分:秒 */
|
|
16
|
+
full: { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false },
|
|
17
|
+
/** 月/日 时:分:秒 */
|
|
18
|
+
mdhms: { month: '2-digit', day: '2-digit', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: false },
|
|
19
|
+
/** 月/日 时:分 */
|
|
20
|
+
mdhm: { month: '2-digit', day: '2-digit', hour: 'numeric', minute: 'numeric', hour12: false },
|
|
21
|
+
};
|
package/package.json
CHANGED
|
@@ -1,91 +1,92 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@peng_kai/kit",
|
|
3
|
-
"type": "module",
|
|
4
|
-
"version": "0.2.0-beta.
|
|
5
|
-
"description": "",
|
|
6
|
-
"author": "",
|
|
7
|
-
"license": "ISC",
|
|
8
|
-
"keywords": [],
|
|
9
|
-
"main": "index.js",
|
|
10
|
-
"scripts": {
|
|
11
|
-
"dev:js": "tsx ./admin/scripts/deploy.ts",
|
|
12
|
-
"lint": "eslint .",
|
|
13
|
-
"lint:fix": "eslint . --fix"
|
|
14
|
-
},
|
|
15
|
-
"peerDependencies": {
|
|
16
|
-
"ant-design-vue": "4.1.2",
|
|
17
|
-
"vue": "3.4.19",
|
|
18
|
-
"vue-router": "4.2.5"
|
|
19
|
-
},
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"@aws-sdk/client-s3": "^3.515.0",
|
|
22
|
-
"@aws-sdk/lib-storage": "^3.515.0",
|
|
23
|
-
"@babel/generator": "^7.23.6",
|
|
24
|
-
"@babel/parser": "^7.23.9",
|
|
25
|
-
"@babel/traverse": "^7.23.9",
|
|
26
|
-
"@babel/types": "^7.23.9",
|
|
27
|
-
"@ckeditor/ckeditor5-adapter-ckfinder": "^41.1.0",
|
|
28
|
-
"@ckeditor/ckeditor5-alignment": "^41.1.0",
|
|
29
|
-
"@ckeditor/ckeditor5-autoformat": "^41.1.0",
|
|
30
|
-
"@ckeditor/ckeditor5-basic-styles": "^41.1.0",
|
|
31
|
-
"@ckeditor/ckeditor5-block-quote": "^41.1.0",
|
|
32
|
-
"@ckeditor/ckeditor5-build-classic": "^41.1.0",
|
|
33
|
-
"@ckeditor/ckeditor5-code-block": "^41.1.0",
|
|
34
|
-
"@ckeditor/ckeditor5-document-outline": "^41.1.0",
|
|
35
|
-
"@ckeditor/ckeditor5-editor-classic": "^41.1.0",
|
|
36
|
-
"@ckeditor/ckeditor5-essentials": "^41.1.0",
|
|
37
|
-
"@ckeditor/ckeditor5-font": "^41.1.0",
|
|
38
|
-
"@ckeditor/ckeditor5-heading": "^41.1.0",
|
|
39
|
-
"@ckeditor/ckeditor5-highlight": "^41.1.0",
|
|
40
|
-
"@ckeditor/ckeditor5-horizontal-line": "^41.1.0",
|
|
41
|
-
"@ckeditor/ckeditor5-html-embed": "^41.1.0",
|
|
42
|
-
"@ckeditor/ckeditor5-html-support": "^41.1.0",
|
|
43
|
-
"@ckeditor/ckeditor5-image": "^41.1.0",
|
|
44
|
-
"@ckeditor/ckeditor5-import-word": "^41.1.0",
|
|
45
|
-
"@ckeditor/ckeditor5-indent": "^41.1.0",
|
|
46
|
-
"@ckeditor/ckeditor5-link": "^41.1.0",
|
|
47
|
-
"@ckeditor/ckeditor5-list": "^41.1.0",
|
|
48
|
-
"@ckeditor/ckeditor5-media-embed": "^41.1.0",
|
|
49
|
-
"@ckeditor/ckeditor5-paragraph": "^41.1.0",
|
|
50
|
-
"@ckeditor/ckeditor5-remove-format": "^41.1.0",
|
|
51
|
-
"@ckeditor/ckeditor5-show-blocks": "^41.1.0",
|
|
52
|
-
"@ckeditor/ckeditor5-source-editing": "^41.1.0",
|
|
53
|
-
"@ckeditor/ckeditor5-table": "^41.1.0",
|
|
54
|
-
"@ckeditor/ckeditor5-theme-lark": "^41.1.0",
|
|
55
|
-
"@ckeditor/ckeditor5-typing": "^41.1.0",
|
|
56
|
-
"@ckeditor/ckeditor5-upload": "^41.1.0",
|
|
57
|
-
"@ckeditor/ckeditor5-vue": "^5.1.0",
|
|
58
|
-
"@ckeditor/ckeditor5-word-count": "^41.1.0",
|
|
59
|
-
"@tanstack/vue-query": "^5.21.4",
|
|
60
|
-
"@vueuse/components": "^10.7.2",
|
|
61
|
-
"@vueuse/core": "^10.7.2",
|
|
62
|
-
"@vueuse/router": "^10.7.2",
|
|
63
|
-
"a-calc": "^1.3.8",
|
|
64
|
-
"ant-design-vue": "^4.1.2",
|
|
65
|
-
"archiver": "^6.0.1",
|
|
66
|
-
"axios": "^1.6.7",
|
|
67
|
-
"bignumber.js": "^9.1.2",
|
|
68
|
-
"chokidar": "^3.6.0",
|
|
69
|
-
"dayjs": "^1.11.10",
|
|
70
|
-
"echarts": "^5.4.3",
|
|
71
|
-
"execa": "^8.0.1",
|
|
72
|
-
"fast-glob": "^3.3.2",
|
|
73
|
-
"localstorage-slim": "^2.7.0",
|
|
74
|
-
"lodash-es": "^4.17.21",
|
|
75
|
-
"nprogress": "^0.2.0",
|
|
76
|
-
"pinia": "^2.1.7",
|
|
77
|
-
"tsx": "^4.7.1",
|
|
78
|
-
"vue": "^3.4.19",
|
|
79
|
-
"vue-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"@
|
|
84
|
-
"@types/
|
|
85
|
-
"@types/
|
|
86
|
-
"@types/
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
|
|
91
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@peng_kai/kit",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.2.0-beta.21",
|
|
5
|
+
"description": "",
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"keywords": [],
|
|
9
|
+
"main": "index.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev:js": "tsx ./admin/scripts/deploy.ts",
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"lint:fix": "eslint . --fix"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"ant-design-vue": "4.1.2",
|
|
17
|
+
"vue": "3.4.19",
|
|
18
|
+
"vue-router": "4.2.5"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@aws-sdk/client-s3": "^3.515.0",
|
|
22
|
+
"@aws-sdk/lib-storage": "^3.515.0",
|
|
23
|
+
"@babel/generator": "^7.23.6",
|
|
24
|
+
"@babel/parser": "^7.23.9",
|
|
25
|
+
"@babel/traverse": "^7.23.9",
|
|
26
|
+
"@babel/types": "^7.23.9",
|
|
27
|
+
"@ckeditor/ckeditor5-adapter-ckfinder": "^41.1.0",
|
|
28
|
+
"@ckeditor/ckeditor5-alignment": "^41.1.0",
|
|
29
|
+
"@ckeditor/ckeditor5-autoformat": "^41.1.0",
|
|
30
|
+
"@ckeditor/ckeditor5-basic-styles": "^41.1.0",
|
|
31
|
+
"@ckeditor/ckeditor5-block-quote": "^41.1.0",
|
|
32
|
+
"@ckeditor/ckeditor5-build-classic": "^41.1.0",
|
|
33
|
+
"@ckeditor/ckeditor5-code-block": "^41.1.0",
|
|
34
|
+
"@ckeditor/ckeditor5-document-outline": "^41.1.0",
|
|
35
|
+
"@ckeditor/ckeditor5-editor-classic": "^41.1.0",
|
|
36
|
+
"@ckeditor/ckeditor5-essentials": "^41.1.0",
|
|
37
|
+
"@ckeditor/ckeditor5-font": "^41.1.0",
|
|
38
|
+
"@ckeditor/ckeditor5-heading": "^41.1.0",
|
|
39
|
+
"@ckeditor/ckeditor5-highlight": "^41.1.0",
|
|
40
|
+
"@ckeditor/ckeditor5-horizontal-line": "^41.1.0",
|
|
41
|
+
"@ckeditor/ckeditor5-html-embed": "^41.1.0",
|
|
42
|
+
"@ckeditor/ckeditor5-html-support": "^41.1.0",
|
|
43
|
+
"@ckeditor/ckeditor5-image": "^41.1.0",
|
|
44
|
+
"@ckeditor/ckeditor5-import-word": "^41.1.0",
|
|
45
|
+
"@ckeditor/ckeditor5-indent": "^41.1.0",
|
|
46
|
+
"@ckeditor/ckeditor5-link": "^41.1.0",
|
|
47
|
+
"@ckeditor/ckeditor5-list": "^41.1.0",
|
|
48
|
+
"@ckeditor/ckeditor5-media-embed": "^41.1.0",
|
|
49
|
+
"@ckeditor/ckeditor5-paragraph": "^41.1.0",
|
|
50
|
+
"@ckeditor/ckeditor5-remove-format": "^41.1.0",
|
|
51
|
+
"@ckeditor/ckeditor5-show-blocks": "^41.1.0",
|
|
52
|
+
"@ckeditor/ckeditor5-source-editing": "^41.1.0",
|
|
53
|
+
"@ckeditor/ckeditor5-table": "^41.1.0",
|
|
54
|
+
"@ckeditor/ckeditor5-theme-lark": "^41.1.0",
|
|
55
|
+
"@ckeditor/ckeditor5-typing": "^41.1.0",
|
|
56
|
+
"@ckeditor/ckeditor5-upload": "^41.1.0",
|
|
57
|
+
"@ckeditor/ckeditor5-vue": "^5.1.0",
|
|
58
|
+
"@ckeditor/ckeditor5-word-count": "^41.1.0",
|
|
59
|
+
"@tanstack/vue-query": "^5.21.4",
|
|
60
|
+
"@vueuse/components": "^10.7.2",
|
|
61
|
+
"@vueuse/core": "^10.7.2",
|
|
62
|
+
"@vueuse/router": "^10.7.2",
|
|
63
|
+
"a-calc": "^1.3.8",
|
|
64
|
+
"ant-design-vue": "^4.1.2",
|
|
65
|
+
"archiver": "^6.0.1",
|
|
66
|
+
"axios": "^1.6.7",
|
|
67
|
+
"bignumber.js": "^9.1.2",
|
|
68
|
+
"chokidar": "^3.6.0",
|
|
69
|
+
"dayjs": "^1.11.10",
|
|
70
|
+
"echarts": "^5.4.3",
|
|
71
|
+
"execa": "^8.0.1",
|
|
72
|
+
"fast-glob": "^3.3.2",
|
|
73
|
+
"localstorage-slim": "^2.7.0",
|
|
74
|
+
"lodash-es": "^4.17.21",
|
|
75
|
+
"nprogress": "^0.2.0",
|
|
76
|
+
"pinia": "^2.1.7",
|
|
77
|
+
"tsx": "^4.7.1",
|
|
78
|
+
"vue": "^3.4.19",
|
|
79
|
+
"vue-i18n": "^9.9.1",
|
|
80
|
+
"vue-router": "^4.2.5"
|
|
81
|
+
},
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"@peng_kai/lint": "^0.1.0",
|
|
84
|
+
"@types/archiver": "^6.0.2",
|
|
85
|
+
"@types/lodash-es": "^4.17.12",
|
|
86
|
+
"@types/node": "18.19.15",
|
|
87
|
+
"@types/nprogress": "^0.2.3",
|
|
88
|
+
"type-fest": "^4.10.2",
|
|
89
|
+
"typescript": "^5.3.3",
|
|
90
|
+
"vue-component-type-helpers": "^1.8.27"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { mapKeys } from 'lodash-es';
|
|
2
|
+
|
|
3
|
+
interface ILocaleMeta {
|
|
4
|
+
label: string
|
|
5
|
+
codes: string[]
|
|
6
|
+
icon?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ILoaders {
|
|
10
|
+
meta: Record<string, ILocaleMeta>
|
|
11
|
+
message: Record<string, () => Promise<Record<string, string>>>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const metaPathRE = /\/([-\w]*)\/(meta)\.ts$/;
|
|
15
|
+
const messagePathRE = /\/([-\w]*)\/(index)\.ts$/;
|
|
16
|
+
|
|
17
|
+
export class LocaleManager {
|
|
18
|
+
public localesLoaded: string[] = [];
|
|
19
|
+
|
|
20
|
+
private metaLoaders: ILoaders['meta'];
|
|
21
|
+
private messageLoaders: ILoaders['message'];
|
|
22
|
+
private localeStorageKey = 'LOCALE';
|
|
23
|
+
private _locale = '';
|
|
24
|
+
|
|
25
|
+
public constructor(loaders: ILoaders) {
|
|
26
|
+
this.metaLoaders = mapKeys(loaders.meta, (_, path) => path.match(metaPathRE)?.[1] ?? path);
|
|
27
|
+
this.messageLoaders = mapKeys(loaders.message, (_, path) => path.match(messagePathRE)?.[1] ?? path);
|
|
28
|
+
this._locale = this.defaultLocale;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 当前区域 */
|
|
32
|
+
public get locale() {
|
|
33
|
+
return this._locale;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 当前区域 */
|
|
37
|
+
public set locale(value: string) {
|
|
38
|
+
if (this.localesAvailable.includes(value)) {
|
|
39
|
+
document.documentElement.lang = value;
|
|
40
|
+
this.setStorageLocale(value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 可用的区域列表 */
|
|
45
|
+
public get localesAvailable() {
|
|
46
|
+
return Object.keys(this.metaLoaders);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 所有区域元数据 */
|
|
50
|
+
public get localeMetas() {
|
|
51
|
+
return this.metaLoaders;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** 获取默认区域 */
|
|
55
|
+
public get defaultLocale() {
|
|
56
|
+
const searchParams = new URLSearchParams(location.search);
|
|
57
|
+
// 获取区域的优先级
|
|
58
|
+
const localeTargets = [searchParams.get('locale'), searchParams.get('lang'), this.getStorageLocale(), navigator.language]
|
|
59
|
+
.filter(locale => !!locale)
|
|
60
|
+
.map(locale => locale!.replace('_', '-'));
|
|
61
|
+
const codeMatrix = this.localesAvailable.map(locale => [locale, ...this.localeMetas[locale].codes]);
|
|
62
|
+
let localeFinal = '';
|
|
63
|
+
|
|
64
|
+
for (const target of localeTargets) {
|
|
65
|
+
for (const codes of codeMatrix) {
|
|
66
|
+
const matched = codes.some(code => code.toUpperCase().startsWith(target.toUpperCase()));
|
|
67
|
+
|
|
68
|
+
if (matched) {
|
|
69
|
+
localeFinal = codes[0];
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (localeFinal)
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
localeFinal = localeFinal || 'en-US';
|
|
79
|
+
this.clearUrlLocale();
|
|
80
|
+
|
|
81
|
+
return localeFinal;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 加载区域消息
|
|
86
|
+
* @param locale 区域
|
|
87
|
+
* @returns 返回加载的消息,如果加载失败则返回 undefined
|
|
88
|
+
*/
|
|
89
|
+
public async loadLocaleMessage(locale: string) {
|
|
90
|
+
if (!this.localesAvailable.includes(locale))
|
|
91
|
+
return;
|
|
92
|
+
|
|
93
|
+
const message = await this.messageLoaders[locale]?.().catch(() => undefined);
|
|
94
|
+
|
|
95
|
+
if (message)
|
|
96
|
+
this.localesLoaded.push(locale);
|
|
97
|
+
|
|
98
|
+
return message;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 定义区域元数据
|
|
103
|
+
* @param meta 区域元数据对象
|
|
104
|
+
* @returns 区域元数据对象
|
|
105
|
+
*/
|
|
106
|
+
public static defineMeta(meta: ILocaleMeta) {
|
|
107
|
+
return meta;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private clearUrlLocale() {
|
|
111
|
+
const url = new URL(location.href);
|
|
112
|
+
url.searchParams.delete('locale');
|
|
113
|
+
url.searchParams.delete('lang');
|
|
114
|
+
|
|
115
|
+
history.replaceState(null, '', url.toString());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private getStorageLocale() {
|
|
119
|
+
return localStorage.getItem(this.localeStorageKey);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private setStorageLocale(locale: string) {
|
|
123
|
+
return localStorage.setItem(this.localeStorageKey, locale);
|
|
124
|
+
}
|
|
125
|
+
}
|
package/utils/date.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import dayjs from 'dayjs';
|
|
2
|
-
import relativeTime from 'dayjs/plugin/relativeTime.js';
|
|
3
|
-
import 'dayjs/locale/zh';
|
|
4
|
-
import 'dayjs/locale/en';
|
|
5
|
-
|
|
6
|
-
export { default as dayjs } from 'dayjs';
|
|
7
|
-
|
|
8
|
-
dayjs.locale('zh');
|
|
9
|
-
dayjs.extend(relativeTime);
|
|
1
|
+
import dayjs from '../libs/dayjs';
|
|
10
2
|
|
|
11
3
|
/**
|
|
12
4
|
* 返回给定日期的一天的开始时间。
|