mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: user input
This commit is contained in:
parent
464890abc5
commit
32dd4b41b6
|
|
@ -29,10 +29,10 @@
|
|||
"cropperjs": "^2.0.0-rc.2",
|
||||
"dingtalk-jsapi": "^3.1.0",
|
||||
"echarts": "^5.6.0",
|
||||
"element-plus": "^2.9.10",
|
||||
"element-plus": "^2.10.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"katex": "^0.16.10",
|
||||
"highlight.js": "^11.11.1",
|
||||
"katex": "^0.16.10",
|
||||
"md-editor-v3": "^5.6.1",
|
||||
"mermaid": "^11.6.0",
|
||||
"moment": "^2.30.1",
|
||||
|
|
|
|||
|
|
@ -169,6 +169,8 @@
|
|||
v-else
|
||||
ref="quickInputRef"
|
||||
v-model="inputValue"
|
||||
:autosize="{ minRows: 1, maxRows: isMobile ? 4 : 10 }"
|
||||
type="textarea"
|
||||
:placeholder="
|
||||
recorderStatus === 'START'
|
||||
? `${$t('chat.inputPlaceholder.speaking')}...`
|
||||
|
|
@ -176,27 +178,17 @@
|
|||
? `${$t('chat.inputPlaceholder.recorderLoading')}...`
|
||||
: $t('chat.inputPlaceholder.default')
|
||||
"
|
||||
:autosize="{ minRows: 1, maxRows: isMobile ? 4 : 10 }"
|
||||
type="textarea"
|
||||
:maxlength="100000"
|
||||
@keydown.enter="sendChatHandle($event)"
|
||||
@paste="handlePaste"
|
||||
@drop="handleDrop"
|
||||
class="chat-operate-textarea"
|
||||
/>
|
||||
|
||||
<div class="operate flex-between">
|
||||
<div>
|
||||
<!-- <el-button
|
||||
v-if="isUserInput || isAPIInput"
|
||||
class="user-input-button mb-8"
|
||||
type="primary"
|
||||
text
|
||||
@click="toggleUserInput"
|
||||
>
|
||||
<AppIcon iconName="app-user-input"></AppIcon>
|
||||
</el-button> -->
|
||||
<slot name="userInput" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<template v-if="props.applicationDetails.stt_model_enable">
|
||||
<span v-if="mode === 'mobile'">
|
||||
|
|
@ -305,6 +297,7 @@ import { ref, computed, onMounted, nextTick, watch, type Ref } from 'vue'
|
|||
import Recorder from 'recorder-core'
|
||||
import TouchChat from './TouchChat.vue'
|
||||
import applicationApi from '@/api/application/application'
|
||||
import UserForm from '@/components/ai-chat/component/user-form/index.vue'
|
||||
import { MsgAlert } from '@/utils/message'
|
||||
import { type chatType } from '@/api/type/application'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
|
@ -329,7 +322,6 @@ const props = withDefaults(
|
|||
isMobile: boolean
|
||||
appId?: string
|
||||
chatId: string
|
||||
showUserInput?: boolean
|
||||
sendMessage: (question: string, other_params_data?: any, chat?: chatType) => void
|
||||
openChatId: () => Promise<string>
|
||||
validate: () => Promise<any>
|
||||
|
|
@ -362,6 +354,31 @@ const localLoading = computed({
|
|||
},
|
||||
})
|
||||
|
||||
const showUserInput = ref(true)
|
||||
const form_data = ref<any>({})
|
||||
const api_form_data = ref<any>({})
|
||||
|
||||
const toggleUserInput = () => {
|
||||
showUserInput.value = !showUserInput.value
|
||||
if (showUserInput.value) {
|
||||
// 保存当前数据作为初始数据(用于可能的恢复)
|
||||
initialFormData.value = JSON.parse(JSON.stringify(form_data.value))
|
||||
initialApiFormData.value = JSON.parse(JSON.stringify(api_form_data.value))
|
||||
}
|
||||
}
|
||||
|
||||
function UserFormConfirm() {
|
||||
showUserInput.value = false
|
||||
}
|
||||
|
||||
function UserFormCancel() {
|
||||
// 恢复初始数据
|
||||
form_data.value = JSON.parse(JSON.stringify(initialFormData.value))
|
||||
api_form_data.value = JSON.parse(JSON.stringify(initialApiFormData.value))
|
||||
userFormRef.value?.render(form_data.value)
|
||||
showUserInput.value = false
|
||||
}
|
||||
|
||||
const upload = ref()
|
||||
|
||||
const imageExtensions = ['JPG', 'JPEG', 'PNG', 'GIF', 'BMP']
|
||||
|
|
@ -807,7 +824,7 @@ function autoSendMessage() {
|
|||
uploadVideoList.value = []
|
||||
uploadOtherList.value = []
|
||||
if (quickInputRef.value) {
|
||||
quickInputRef.value.textareaStyle.height = '45px'
|
||||
quickInputRef.value.textarea.style.height = '45px'
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
@ -901,10 +918,10 @@ onMounted(() => {
|
|||
}, 100)
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (quickInputRef.value && mode === 'embed') {
|
||||
nextTick(() => {
|
||||
quickInputRef.value.textarea.style.height = '0'
|
||||
}
|
||||
}, 1800)
|
||||
})
|
||||
}, 800)
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
|
@ -914,6 +931,7 @@ onMounted(() => {
|
|||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
|
||||
:deep(.operate-textarea) {
|
||||
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
|
||||
background-color: #ffffff;
|
||||
|
|
@ -931,6 +949,8 @@ onMounted(() => {
|
|||
resize: none;
|
||||
padding: 13px 16px;
|
||||
box-sizing: border-box;
|
||||
min-height: 47px !important;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.operate {
|
||||
|
|
@ -986,4 +1006,12 @@ onMounted(() => {
|
|||
}
|
||||
}
|
||||
}
|
||||
.popperUserInput {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
left: 0;
|
||||
bottom: 50px;
|
||||
width: calc(100% - 50px);
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -8,51 +8,43 @@
|
|||
>
|
||||
<el-card shadow="always" class="border-r-8" style="--el-card-padding: 16px 8px">
|
||||
<div class="flex align-center cursor w-full" style="padding: 0 8px">
|
||||
<!-- <el-icon class="mr-8 arrow-icon" :class="showUserInput ? 'rotate-90' : ''"
|
||||
><CaretRight
|
||||
/></el-icon> -->
|
||||
<span class="break-all ellipsis-1 mr-16" :title="inputFieldConfig.title">
|
||||
{{ inputFieldConfig.title }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<el-scrollbar :max-height="first ? 0 : 450">
|
||||
<el-collapse-transition>
|
||||
<div
|
||||
v-show="showUserInput"
|
||||
class="mt-16"
|
||||
style="padding: 0 8px; height: calc(100% - 100px)"
|
||||
>
|
||||
<DynamicsForm
|
||||
:key="dynamicsFormRefresh"
|
||||
v-model="form_data_context"
|
||||
:model="form_data_context"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
:render_data="inputFieldList"
|
||||
ref="dynamicsFormRef"
|
||||
/>
|
||||
<DynamicsForm
|
||||
v-if="type === 'debug-ai-chat'"
|
||||
v-model="api_form_data_context"
|
||||
:model="api_form_data_context"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
:render_data="apiInputFieldList"
|
||||
ref="dynamicsFormRef2"
|
||||
/>
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
<div class="mt-16" style="padding: 0 8px; height: calc(100% - 100px)">
|
||||
<DynamicsForm
|
||||
:key="dynamicsFormRefresh"
|
||||
v-model="form_data_context"
|
||||
:model="form_data_context"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
:render_data="inputFieldList"
|
||||
ref="dynamicsFormRef"
|
||||
/>
|
||||
<DynamicsForm
|
||||
v-if="type === 'debug-ai-chat'"
|
||||
v-model="api_form_data_context"
|
||||
:model="api_form_data_context"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
:render_data="apiInputFieldList"
|
||||
ref="dynamicsFormRef2"
|
||||
/>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
|
||||
<div class="text-right mr-8">
|
||||
<el-button type="primary" v-if="first" @click="confirmHandle">{{
|
||||
$t('chat.operation.startChat')
|
||||
}}</el-button>
|
||||
<el-button v-if="!first" @click="cancelHandle">{{ $t('common.cancel') }}</el-button>
|
||||
<div class="text-left ml-8">
|
||||
<el-button type="primary" class="w-full" v-if="first" @click="confirmHandle">
|
||||
<AppIcon iconName="app-chat" class="mr-4"></AppIcon>
|
||||
{{ $t('chat.operation.startChat') }}</el-button
|
||||
>
|
||||
<el-button type="primary" v-if="!first" @click="confirmHandle">{{
|
||||
$t('common.confirm')
|
||||
}}</el-button>
|
||||
<el-button v-if="!first" @click="cancelHandle">{{ $t('common.cancel') }}</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
|
@ -66,21 +58,20 @@ import { MsgWarning } from '@/utils/message'
|
|||
import { t } from '@/locales'
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { accessToken }
|
||||
params: { accessToken },
|
||||
} = route
|
||||
const props = defineProps<{
|
||||
application: any
|
||||
type: 'log' | 'ai-chat' | 'debug-ai-chat'
|
||||
api_form_data: any
|
||||
form_data: any
|
||||
first: boolean
|
||||
first?: boolean
|
||||
}>()
|
||||
// 用于刷新动态表单
|
||||
const dynamicsFormRefresh = ref(0)
|
||||
const inputFieldList = ref<FormField[]>([])
|
||||
const apiInputFieldList = ref<FormField[]>([])
|
||||
const inputFieldConfig = ref({ title: t('chat.userInput') })
|
||||
const showUserInput = ref(true)
|
||||
const firstMounted = ref(false)
|
||||
|
||||
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
||||
|
|
@ -94,7 +85,7 @@ const api_form_data_context = computed({
|
|||
},
|
||||
set: (data) => {
|
||||
emit('update:api_form_data', data)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const form_data_context = computed({
|
||||
|
|
@ -103,14 +94,14 @@ const form_data_context = computed({
|
|||
},
|
||||
set: (data) => {
|
||||
emit('update:form_data', data)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.application,
|
||||
(data) => {
|
||||
handleInputFieldList()
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
function handleInputFieldList() {
|
||||
|
|
@ -128,7 +119,7 @@ function handleInputFieldList() {
|
|||
input_type: 'TextInput',
|
||||
label: v.name,
|
||||
default_value: default_value[v.variable],
|
||||
required: v.is_required
|
||||
required: v.is_required,
|
||||
}
|
||||
case 'select':
|
||||
return {
|
||||
|
|
@ -139,7 +130,7 @@ function handleInputFieldList() {
|
|||
required: v.is_required,
|
||||
option_list: v.optionList.map((o: any) => {
|
||||
return { key: o, value: o }
|
||||
})
|
||||
}),
|
||||
}
|
||||
case 'date':
|
||||
return {
|
||||
|
|
@ -151,8 +142,8 @@ function handleInputFieldList() {
|
|||
attrs: {
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
||||
type: 'datetime'
|
||||
}
|
||||
type: 'datetime',
|
||||
},
|
||||
}
|
||||
default:
|
||||
return v
|
||||
|
|
@ -169,7 +160,7 @@ function handleInputFieldList() {
|
|||
input_type: 'TextInput',
|
||||
label: v.name,
|
||||
default_value: default_value[v.variable],
|
||||
required: v.is_required
|
||||
required: v.is_required,
|
||||
}
|
||||
case 'select':
|
||||
return {
|
||||
|
|
@ -180,7 +171,7 @@ function handleInputFieldList() {
|
|||
required: v.is_required,
|
||||
option_list: v.optionList.map((o: any) => {
|
||||
return { key: o, value: o }
|
||||
})
|
||||
}),
|
||||
}
|
||||
case 'date':
|
||||
return {
|
||||
|
|
@ -192,8 +183,8 @@ function handleInputFieldList() {
|
|||
attrs: {
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
||||
type: 'datetime'
|
||||
}
|
||||
type: 'datetime',
|
||||
},
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
|
@ -210,7 +201,7 @@ function handleInputFieldList() {
|
|||
input_type: 'TextInput',
|
||||
label: v.variable,
|
||||
default_value: v.default_value || default_value[v.variable],
|
||||
required: v.is_required
|
||||
required: v.is_required,
|
||||
}
|
||||
case 'select':
|
||||
return {
|
||||
|
|
@ -221,7 +212,7 @@ function handleInputFieldList() {
|
|||
required: v.is_required,
|
||||
option_list: v.optionList.map((o: any) => {
|
||||
return { key: o, value: o }
|
||||
})
|
||||
}),
|
||||
}
|
||||
case 'date':
|
||||
return {
|
||||
|
|
@ -233,8 +224,8 @@ function handleInputFieldList() {
|
|||
attrs: {
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
||||
type: 'datetime'
|
||||
}
|
||||
type: 'datetime',
|
||||
},
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
|
@ -251,7 +242,7 @@ function handleInputFieldList() {
|
|||
input_type: 'TextInput',
|
||||
label: v.name,
|
||||
default_value: default_value[v.variable],
|
||||
required: v.is_required
|
||||
required: v.is_required,
|
||||
}
|
||||
case 'select':
|
||||
return {
|
||||
|
|
@ -262,7 +253,7 @@ function handleInputFieldList() {
|
|||
required: v.is_required,
|
||||
option_list: v.optionList.map((o: any) => {
|
||||
return { key: o, value: o }
|
||||
})
|
||||
}),
|
||||
}
|
||||
case 'date':
|
||||
return {
|
||||
|
|
@ -274,8 +265,8 @@ function handleInputFieldList() {
|
|||
attrs: {
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
||||
type: 'datetime'
|
||||
}
|
||||
type: 'datetime',
|
||||
},
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
|
@ -329,7 +320,7 @@ const validate_query = () => {
|
|||
}
|
||||
if (msg.length > 0) {
|
||||
MsgWarning(
|
||||
`${t('chat.tip.inputParamMessage1')} ${msg.join('、')}${t('chat.tip.inputParamMessage2')}`
|
||||
`${t('chat.tip.inputParamMessage1')} ${msg.join('、')}${t('chat.tip.inputParamMessage2')}`,
|
||||
)
|
||||
return Promise.reject(false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,9 +77,17 @@
|
|||
v-if="type !== 'log'"
|
||||
>
|
||||
<template #operateBefore>
|
||||
<slot name="operateBefore">
|
||||
<span></span>
|
||||
</slot>
|
||||
<slot name="operateBefore"> </slot>
|
||||
</template>
|
||||
<template #userInput>
|
||||
<el-button
|
||||
v-if="isUserInput || isAPIInput"
|
||||
class="user-input-button mb-8"
|
||||
@click="toggleUserInput"
|
||||
>
|
||||
<el-icon :size="16" class="mr-4"><EditPen /></el-icon>
|
||||
{{ $t('chat.userInput') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</ChatInputOperate>
|
||||
|
||||
|
|
@ -647,8 +655,8 @@ defineExpose({
|
|||
.popperUserInput {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
right: 50px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
bottom: 50px;
|
||||
width: calc(100% - 50px);
|
||||
max-width: 400px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -550,4 +550,25 @@ export default {
|
|||
])
|
||||
},
|
||||
},
|
||||
'app-chat': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
style: { height: '100%', width: '100%' },
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M512 64c247.424 0 448 200.576 448 448S759.424 960 512 960H106.666667a42.666667 42.666667 0 0 1-42.666667-42.666667V512C64 264.576 264.576 64 512 64z m-362.666667 810.666667H512A362.666667 362.666667 0 1 0 149.333333 512v362.666667z m170.666667-298.666667h213.333333a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333h-213.333333A21.333333 21.333333 0 0 1 298.666667 640v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333z m0-170.666667h384a21.333333 21.333333 0 0 1 21.333333 21.333334v42.666666a21.333333 21.333333 0 0 1-21.333333 21.333334h-384A21.333333 21.333333 0 0 1 298.666667 469.333333v-42.666666a21.333333 21.333333 0 0 1 21.333333-21.333334z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ interface ChatUser {
|
|||
// 用户id
|
||||
id: string
|
||||
}
|
||||
interface Application {}
|
||||
interface Chat {
|
||||
chat_profile?: ChatProfile
|
||||
application?: Application
|
||||
chatUserProfile?: ChatUserProfile
|
||||
application?: any
|
||||
chatUserProfile?: ChatUserProfile
|
||||
token?: string
|
||||
accessToken?: string
|
||||
}
|
||||
|
|
@ -28,6 +27,7 @@ const useChatUserStore = defineStore('chat-user', {
|
|||
getChatProfile() {
|
||||
return ChatAPI.chatProfile(this.accessToken as string).then((ok) => {
|
||||
this.chat_profile = ok.data
|
||||
|
||||
return this.chat_profile
|
||||
})
|
||||
},
|
||||
|
|
@ -38,6 +38,8 @@ const useChatUserStore = defineStore('chat-user', {
|
|||
applicationProfile() {
|
||||
return ChatAPI.applicationProfile().then((ok) => {
|
||||
this.application = ok.data
|
||||
this.application['custom_theme']['theme_color'] =
|
||||
ok.data?.custom_theme.theme_color || '#3370FF'
|
||||
})
|
||||
},
|
||||
isAuthentication() {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ const useThemeStore = defineStore('theme', {
|
|||
|
||||
setTheme(data?: any) {
|
||||
const { changeTheme } = useElementPlusTheme(this.themeInfo?.theme || defalueColor)
|
||||
changeTheme(defalueColor)
|
||||
changeTheme(data?.['theme'])
|
||||
changeTheme(data?.['theme'] || defalueColor)
|
||||
this.themeInfo = cloneDeep(data)
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import type { User } from '@/api/type/user'
|
|||
import UserApi from '@/api/user/user'
|
||||
import LoginApi from '@/api/user/login'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import ThemeApi from '@/api/system-settings/theme'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
// import { defaultPlatformSetting } from '@/utils/theme'
|
||||
|
||||
|
|
@ -141,6 +140,7 @@ const useUserStore = defineStore('user', {
|
|||
theme.themeInfo = {
|
||||
...defaultPlatformSetting,
|
||||
}
|
||||
theme.setTheme()
|
||||
}
|
||||
resolve(ok)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
<el-row class="not-found-container">
|
||||
<el-col class="img" :xs="0" :sm="0" :md="12" :lg="12" :xl="12"> </el-col>
|
||||
<el-col class="message-container" :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
|
||||
<div class="title">{{ $t('views.common.notFound.title') }}</div>
|
||||
<div class="message">{{ $t('views.common.notFound.message') }}</div>
|
||||
<div class="title">{{ $t('common.notFound.title') }}</div>
|
||||
<div class="message">{{ $t('common.notFound.message') }}</div>
|
||||
<!-- TODO 暂时不处理 -->
|
||||
<!-- <div class="operate"><el-button type="primary" @click="router.push('/')">{{ $t('views.notFound.operate') }}</el-button></div> -->
|
||||
</el-col>
|
||||
|
|
|
|||
|
|
@ -30,14 +30,5 @@ const is_auth = computed({
|
|||
emit('update:modelValue', v)
|
||||
},
|
||||
})
|
||||
|
||||
const customStyle = computed(() => {
|
||||
return {
|
||||
background: props.application_profile?.custom_theme?.theme_color,
|
||||
color: props.application_profile?.custom_theme?.header_font_color,
|
||||
border: 'none',
|
||||
...props.style,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
|
|||
|
|
@ -4,29 +4,41 @@
|
|||
:class="classObj"
|
||||
v-loading="loading"
|
||||
:style="{
|
||||
'--el-color-primary': applicationDetail?.custom_theme?.theme_color,
|
||||
'--el-color-primary-light-9': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.1),
|
||||
'--el-color-primary': applicationDetail?.custom_theme?.theme_color,
|
||||
'--el-color-primary-light-9': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.1),
|
||||
}"
|
||||
>
|
||||
<div class="flex h-full w-full">
|
||||
<div class="chat-pc__left">
|
||||
<el-menu class="w-full h-full" :default-active="currentChatId" :collapse="isPcCollapse" collapse-transition popper-class="chat-pc-popper">
|
||||
<div style="padding: 16px 18px 0 18px;">
|
||||
<el-menu
|
||||
class="w-full h-full"
|
||||
:default-active="currentChatId"
|
||||
:collapse="isPcCollapse"
|
||||
collapse-transition
|
||||
popper-class="chat-pc-popper"
|
||||
>
|
||||
<div style="padding: 16px 18px 0 18px">
|
||||
<div class="flex align-center mb-16">
|
||||
<div class="flex">
|
||||
<el-avatar
|
||||
v-if="isAppIcon(applicationDetail?.icon)"
|
||||
shape="square"
|
||||
:size="32"
|
||||
style="background: none"
|
||||
>
|
||||
<div class="flex mr-8">
|
||||
<el-avatar
|
||||
v-if="isAppIcon(applicationDetail?.icon)"
|
||||
shape="square"
|
||||
:size="32"
|
||||
style="background: none"
|
||||
>
|
||||
<img :src="applicationDetail?.icon" alt="" />
|
||||
</el-avatar>
|
||||
<LogoIcon v-else height="32px" />
|
||||
</div>
|
||||
<h4 v-show="!isPcCollapse">{{ applicationDetail?.name }}</h4>
|
||||
</div>
|
||||
<el-button v-show="!isPcCollapse" class="add-button w-full primary" @click="newChat">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
v-show="!isPcCollapse"
|
||||
class="add-button w-full primary"
|
||||
@click="newChat"
|
||||
>
|
||||
<AppIcon iconName="app-create-chat"></AppIcon>
|
||||
<span class="ml-4">{{ $t('chat.createChat') }}</span>
|
||||
</el-button>
|
||||
|
|
@ -37,11 +49,11 @@
|
|||
<div class="p-8 pt-0">
|
||||
<common-list
|
||||
:style="{
|
||||
'--el-color-primary': applicationDetail?.custom_theme?.theme_color,
|
||||
'--el-color-primary-light-9': hexToRgba(
|
||||
applicationDetail?.custom_theme?.theme_color,
|
||||
0.1,
|
||||
),
|
||||
'--el-color-primary': applicationDetail?.custom_theme?.theme_color,
|
||||
'--el-color-primary-light-9': hexToRgba(
|
||||
applicationDetail?.custom_theme?.theme_color,
|
||||
0.1,
|
||||
),
|
||||
}"
|
||||
:data="chatLogData"
|
||||
class="mt-8"
|
||||
|
|
@ -99,8 +111,15 @@
|
|||
</el-icon>
|
||||
</template>
|
||||
<el-menu-item-group v-loading="left_loading">
|
||||
<template #title><span>{{ $t('chat.history') }}</span></template>
|
||||
<el-menu-item v-for="row in chatLogData" :index="row.id" :key="row.id" @click="clickListHandle(row)">
|
||||
<template #title
|
||||
><span>{{ $t('chat.history') }}</span></template
|
||||
>
|
||||
<el-menu-item
|
||||
v-for="row in chatLogData"
|
||||
:index="row.id"
|
||||
:key="row.id"
|
||||
@click="clickListHandle(row)"
|
||||
>
|
||||
<div class="flex-between w-full lighter">
|
||||
<span :title="row.abstract">
|
||||
{{ row.abstract }}
|
||||
|
|
@ -146,12 +165,14 @@
|
|||
<el-avatar :size="32">
|
||||
<img src="@/assets/user-icon.svg" style="width: 54%" alt="" />
|
||||
</el-avatar>
|
||||
<span v-show="!isPcCollapse" class="ml-8 color-text-primary">{{ chatUser.chatUserProfile?.nick_name }}</span>
|
||||
<span v-show="!isPcCollapse" class="ml-8 color-text-primary">{{
|
||||
chatUser.chatUserProfile?.nick_name
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="avatar-dropdown">
|
||||
<div class="flex align-center" style="padding: 8px 12px;">
|
||||
<div class="flex align-center" style="padding: 8px 12px">
|
||||
<div class="mr-8 flex align-center">
|
||||
<el-avatar :size="40">
|
||||
<img src="@/assets/user-icon.svg" style="width: 54%" alt="" />
|
||||
|
|
@ -159,26 +180,41 @@
|
|||
</div>
|
||||
<div>
|
||||
<h4 class="medium mb-4">{{ chatUser.chatUserProfile?.nick_name }}</h4>
|
||||
<div class="color-secondary">{{ `${t('common.username')}: ${chatUser.chatUserProfile?.username}` }}</div>
|
||||
<div class="color-secondary">
|
||||
{{ `${t('common.username')}: ${chatUser.chatUserProfile?.username}` }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dropdown-item v-if="chatUser.chatUserProfile?.source === 'LOCAL'" class="border-t" style="padding-top: 8px; padding-bottom: 8px;" @click="openResetPassword">
|
||||
<el-dropdown-item
|
||||
v-if="chatUser.chatUserProfile?.source === 'LOCAL'"
|
||||
class="border-t"
|
||||
style="padding-top: 8px; padding-bottom: 8px"
|
||||
@click="openResetPassword"
|
||||
>
|
||||
<AppIcon iconName="app-export" />
|
||||
{{ $t('views.login.resetPassword') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="chatUser.chatUserProfile?.source === 'LOCAL'" class="border-t" style="padding-top: 8px; padding-bottom: 8px;" @click="logout">
|
||||
<el-dropdown-item
|
||||
v-if="chatUser.chatUserProfile?.source === 'LOCAL'"
|
||||
class="border-t"
|
||||
style="padding-top: 8px; padding-bottom: 8px"
|
||||
@click="logout"
|
||||
>
|
||||
<AppIcon iconName="app-export" />
|
||||
{{ $t('layout.logout') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
</el-menu>
|
||||
<el-button v-if="!common.isMobile()" class="pc-collapse" circle size="small"
|
||||
@click="isPcCollapse = !isPcCollapse">
|
||||
<el-button
|
||||
v-if="!common.isMobile()"
|
||||
class="pc-collapse cursor"
|
||||
circle
|
||||
@click="isPcCollapse = !isPcCollapse"
|
||||
>
|
||||
<el-icon>
|
||||
<component :is="isPcCollapse ? 'Fold' : 'Expand'" />
|
||||
<component :is="isPcCollapse ? 'ArrowRightBold' : 'ArrowLeftBold'" />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
|
@ -237,14 +273,25 @@
|
|||
</AiChat>
|
||||
</div>
|
||||
</el-splitter-panel>
|
||||
<el-splitter-panel class="execution-detail-panel" v-model:size="rightPanelSize" :resizable="false" collapsible>
|
||||
<el-splitter-panel
|
||||
class="execution-detail-panel"
|
||||
v-model:size="rightPanelSize"
|
||||
:resizable="false"
|
||||
collapsible
|
||||
>
|
||||
<div class="p-16 flex-between border-b">
|
||||
<h4 class="medium">{{ rightPanelTitle }}</h4>
|
||||
<el-icon size="20" class="cursor" @click="closeExecutionDetail"><Close /></el-icon>
|
||||
</div>
|
||||
<div class="execution-detail-content" v-loading="rightPanelLoading">
|
||||
<ParagraphSourceContent v-if="rightPanelType === 'knowledgeSource'" :detail="rightPanelDetail" />
|
||||
<ExecutionDetailContent v-if="rightPanelType === 'executionDetail'" :detail="executionDetail" />
|
||||
<ParagraphSourceContent
|
||||
v-if="rightPanelType === 'knowledgeSource'"
|
||||
:detail="rightPanelDetail"
|
||||
/>
|
||||
<ExecutionDetailContent
|
||||
v-if="rightPanelType === 'executionDetail'"
|
||||
:detail="executionDetail"
|
||||
/>
|
||||
</div>
|
||||
</el-splitter-panel>
|
||||
</el-splitter>
|
||||
|
|
@ -257,7 +304,11 @@
|
|||
</div>
|
||||
|
||||
<EditTitleDialog ref="EditTitleDialogRef" @refresh="refreshFieldTitle" />
|
||||
<ResetPassword ref="resetPasswordRef" emitConfirm @confirm="handleResetPassword"></ResetPassword>
|
||||
<ResetPassword
|
||||
ref="resetPasswordRef"
|
||||
emitConfirm
|
||||
@confirm="handleResetPassword"
|
||||
></ResetPassword>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -288,11 +339,14 @@ const EditTitleDialogRef = ref()
|
|||
|
||||
const isCollapse = ref(false)
|
||||
const isPcCollapse = ref(false)
|
||||
watch(() => common.device, () => {
|
||||
if (common.isMobile()) {
|
||||
isPcCollapse.value = false
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => common.device,
|
||||
() => {
|
||||
if (common.isMobile()) {
|
||||
isPcCollapse.value = false
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
const logout = () => {
|
||||
chatUser.logout().then(() => {
|
||||
|
|
@ -550,7 +604,7 @@ async function openExecutionDetail(row: any) {
|
|||
}
|
||||
}
|
||||
|
||||
async function openKnowledgeSource (row: any) {
|
||||
async function openKnowledgeSource(row: any) {
|
||||
rightPanelTitle.value = t('chat.KnowledgeSource.title')
|
||||
rightPanelType.value = 'knowledgeSource'
|
||||
// TODO 数据
|
||||
|
|
@ -617,13 +671,12 @@ function closeExecutionDetail() {
|
|||
margin: 16px;
|
||||
box-sizing: border-box;
|
||||
&:hover {
|
||||
background-color: #1F23291A;
|
||||
background-color: #1f23291a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.el-menu--collapse {
|
||||
|
||||
.el-menu-item,
|
||||
.el-menu-tooltip__trigger,
|
||||
.el-sub-menu__title {
|
||||
|
|
@ -643,7 +696,7 @@ function closeExecutionDetail() {
|
|||
|
||||
.el-menu-item:hover .el-menu-tooltip__trigger,
|
||||
.el-sub-menu__title:hover {
|
||||
background-color: #1F23291A;
|
||||
background-color: #1f23291a;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
|
|
@ -663,8 +716,8 @@ function closeExecutionDetail() {
|
|||
.pc-collapse {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: -12px;
|
||||
box-shadow: 0px 5px 10px 0px #1F23291A;
|
||||
right: -15px;
|
||||
box-shadow: 0px 5px 10px 0px #1f23291a;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -678,7 +731,8 @@ function closeExecutionDetail() {
|
|||
height: calc(100vh - 85px);
|
||||
}
|
||||
|
||||
.el-splitter-bar__collapse-icon, .el-splitter-bar__dragger {
|
||||
.el-splitter-bar__collapse-icon,
|
||||
.el-splitter-bar__dragger {
|
||||
display: none;
|
||||
}
|
||||
.execution-detail-panel {
|
||||
|
|
@ -741,10 +795,10 @@ function closeExecutionDetail() {
|
|||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
&:hover {
|
||||
background-color: #1F23291A;
|
||||
background-color: #1f23291a;
|
||||
}
|
||||
&.is-active {
|
||||
background-color: #3370FF1A;
|
||||
background-color: #3370ff1a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ export default defineConfig((conf: any) => {
|
|||
const ENV = loadEnv(mode, envDir)
|
||||
const proxyConf: Record<string, string | ProxyOptions> = {}
|
||||
proxyConf['/admin/api'] = {
|
||||
//target: 'http://47.92.195.88:8080/',
|
||||
target: 'http://127.0.0.1:8080',
|
||||
target: 'http://47.92.195.88:8080/',
|
||||
// target: 'http://127.0.0.1:8080',
|
||||
changeOrigin: true,
|
||||
}
|
||||
proxyConf['/oss'] = {
|
||||
|
|
@ -46,6 +46,7 @@ export default defineConfig((conf: any) => {
|
|||
rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
|
||||
}
|
||||
proxyConf['/chat/api'] = {
|
||||
// target: 'http://47.92.195.88:8080/',
|
||||
target: 'http://127.0.0.1:8080',
|
||||
changeOrigin: true,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue