12
12
</span >
13
13
</div >
14
14
<div class =" mt-2.5" >
15
- <Codemirror
16
- ref =" logContainer"
17
- :style =" styleObject"
18
- :autofocus =" true"
19
- :placeholder =" $t('website.noLog')"
20
- :indent-with-tab =" true"
21
- :tabSize =" 4"
22
- :lineWrapping =" true"
23
- :matchBrackets =" true"
24
- theme =" cobalt"
25
- :styleActiveLine =" true"
26
- :extensions =" extensions"
27
- v-model =" content"
28
- :disabled =" true"
29
- @ready =" handleReady"
30
- />
15
+ <highlightjs
16
+ ref =" editorRef"
17
+ class =" editor-main"
18
+ language =" JavaScript"
19
+ :autodetect =" false"
20
+ :code =" content"
21
+ ></highlightjs >
31
22
</div >
32
23
</div >
33
24
</template >
34
25
<script lang="ts" setup>
35
- import { Codemirror } from ' vue-codemirror' ;
36
- import { javascript } from ' @codemirror/lang-javascript' ;
37
- import { oneDark } from ' @codemirror/theme-one-dark' ;
38
- import { computed , nextTick , onMounted , onUnmounted , reactive , ref , shallowRef } from ' vue' ;
26
+ import { nextTick , onMounted , onUnmounted , reactive , ref } from ' vue' ;
39
27
import { downloadFile } from ' @/utils/util' ;
40
28
import { ReadByLine } from ' @/api/modules/files' ;
41
29
import { watch } from ' vue' ;
42
30
43
- const extensions = [ javascript (), oneDark ] ;
31
+ const editorRef = ref () ;
44
32
45
33
interface LogProps {
46
34
id? : number ;
@@ -61,7 +49,7 @@ const props = defineProps({
61
49
},
62
50
style: {
63
51
type: String ,
64
- default: ' height: calc(100vh - 200px); width: 100%; min-height: 400px' ,
52
+ default: ' height: calc(100vh - 200px); width: 100%; min-height: 400px; overflow: auto; ' ,
65
53
},
66
54
defaultButton: {
67
55
type: Boolean ,
@@ -84,29 +72,23 @@ const data = ref({
84
72
85
73
let timer: NodeJS .Timer | null = null ;
86
74
const tailLog = ref (false );
87
- const view = shallowRef ();
88
75
const content = ref (' ' );
89
76
const end = ref (false );
90
77
const lastContent = ref (' ' );
91
- const logContainer = ref ();
92
78
const scrollerElement = ref <HTMLElement | null >(null );
79
+ const minPage = ref (1 );
80
+ const maxPage = ref (1 );
93
81
94
82
const readReq = reactive ({
95
83
id: 0 ,
96
84
type: ' ' ,
97
85
name: ' ' ,
98
- page: 0 ,
99
- pageSize: 2000 ,
86
+ page: 1 ,
87
+ pageSize: 500 ,
88
+ latest: false ,
100
89
});
101
90
const emit = defineEmits ([' update:loading' , ' update:hasContent' , ' update:isReading' ]);
102
91
103
- const handleReady = (payload ) => {
104
- view .value = payload .view ;
105
- const editorContainer = payload .container ;
106
- const editorElement = editorContainer .querySelector (' .cm-editor' );
107
- scrollerElement .value = editorElement .querySelector (' .cm-scroller' ) as HTMLElement ;
108
- };
109
-
110
92
const loading = ref (props .loading );
111
93
112
94
watch (
@@ -121,25 +103,6 @@ const changeLoading = () => {
121
103
emit (' update:loading' , loading .value );
122
104
};
123
105
124
- const styleObject = computed (() => {
125
- const styles = {};
126
- let style = ' height: calc(100vh - 200px); width: 100%; min-height: 400px' ;
127
- if (props .style != null && props .style != ' ' ) {
128
- style = props .style ;
129
- }
130
- style .split (' ;' ).forEach ((styleRule ) => {
131
- const [property, value] = styleRule .split (' :' );
132
- if (property && value ) {
133
- const formattedProperty = property
134
- .trim ()
135
- .replace (/ ([a-z ] )([A-Z ] )/ g , ' $1-$2' )
136
- .toLowerCase ();
137
- styles [formattedProperty ] = value .trim ();
138
- }
139
- });
140
- return styles ;
141
- });
142
-
143
106
const stopSignals = [
144
107
' docker-compose up failed!' ,
145
108
' docker-compose up successful!' ,
@@ -151,18 +114,16 @@ const stopSignals = [
151
114
' image push successful!' ,
152
115
];
153
116
154
- const getContent = () => {
117
+ const getContent = (pre : boolean ) => {
155
118
emit (' update:isReading' , true );
156
- if (! end .value ) {
157
- readReq .page += 1 ;
158
- }
159
119
readReq .id = props .config .id ;
160
120
readReq .type = props .config .type ;
161
121
readReq .name = props .config .name ;
162
122
ReadByLine (readReq ).then ((res ) => {
163
123
if (! end .value && res .data .end ) {
164
124
lastContent .value = content .value ;
165
125
}
126
+
166
127
res .data .content = res .data .content .replace (/ \\ u(\w {4} )/ g , function (match , grp ) {
167
128
return String .fromCharCode (parseInt (grp , 16 ));
168
129
});
@@ -175,28 +136,38 @@ const getContent = () => {
175
136
if (lastContent .value == ' ' ) {
176
137
content .value = res .data .content ;
177
138
} else {
178
- content .value = lastContent .value + ' \n ' + res .data .content ;
139
+ content .value = pre
140
+ ? res .data .content + ' \n ' + lastContent .value
141
+ : lastContent .value + ' \n ' + res .data .content ;
179
142
}
180
143
} else {
181
144
if (content .value == ' ' ) {
182
145
content .value = res .data .content ;
183
146
} else {
184
- content .value = content .value + ' \n ' + res .data .content ;
147
+ content .value = pre
148
+ ? res .data .content + ' \n ' + content .value
149
+ : content .value + ' \n ' + res .data .content ;
185
150
}
186
151
}
187
152
}
188
153
end .value = res .data .end ;
189
154
emit (' update:hasContent' , content .value !== ' ' );
190
155
nextTick (() => {
191
- const state = view .value .state ;
192
- view .value .dispatch ({
193
- selection: { anchor: state .doc .length , head: state .doc .length },
194
- });
195
- view .value .focus ();
196
- const firstLine = view .value .state .doc .line (view .value .state .doc .lines );
197
- const { top } = view .value .lineBlockAt (firstLine .from );
198
- scrollerElement .value .scrollTo ({ top , behavior: ' instant' });
156
+ if (pre ) {
157
+ if (scrollerElement .value .scrollHeight > 2000 ) {
158
+ scrollerElement .value .scrollTop = 2000 ;
159
+ }
160
+ } else {
161
+ scrollerElement .value .scrollTop = scrollerElement .value .scrollHeight ;
162
+ }
199
163
});
164
+
165
+ if (readReq .latest ) {
166
+ readReq .page = res .data .total ;
167
+ readReq .latest = false ;
168
+ maxPage .value = res .data .total ;
169
+ minPage .value = res .data .total ;
170
+ }
200
171
});
201
172
};
202
173
@@ -206,7 +177,7 @@ const changeTail = (fromOutSide: boolean) => {
206
177
}
207
178
if (tailLog .value ) {
208
179
timer = setInterval (() => {
209
- getContent ();
180
+ getContent (false );
210
181
}, 1000 * 2 );
211
182
} else {
212
183
onCloseLog ();
@@ -230,6 +201,10 @@ function isScrolledToBottom(element: HTMLElement): boolean {
230
201
return element .scrollTop + element .clientHeight + 1 >= element .scrollHeight ;
231
202
}
232
203
204
+ function isScrolledToTop(element : HTMLElement ): boolean {
205
+ return element .scrollTop === 0 ;
206
+ }
207
+
233
208
const init = () => {
234
209
if (props .config .tail ) {
235
210
tailLog .value = props .config .tail ;
@@ -239,30 +214,56 @@ const init = () => {
239
214
if (tailLog .value ) {
240
215
changeTail (false );
241
216
}
242
- getContent ();
217
+ readReq .latest = true ;
218
+ getContent (false );
219
+
220
+ nextTick (() => {});
221
+ };
222
+
223
+ const clearLog = (): void => {
224
+ content .value = ' ' ;
225
+ };
243
226
227
+ const initCodemirror = () => {
244
228
nextTick (() => {
245
- if (scrollerElement .value ) {
229
+ if (editorRef .value ) {
230
+ scrollerElement .value = editorRef .value .$el as HTMLElement ;
246
231
scrollerElement .value .addEventListener (' scroll' , function () {
247
232
if (isScrolledToBottom (scrollerElement .value )) {
248
- getContent ();
233
+ readReq .page = maxPage .value ;
234
+ getContent (false );
235
+ }
236
+ if (isScrolledToTop (scrollerElement .value )) {
237
+ readReq .page = minPage .value - 1 ;
238
+ if (readReq .page < 1 ) {
239
+ return ;
240
+ }
241
+ minPage .value = readReq .page ;
242
+ getContent (true );
249
243
}
250
244
});
245
+ let hljsDom = scrollerElement .value .querySelector (' .hljs' ) as HTMLElement ;
246
+ hljsDom .style [' min-height' ] = ' 300px' ;
251
247
}
252
248
});
253
249
};
254
250
255
- const clearLog = (): void => {
256
- content .value = ' ' ;
257
- };
258
-
259
251
onUnmounted (() => {
260
252
onCloseLog ();
261
253
});
262
254
263
255
onMounted (() => {
256
+ initCodemirror ();
264
257
init ();
265
258
});
266
259
267
260
defineExpose ({ changeTail , onDownload , clearLog });
268
261
</script >
262
+ <style lang="scss" scoped>
263
+ .editor-main {
264
+ height : calc (100vh - 480px );
265
+ width : 100% ;
266
+ min-height : 400px ;
267
+ overflow : auto ;
268
+ }
269
+ </style >
0 commit comments