@peng_kai/kit 0.1.17 → 0.2.0-beta.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/admin/adminPlugin.ts +47 -0
- package/admin/components/filter/src/FilterParam.vue +76 -78
- package/admin/components/filter/src/FilterReset.vue +2 -2
- package/admin/components/filter/src/useFilterParams.ts +75 -25
- package/admin/components/filter/src/useFilterQuery.ts +32 -16
- package/admin/components/rich-text/index.ts +2 -0
- package/admin/components/rich-text/src/RichText.vue +342 -0
- package/admin/components/rich-text/src/imageUploader.ts +34 -0
- package/admin/components/rich-text/src/type.d.ts +7 -0
- package/admin/components/text/src/Datetime.vue +47 -48
- package/admin/components/upload/index.ts +2 -0
- package/admin/components/upload/src/PictureCardUpload.vue +143 -0
- package/admin/components/upload/src/customRequests.ts +31 -0
- package/admin/defines/index.ts +1 -1
- package/admin/defines/route/helpers.ts +0 -1
- package/admin/defines/startup/defineStartup.ts +8 -1
- package/admin/defines/startup/index.ts +1 -1
- package/admin/defines/startup/{getStartups.ts → runStartup.ts} +16 -7
- package/admin/layout/large/Breadcrumb.vue +68 -69
- package/admin/layout/large/Content.vue +23 -24
- package/admin/layout/large/Menu.vue +68 -69
- package/admin/layout/large/PageTab.vue +70 -71
- package/admin/permission/index.ts +2 -4
- package/admin/permission/routerGuard.ts +41 -43
- package/admin/permission/vuePlugin.ts +46 -30
- package/admin/route-guards/collapseMenu.ts +3 -3
- package/admin/route-guards/pageTitle.ts +18 -19
- package/admin/{hooks/useMenu.ts → stores/createUseMenuStore.ts} +133 -128
- package/admin/{hooks/usePage.ts → stores/createUsePageStore.ts} +145 -141
- package/admin/stores/createUsePageTabStore.ts +43 -0
- package/admin/{permission/usePermission.ts → stores/createUsePermissionStore.ts} +57 -52
- package/admin/stores/index.ts +8 -0
- package/admin/styles/classCover.scss +8 -0
- package/antd/hooks/useAntdForm.helpers.ts +92 -8
- package/antd/hooks/useAntdForm.ts +55 -63
- package/antd/hooks/useAntdTable.ts +12 -0
- package/antd/index.ts +1 -1
- package/libs/a-calc.ts +1 -0
- package/libs/axios.ts +2 -0
- package/libs/bignumber.ts +2 -0
- package/libs/dayjs.ts +5 -0
- package/libs/echarts.ts +5 -0
- package/libs/localstorage-slim.ts +2 -0
- package/libs/lodash-es.ts +1 -0
- package/libs/pinia.ts +1 -0
- package/libs/vue-query.ts +1 -0
- package/libs/vueuse.ts +3 -0
- package/package.json +55 -16
- package/request/helpers.ts +20 -1
- package/request/queryClient.ts +34 -21
- package/utils/upload/AwsS3.ts +76 -0
- package/utils/upload/fileHandlers.ts +27 -0
- package/utils/upload/index.ts +2 -0
- package/vite/index.d.ts +1 -0
- package/vite/index.mjs +27 -0
- package/vue/components/echarts/index.ts +1 -0
- package/vue/components/echarts/src/ECharts.vue +48 -0
- package/vue/components/index.ts +1 -0
- package/vue/components/infinite-query/src/InfiniteQuery.vue +2 -8
- package/vue/components/test/KitTest.vue +9 -0
- package/vue/components/test/testStore.ts +11 -0
- package/admin/hooks/index.ts +0 -5
- package/admin/hooks/usePageTab.ts +0 -35
- package/kitDependencies.ts +0 -43
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useVModel } from '@vueuse/core';
|
|
3
|
+
import CKEditor from '@ckeditor/ckeditor5-vue';
|
|
4
|
+
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
|
|
5
|
+
import { Alignment } from '@ckeditor/ckeditor5-alignment';
|
|
6
|
+
import { Autoformat } from '@ckeditor/ckeditor5-autoformat';
|
|
7
|
+
import { Bold, Code, Italic, Strikethrough, Subscript, Superscript, Underline } from '@ckeditor/ckeditor5-basic-styles';
|
|
8
|
+
import { BlockQuote } from '@ckeditor/ckeditor5-block-quote';
|
|
9
|
+
import { CodeBlock } from '@ckeditor/ckeditor5-code-block';
|
|
10
|
+
import { Essentials } from '@ckeditor/ckeditor5-essentials';
|
|
11
|
+
import { Font } from '@ckeditor/ckeditor5-font';
|
|
12
|
+
import { Heading } from '@ckeditor/ckeditor5-heading';
|
|
13
|
+
import { Highlight } from '@ckeditor/ckeditor5-highlight';
|
|
14
|
+
import { HorizontalLine } from '@ckeditor/ckeditor5-horizontal-line';
|
|
15
|
+
import { GeneralHtmlSupport } from '@ckeditor/ckeditor5-html-support';
|
|
16
|
+
import { HtmlEmbed } from '@ckeditor/ckeditor5-html-embed';
|
|
17
|
+
import { AutoImage, Image, ImageCaption, ImageInsert, ImageResize, ImageStyle, ImageToolbar, ImageUpload, PictureEditing } from '@ckeditor/ckeditor5-image';
|
|
18
|
+
import { Indent, IndentBlock } from '@ckeditor/ckeditor5-indent';
|
|
19
|
+
import { AutoLink, Link, LinkImage } from '@ckeditor/ckeditor5-link';
|
|
20
|
+
import { List, ListProperties, TodoList } from '@ckeditor/ckeditor5-list'; import { MediaEmbed } from '@ckeditor/ckeditor5-media-embed';
|
|
21
|
+
import { Paragraph } from '@ckeditor/ckeditor5-paragraph';
|
|
22
|
+
import { RemoveFormat } from '@ckeditor/ckeditor5-remove-format';
|
|
23
|
+
import { Table, TableCaption, TableCellProperties, TableColumnResize, TableProperties, TableToolbar } from '@ckeditor/ckeditor5-table';
|
|
24
|
+
import { TextTransformation } from '@ckeditor/ckeditor5-typing';
|
|
25
|
+
import { WordCount } from '@ckeditor/ckeditor5-word-count';
|
|
26
|
+
import { SourceEditing } from '@ckeditor/ckeditor5-source-editing';
|
|
27
|
+
import { ShowBlocks } from '@ckeditor/ckeditor5-show-blocks';
|
|
28
|
+
import type { CKEditorConfig, PluginConstructor } from './type';
|
|
29
|
+
|
|
30
|
+
import '@ckeditor/ckeditor5-build-classic/build/translations/zh-cn';
|
|
31
|
+
import '@ckeditor/ckeditor5-html-embed/build/translations/zh-cn';
|
|
32
|
+
|
|
33
|
+
const editorConfig: CKEditorConfig = {
|
|
34
|
+
plugins: [
|
|
35
|
+
Alignment,
|
|
36
|
+
Autoformat,
|
|
37
|
+
AutoImage,
|
|
38
|
+
AutoLink,
|
|
39
|
+
BlockQuote,
|
|
40
|
+
Bold,
|
|
41
|
+
Code,
|
|
42
|
+
CodeBlock,
|
|
43
|
+
Essentials,
|
|
44
|
+
Font,
|
|
45
|
+
GeneralHtmlSupport,
|
|
46
|
+
HtmlEmbed,
|
|
47
|
+
Heading,
|
|
48
|
+
Highlight,
|
|
49
|
+
HorizontalLine,
|
|
50
|
+
Image,
|
|
51
|
+
ImageCaption,
|
|
52
|
+
ImageInsert,
|
|
53
|
+
ImageResize,
|
|
54
|
+
ImageStyle,
|
|
55
|
+
ImageToolbar,
|
|
56
|
+
ImageUpload,
|
|
57
|
+
Indent,
|
|
58
|
+
IndentBlock,
|
|
59
|
+
Italic,
|
|
60
|
+
Link,
|
|
61
|
+
LinkImage,
|
|
62
|
+
List,
|
|
63
|
+
ListProperties,
|
|
64
|
+
TodoList,
|
|
65
|
+
MediaEmbed,
|
|
66
|
+
Paragraph,
|
|
67
|
+
PictureEditing,
|
|
68
|
+
RemoveFormat,
|
|
69
|
+
Strikethrough,
|
|
70
|
+
Subscript,
|
|
71
|
+
Superscript,
|
|
72
|
+
Table,
|
|
73
|
+
TableCaption,
|
|
74
|
+
TableCellProperties,
|
|
75
|
+
TableColumnResize,
|
|
76
|
+
TableProperties,
|
|
77
|
+
TableToolbar,
|
|
78
|
+
TextTransformation,
|
|
79
|
+
Underline,
|
|
80
|
+
WordCount,
|
|
81
|
+
SourceEditing,
|
|
82
|
+
ShowBlocks,
|
|
83
|
+
],
|
|
84
|
+
toolbar: {
|
|
85
|
+
items: [
|
|
86
|
+
'undo',
|
|
87
|
+
'redo',
|
|
88
|
+
'|',
|
|
89
|
+
'showBlocks',
|
|
90
|
+
'selectAll',
|
|
91
|
+
'|',
|
|
92
|
+
'heading',
|
|
93
|
+
'|',
|
|
94
|
+
'fontSize',
|
|
95
|
+
'fontFamily',
|
|
96
|
+
'fontColor',
|
|
97
|
+
'fontBackgroundColor',
|
|
98
|
+
'|',
|
|
99
|
+
'bold',
|
|
100
|
+
'italic',
|
|
101
|
+
'underline',
|
|
102
|
+
{
|
|
103
|
+
label: 'Formatting',
|
|
104
|
+
icon: 'text',
|
|
105
|
+
items: ['strikethrough', 'subscript', 'superscript', 'code', 'horizontalLine', '|', 'removeFormat'],
|
|
106
|
+
},
|
|
107
|
+
'|',
|
|
108
|
+
'link',
|
|
109
|
+
'insertImage',
|
|
110
|
+
'insertTable',
|
|
111
|
+
{
|
|
112
|
+
label: 'Insert',
|
|
113
|
+
icon: 'plus',
|
|
114
|
+
items: ['highlight', 'blockQuote', 'mediaEmbed', 'codeBlock', 'htmlEmbed'],
|
|
115
|
+
},
|
|
116
|
+
'|',
|
|
117
|
+
'alignment',
|
|
118
|
+
'|',
|
|
119
|
+
'bulletedList',
|
|
120
|
+
'numberedList',
|
|
121
|
+
'todoList',
|
|
122
|
+
'outdent',
|
|
123
|
+
'indent',
|
|
124
|
+
'|',
|
|
125
|
+
'sourceEditing',
|
|
126
|
+
],
|
|
127
|
+
shouldNotGroupWhenFull: true,
|
|
128
|
+
},
|
|
129
|
+
htmlSupport: {
|
|
130
|
+
allow: [
|
|
131
|
+
{
|
|
132
|
+
name: /^.*$/,
|
|
133
|
+
styles: true,
|
|
134
|
+
attributes: true,
|
|
135
|
+
classes: true,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
fontSize: {
|
|
140
|
+
options: [10, 12, 14, 'default', 18, 20, 22],
|
|
141
|
+
supportAllValues: true,
|
|
142
|
+
},
|
|
143
|
+
image: {
|
|
144
|
+
styles: [
|
|
145
|
+
'alignCenter',
|
|
146
|
+
'alignLeft',
|
|
147
|
+
'alignRight',
|
|
148
|
+
] as any,
|
|
149
|
+
resizeOptions: [
|
|
150
|
+
{ name: 'resizeImage:original', label: 'Original', value: null },
|
|
151
|
+
{ name: 'resizeImage:25', label: '25%', value: '25' },
|
|
152
|
+
{ name: 'resizeImage:50', label: '50%', value: '50' },
|
|
153
|
+
{ name: 'resizeImage:75', label: '75%', value: '75' },
|
|
154
|
+
],
|
|
155
|
+
toolbar: [
|
|
156
|
+
'imageTextAlternative',
|
|
157
|
+
'toggleImageCaption',
|
|
158
|
+
'|',
|
|
159
|
+
'imageStyle:inline',
|
|
160
|
+
'imageStyle:wrapText',
|
|
161
|
+
'imageStyle:breakText',
|
|
162
|
+
'imageStyle:side',
|
|
163
|
+
'|',
|
|
164
|
+
'resizeImage',
|
|
165
|
+
],
|
|
166
|
+
resizeUnit: 'px',
|
|
167
|
+
},
|
|
168
|
+
list: {
|
|
169
|
+
properties: {
|
|
170
|
+
styles: true,
|
|
171
|
+
startIndex: true,
|
|
172
|
+
reversed: true,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
link: {
|
|
176
|
+
addTargetToExternalLinks: true,
|
|
177
|
+
defaultProtocol: 'https://',
|
|
178
|
+
decorators: {
|
|
179
|
+
toggleDownloadable: {
|
|
180
|
+
mode: 'manual',
|
|
181
|
+
label: 'Downloadable',
|
|
182
|
+
attributes: {
|
|
183
|
+
download: 'file',
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
table: {
|
|
189
|
+
contentToolbar: [
|
|
190
|
+
'tableColumn',
|
|
191
|
+
'tableRow',
|
|
192
|
+
'mergeTableCells',
|
|
193
|
+
'tableProperties',
|
|
194
|
+
'tableCellProperties',
|
|
195
|
+
'toggleTableCaption',
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
htmlEmbed: {
|
|
199
|
+
showPreviews: true,
|
|
200
|
+
},
|
|
201
|
+
wordCount: {
|
|
202
|
+
displayWords: true,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
</script>
|
|
206
|
+
|
|
207
|
+
<script setup lang="ts">
|
|
208
|
+
const props = withDefaults(defineProps<{
|
|
209
|
+
modelValue?: string
|
|
210
|
+
plugins?: PluginConstructor[]
|
|
211
|
+
}>(), {
|
|
212
|
+
modelValue: '',
|
|
213
|
+
plugins: () => [],
|
|
214
|
+
});
|
|
215
|
+
const emits = defineEmits<{
|
|
216
|
+
(e: 'update:modelValue', value: string): void
|
|
217
|
+
}>();
|
|
218
|
+
|
|
219
|
+
const editorData = useVModel(props, 'modelValue', emits);
|
|
220
|
+
const localeEditorConfig = { ...editorConfig };
|
|
221
|
+
localeEditorConfig.extraPlugins = [...props.plugins];
|
|
222
|
+
</script>
|
|
223
|
+
|
|
224
|
+
<template>
|
|
225
|
+
<div class="editor-wrapper">
|
|
226
|
+
<CKEditor.component v-model="editorData" :editor="ClassicEditor" :config="localeEditorConfig" />
|
|
227
|
+
</div>
|
|
228
|
+
</template>
|
|
229
|
+
|
|
230
|
+
<style scoped lang="scss">
|
|
231
|
+
.editor-wrapper {
|
|
232
|
+
:deep(.ck-editor__main > .ck-content) {
|
|
233
|
+
height: 500px;
|
|
234
|
+
overflow: auto;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
:root.dark .editor-wrapper {
|
|
239
|
+
/* Overrides the border radius setting in the theme. */
|
|
240
|
+
// --ck-border-radius: 4px;
|
|
241
|
+
|
|
242
|
+
/* Overrides the default font size in the theme. */
|
|
243
|
+
// --ck-font-size-base: 14px;
|
|
244
|
+
|
|
245
|
+
/* Helper variables to avoid duplication in the colors. */
|
|
246
|
+
--ck-custom-background: hsl(270deg 1% 29%);
|
|
247
|
+
--ck-custom-foreground: hsl(255deg 3% 18%);
|
|
248
|
+
--ck-custom-border: hsl(300deg 1% 22%);
|
|
249
|
+
--ck-custom-white: hsl(0deg 0% 100%);
|
|
250
|
+
|
|
251
|
+
/* -- Overrides generic colors. ------------------------------------------------------------- */
|
|
252
|
+
|
|
253
|
+
--ck-color-base-foreground: var(--ck-custom-background);
|
|
254
|
+
--ck-color-focus-border: hsl(208deg 90% 62%);
|
|
255
|
+
--ck-color-text: hsl(0deg 0% 98%);
|
|
256
|
+
--ck-color-shadow-drop: hsl(0deg 0% 0% / 20%);
|
|
257
|
+
--ck-color-shadow-inner: hsl(0deg 0% 0% / 10%);
|
|
258
|
+
|
|
259
|
+
/* -- Overrides the default .ck-button class colors. ---------------------------------------- */
|
|
260
|
+
|
|
261
|
+
--ck-color-button-default-background: var(--ck-custom-background);
|
|
262
|
+
--ck-color-button-default-hover-background: hsl(270deg 1% 22%);
|
|
263
|
+
--ck-color-button-default-active-background: hsl(270deg 2% 20%);
|
|
264
|
+
--ck-color-button-default-active-shadow: hsl(270deg 2% 23%);
|
|
265
|
+
--ck-color-button-default-disabled-background: var(--ck-custom-background);
|
|
266
|
+
--ck-color-button-on-background: var(--ck-custom-foreground);
|
|
267
|
+
--ck-color-button-on-hover-background: hsl(255deg 4% 16%);
|
|
268
|
+
--ck-color-button-on-active-background: hsl(255deg 4% 14%);
|
|
269
|
+
--ck-color-button-on-active-shadow: hsl(240deg 3% 19%);
|
|
270
|
+
--ck-color-button-on-disabled-background: var(--ck-custom-foreground);
|
|
271
|
+
--ck-color-button-action-background: hsl(168deg 76% 42%);
|
|
272
|
+
--ck-color-button-action-hover-background: hsl(168deg 76% 38%);
|
|
273
|
+
--ck-color-button-action-active-background: hsl(168deg 76% 36%);
|
|
274
|
+
--ck-color-button-action-active-shadow: hsl(168deg 75% 34%);
|
|
275
|
+
--ck-color-button-action-disabled-background: hsl(168deg 76% 42%);
|
|
276
|
+
--ck-color-button-action-text: var(--ck-custom-white);
|
|
277
|
+
--ck-color-button-save: hsl(120deg 100% 46%);
|
|
278
|
+
--ck-color-button-cancel: hsl(15deg 100% 56%);
|
|
279
|
+
|
|
280
|
+
/* -- Overrides the default .ck-dropdown class colors. -------------------------------------- */
|
|
281
|
+
|
|
282
|
+
--ck-color-dropdown-panel-background: var(--ck-custom-background);
|
|
283
|
+
--ck-color-dropdown-panel-border: var(--ck-custom-foreground);
|
|
284
|
+
|
|
285
|
+
/* -- Overrides the default .ck-splitbutton class colors. ----------------------------------- */
|
|
286
|
+
|
|
287
|
+
--ck-color-split-button-hover-background: var(--ck-color-button-default-hover-background);
|
|
288
|
+
--ck-color-split-button-hover-border: var(--ck-custom-foreground);
|
|
289
|
+
|
|
290
|
+
/* -- Overrides the default .ck-input class colors. ----------------------------------------- */
|
|
291
|
+
|
|
292
|
+
--ck-color-input-background: var(--ck-custom-background);
|
|
293
|
+
--ck-color-input-border: hsl(257deg 3% 43%);
|
|
294
|
+
--ck-color-input-text: hsl(0deg 0% 98%);
|
|
295
|
+
--ck-color-input-disabled-background: hsl(255deg 4% 21%);
|
|
296
|
+
--ck-color-input-disabled-border: hsl(250deg 3% 38%);
|
|
297
|
+
--ck-color-input-disabled-text: hsl(0deg 0% 78%);
|
|
298
|
+
|
|
299
|
+
/* -- Overrides the default .ck-labeled-field-view class colors. ---------------------------- */
|
|
300
|
+
|
|
301
|
+
--ck-color-labeled-field-label-background: var(--ck-custom-background);
|
|
302
|
+
|
|
303
|
+
/* -- Overrides the default .ck-list class colors. ------------------------------------------ */
|
|
304
|
+
|
|
305
|
+
--ck-color-list-background: var(--ck-custom-background);
|
|
306
|
+
--ck-color-list-button-hover-background: var(--ck-custom-foreground);
|
|
307
|
+
--ck-color-list-button-on-background: hsl(208deg 88% 52%);
|
|
308
|
+
--ck-color-list-button-on-text: var(--ck-custom-white);
|
|
309
|
+
|
|
310
|
+
/* -- Overrides the default .ck-balloon-panel class colors. --------------------------------- */
|
|
311
|
+
|
|
312
|
+
--ck-color-panel-background: var(--ck-custom-background);
|
|
313
|
+
--ck-color-panel-border: var(--ck-custom-border);
|
|
314
|
+
|
|
315
|
+
/* -- Overrides the default .ck-toolbar class colors. --------------------------------------- */
|
|
316
|
+
|
|
317
|
+
--ck-color-toolbar-background: var(--ck-custom-background);
|
|
318
|
+
--ck-color-toolbar-border: var(--ck-custom-border);
|
|
319
|
+
|
|
320
|
+
/* -- Overrides the default .ck-tooltip class colors. --------------------------------------- */
|
|
321
|
+
|
|
322
|
+
--ck-color-tooltip-background: hsl(252deg 7% 14%);
|
|
323
|
+
--ck-color-tooltip-text: hsl(0deg 0% 93%);
|
|
324
|
+
|
|
325
|
+
/* -- Overrides the default colors used by the ckeditor5-image package. --------------------- */
|
|
326
|
+
|
|
327
|
+
--ck-color-image-caption-background: hsl(0deg 0% 97%);
|
|
328
|
+
--ck-color-image-caption-text: hsl(0deg 0% 20%);
|
|
329
|
+
|
|
330
|
+
/* -- Overrides the default colors used by the ckeditor5-widget package. -------------------- */
|
|
331
|
+
|
|
332
|
+
--ck-color-widget-blurred-border: hsl(0deg 0% 87%);
|
|
333
|
+
--ck-color-widget-hover-border: hsl(43deg 100% 68%);
|
|
334
|
+
--ck-color-widget-editable-focus-background: var(--ck-custom-white);
|
|
335
|
+
|
|
336
|
+
/* -- Overrides the default colors used by the ckeditor5-link package. ---------------------- */
|
|
337
|
+
|
|
338
|
+
--ck-color-link-default: hsl(190deg 100% 75%);
|
|
339
|
+
--ck-color-base-background: #141414;
|
|
340
|
+
--ck-color-base-border: #424242;
|
|
341
|
+
}
|
|
342
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AwsS3 } from '../../../../utils/upload';
|
|
2
|
+
import type { PluginConstructor } from './type';
|
|
3
|
+
|
|
4
|
+
export { createImageUploaderForAws3 };
|
|
5
|
+
|
|
6
|
+
function createImageUploaderForAws3(awsS3: AwsS3, rootDir?: string): PluginConstructor {
|
|
7
|
+
return function (editor) {
|
|
8
|
+
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
|
|
9
|
+
return {
|
|
10
|
+
async upload() {
|
|
11
|
+
const file = await loader.file;
|
|
12
|
+
|
|
13
|
+
if (file) {
|
|
14
|
+
const { uploader, fileURL } = await awsS3.upload(file, rootDir);
|
|
15
|
+
|
|
16
|
+
uploader.on('httpUploadProgress', (progress) => {
|
|
17
|
+
loader.uploadTotal = progress.total ?? null;
|
|
18
|
+
loader.uploaded = progress.loaded ?? 0;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
await uploader.done();
|
|
22
|
+
|
|
23
|
+
return { default: fileURL };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {};
|
|
27
|
+
},
|
|
28
|
+
abort() {
|
|
29
|
+
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type CKEditor from '@ckeditor/ckeditor5-vue';
|
|
2
|
+
import type { RequiredDeep } from 'type-fest';
|
|
3
|
+
import type { ComponentProps } from 'vue-component-type-helpers';
|
|
4
|
+
|
|
5
|
+
export type CKEditorProps = NonNullable<ComponentProps<typeof CKEditor['component']>>;
|
|
6
|
+
export type CKEditorConfig = NonNullable<CKEditorProps['config']>;
|
|
7
|
+
export type PluginConstructor = NonNullable<CKEditorConfig['extraPlugins']>[number];
|
|
@@ -1,48 +1,47 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { Tooltip as ATooltip } from 'ant-design-vue';
|
|
3
|
-
import { computed } from 'vue';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
defineOptions({
|
|
7
|
-
inheritAttrs: false,
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
const props = withDefaults(
|
|
11
|
-
defineProps<{
|
|
12
|
-
timestamp?: number | string
|
|
13
|
-
template?: string
|
|
14
|
-
}>(),
|
|
15
|
-
{
|
|
16
|
-
template: 'MM-DD HH:mm:ss',
|
|
17
|
-
},
|
|
18
|
-
);
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<div>{{ dayjs(timestamp).
|
|
38
|
-
|
|
39
|
-
</
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</style>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Tooltip as ATooltip } from 'ant-design-vue';
|
|
3
|
+
import { computed } from 'vue';
|
|
4
|
+
import { dayjs } from '../../../../utils/date';
|
|
5
|
+
|
|
6
|
+
defineOptions({
|
|
7
|
+
inheritAttrs: false,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(
|
|
11
|
+
defineProps<{
|
|
12
|
+
timestamp?: number | string
|
|
13
|
+
template?: string
|
|
14
|
+
}>(),
|
|
15
|
+
{
|
|
16
|
+
template: 'MM-DD HH:mm:ss',
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
const timestamp = computed(() => {
|
|
20
|
+
let tsStr = String(props.timestamp);
|
|
21
|
+
|
|
22
|
+
if (tsStr.length === 10)
|
|
23
|
+
tsStr += '000';
|
|
24
|
+
if (tsStr.length !== 13)
|
|
25
|
+
return;
|
|
26
|
+
|
|
27
|
+
const tsNum = Number.parseInt(tsStr);
|
|
28
|
+
|
|
29
|
+
return Number.isNaN(tsNum) ? undefined : tsNum;
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<ATooltip destroyTooltipOnHide>
|
|
35
|
+
<template v-if="timestamp" #title>
|
|
36
|
+
<div>{{ dayjs(timestamp).fromNow?.() }}</div>
|
|
37
|
+
<div>{{ dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss') }}</div>
|
|
38
|
+
</template>
|
|
39
|
+
<span v-bind="$attrs" class="text">{{ timestamp ? dayjs(timestamp).format(props.template) : '-' }}</span>
|
|
40
|
+
</ATooltip>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<style scoped lang="scss">
|
|
44
|
+
.text {
|
|
45
|
+
font-variant-numeric: tabular-nums;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { message } from 'ant-design-vue';
|
|
3
|
+
import type { UploadProps } from 'ant-design-vue';
|
|
4
|
+
import type { PreviewGroupPreview } from 'ant-design-vue/es/vc-image/src/PreviewGroup';
|
|
5
|
+
import { useVModel } from '@vueuse/core';
|
|
6
|
+
import { ref } from 'vue';
|
|
7
|
+
import type { AwsS3 } from '../../../../utils/upload';
|
|
8
|
+
import { createAwsS3Request } from './customRequests';
|
|
9
|
+
|
|
10
|
+
type UploadFile = Parameters<NonNullable<UploadProps['onPreview']>>['0'];
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script lang="ts" setup>
|
|
14
|
+
const props = withDefaults(
|
|
15
|
+
defineProps<{
|
|
16
|
+
/** 上传文件的数组 */
|
|
17
|
+
modelValue?: UploadFile[]
|
|
18
|
+
/** awsS3 实例对象 */
|
|
19
|
+
awsS3: AwsS3
|
|
20
|
+
/** 根目录 */
|
|
21
|
+
rootDir?: string
|
|
22
|
+
/** 可以上传的最大文件数 */
|
|
23
|
+
maxCount?: number
|
|
24
|
+
/** 显示图片卡的行数,或 “auto-fill” 以根据可用空间自动调整行数。 */
|
|
25
|
+
rowCount?: number | 'auto-fill'
|
|
26
|
+
/** 图片卡的大小 */
|
|
27
|
+
cardSize?: string
|
|
28
|
+
/** 允许的图片后缀 */
|
|
29
|
+
allowExts?: string[]
|
|
30
|
+
}>(),
|
|
31
|
+
{
|
|
32
|
+
modelValue: () => [],
|
|
33
|
+
maxCount: 2,
|
|
34
|
+
rowCount: 'auto-fill',
|
|
35
|
+
cardSize: '90px',
|
|
36
|
+
allowExts: () => ['jpg', 'jpeg', 'png', 'gif', 'apng', 'webp', 'svg'],
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
const emits = defineEmits<{
|
|
40
|
+
(e: 'update:modelValue', value: UploadFile[]): void
|
|
41
|
+
}>();
|
|
42
|
+
|
|
43
|
+
const fileList = useVModel(props, 'modelValue', emits);
|
|
44
|
+
const preview = ref<PreviewGroupPreview>({
|
|
45
|
+
visible: false,
|
|
46
|
+
onVisibleChange(value) {
|
|
47
|
+
preview.value.visible = value;
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
function handlePreview(file: UploadFile) {
|
|
52
|
+
preview.value.src = file.url || file.thumbUrl;
|
|
53
|
+
preview.value.visible = true;
|
|
54
|
+
preview.value.current = fileList.value?.findIndex(item => preview.value.src === (item.url || item.thumbUrl)) ?? 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function beforeUpload(file: UploadFile) {
|
|
58
|
+
const isImg = props.allowExts.some(item => String(file.type).toLowerCase().includes(item));
|
|
59
|
+
|
|
60
|
+
if (!isImg)
|
|
61
|
+
message.error(`${file.name} 不是图片 (${props.allowExts.join(',')})`);
|
|
62
|
+
|
|
63
|
+
return isImg;
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<div :class="{ 'w-fit': typeof props.rowCount === 'number' }">
|
|
69
|
+
<AUpload
|
|
70
|
+
v-model:fileList="fileList" class="pic-card-upload" listType="picture-card" multiple :maxCount="$props.maxCount"
|
|
71
|
+
:beforeUpload="beforeUpload" :customRequest="createAwsS3Request($props.awsS3, $props.rootDir)" @preview="handlePreview"
|
|
72
|
+
>
|
|
73
|
+
<i v-if="fileList.length < props.maxCount" class="i-ant-design:plus-outlined text-26px text-$antd-colorTextTertiary" />
|
|
74
|
+
</AUpload>
|
|
75
|
+
|
|
76
|
+
<div style="display: none">
|
|
77
|
+
<AImagePreviewGroup :preview="preview">
|
|
78
|
+
<AImage
|
|
79
|
+
v-for="item of fileList"
|
|
80
|
+
:key="item.uid"
|
|
81
|
+
:src="item.url || item.thumbUrl"
|
|
82
|
+
/>
|
|
83
|
+
</AImagePreviewGroup>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
87
|
+
|
|
88
|
+
<style scoped lang="scss">
|
|
89
|
+
/* stylelint-disable function-no-unknown */
|
|
90
|
+
|
|
91
|
+
.pic-card-upload.ant-upload-wrapper {
|
|
92
|
+
display: block;
|
|
93
|
+
|
|
94
|
+
:deep(.ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item) {
|
|
95
|
+
padding: 0;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
:deep(.ant-upload-list::before) {
|
|
100
|
+
display: none;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
:deep(.ant-upload-list-picture-card) {
|
|
104
|
+
display: grid;
|
|
105
|
+
grid-template-columns: repeat(v-bind('$props.rowCount'), v-bind('$props.cardSize'));
|
|
106
|
+
gap: 10px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
:deep(.ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container),
|
|
110
|
+
:deep(.ant-upload.ant-upload-select) {
|
|
111
|
+
width: v-bind('$props.cardSize');
|
|
112
|
+
height: v-bind('$props.cardSize');
|
|
113
|
+
margin: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
:deep(.ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item::before ) {
|
|
117
|
+
width: 100%;
|
|
118
|
+
height: 100%;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
:deep(.ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-thumbnail img) {
|
|
122
|
+
object-fit: cover;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
:deep(.ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-progress) {
|
|
126
|
+
bottom: calc(50% - 22px);
|
|
127
|
+
left: 50%;
|
|
128
|
+
line-height: 1em;
|
|
129
|
+
transform: translateX(-50%);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
:deep(.ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-thumbnail) {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: center;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:deep(.ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-file+.ant-upload-list-item-name) {
|
|
139
|
+
left: 50%;
|
|
140
|
+
transform: translateX(-50%);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
</style>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { UploadProps } from 'ant-design-vue';
|
|
2
|
+
import type { AwsS3 } from '../../../../utils/upload';
|
|
3
|
+
|
|
4
|
+
type UploadRequestOption = Parameters<NonNullable<UploadProps['customRequest']>>['0'];
|
|
5
|
+
|
|
6
|
+
export function createAwsS3Request(awsS3: AwsS3, rootPath?: string) {
|
|
7
|
+
return async (options: UploadRequestOption) => {
|
|
8
|
+
if (!(options.file instanceof File))
|
|
9
|
+
throw new Error('options.file 不是 File 对象');
|
|
10
|
+
|
|
11
|
+
const { uploader, fileURL } = await awsS3.upload(options.file, rootPath);
|
|
12
|
+
|
|
13
|
+
uploader.on('httpUploadProgress', (progress) => {
|
|
14
|
+
const percent = (progress.loaded ?? 0) / (progress.total ?? 1) * 100;
|
|
15
|
+
options.onProgress?.({ percent });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
await uploader.done();
|
|
19
|
+
options.onSuccess?.({
|
|
20
|
+
uid: (options.file as any).uid,
|
|
21
|
+
name: fileURL.split('/').pop(),
|
|
22
|
+
url: fileURL,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
abort() {
|
|
27
|
+
uploader.abort();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
package/admin/defines/index.ts
CHANGED
|
@@ -38,7 +38,6 @@ export function getMenusByRouter(router: Router) {
|
|
|
38
38
|
|
|
39
39
|
export function printRounesNameInterface(routes: { name: PropertyKey }[]) {
|
|
40
40
|
console.groupCollapsed('路由命名');
|
|
41
|
-
console.log('复制以下内容到 AppRouteNames');
|
|
42
41
|
const routesName = new Set();
|
|
43
42
|
routes.forEach((route) => {
|
|
44
43
|
if (typeof route.name === 'string')
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { App } from 'vue';
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export interface IHooks {
|
|
4
|
+
onMount: (cb: () => void) => void
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type StartupFn = (
|
|
8
|
+
app: App,
|
|
9
|
+
hooks: IHooks
|
|
10
|
+
) => (void | Promise<void>);
|
|
4
11
|
|
|
5
12
|
export const StartupSymbol = Symbol('app-startup');
|
|
6
13
|
|