Skip to content

Commit 3934b45

Browse files
authored
Merge pull request #5064 from jumpserver/dev
v4.10.2
2 parents 0c5e84d + 0b27a01 commit 3934b45

File tree

50 files changed

+673
-154
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+673
-154
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM jumpserver/lina-base:20250508_085854 AS stage-build
1+
FROM jumpserver/lina-base:20250616_083043 AS stage-build
22

33
ARG VERSION
44
ENV VERSION=$VERSION

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
"vue-i18n": "^8.15.5",
7777
"vue-json-editor": "^1.4.3",
7878
"vue-markdown": "^2.2.4",
79-
"vue-moment": "^4.1.0",
8079
"vue-password-strength-meter": "^1.7.2",
8180
"vue-router": "3.0.6",
8281
"vue-select": "^3.9.5",

src/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export default {
7474
},
7575
7676
createWatermark() {
77-
if (this.currentUser?.username && this.publicSettings?.SECURITY_WATERMARK_ENABLED && this.$store.getters.hasValidLicense) {
77+
if (this.currentUser?.username && this.publicSettings?.SECURITY_WATERMARK_ENABLED) {
7878
this.watermark = new Watermark({
7979
content: this.getWaterMarkContent(),
8080
width: this.publicSettings?.SECURITY_WATERMARK_WIDTH,

src/assets/img/cloud/smartx.svg

Lines changed: 1 addition & 0 deletions
Loading

src/components/Apps/ChatAi/components/ChitChat/ChatInput.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="container">
3-
<div class="chat-action">
3+
<div v-if="hasPrompt" class="chat-action">
44
<Select2
55
v-model="select.value"
66
:disabled="isLoading || isSelectDisabled"
@@ -36,6 +36,10 @@ export default {
3636
expanded: {
3737
type: Boolean,
3838
default: false
39+
},
40+
hasPrompt: {
41+
type: Boolean,
42+
default: true
3943
}
4044
},
4145
data() {

src/components/Apps/ChatAi/components/ChitChat/ChatMessage.vue

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,15 @@
3333
<!-- eslint-disable-next-line -->
3434
<div class="divider"></div>
3535
<p>
36-
<MessageText :message="item.reasoning" />
36+
<MessageText :message="item.reasoning" @insert-code="handleInsertCode" />
3737
</p>
3838
</div>
3939

4040
<div class="thinking-result">
4141
<span v-if="isServerError" class="error">
4242
{{ isServerError }}
4343
</span>
44-
<MessageText :message="item.result" />
45-
</div>
44+
<MessageText :message="item.result" :is-terminal="isTerminal" @insert-code="handleInsertCode" /></div>
4645
</div>
4746
</div>
4847
<div class="action">
@@ -93,6 +92,10 @@ export default {
9392
type: Object,
9493
default: () => {
9594
}
95+
},
96+
isTerminal: {
97+
type: Boolean,
98+
default: false
9699
}
97100
},
98101
data() {
@@ -142,6 +145,9 @@ export default {
142145
if (value === 'copy') {
143146
copy(this.item.result.content)
144147
}
148+
},
149+
handleInsertCode(code) {
150+
this.$emit('insert-code', code)
145151
}
146152
}
147153
}

src/components/Apps/ChatAi/components/ChitChat/MessageText.vue

Lines changed: 89 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ export default {
2525
type: Object,
2626
default: () => {
2727
}
28+
},
29+
isTerminal: {
30+
type: Boolean,
31+
default: false
2832
}
2933
},
3034
data() {
@@ -45,10 +49,10 @@ export default {
4549
this.init()
4650
},
4751
updated() {
48-
this.addCopyEvents()
52+
this.addEvents()
4953
},
5054
destroyed() {
51-
this.removeCopyEvents()
55+
this.removeEvents()
5256
},
5357
methods: {
5458
init() {
@@ -69,26 +73,64 @@ export default {
6973
this.markdown.use(mdKatex, { blockClass: 'katexmath-block rounded-md', errorColor: ' #cc0000' })
7074
},
7175
highlightBlock(str, lang) {
72-
return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">${'Copy'}</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`
76+
let insertSpanHtml = `<span class="code-block-header__insert">${this.$t('Insert')}</span>`
77+
if (!this.isTerminal) {
78+
insertSpanHtml = ''
79+
}
80+
return `<pre class="code-block-wrapper">
81+
<div class="code-block-header">
82+
<span class="code-block-header__lang">${lang}</span>
83+
<span class="code-block-header__actions">
84+
${insertSpanHtml}
85+
<span class="code-block-header__copy">${this.$t('Copy')}</span>
86+
</span>
87+
</div>
88+
<code class="hljs code-block-body ${lang}">${str}</code></pre>`
7389
},
74-
addCopyEvents() {
75-
const copyBtn = document.querySelectorAll('.code-block-header__copy')
76-
copyBtn.forEach((btn) => {
77-
btn.addEventListener('click', () => {
78-
const code = btn.parentElement?.nextElementSibling?.textContent
79-
if (code) {
80-
copy(code)
81-
}
90+
addEvents() {
91+
this.addBtnClickEvents('.code-block-header__copy', this.handlerClickCopy)
92+
this.addBtnClickEvents('.code-block-header__insert', this.handlerClickInsert)
93+
},
94+
95+
handlerClickCopy(event) {
96+
const wrapper = event.target.closest('.code-block-wrapper')
97+
if (wrapper) {
98+
// 查找里面的 code 元素
99+
const codeElement = wrapper.querySelector('code.code-block-body')
100+
if (codeElement) {
101+
const codeText = codeElement.textContent
102+
copy(codeText)
103+
}
104+
}
105+
},
106+
handlerClickInsert(event) {
107+
const wrapper = event.target.closest('.code-block-wrapper')
108+
if (wrapper) {
109+
// 查找里面的 code 元素
110+
const codeElement = wrapper.querySelector('code.code-block-body')
111+
if (codeElement) {
112+
const codeText = codeElement.textContent
113+
this.$emit('insert-code', codeText)
114+
}
115+
}
116+
},
117+
addBtnClickEvents(selector, callback) {
118+
const buttons = this.$refs.textRef.querySelectorAll(selector)
119+
buttons.forEach((btn) => {
120+
btn.addEventListener('click', callback)
121+
})
122+
},
123+
removeBtnClickEvent(selector) {
124+
const buttons = this.$refs.textRef.querySelectorAll(selector)
125+
buttons.forEach((btn) => {
126+
btn.removeEventListener('click', () => {
82127
})
83128
})
84129
},
85-
removeCopyEvents() {
130+
removeEvents() {
86131
if (this.$refs.textRef) {
87-
const copyBtn = this.$refs.textRef.querySelectorAll('.code-block-header__copy')
88-
copyBtn.forEach((btn) => {
89-
btn.removeEventListener('click', () => {
90-
})
91-
})
132+
this.removeBtnClickEvent('.code-block-header__copy')
133+
this.addBtnClickEvents('.code-block-header__insert')
92134
}
93135
}
94136
}
@@ -98,6 +140,7 @@ export default {
98140
<style lang="scss" scoped>
99141
.markdown-body {
100142
font-size: 13px;
143+
max-width: 300px;;
101144
102145
&::v-deep p {
103146
margin-bottom: 0 !important;
@@ -115,26 +158,46 @@ export default {
115158
116159
&::v-deep .code-block-wrapper {
117160
background: #1F2329;
118-
padding: 2px 6px;
161+
padding: 0;
119162
margin: 5px 0;
163+
display: flex;
164+
flex-direction: column;
165+
overflow: hidden;
120166
121167
.code-block-body {
122-
padding: 5px 10px 0;
168+
padding: 5px 10px;
123169
}
124-
;
125170
126171
.code-block-header {
127172
margin-bottom: 4px;
128173
overflow: hidden;
129174
background: #353946;
130175
color: #c2d1e1;
176+
display: flex;
177+
justify-content: space-between;
178+
align-items: center;
179+
padding: 4px 8px;
180+
width: 100%;
181+
box-sizing: border-box;
182+
183+
.code-block-header__actions {
184+
display: flex;
185+
gap: 8px;
186+
187+
.code-block-header__copy {
188+
cursor: pointer;
131189
132-
.code-block-header__copy {
133-
float: right;
134-
cursor: pointer;
190+
&:hover {
191+
color: #6e747b;
192+
}
193+
}
194+
195+
.code-block-header__insert {
196+
cursor: pointer;
135197
136-
&:hover {
137-
color: #6e747b;
198+
&:hover {
199+
color: #6e747b;
200+
}
138201
}
139202
}
140203
}
@@ -178,6 +241,7 @@ export default {
178241
0% {
179242
opacity: 1;
180243
}
244+
181245
100% {
182246
opacity: 0;
183247
}

src/components/Apps/ChatAi/components/ChitChat/index.vue

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</div>
1818
</div>
1919
</div>
20-
<ChatMessage v-for="(item, index) in activeChat.chats" :key="index" :item="item" />
20+
<ChatMessage v-for="(item, index) in activeChat.chats" :key="index" :item="item" :is-terminal="isTerminal" @insert-code="insertCode" />
2121
</div>
2222
<div class="input-box">
2323
<el-button
@@ -28,7 +28,7 @@
2828
size="small"
2929
@click="onStopHandle"
3030
>{{ $tc('Stop') }}</el-button>
31-
<ChatInput ref="chatInput" :expanded="expanded" @send="onSendHandle" @select-prompt="onSelectPromptHandle" />
31+
<ChatInput ref="chatInput" :expanded="expanded" :has-prompt="!isTerminal" @send="onSendHandle" @select-prompt="onSelectPromptHandle" />
3232
</div>
3333
</div>
3434
</template>
@@ -68,7 +68,10 @@ export default {
6868
prompt: '',
6969
conversationId: '',
7070
showIntroduction: false,
71-
introduction: []
71+
introduction: [],
72+
terminalContext: null,
73+
isTerminal: false,
74+
sessionChat: {}
7275
}
7376
},
7477
computed: {
@@ -100,6 +103,9 @@ export default {
100103
this.showIntroduction = true
101104
this.conversationId = ''
102105
this.$refs.chatInput.select.value = ''
106+
if (this.terminalContext) {
107+
this.prompt = this.terminalContext.content || ''
108+
}
103109
const chat = {
104110
message: {
105111
content: this.$t('ChatHello'),
@@ -150,6 +156,32 @@ export default {
150156
addMessageToActiveChat(data)
151157
setLoading(true)
152158
},
159+
onTerminalContext(terminalContext) {
160+
const originSessionId = this.terminalContext?.sessionId
161+
const newSessionId = terminalContext.sessionId || ''
162+
if (originSessionId) {
163+
this.saveSessionChat(originSessionId)
164+
}
165+
this.terminalContext = terminalContext
166+
this.isTerminal = true
167+
this.prompt = terminalContext.content || ''
168+
if (originSessionId !== newSessionId) {
169+
if (this.sessionChat[newSessionId]) {
170+
clearChats()
171+
for (const chat of this.sessionChat[newSessionId]) {
172+
addChatMessageById(chat)
173+
}
174+
} else {
175+
this.onNewChat()
176+
}
177+
}
178+
},
179+
saveSessionChat(sessionId) {
180+
if (this.terminalContext) {
181+
this.sessionChat[sessionId] = JSON.parse(JSON.stringify(this.activeChat.chats))
182+
}
183+
},
184+
153185
onSendHandle(value) {
154186
this.showIntroduction = false
155187
this.socket = ws || {}
@@ -204,6 +236,15 @@ export default {
204236
sendIntroduction(item) {
205237
this.showIntroduction = false
206238
this.onSendHandle(item.content)
239+
},
240+
insertCode(code) {
241+
this.sendPostMessage({
242+
name: 'INSERT_TERMINAL_CODE',
243+
data: code.replace(/^[\s\r\n]+|[\s\r\n]+$/g, '')
244+
})
245+
},
246+
sendPostMessage(data) {
247+
window.parent.postMessage(data)
207248
}
208249
}
209250
}

0 commit comments

Comments
 (0)