@peng_kai/kit 0.2.0-beta.27 → 0.2.0-beta.29
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/components/rich-text/index.ts +1 -1
- package/admin/components/rich-text/src/RichText.new.vue +164 -0
- package/admin/components/rich-text/src/RichText.vue +3 -6
- package/admin/components/rich-text/src/editorConfig.ts +126 -0
- package/admin/components/rich-text/src/imageUploader.ts +20 -18
- package/admin/components/scroll-nav/src/ScrollNav.vue +1 -1
- package/admin/components/settings/src/Settings.vue +5 -1
- package/admin/defines/route/defineRoute.ts +2 -4
- package/admin/defines/route/getRoutes.ts +4 -4
- package/admin/defines/route-guard/defineRouteGuard.ts +1 -4
- package/admin/defines/route-guard/getRouteGuards.ts +5 -7
- package/admin/defines/startup/defineStartup.ts +1 -3
- package/admin/defines/startup/runStartup.ts +4 -6
- package/admin/permission/routerGuard.ts +1 -1
- package/admin/styles/classCover.scss +90 -0
- package/package.json +32 -32
- package/request/interceptors/returnResultType.ts +3 -3
- package/request/interceptors/toLogin.ts +27 -10
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as RichText } from './src/RichText.vue';
|
|
1
|
+
export { default as RichText } from './src/RichText.new.vue';
|
|
2
2
|
export { createImageUploaderForAws3 } from './src/imageUploader';
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useIntervalFn } from '@vueuse/core';
|
|
3
|
+
import CKEditor from '@ckeditor/ckeditor5-vue';
|
|
4
|
+
import { shallowRef } from 'vue';
|
|
5
|
+
import { useInjectDisabled } from 'ant-design-vue/es/config-provider/DisabledContext';
|
|
6
|
+
import { defaultConfig } from './editorConfig';
|
|
7
|
+
import 'https://cdn.ckeditor.com/ckeditor5/41.1.0/super-build/ckeditor.js';
|
|
8
|
+
import 'https://cdn.ckeditor.com/ckeditor5/41.1.0/super-build/translations/zh-cn.js';
|
|
9
|
+
|
|
10
|
+
function useClassicEditor() {
|
|
11
|
+
const ClassicEditor = shallowRef();
|
|
12
|
+
|
|
13
|
+
const { pause } = useIntervalFn(() => {
|
|
14
|
+
ClassicEditor.value = (window as any).CKEDITOR?.ClassicEditor;
|
|
15
|
+
ClassicEditor.value && pause();
|
|
16
|
+
}, 500);
|
|
17
|
+
|
|
18
|
+
return ClassicEditor;
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
const props = defineProps(['modelValue', 'disabled', 'plugins']);
|
|
24
|
+
const emits = defineEmits<{
|
|
25
|
+
(e: 'update:modelValue', value: string): void
|
|
26
|
+
}>();
|
|
27
|
+
|
|
28
|
+
const ClassicEditor = useClassicEditor();
|
|
29
|
+
const disabled = useInjectDisabled();
|
|
30
|
+
const editorConfig = { ...defaultConfig };
|
|
31
|
+
editorConfig.extraPlugins = props.plugins;
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div class="editor-wrapper">
|
|
36
|
+
<CKEditor.component
|
|
37
|
+
v-if="ClassicEditor"
|
|
38
|
+
:modelValue="props.modelValue"
|
|
39
|
+
:editor="ClassicEditor"
|
|
40
|
+
:config="editorConfig"
|
|
41
|
+
:disabled="props.disabled ?? disabled"
|
|
42
|
+
@update:modelValue="v => emits('update:modelValue', v)"
|
|
43
|
+
/>
|
|
44
|
+
<div v-else class="flex justify-center">
|
|
45
|
+
<i class="i-svg-spinners:180-ring-with-bg block text-5 text-$loading-color" />
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<style scoped lang="scss">
|
|
51
|
+
.editor-wrapper {
|
|
52
|
+
--loading-color: var(--antd-colorPrimary);
|
|
53
|
+
|
|
54
|
+
:deep(.ck-editor__main > .ck-content) {
|
|
55
|
+
height: 500px;
|
|
56
|
+
overflow: auto;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:root.dark .editor-wrapper {
|
|
61
|
+
/* Overrides the border radius setting in the theme. */
|
|
62
|
+
// --ck-border-radius: 4px;
|
|
63
|
+
|
|
64
|
+
/* Overrides the default font size in the theme. */
|
|
65
|
+
// --ck-font-size-base: 14px;
|
|
66
|
+
|
|
67
|
+
/* Helper variables to avoid duplication in the colors. */
|
|
68
|
+
--ck-custom-background: hsl(270deg 1% 29%);
|
|
69
|
+
--ck-custom-foreground: hsl(255deg 3% 18%);
|
|
70
|
+
--ck-custom-border: hsl(300deg 1% 22%);
|
|
71
|
+
--ck-custom-white: hsl(0deg 0% 100%);
|
|
72
|
+
|
|
73
|
+
/* -- Overrides generic colors. ------------------------------------------------------------- */
|
|
74
|
+
|
|
75
|
+
--ck-color-base-foreground: var(--ck-custom-background);
|
|
76
|
+
--ck-color-focus-border: hsl(208deg 90% 62%);
|
|
77
|
+
--ck-color-text: hsl(0deg 0% 98%);
|
|
78
|
+
--ck-color-shadow-drop: hsl(0deg 0% 0% / 20%);
|
|
79
|
+
--ck-color-shadow-inner: hsl(0deg 0% 0% / 10%);
|
|
80
|
+
|
|
81
|
+
/* -- Overrides the default .ck-button class colors. ---------------------------------------- */
|
|
82
|
+
|
|
83
|
+
--ck-color-button-default-background: var(--ck-custom-background);
|
|
84
|
+
--ck-color-button-default-hover-background: hsl(270deg 1% 22%);
|
|
85
|
+
--ck-color-button-default-active-background: hsl(270deg 2% 20%);
|
|
86
|
+
--ck-color-button-default-active-shadow: hsl(270deg 2% 23%);
|
|
87
|
+
--ck-color-button-default-disabled-background: var(--ck-custom-background);
|
|
88
|
+
--ck-color-button-on-background: var(--ck-custom-foreground);
|
|
89
|
+
--ck-color-button-on-hover-background: hsl(255deg 4% 16%);
|
|
90
|
+
--ck-color-button-on-active-background: hsl(255deg 4% 14%);
|
|
91
|
+
--ck-color-button-on-active-shadow: hsl(240deg 3% 19%);
|
|
92
|
+
--ck-color-button-on-disabled-background: var(--ck-custom-foreground);
|
|
93
|
+
--ck-color-button-action-background: hsl(168deg 76% 42%);
|
|
94
|
+
--ck-color-button-action-hover-background: hsl(168deg 76% 38%);
|
|
95
|
+
--ck-color-button-action-active-background: hsl(168deg 76% 36%);
|
|
96
|
+
--ck-color-button-action-active-shadow: hsl(168deg 75% 34%);
|
|
97
|
+
--ck-color-button-action-disabled-background: hsl(168deg 76% 42%);
|
|
98
|
+
--ck-color-button-action-text: var(--ck-custom-white);
|
|
99
|
+
--ck-color-button-save: hsl(120deg 100% 46%);
|
|
100
|
+
--ck-color-button-cancel: hsl(15deg 100% 56%);
|
|
101
|
+
|
|
102
|
+
/* -- Overrides the default .ck-dropdown class colors. -------------------------------------- */
|
|
103
|
+
|
|
104
|
+
--ck-color-dropdown-panel-background: var(--ck-custom-background);
|
|
105
|
+
--ck-color-dropdown-panel-border: var(--ck-custom-foreground);
|
|
106
|
+
|
|
107
|
+
/* -- Overrides the default .ck-splitbutton class colors. ----------------------------------- */
|
|
108
|
+
|
|
109
|
+
--ck-color-split-button-hover-background: var(--ck-color-button-default-hover-background);
|
|
110
|
+
--ck-color-split-button-hover-border: var(--ck-custom-foreground);
|
|
111
|
+
|
|
112
|
+
/* -- Overrides the default .ck-input class colors. ----------------------------------------- */
|
|
113
|
+
|
|
114
|
+
--ck-color-input-background: var(--ck-custom-background);
|
|
115
|
+
--ck-color-input-border: hsl(257deg 3% 43%);
|
|
116
|
+
--ck-color-input-text: hsl(0deg 0% 98%);
|
|
117
|
+
--ck-color-input-disabled-background: hsl(255deg 4% 21%);
|
|
118
|
+
--ck-color-input-disabled-border: hsl(250deg 3% 38%);
|
|
119
|
+
--ck-color-input-disabled-text: hsl(0deg 0% 78%);
|
|
120
|
+
|
|
121
|
+
/* -- Overrides the default .ck-labeled-field-view class colors. ---------------------------- */
|
|
122
|
+
|
|
123
|
+
--ck-color-labeled-field-label-background: var(--ck-custom-background);
|
|
124
|
+
|
|
125
|
+
/* -- Overrides the default .ck-list class colors. ------------------------------------------ */
|
|
126
|
+
|
|
127
|
+
--ck-color-list-background: var(--ck-custom-background);
|
|
128
|
+
--ck-color-list-button-hover-background: var(--ck-custom-foreground);
|
|
129
|
+
--ck-color-list-button-on-background: hsl(208deg 88% 52%);
|
|
130
|
+
--ck-color-list-button-on-text: var(--ck-custom-white);
|
|
131
|
+
|
|
132
|
+
/* -- Overrides the default .ck-balloon-panel class colors. --------------------------------- */
|
|
133
|
+
|
|
134
|
+
--ck-color-panel-background: var(--ck-custom-background);
|
|
135
|
+
--ck-color-panel-border: var(--ck-custom-border);
|
|
136
|
+
|
|
137
|
+
/* -- Overrides the default .ck-toolbar class colors. --------------------------------------- */
|
|
138
|
+
|
|
139
|
+
--ck-color-toolbar-background: var(--ck-custom-background);
|
|
140
|
+
--ck-color-toolbar-border: var(--ck-custom-border);
|
|
141
|
+
|
|
142
|
+
/* -- Overrides the default .ck-tooltip class colors. --------------------------------------- */
|
|
143
|
+
|
|
144
|
+
--ck-color-tooltip-background: hsl(252deg 7% 14%);
|
|
145
|
+
--ck-color-tooltip-text: hsl(0deg 0% 93%);
|
|
146
|
+
|
|
147
|
+
/* -- Overrides the default colors used by the ckeditor5-image package. --------------------- */
|
|
148
|
+
|
|
149
|
+
--ck-color-image-caption-background: hsl(0deg 0% 97%);
|
|
150
|
+
--ck-color-image-caption-text: hsl(0deg 0% 20%);
|
|
151
|
+
|
|
152
|
+
/* -- Overrides the default colors used by the ckeditor5-widget package. -------------------- */
|
|
153
|
+
|
|
154
|
+
--ck-color-widget-blurred-border: hsl(0deg 0% 87%);
|
|
155
|
+
--ck-color-widget-hover-border: hsl(43deg 100% 68%);
|
|
156
|
+
--ck-color-widget-editable-focus-background: var(--ck-custom-white);
|
|
157
|
+
|
|
158
|
+
/* -- Overrides the default colors used by the ckeditor5-link package. ---------------------- */
|
|
159
|
+
|
|
160
|
+
--ck-color-link-default: hsl(190deg 100% 75%);
|
|
161
|
+
--ck-color-base-background: #141414;
|
|
162
|
+
--ck-color-base-border: #424242;
|
|
163
|
+
}
|
|
164
|
+
</style>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { defineModel, defineProps, withDefaults } from 'vue';
|
|
3
3
|
import CKEditor from '@ckeditor/ckeditor5-vue';
|
|
4
4
|
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
|
|
5
5
|
import { Alignment } from '@ckeditor/ckeditor5-alignment';
|
|
@@ -212,18 +212,15 @@ const props = withDefaults(defineProps<{
|
|
|
212
212
|
modelValue: '',
|
|
213
213
|
plugins: () => [],
|
|
214
214
|
});
|
|
215
|
-
const emits = defineEmits<{
|
|
216
|
-
(e: 'update:modelValue', value: string): void
|
|
217
|
-
}>();
|
|
218
215
|
|
|
219
|
-
const
|
|
216
|
+
const modelValue = defineModel({ default: '' });
|
|
220
217
|
const localeEditorConfig = { ...editorConfig };
|
|
221
218
|
localeEditorConfig.extraPlugins = [...props.plugins];
|
|
222
219
|
</script>
|
|
223
220
|
|
|
224
221
|
<template>
|
|
225
222
|
<div class="editor-wrapper">
|
|
226
|
-
<CKEditor.component v-model="
|
|
223
|
+
<CKEditor.component v-model="modelValue" :editor="ClassicEditor" :config="localeEditorConfig" />
|
|
227
224
|
</div>
|
|
228
225
|
</template>
|
|
229
226
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export const defaultConfig: Record<string, any> = {
|
|
2
|
+
language: {
|
|
3
|
+
ui: 'zh-cn',
|
|
4
|
+
},
|
|
5
|
+
removePlugins: ['ImportWord', 'ExportWord', 'RevisionHistory', 'RealTimeCollaborativeEditing', 'RealTimeCollaborativeComments', 'RealTimeCollaborativeRevisionHistory', 'RealTimeCollaborativeTrackChanges', 'PresenceList', 'WProofreader', 'DocumentOutline', 'Comments', 'TrackChanges', 'TrackChangesData', 'TableOfContents', 'SlashCommand', 'PasteFromOfficeEnhanced', 'ContentTemplates', 'FormatPainter', 'Mentions', 'PageBreak', 'Pagination', 'AIAssistant', 'CaseChange', 'Template'],
|
|
6
|
+
toolbar: {
|
|
7
|
+
items: [
|
|
8
|
+
'undo',
|
|
9
|
+
'redo',
|
|
10
|
+
'|',
|
|
11
|
+
'showBlocks',
|
|
12
|
+
'selectAll',
|
|
13
|
+
'|',
|
|
14
|
+
'heading',
|
|
15
|
+
'|',
|
|
16
|
+
'fontSize',
|
|
17
|
+
'fontFamily',
|
|
18
|
+
'fontColor',
|
|
19
|
+
'fontBackgroundColor',
|
|
20
|
+
'|',
|
|
21
|
+
'bold',
|
|
22
|
+
'italic',
|
|
23
|
+
'underline',
|
|
24
|
+
{
|
|
25
|
+
label: 'Formatting',
|
|
26
|
+
icon: 'text',
|
|
27
|
+
items: ['strikethrough', 'subscript', 'superscript', 'code', 'horizontalLine', '|', 'removeFormat'],
|
|
28
|
+
},
|
|
29
|
+
'|',
|
|
30
|
+
'link',
|
|
31
|
+
'uploadImage',
|
|
32
|
+
'insertTable',
|
|
33
|
+
{
|
|
34
|
+
label: 'Insert',
|
|
35
|
+
icon: 'plus',
|
|
36
|
+
items: ['highlight', 'blockQuote', 'mediaEmbed', 'codeBlock', 'htmlEmbed'],
|
|
37
|
+
},
|
|
38
|
+
'|',
|
|
39
|
+
'alignment',
|
|
40
|
+
'|',
|
|
41
|
+
'bulletedList',
|
|
42
|
+
'numberedList',
|
|
43
|
+
'todoList',
|
|
44
|
+
'outdent',
|
|
45
|
+
'indent',
|
|
46
|
+
'|',
|
|
47
|
+
'sourceEditing',
|
|
48
|
+
],
|
|
49
|
+
shouldNotGroupWhenFull: true,
|
|
50
|
+
},
|
|
51
|
+
htmlSupport: {
|
|
52
|
+
allow: [
|
|
53
|
+
{
|
|
54
|
+
name: /^.*$/,
|
|
55
|
+
styles: true,
|
|
56
|
+
attributes: true,
|
|
57
|
+
classes: true,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
fontSize: {
|
|
62
|
+
options: [10, 12, 14, 'default', 18, 20, 22],
|
|
63
|
+
supportAllValues: true,
|
|
64
|
+
},
|
|
65
|
+
image: {
|
|
66
|
+
styles: [
|
|
67
|
+
'alignCenter',
|
|
68
|
+
'alignLeft',
|
|
69
|
+
'alignRight',
|
|
70
|
+
],
|
|
71
|
+
resizeOptions: [
|
|
72
|
+
{ name: 'resizeImage:original', label: 'Original', value: null },
|
|
73
|
+
{ name: 'resizeImage:25', label: '25%', value: '25' },
|
|
74
|
+
{ name: 'resizeImage:50', label: '50%', value: '50' },
|
|
75
|
+
{ name: 'resizeImage:75', label: '75%', value: '75' },
|
|
76
|
+
],
|
|
77
|
+
toolbar: [
|
|
78
|
+
'imageTextAlternative',
|
|
79
|
+
'toggleImageCaption',
|
|
80
|
+
'|',
|
|
81
|
+
'imageStyle:inline',
|
|
82
|
+
'imageStyle:wrapText',
|
|
83
|
+
'imageStyle:breakText',
|
|
84
|
+
'imageStyle:side',
|
|
85
|
+
'|',
|
|
86
|
+
'resizeImage',
|
|
87
|
+
],
|
|
88
|
+
resizeUnit: 'px',
|
|
89
|
+
},
|
|
90
|
+
list: {
|
|
91
|
+
properties: {
|
|
92
|
+
styles: true,
|
|
93
|
+
startIndex: true,
|
|
94
|
+
reversed: true,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
link: {
|
|
98
|
+
addTargetToExternalLinks: true,
|
|
99
|
+
defaultProtocol: 'https://',
|
|
100
|
+
decorators: {
|
|
101
|
+
toggleDownloadable: {
|
|
102
|
+
mode: 'manual',
|
|
103
|
+
label: 'Downloadable',
|
|
104
|
+
attributes: {
|
|
105
|
+
download: 'file',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
table: {
|
|
111
|
+
contentToolbar: [
|
|
112
|
+
'tableColumn',
|
|
113
|
+
'tableRow',
|
|
114
|
+
'mergeTableCells',
|
|
115
|
+
'tableProperties',
|
|
116
|
+
'tableCellProperties',
|
|
117
|
+
'toggleTableCaption',
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
htmlEmbed: {
|
|
121
|
+
showPreviews: true,
|
|
122
|
+
},
|
|
123
|
+
wordCount: {
|
|
124
|
+
displayWords: true,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
@@ -5,30 +5,32 @@ export { createImageUploaderForAws3 };
|
|
|
5
5
|
|
|
6
6
|
function createImageUploaderForAws3(awsS3: AwsS3, rootDir?: string): PluginConstructor {
|
|
7
7
|
return function (editor) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
setTimeout(() => {
|
|
9
|
+
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
|
|
10
|
+
return {
|
|
11
|
+
async upload() {
|
|
12
|
+
const file = await loader.file;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
if (file) {
|
|
15
|
+
const { uploader, fileURL } = await awsS3.upload(file, rootDir);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
uploader.on('httpUploadProgress', (progress) => {
|
|
18
|
+
loader.uploadTotal = progress.total ?? null;
|
|
19
|
+
loader.uploaded = progress.loaded ?? 0;
|
|
20
|
+
});
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
await uploader.done();
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
return { default: fileURL };
|
|
25
|
+
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
return {};
|
|
28
|
+
},
|
|
29
|
+
abort() {
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
},
|
|
32
|
+
};
|
|
31
33
|
};
|
|
32
|
-
};
|
|
34
|
+
});
|
|
33
35
|
};
|
|
34
36
|
}
|
|
@@ -10,7 +10,7 @@ const $content = document.querySelector(props.selector) as HTMLElement;
|
|
|
10
10
|
const $contentParent = $content.parentElement;
|
|
11
11
|
const { height: contentParentH } = useElementSize($contentParent);
|
|
12
12
|
const { height: contentH } = useElementSize($content);
|
|
13
|
-
const visible = computed(() => contentParentH.value *
|
|
13
|
+
const visible = computed(() => contentParentH.value * 1.5 < contentH.value);
|
|
14
14
|
|
|
15
15
|
function scrollTo(top: number) {
|
|
16
16
|
$contentParent?.scrollTo({ top });
|
|
@@ -119,6 +119,9 @@ const antdPropsResolvers: Record<number, (config: IConfigDetail) => IConfigDetai
|
|
|
119
119
|
},
|
|
120
120
|
};
|
|
121
121
|
const antdValueResolvers: Record<number, (value: any) => any> = {
|
|
122
|
+
[FormTypes.NUMBER_INPUT](value) {
|
|
123
|
+
return String(value);
|
|
124
|
+
},
|
|
122
125
|
[FormTypes.CHECKBOX](value) {
|
|
123
126
|
if (Array.isArray(value))
|
|
124
127
|
return value.join(',');
|
|
@@ -211,6 +214,7 @@ const settingForm = useAntdForm(formSchema, {
|
|
|
211
214
|
return mapValues(state, (v, k) => {
|
|
212
215
|
const formType = configMap.value[k].form_type;
|
|
213
216
|
const resolver = antdValueResolvers[formType];
|
|
217
|
+
|
|
214
218
|
return resolver ? resolver(v) : v;
|
|
215
219
|
});
|
|
216
220
|
},
|
|
@@ -221,7 +225,7 @@ async function submitSetting() {
|
|
|
221
225
|
const body = await settingForm.$form.validate?.().catch(() => {});
|
|
222
226
|
|
|
223
227
|
if (body)
|
|
224
|
-
await settingMutator.mutateAsync({ requestBody:
|
|
228
|
+
await settingMutator.mutateAsync({ requestBody: settingForm.stateTF });
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
/** 重置表单内容 */
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { RouteRecordRaw } from 'vue-router';
|
|
2
2
|
import { definePage } from '../page';
|
|
3
3
|
|
|
4
|
-
export { defineRoute
|
|
5
|
-
|
|
6
|
-
const RouteSymbol = Symbol('app-route');
|
|
4
|
+
export { defineRoute };
|
|
7
5
|
|
|
8
6
|
/** 定义路由 */
|
|
9
7
|
function defineRoute(route: (params: { definePage: typeof definePage }) => RouteRecordRaw[]) {
|
|
10
8
|
const routeFn: any = () => route({ definePage });
|
|
11
|
-
routeFn
|
|
9
|
+
routeFn.isRoute = true;
|
|
12
10
|
|
|
13
11
|
return routeFn;
|
|
14
12
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { RouteRecordRaw } from 'vue-router';
|
|
2
2
|
import merge from 'lodash-es/merge';
|
|
3
3
|
import { ENV } from '../../../utils';
|
|
4
|
-
import { RouteSymbol } from './defineRoute';
|
|
5
4
|
|
|
6
5
|
export { getRoutes };
|
|
7
6
|
|
|
@@ -14,10 +13,11 @@ async function getRoutes() {
|
|
|
14
13
|
let routes: RouteRecordRaw[] = [];
|
|
15
14
|
|
|
16
15
|
for (const name in routeFiles) {
|
|
17
|
-
const
|
|
16
|
+
const moduleLoader: any = routeFiles[name];
|
|
17
|
+
const routeDefineFn = (typeof moduleLoader === 'function' ? await moduleLoader() : moduleLoader)?.default;
|
|
18
18
|
|
|
19
|
-
if (
|
|
20
|
-
|
|
19
|
+
if (routeDefineFn?.isRoute)
|
|
20
|
+
routes.push(...routeDefineFn());
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// 处理路由
|
|
@@ -6,12 +6,9 @@ export interface IGuardConfig {
|
|
|
6
6
|
setup: (router: Router) => void
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
// 路由守卫标识
|
|
10
|
-
export const RouteGuardSymbol = Symbol('app-route-guard');
|
|
11
|
-
|
|
12
9
|
// 定义路由守卫
|
|
13
10
|
export function defineRouteGuard(guard: IGuardConfig) {
|
|
14
|
-
(guard as any)
|
|
11
|
+
(guard as any).isRouteGuard = true;
|
|
15
12
|
guard.order ??= 10;
|
|
16
13
|
|
|
17
14
|
return guard;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ENV } from '../../../utils';
|
|
2
|
-
import { RouteGuardSymbol } from './defineRouteGuard';
|
|
3
2
|
import type { IGuardConfig } from './defineRouteGuard';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -14,13 +13,12 @@ export async function getRouteGuards() {
|
|
|
14
13
|
const routeGuardRecord: { file: string, order: number }[] = [];
|
|
15
14
|
|
|
16
15
|
for (const name in routeGuardFiles) {
|
|
17
|
-
const
|
|
16
|
+
const moduleLoader: any = routeGuardFiles[name];
|
|
17
|
+
const routeGuard = (typeof moduleLoader === 'function' ? await moduleLoader() : moduleLoader)?.default;
|
|
18
18
|
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
routeGuards.push(guard);
|
|
23
|
-
routeGuardRecord.push({ file: name, order: guard.order });
|
|
19
|
+
if (routeGuard?.isRouteGuard) {
|
|
20
|
+
routeGuards.push(routeGuard);
|
|
21
|
+
routeGuardRecord.push({ file: name, order: routeGuard.order });
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
|
|
@@ -9,10 +9,8 @@ export type StartupFn = (
|
|
|
9
9
|
hooks: IHooks
|
|
10
10
|
) => (void | Promise<void>);
|
|
11
11
|
|
|
12
|
-
export const StartupSymbol = Symbol('app-startup');
|
|
13
|
-
|
|
14
12
|
export function defineStartup(startup: StartupFn) {
|
|
15
|
-
(startup as any)
|
|
13
|
+
(startup as any).isAppStartup = true;
|
|
16
14
|
|
|
17
15
|
return startup;
|
|
18
16
|
}
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import type { App } from 'vue';
|
|
2
2
|
import { ENV } from '../../../utils';
|
|
3
|
-
import { StartupSymbol } from './defineStartup';
|
|
4
3
|
import type { StartupFn } from './defineStartup';
|
|
5
4
|
|
|
6
5
|
export async function runStartup(app: App) {
|
|
7
|
-
const moduleLoaders = runStartup.modules as Record<string,
|
|
6
|
+
const moduleLoaders = runStartup.modules as Record<string, any>;
|
|
8
7
|
const startupPaths: string[] = [];
|
|
9
8
|
const onMountCallbacks: Function[] = [];
|
|
10
9
|
(app as any).deps = {};
|
|
11
10
|
|
|
12
|
-
for (const [path,
|
|
13
|
-
const
|
|
14
|
-
const plugin: StartupFn = module?.default ?? {};
|
|
11
|
+
for (const [path, loader] of Object.entries(moduleLoaders)) {
|
|
12
|
+
const plugin: StartupFn = (typeof loader === 'function' ? await loader() : loader)?.default;
|
|
15
13
|
|
|
16
|
-
if (!plugin?.
|
|
14
|
+
if (!(plugin as any)?.isAppStartup)
|
|
17
15
|
continue;
|
|
18
16
|
|
|
19
17
|
startupPaths.push(path);
|
|
@@ -26,7 +26,7 @@ export function setupPermissionRouterGuard(router: Router, rouneNames: { index:
|
|
|
26
26
|
|
|
27
27
|
// 未登录状态进入需要登录权限的页面
|
|
28
28
|
else if (!isLogin && needLogin)
|
|
29
|
-
return next({ name: rouneNames.login, replace: true });
|
|
29
|
+
return next({ name: rouneNames.login, replace: true, query: { redirect: to.fullPath } });
|
|
30
30
|
|
|
31
31
|
// 登录状态进入需要登录权限的页面,有权限直接通行
|
|
32
32
|
else if (isLogin && needLogin && hasPermission)
|
|
@@ -204,3 +204,93 @@
|
|
|
204
204
|
flex: 1 1 auto;
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
+
|
|
208
|
+
// Modal 组件中的 Card 组件样式(为了和原 Modal 组件一样)
|
|
209
|
+
.ant-card.antd-cover__card-in-modal {
|
|
210
|
+
--padding-size: 22px;
|
|
211
|
+
|
|
212
|
+
pointer-events: all;
|
|
213
|
+
|
|
214
|
+
@media bp-lt-mobilel {
|
|
215
|
+
--padding-size: 16px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.ant-card-head {
|
|
219
|
+
min-height: 56px;
|
|
220
|
+
padding: 0 var(--padding-size);
|
|
221
|
+
|
|
222
|
+
@media bp-lt-mobilel {
|
|
223
|
+
min-height: 51px;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.ant-card-body {
|
|
228
|
+
height: var(--body-height, auto);
|
|
229
|
+
min-height: var(--min-body-height, auto);
|
|
230
|
+
max-height: var(--max-body-height, auto);
|
|
231
|
+
padding: var(--padding-size);
|
|
232
|
+
overflow-y: auto;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.ant-card-extra .close-btn {
|
|
236
|
+
--icon-color: var(--antd-colorTextTertiary);
|
|
237
|
+
--bg-color: transparent;
|
|
238
|
+
|
|
239
|
+
position: relative;
|
|
240
|
+
display: flex;
|
|
241
|
+
align-items: center;
|
|
242
|
+
justify-content: center;
|
|
243
|
+
width: 22px;
|
|
244
|
+
height: 22px;
|
|
245
|
+
padding: 0;
|
|
246
|
+
font-size: 18px;
|
|
247
|
+
cursor: pointer;
|
|
248
|
+
background-color: var(--bg-color);
|
|
249
|
+
border: 0;
|
|
250
|
+
border-radius: 4px;
|
|
251
|
+
transition: all 100ms;
|
|
252
|
+
|
|
253
|
+
&::before,
|
|
254
|
+
&::after {
|
|
255
|
+
position: absolute;
|
|
256
|
+
top: 50%;
|
|
257
|
+
left: 50%;
|
|
258
|
+
display: block;
|
|
259
|
+
width: 70%;
|
|
260
|
+
height: 1.5px;
|
|
261
|
+
content: '';
|
|
262
|
+
background-color: var(--icon-color);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
&::before {
|
|
266
|
+
transform: translate(-50%, -50%) rotateZ(45deg);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
&::after {
|
|
270
|
+
transform: translate(-50%, -50%) rotateZ(-45deg);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
&:hover {
|
|
274
|
+
--icon-color: var(--antd-colorText);
|
|
275
|
+
--bg-color: var(--antd-colorFillSecondary);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.ant-card-actions {
|
|
280
|
+
display: flex;
|
|
281
|
+
align-items: center;
|
|
282
|
+
justify-content: flex-end !important;
|
|
283
|
+
min-height: 56px;
|
|
284
|
+
padding: 0 var(--padding-size);
|
|
285
|
+
|
|
286
|
+
> li {
|
|
287
|
+
width: auto !important;
|
|
288
|
+
margin: 0;
|
|
289
|
+
border-inline-end: none !important;
|
|
290
|
+
|
|
291
|
+
&:not(:last-child) {
|
|
292
|
+
margin-right: 8px;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peng_kai/kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.0-beta.
|
|
4
|
+
"version": "0.2.0-beta.29",
|
|
5
5
|
"description": "",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "ISC",
|
|
@@ -14,16 +14,41 @@
|
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"ant-design-vue": "4.1.2",
|
|
17
|
-
"vue": "3.4.
|
|
17
|
+
"vue": "3.4.21",
|
|
18
18
|
"vue-router": "4.3.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@aws-sdk/client-s3": "^3.
|
|
22
|
-
"@aws-sdk/lib-storage": "^3.
|
|
21
|
+
"@aws-sdk/client-s3": "^3.525.0",
|
|
22
|
+
"@aws-sdk/lib-storage": "^3.525.1",
|
|
23
23
|
"@babel/generator": "^7.23.6",
|
|
24
|
-
"@babel/parser": "^7.
|
|
25
|
-
"@babel/traverse": "^7.
|
|
26
|
-
"@babel/types": "^7.
|
|
24
|
+
"@babel/parser": "^7.24.0",
|
|
25
|
+
"@babel/traverse": "^7.24.0",
|
|
26
|
+
"@babel/types": "^7.24.0",
|
|
27
|
+
"@ckeditor/ckeditor5-vue": "^5.1.0",
|
|
28
|
+
"@tanstack/vue-query": "^5.25.0",
|
|
29
|
+
"@vueuse/components": "^10.9.0",
|
|
30
|
+
"@vueuse/core": "^10.9.0",
|
|
31
|
+
"@vueuse/router": "^10.9.0",
|
|
32
|
+
"a-calc": "^1.3.9",
|
|
33
|
+
"ant-design-vue": "^4.1.2",
|
|
34
|
+
"archiver": "^6.0.1",
|
|
35
|
+
"axios": "^1.6.7",
|
|
36
|
+
"bignumber.js": "^9.1.2",
|
|
37
|
+
"chokidar": "^3.6.0",
|
|
38
|
+
"dayjs": "^1.11.10",
|
|
39
|
+
"echarts": "^5.4.3",
|
|
40
|
+
"execa": "^8.0.1",
|
|
41
|
+
"fast-glob": "^3.3.2",
|
|
42
|
+
"localstorage-slim": "^2.7.0",
|
|
43
|
+
"lodash-es": "^4.17.21",
|
|
44
|
+
"nprogress": "^0.2.0",
|
|
45
|
+
"pinia": "^2.1.7",
|
|
46
|
+
"tsx": "^4.7.1",
|
|
47
|
+
"vue": "^3.4.21",
|
|
48
|
+
"vue-i18n": "^9.10.1",
|
|
49
|
+
"vue-router": "^4.3.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
27
52
|
"@ckeditor/ckeditor5-adapter-ckfinder": "^41.1.0",
|
|
28
53
|
"@ckeditor/ckeditor5-alignment": "^41.1.0",
|
|
29
54
|
"@ckeditor/ckeditor5-autoformat": "^41.1.0",
|
|
@@ -54,32 +79,7 @@
|
|
|
54
79
|
"@ckeditor/ckeditor5-theme-lark": "^41.1.0",
|
|
55
80
|
"@ckeditor/ckeditor5-typing": "^41.1.0",
|
|
56
81
|
"@ckeditor/ckeditor5-upload": "^41.1.0",
|
|
57
|
-
"@ckeditor/ckeditor5-vue": "^5.1.0",
|
|
58
82
|
"@ckeditor/ckeditor5-word-count": "^41.1.0",
|
|
59
|
-
"@tanstack/vue-query": "^5.24.1",
|
|
60
|
-
"@vueuse/components": "^10.8.0",
|
|
61
|
-
"@vueuse/core": "^10.8.0",
|
|
62
|
-
"@vueuse/router": "^10.8.0",
|
|
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.3.0"
|
|
81
|
-
},
|
|
82
|
-
"devDependencies": {
|
|
83
83
|
"@peng_kai/lint": "^0.1.0",
|
|
84
84
|
"@types/archiver": "^6.0.2",
|
|
85
85
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -7,15 +7,15 @@ import { ApiCode, ApiError, isTimeout } from '../helpers';
|
|
|
7
7
|
export function returnResultType(): Parameters<AxiosInterceptorManager<any>['use']> {
|
|
8
8
|
return [
|
|
9
9
|
(resp) => {
|
|
10
|
-
const
|
|
10
|
+
const resultType = resp?.config?.resultType;
|
|
11
11
|
|
|
12
12
|
if (resultType === 'api')
|
|
13
|
-
return resp
|
|
13
|
+
return resp?.data;
|
|
14
14
|
|
|
15
15
|
else if (resultType === 'axios')
|
|
16
16
|
return resp;
|
|
17
17
|
|
|
18
|
-
return resp
|
|
18
|
+
return resp?.data?.data;
|
|
19
19
|
},
|
|
20
20
|
(error) => {
|
|
21
21
|
let code = error?.response?.data?.code || error?.response?.status || ApiCode.UNKNOWN;
|
|
@@ -2,25 +2,42 @@ import type { AxiosInterceptorManager } from 'axios';
|
|
|
2
2
|
|
|
3
3
|
const REDIRECT_KEY = 'redirect';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
interface IParams {
|
|
6
|
+
loginPath?: string
|
|
7
|
+
code?: number
|
|
8
|
+
toLogin?: (targetUrl: URL) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const defaultParams: Required<IParams> = {
|
|
12
|
+
loginPath: `${window.location.origin}/auth/login`,
|
|
13
|
+
code: 15001,
|
|
14
|
+
toLogin(targetUrl: URL) {
|
|
15
|
+
window.history.replaceState(null, '', targetUrl.toString());
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function toLogin(params: IParams = defaultParams): Parameters<AxiosInterceptorManager<any>['use']> {
|
|
20
|
+
const _params = { ...defaultParams, ...params };
|
|
21
|
+
|
|
6
22
|
return [
|
|
7
23
|
undefined,
|
|
8
24
|
(err) => {
|
|
9
|
-
if (err.code !== code)
|
|
25
|
+
if (err.code !== _params.code)
|
|
10
26
|
throw err;
|
|
11
27
|
|
|
12
|
-
const
|
|
13
|
-
const
|
|
28
|
+
const currentUrl = new URL(window.location.href);
|
|
29
|
+
const targetUrl = new URL(_params.loginPath);
|
|
14
30
|
|
|
15
|
-
if (
|
|
16
|
-
|
|
31
|
+
if (currentUrl.searchParams.has(REDIRECT_KEY))
|
|
32
|
+
targetUrl.searchParams.set(REDIRECT_KEY, currentUrl.searchParams.get(REDIRECT_KEY)!);
|
|
17
33
|
else
|
|
18
|
-
|
|
34
|
+
targetUrl.searchParams.set(REDIRECT_KEY, window.location.href);
|
|
19
35
|
|
|
20
|
-
if (
|
|
21
|
-
|
|
36
|
+
if (currentUrl.toString() === targetUrl.toString())
|
|
37
|
+
throw err;
|
|
22
38
|
|
|
23
|
-
|
|
39
|
+
_params.toLogin(targetUrl);
|
|
40
|
+
throw err;
|
|
24
41
|
},
|
|
25
42
|
];
|
|
26
43
|
}
|