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