feat: style

v3.2
wangdan-fit2cloud 2025-07-10 22:33:39 +08:00
parent f83336df8c
commit 4437361eed
30 changed files with 567 additions and 522 deletions

View File

@ -240,8 +240,8 @@ function initMaxkbStyle(root, maxkbId){
} }
#maxkb-chat-container { #maxkb-chat-container {
width: 450px; width: 460px;
height: 600px; height: 680px;
display:none; display:none;
} }
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {

View File

@ -1,48 +0,0 @@
import { Result } from '@/request/Result'
import { get, put } from '@/request/index'
import useStore from '@/stores'
import { type Ref } from 'vue'
const prefix: any = { _value: '/workspace/' }
Object.defineProperty(prefix, 'value', {
get: function () {
const { user } = useStore()
return this._value + user.getWorkspaceId() + '/application'
},
})
/**
* -AccessToken
* @param application_id
*/
const getAccessToken: (application_id: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
application_id,
loading,
) => {
return get(`${prefix.value}/${application_id}/setting`, undefined, loading)
}
/**
* -AccessToken
* @param application_id
* data {
* "show_source": boolean,
* "show_history": boolean,
* "draggable": boolean,
* "show_guide": boolean,
* "avatar": file,
* "float_icon": file,
* }
*/
const putAccessToken: (
application_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, data, loading) => {
return put(`${prefix.value}/${application_id}/setting`, data, undefined, loading)
}
export default {
getAccessToken,
putAccessToken,
}

View File

@ -120,6 +120,27 @@ const putAccessToken: (
return put(`${prefix.value}/${application_id}/access_token`, data, undefined, loading) return put(`${prefix.value}/${application_id}/access_token`, data, undefined, loading)
} }
/**
* -AccessToken
* @param application_id
* data {
* "show_source": boolean,
* "show_history": boolean,
* "draggable": boolean,
* "show_guide": boolean,
* "avatar": file,
* "float_icon": file,
* }
*/
const putXpackAccessToken: (
application_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, data, loading) => {
return put(`${prefix.value}/${application_id}/setting`, data, undefined, loading)
}
/** /**
* *
*/ */
@ -331,6 +352,7 @@ export default {
getApplicationDetail, getApplicationDetail,
getAccessToken, getAccessToken,
putAccessToken, putAccessToken,
putXpackAccessToken,
exportApplication, exportApplication,
importApplication, importApplication,
getStatistics, getStatistics,

View File

@ -42,6 +42,7 @@
<!-- 知识来源 --> <!-- 知识来源 -->
<KnowledgeSourceComponent <KnowledgeSourceComponent
:data="chatRecord" :data="chatRecord"
:application="application"
:type="application.type" :type="application.type"
:executionIsRightPanel="props.executionIsRightPanel" :executionIsRightPanel="props.executionIsRightPanel"
@open-execution-detail="emit('openExecutionDetail')" @open-execution-detail="emit('openExecutionDetail')"
@ -90,8 +91,6 @@ const props = defineProps<{
executionIsRightPanel?: boolean executionIsRightPanel?: boolean
}>() }>()
const { user } = useStore()
const emit = defineEmits([ const emit = defineEmits([
'update:chatRecord', 'update:chatRecord',
'openExecutionDetail', 'openExecutionDetail',
@ -100,10 +99,10 @@ const emit = defineEmits([
]) ])
const showAvatar = computed(() => { const showAvatar = computed(() => {
return user.isEE() || user.isPE() ? props.application.show_avatar : true return props.application.show_avatar == undefined ? true : props.application.show_avatar
}) })
const showUserAvatar = computed(() => { const showUserAvatar = computed(() => {
return user.isEE() || user.isPE() ? props.application.show_user_avatar : true return props.application.show_user_avatar == undefined ? true : props.application.show_user_avatar
}) })
const chatMessage = (question: string, type: 'old' | 'new', other_params_data?: any) => { const chatMessage = (question: string, type: 'old' | 'new', other_params_data?: any) => {
if (type === 'old') { if (type === 'old') {
@ -150,7 +149,11 @@ function showSource(row: any) {
if (props.type === 'log') { if (props.type === 'log') {
return true return true
} else if (row.write_ed && 500 !== row.status) { } else if (row.write_ed && 500 !== row.status) {
if (props.type === 'debug-ai-chat' || props.application?.show_source) { if (
props.type === 'debug-ai-chat' ||
props.application?.show_source ||
props.application?.show_exec
) {
return true return true
} }
} }

View File

@ -193,7 +193,7 @@
> >
<div class="card-never border-r-6" v-if="item.type !== WorkflowType.Application"> <div class="card-never border-r-6" v-if="item.type !== WorkflowType.Application">
<h5 class="p-8-12"> <h5 class="p-8-12">
{{ $t('views.application.applicationForm.form.roleSettings.label') }} {{ $t('views.application.form.roleSettings.label') }}
</h5> </h5>
<div class="p-8-12 border-t-dashed lighter"> <div class="p-8-12 border-t-dashed lighter">
{{ item.system || '-' }} {{ item.system || '-' }}
@ -503,7 +503,7 @@
<template v-if="item.type == WorkflowType.ImageUnderstandNode"> <template v-if="item.type == WorkflowType.ImageUnderstandNode">
<div class="card-never border-r-6" v-if="item.type !== WorkflowType.Application"> <div class="card-never border-r-6" v-if="item.type !== WorkflowType.Application">
<h5 class="p-8-12"> <h5 class="p-8-12">
{{ $t('views.application.applicationForm.form.roleSettings.label') }} {{ $t('views.application.form.roleSettings.label') }}
</h5> </h5>
<div class="p-8-12 border-t-dashed lighter"> <div class="p-8-12 border-t-dashed lighter">
{{ item.system || '-' }} {{ item.system || '-' }}

View File

@ -6,7 +6,7 @@
<ParagraphCard :data="item" :content="item.content" :index="index" /> <ParagraphCard :data="item" :content="item.content" :index="index" />
</template> </template>
</div> </div>
<span v-else> - </span> <span v-else> {{ $t('chat.KnowledgeSource.noSource') }}</span>
</div> </div>
</el-scrollbar> </el-scrollbar>
</template> </template>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="chat-knowledge-source"> <div class="chat-knowledge-source">
<div class="flex align-center mt-16"> <div class="flex align-center mt-16" v-if="application.show_source">
<span class="mr-4 color-secondary">{{ $t('chat.KnowledgeSource.title') }}</span> <span class="mr-4 color-secondary">{{ $t('chat.KnowledgeSource.title') }}</span>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button type="primary" class="mr-8" link @click="openParagraph(data)"> <el-button type="primary" class="mr-8" link @click="openParagraph(data)">
@ -9,7 +9,7 @@
{{ data.paragraph_list?.length || 0 }}</el-button {{ data.paragraph_list?.length || 0 }}</el-button
> >
</div> </div>
<div class="mt-8"> <div class="mt-8" v-if="application.show_source">
<el-row :gutter="8" v-if="uniqueParagraphList?.length"> <el-row :gutter="8" v-if="uniqueParagraphList?.length">
<template v-for="(item, index) in uniqueParagraphList" :key="index"> <template v-for="(item, index) in uniqueParagraphList" :key="index">
<el-col :span="12" class="mb-8"> <el-col :span="12" class="mb-8">
@ -44,6 +44,7 @@
</div> </div>
<div <div
v-if="application.show_exec"
class="execution-details border-t color-secondary flex-between mt-12" class="execution-details border-t color-secondary flex-between mt-12"
style="padding-top: 12px; padding-bottom: 8px" style="padding-top: 12px; padding-bottom: 8px"
> >
@ -104,6 +105,10 @@ const props = defineProps({
type: Boolean, type: Boolean,
required: false, required: false,
}, },
application: {
type: Object,
default: () => {},
},
}) })
const emit = defineEmits(['openExecutionDetail', 'openParagraph', 'openParagraphDocument']) const emit = defineEmits(['openExecutionDetail', 'openParagraph', 'openParagraphDocument'])

View File

@ -9,7 +9,7 @@
class="content" class="content"
v-if="prologue" v-if="prologue"
:style="{ :style="{
'padding-right': showUserAvatar ? 'var(--padding-left)' : '0' 'padding-right': showUserAvatar ? 'var(--padding-left)' : '0',
}" }"
> >
<el-card shadow="always" class="border-r-8" style="--el-card-padding: 10px 16px 12px"> <el-card shadow="always" class="border-r-8" style="--el-card-padding: 10px 16px 12px">
@ -35,13 +35,12 @@ const props = defineProps<{
sendMessage: (question: string, other_params_data?: any, chat?: chatType) => void sendMessage: (question: string, other_params_data?: any, chat?: chatType) => void
}>() }>()
const { user } = useStore()
const showAvatar = computed(() => { const showAvatar = computed(() => {
return (user.isEE() || user.isPE()) ? props.application.show_avatar : true return props.application.show_avatar == undefined ? true : props.application.show_avatar
}) })
const showUserAvatar = computed(() => { const showUserAvatar = computed(() => {
return user.isEE() || user.isPE() ? props.application.show_user_avatar : true return props.application.show_user_avatar == undefined ? true : props.application.show_user_avatar
}) })
const toQuickQuestion = (match: string, offset: number, input: string) => { const toQuickQuestion = (match: string, offset: number, input: string) => {
@ -54,7 +53,7 @@ const prologue = computed(() => {
/<html_rander>[\d\D]*?<\/html_rander>/g, /<html_rander>[\d\D]*?<\/html_rander>/g,
/<echarts_rander>[\d\D]*?<\/echarts_rander>/g, /<echarts_rander>[\d\D]*?<\/echarts_rander>/g,
/<quick_question>[\d\D]*?<\/quick_question>/g, /<quick_question>[\d\D]*?<\/quick_question>/g,
/<form_rander>[\d\D]*?<\/form_rander>/g /<form_rander>[\d\D]*?<\/form_rander>/g,
] ]
let _temp = temp let _temp = temp
for (const index in tag_list) { for (const index in tag_list) {

View File

@ -106,10 +106,8 @@ const props = defineProps<{
type: 'log' | 'ai-chat' | 'debug-ai-chat' type: 'log' | 'ai-chat' | 'debug-ai-chat'
}>() }>()
const { user } = useStore()
const showAvatar = computed(() => { const showAvatar = computed(() => {
return user.isEE() || user.isPE() ? props.application.show_user_avatar : true return props.application.show_avatar == undefined ? true : props.application.show_avatar
}) })
const document_list = computed(() => { const document_list = computed(() => {

View File

@ -86,7 +86,9 @@
@click="toggleUserInput" @click="toggleUserInput"
> >
<el-icon :size="16" class="mr-4"><EditPen /></el-icon> <el-icon :size="16" class="mr-4"><EditPen /></el-icon>
{{ $t('chat.userInput') }} <span class="ellipsis">
{{ userInputTitle || $t('chat.userInput') }}
</span>
</el-button> </el-button>
</template> </template>
</ChatInputOperate> </ChatInputOperate>
@ -171,6 +173,12 @@ const isUserInput = computed(
props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0] props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0]
.properties.user_input_field_list.length > 0, .properties.user_input_field_list.length > 0,
) )
const userInputTitle = computed(
() =>
props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0]
.properties?.user_input_config?.title,
)
const isAPIInput = computed( const isAPIInput = computed(
() => () =>
props.type === 'debug-ai-chat' && props.type === 'debug-ai-chat' &&
@ -543,7 +551,7 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
if (props.chatId === 'new') { if (props.chatId === 'new') {
emit('refresh', chartOpenId.value) emit('refresh', chartOpenId.value)
} }
return (id || props.applicationDetails?.show_source) && getSourceDetail(chat) return (id || props.applicationDetails?.show_source || props.applicationDetails?.show_exec) && getSourceDetail(chat)
}) })
.finally(() => { .finally(() => {
ChatManagement.close(chat.id) ChatManagement.close(chat.id)

View File

@ -92,6 +92,7 @@ export default {
referenceParagraph: 'Cited Segment', referenceParagraph: 'Cited Segment',
consume: 'Tokens', consume: 'Tokens',
consumeTime: 'Runtime', consumeTime: 'Runtime',
noSource: 'No source found',
}, },
paragraphSource: { paragraphSource: {
title: 'Knowledge Quote', title: 'Knowledge Quote',

View File

@ -93,7 +93,7 @@ export default {
notFound: { notFound: {
title: '404', title: '404',
NoService: 'Currently unable to access services', NoService: 'Currently unable to access services',
NoPermission: 'No permission to access', NoPermission: 'The current user does not have permission to access, please contact the administrator',
operate: 'Back to Home', operate: 'Back to Home',
}, },
custom: 'Custom', custom: 'Custom',

View File

@ -94,6 +94,7 @@ export default {
referenceParagraph: '引用分段', referenceParagraph: '引用分段',
consume: '消耗tokens', consume: '消耗tokens',
consumeTime: '耗时', consumeTime: '耗时',
noSource: '没有检索到知识来源'
}, },
paragraphSource: { paragraphSource: {
title: '知识库引用', title: '知识库引用',

View File

@ -97,7 +97,7 @@ export default {
notFound: { notFound: {
title: '404', title: '404',
NoService: '暂时无法访问服务', NoService: '暂时无法访问服务',
NoPermission:'没有权限访问', NoPermission:'当前用户暂无权限访问,请联系管理员',
operate: '返回首页', operate: '返回首页',
}, },
custom: '自定义', custom: '自定义',

View File

@ -90,6 +90,7 @@ export default {
referenceParagraph: '引用段落', referenceParagraph: '引用段落',
consume: '消耗tokens', consume: '消耗tokens',
consumeTime: '耗時', consumeTime: '耗時',
noSource: '沒有检索到知識來源',
}, },
paragraphSource: { paragraphSource: {
title: '知識庫引用', title: '知識庫引用',

View File

@ -93,7 +93,7 @@ export default {
notFound: { notFound: {
title: '404', title: '404',
NoService: '暫時無法訪問服務', NoService: '暫時無法訪問服務',
NoPermission: '沒有權限訪問', NoPermission: '當前用戶暫無權限訪問,請聯系管理員',
operate: '返回首頁', operate: '返回首頁',
}, },
custom: '自定義', custom: '自定義',

View File

@ -1,14 +1,11 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import applicationApi from '@/api/application/application' import applicationApi from '@/api/application/application'
import applicationXpackApi from '@/api/application/application-xpack'
import { type Ref } from 'vue' import { type Ref } from 'vue'
import useUserStore from './user'
const useApplicationStore = defineStore('application', { const useApplicationStore = defineStore('application', {
state: () => ({ state: () => ({
location: `${window.location.origin}${window.MaxKB.chatPrefix}/`, location: `${window.location.origin}${window.MaxKB.chatPrefix}/`,
}), }),
actions: { actions: {
async asyncGetApplicationDetail(id: string, loading?: Ref<boolean>) { async asyncGetApplicationDetail(id: string, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
applicationApi applicationApi
@ -24,17 +21,6 @@ const useApplicationStore = defineStore('application', {
async asyncGetAccessToken(id: string, loading?: Ref<boolean>) { async asyncGetAccessToken(id: string, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const user = useUserStore()
// if (user.isEE() || user.isPE()) {
// applicationXpackApi
// .getAccessToken(id, loading)
// .then((data) => {
// resolve(data)
// })
// .catch((error) => {
// reject(error)
// })
// } else {
applicationApi applicationApi
.getAccessToken(id, loading) .getAccessToken(id, loading)
.then((data) => { .then((data) => {
@ -43,7 +29,6 @@ const useApplicationStore = defineStore('application', {
.catch((error) => { .catch((error) => {
reject(error) reject(error)
}) })
// }
}) })
}, },

View File

@ -44,15 +44,6 @@ const useChatUserStore = defineStore('chat-user', {
return ChatAPI.applicationProfile().then((ok) => { return ChatAPI.applicationProfile().then((ok) => {
this.application = ok.data this.application = ok.data
localStorage.setItem(`${this.accessToken}-locale`, ok.data?.language || this.getLanguage()) localStorage.setItem(`${this.accessToken}-locale`, ok.data?.language || this.getLanguage())
if (this.application.custom_theme) {
this.application['custom_theme']['theme_color'] =
ok.data?.custom_theme?.theme_color || '#3370FF'
} else {
this.application.custom_theme = {
theme_color: ok.data?.custom_theme?.theme_color || '#3370FF',
}
}
}) })
}, },
isAuthentication() { isAuthentication() {

View File

@ -108,14 +108,14 @@ function deleteApiKey(row: any) {
.catch(() => {}) .catch(() => {})
} }
function changeState(row: any) { async function changeState(row: any) {
const obj = { const obj = {
is_active: !row.is_active is_active: !row.is_active
} }
const str = obj.is_active const str = obj.is_active
? t('views.applicationOverview.appInfo.APIKeyDialog.enabledSuccess') ? t('views.applicationOverview.appInfo.APIKeyDialog.enabledSuccess')
: t('views.applicationOverview.appInfo.APIKeyDialog.disabledSuccess') : t('views.applicationOverview.appInfo.APIKeyDialog.disabledSuccess')
applicationKeyApi await applicationKeyApi
.putAPIKey(id as string, row.id, obj, loading) .putAPIKey(id as string, row.id, obj, loading)
.then((res) => { .then((res) => {
MsgSuccess(str) MsgSuccess(str)

View File

@ -376,12 +376,12 @@ function refreshAccessToken() {
.catch(() => {}) .catch(() => {})
} }
function changeState(bool: boolean) { async function changeState(bool: boolean) {
const obj = { const obj = {
is_active: !bool, is_active: !bool,
} }
const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess') const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess')
updateAccessToken(obj, str) await updateAccessToken(obj, str)
.then(() => { .then(() => {
return true return true
}) })

View File

@ -26,7 +26,7 @@
</div> </div>
</template> </template>
<div class="flex"> <div class="flex" style="height: 570px">
<div class="setting-preview border border-r-6 mr-16" style="min-width: 400px"> <div class="setting-preview border border-r-6 mr-16" style="min-width: 400px">
<div <div
class="setting-preview-container" class="setting-preview-container"
@ -167,12 +167,15 @@
/> />
</div> </div>
</div> </div>
<el-scrollbar>
<div class="p-8">
<el-form ref="displayFormRef" :model="xpackForm"> <el-form ref="displayFormRef" :model="xpackForm">
<el-row class="w-full mb-8"> <el-row class="w-full mb-8">
<el-col :span="12"> <el-col :span="12">
<h5 class="mb-8"> <h5 class="mb-8">
{{ $t('views.applicationOverview.appInfo.SettingDisplayDialog.customThemeColor') }} {{
$t('views.applicationOverview.appInfo.SettingDisplayDialog.customThemeColor')
}}
</h5> </h5>
<div> <div>
<el-color-picker v-model="xpackForm.custom_theme.theme_color" /> <el-color-picker v-model="xpackForm.custom_theme.theme_color" />
@ -186,7 +189,9 @@
<el-col :span="12"> <el-col :span="12">
<h5 class="mb-8"> <h5 class="mb-8">
{{ {{
$t('views.applicationOverview.appInfo.SettingDisplayDialog.headerTitleFontColor') $t(
'views.applicationOverview.appInfo.SettingDisplayDialog.headerTitleFontColor',
)
}} }}
</h5> </h5>
<el-color-picker v-model="xpackForm.custom_theme.header_font_color" /> <el-color-picker v-model="xpackForm.custom_theme.header_font_color" />
@ -254,7 +259,9 @@
</span> </span>
</div> </div>
<el-text type="info" size="small"> <el-text type="info" size="small">
{{ $t('views.applicationOverview.appInfo.SettingDisplayDialog.chatBackgroundMessage') }} {{
$t('views.applicationOverview.appInfo.SettingDisplayDialog.chatBackgroundMessage')
}}
</el-text> </el-text>
</el-card> </el-card>
<!-- AI回复头像 --> <!-- AI回复头像 -->
@ -305,7 +312,9 @@
:auto-upload="false" :auto-upload="false"
:show-file-list="false" :show-file-list="false"
accept="image/jpeg, image/png, image/gif" accept="image/jpeg, image/png, image/gif"
:on-change="(file: any, fileList: any) => onChange(file, fileList, 'user_avatar')" :on-change="
(file: any, fileList: any) => onChange(file, fileList, 'user_avatar')
"
> >
<el-button size="small"> <el-button size="small">
{{ $t('views.applicationOverview.appInfo.SettingDisplayDialog.replace') }} {{ $t('views.applicationOverview.appInfo.SettingDisplayDialog.replace') }}
@ -423,7 +432,9 @@
<el-space direction="vertical" alignment="start" :size="2"> <el-space direction="vertical" alignment="start" :size="2">
<el-checkbox <el-checkbox
v-model="xpackForm.show_source" v-model="xpackForm.show_source"
:label="$t('views.applicationOverview.appInfo.SettingDisplayDialog.showSourceLabel')" :label="
$t('views.applicationOverview.appInfo.SettingDisplayDialog.showSourceLabel')
"
/> />
<el-checkbox <el-checkbox
v-model="xpackForm.show_exec" v-model="xpackForm.show_exec"
@ -452,6 +463,8 @@
</el-space> </el-space>
</el-form> </el-form>
</div> </div>
</el-scrollbar>
</div>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
@ -468,7 +481,7 @@ import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import type { FormInstance, FormRules, UploadFiles } from 'element-plus' import type { FormInstance, FormRules, UploadFiles } from 'element-plus'
import { isAppIcon } from '@/utils/common' import { isAppIcon } from '@/utils/common'
import applicationXpackApi from '@/api/application/application-xpack' import applicationApi from '@/api/application/application'
import { MsgSuccess, MsgError } from '@/utils/message' import { MsgSuccess, MsgError } from '@/utils/message'
import { langList, t } from '@/locales' import { langList, t } from '@/locales'
import useStore from '@/stores' import useStore from '@/stores'
@ -650,7 +663,7 @@ const submit = async (formEl: FormInstance | undefined) => {
fd.append(item, xpackForm.value[item]) fd.append(item, xpackForm.value[item])
} }
}) })
applicationXpackApi.putAccessToken(id as string, fd, loading).then((res) => { applicationApi.putXpackAccessToken(id as string, fd, loading).then((res) => {
emit('refresh') emit('refresh')
// @ts-ignore // @ts-ignore
MsgSuccess(t('common.settingSuccess')) MsgSuccess(t('common.settingSuccess'))

View File

@ -2,40 +2,61 @@
<div class="w-full"> <div class="w-full">
<div v-if="data" class="flex align-center"> <div v-if="data" class="flex align-center">
<AppIcon iconName="app-folder" style="font-size: 20px"></AppIcon> <AppIcon iconName="app-folder" style="font-size: 20px"></AppIcon>
<span class="ml-8 ellipsis color-text-primary lighter" style="max-width: 110px" :title="data.name"> <span
class="ml-8 ellipsis color-text-primary lighter"
style="max-width: 110px"
:title="data.name"
>
{{ data.name }} {{ data.name }}
</span> </span>
</div> </div>
<transition name="el-fade-in-linear"> <transition name="el-fade-in-linear">
<div v-if="props.list?.length || (props.node?.expanded && toolList.length)" <div
class="list border-r-4 layout-bg flex-wrap" @click.stop> v-if="props.list?.length || (props.node?.expanded && toolList.length)"
class="list border-r-4 layout-bg flex-wrap"
@click.stop
>
<el-popover v-for="item in toolList" :key="item.id" placement="right" :width="280"> <el-popover v-for="item in toolList" :key="item.id" placement="right" :width="280">
<template #reference> <template #reference>
<div class="list-item flex align-center border border-r-6 p-8-12 cursor" style="width: 39%" <div
@click.stop="emit('clickNodes', item)" @mousedown.stop="emit('onmousedown', item)"> class="list-item flex align-center border border-r-6 p-8-12 cursor"
style="width: 39%"
@click.stop="emit('clickNodes', item)"
@mousedown.stop="emit('onmousedown', item)"
>
<LogoIcon v-if="item.resource_type === 'application'" height="32px" /> <LogoIcon v-if="item.resource_type === 'application'" height="32px" />
<el-avatar v-else-if="isAppIcon(item?.icon)" shape="square" :size="32" style="background: none"> <el-avatar
v-else-if="isAppIcon(item?.icon)"
shape="square"
:size="32"
style="background: none"
>
<img :src="resetUrl(item?.icon)" alt="" /> <img :src="resetUrl(item?.icon)" alt="" />
</el-avatar> </el-avatar>
<el-avatar v-else class="avatar-green" shape="square" :size="32"> <el-avatar v-else class="avatar-green" shape="square" :size="32">
<img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" /> <img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" />
</el-avatar> </el-avatar>
<span class="ml-8 ellipsis">{{ item.name }}</span> <span class="ml-8 ellipsis" :title="item.name">{{ item.name }}</span>
</div> </div>
</template> </template>
<template #default> <template #default>
<div class="flex-between mb-8"> <div class="flex-between">
<div class="flex align-center"> <div class="flex align-center">
<LogoIcon v-if="item.resource_type === 'application'" height="32px" /> <LogoIcon v-if="item.resource_type === 'application'" height="32px" />
<el-avatar v-else-if="isAppIcon(item?.icon)" shape="square" :size="32" style="background: none"> <el-avatar
v-else-if="isAppIcon(item?.icon)"
shape="square"
:size="32"
style="background: none"
>
<img :src="resetUrl(item?.icon)" alt="" /> <img :src="resetUrl(item?.icon)" alt="" />
</el-avatar> </el-avatar>
<el-avatar v-else class="avatar-green" shape="square" :size="32"> <el-avatar v-else class="avatar-green" shape="square" :size="32">
<img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" /> <img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" />
</el-avatar> </el-avatar>
<span class="font-medium ml-8">{{ item.name }}</span> <span class="medium ml-8 ellipsis" :title="item.name">{{ item.name }}</span>
</div> </div>
<div v-if="item.type" class="status-tag" style="margin-left: auto"> <div v-if="item.type" class="status-tag" style="margin-left: auto">
<el-tag type="warning" v-if="isWorkFlow(item.type)" style="height: 22px"> <el-tag type="warning" v-if="isWorkFlow(item.type)" style="height: 22px">
@ -46,7 +67,7 @@
</el-tag> </el-tag>
</div> </div>
</div> </div>
<el-text type="info" size="small">{{ item.desc }}</el-text> <el-text type="info" size="small" class="mt-4">{{ item.desc }}</el-text>
</template> </template>
</el-popover> </el-popover>
</div> </div>
@ -66,9 +87,9 @@ const props = defineProps<{
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'clickNodes', item: any): void; (e: 'clickNodes', item: any): void
(e: 'onmousedown', item: any): void; (e: 'onmousedown', item: any): void
}>(); }>()
const toolList = computed(() => props.list ?? props.data?.cardList ?? []) const toolList = computed(() => props.list ?? props.data?.cardList ?? [])
</script> </script>

View File

@ -3,7 +3,7 @@
<div class="header border-b flex-between p-12-24 white-bg"> <div class="header border-b flex-between p-12-24 white-bg">
<div class="flex align-center"> <div class="flex align-center">
<back-button @click="back"></back-button> <back-button @click="back"></back-button>
<h4>{{ detail?.name }}</h4> <h4 class="ellipsis" style="max-width: 300px" :title="detail?.name">{{ detail?.name }}</h4>
<div v-if="showHistory && disablePublic"> <div v-if="showHistory && disablePublic">
<el-text type="info" class="ml-16 color-secondary" <el-text type="info" class="ml-16 color-secondary"
>{{ $t('views.applicationWorkflow.info.previewVersion') }} >{{ $t('views.applicationWorkflow.info.previewVersion') }}
@ -102,7 +102,7 @@
<LogoIcon v-else height="32px" /> <LogoIcon v-else height="32px" />
</div> </div>
<h4> <h4 class="ellipsis" style="max-width: 270px" :title="detail?.name">
{{ detail?.name || $t('views.application.form.appName.label') }} {{ detail?.name || $t('views.application.form.appName.label') }}
</h4> </h4>
</div> </div>
@ -598,8 +598,8 @@ onBeforeUnmount(() => {
bottom: 16px; bottom: 16px;
right: 16px; right: 16px;
overflow: hidden; overflow: hidden;
width: 450px; width: 460px;
height: 600px; height: 680px;
.workflow-debug-header { .workflow-debug-header {
background: var(--app-header-bg-color); background: var(--app-header-bg-color);
height: var(--app-header-height); height: var(--app-header-height);

View File

@ -4,12 +4,18 @@
v-loading="loading" v-loading="loading"
:style="{ :style="{
'--el-color-primary': applicationDetail?.custom_theme?.theme_color, '--el-color-primary': applicationDetail?.custom_theme?.theme_color,
'--el-color-primary-light-9': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.1), '--el-color-primary-light-9': hexToRgba(
'--el-color-primary-light-6': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.4), applicationDetail?.custom_theme?.theme_color || '#3370FF',
0.1,
),
'--el-color-primary-light-6': hexToRgba(
applicationDetail?.custom_theme?.theme_color || '#3370FF',
0.4,
),
backgroundImage: `url(${applicationDetail?.chat_background})`, backgroundImage: `url(${applicationDetail?.chat_background})`,
}" }"
> >
<div class="chat-embed__header" :style="(user.isEE() || user.isPE()) && customStyle"> <div class="chat-embed__header" :style="customStyle">
<div class="flex-between"> <div class="flex-between">
<div class="flex align-center"> <div class="flex align-center">
<AppIcon <AppIcon
@ -33,9 +39,16 @@
<LogoIcon v-else height="32px" /> <LogoIcon v-else height="32px" />
</div> </div>
<h4>{{ applicationDetail?.name }}</h4> <h4 class="ellipsis" style="max-width: 270px" :title="applicationDetail?.name">
{{ applicationDetail?.name }}
</h4>
</div> </div>
<el-button text @click="newChat" style="margin-right: 85px"> <el-button
text
@click="newChat"
style="margin-right: 85px"
:style="{ color: applicationDetail?.custom_theme?.header_font_color }"
>
<AppIcon iconName="app-create-chat" style="font-size: 20px"></AppIcon> <AppIcon iconName="app-create-chat" style="font-size: 20px"></AppIcon>
</el-button> </el-button>
</div> </div>
@ -75,12 +88,10 @@
import { ref, onMounted, reactive, nextTick, computed } from 'vue' import { ref, onMounted, reactive, nextTick, computed } from 'vue'
import { isAppIcon } from '@/utils/common' import { isAppIcon } from '@/utils/common'
import { hexToRgba } from '@/utils/theme' import { hexToRgba } from '@/utils/theme'
import useStore from '@/stores'
import { t } from '@/locales' import { t } from '@/locales'
import ChatHistoryDrawer from './component/ChatHistoryDrawer.vue' import ChatHistoryDrawer from './component/ChatHistoryDrawer.vue'
import chatAPI from '@/api/chat/chat' import chatAPI from '@/api/chat/chat'
const { user } = useStore()
const AiChatRef = ref() const AiChatRef = ref()
const loading = ref(false) const loading = ref(false)
const left_loading = ref(false) const left_loading = ref(false)

View File

@ -5,22 +5,24 @@
:class="classObj" :class="classObj"
:style="{ :style="{
'--el-color-primary': applicationDetail?.custom_theme?.theme_color, '--el-color-primary': applicationDetail?.custom_theme?.theme_color,
'--el-color-primary-light-9': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.1), '--el-color-primary-light-9': hexToRgba(
'--el-color-primary-light-6': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.4), applicationDetail?.custom_theme?.theme_color || '#3370FF',
0.1,
),
'--el-color-primary-light-6': hexToRgba(
applicationDetail?.custom_theme?.theme_color || '#3370FF',
0.4,
),
backgroundImage: `url(${applicationDetail?.chat_background})`, backgroundImage: `url(${applicationDetail?.chat_background})`,
}" }"
> >
<div class="chat-mobile__header" :style="(user.isEE() || user.isPE()) && customStyle"> <div class="chat-mobile__header" :style="customStyle">
<div class="flex-between"> <div class="flex-between">
<div class="flex align-center"> <div class="flex align-center">
<AppIcon <AppIcon
iconName="app-mobile-open-history" iconName="app-mobile-open-history"
style="font-size: 20px" style="font-size: 20px"
class="ml-16 cursor" class="ml-16 cursor"
:style="{
color: applicationDetail?.custom_theme?.header_font_color,
}"
@click.prevent.stop="show = true" @click.prevent.stop="show = true"
/> />
<div class="mr-12 ml-16 flex"> <div class="mr-12 ml-16 flex">
@ -35,9 +37,16 @@
<LogoIcon v-else height="32px" /> <LogoIcon v-else height="32px" />
</div> </div>
<h4>{{ applicationDetail?.name }}</h4> <h4 class="ellipsis" style="max-width: 270px" :title="applicationDetail?.name">
{{ applicationDetail?.name }}
</h4>
</div> </div>
<el-button text @click="newChat" class="mr-16"> <el-button
text
@click="newChat"
class="mr-16"
:style="{ color: applicationDetail?.custom_theme?.header_font_color }"
>
<AppIcon iconName="app-create-chat" style="font-size: 20px"></AppIcon> <AppIcon iconName="app-create-chat" style="font-size: 20px"></AppIcon>
</el-button> </el-button>
</div> </div>
@ -81,7 +90,7 @@ import { t } from '@/locales'
import ChatHistoryDrawer from './component/ChatHistoryDrawer.vue' import ChatHistoryDrawer from './component/ChatHistoryDrawer.vue'
import chatAPI from '@/api/chat/chat' import chatAPI from '@/api/chat/chat'
const { user, common } = useStore() const { common } = useStore()
const AiChatRef = ref() const AiChatRef = ref()
const loading = ref(false) const loading = ref(false)

View File

@ -5,8 +5,14 @@
v-loading="loading || left_loading" v-loading="loading || left_loading"
:style="{ :style="{
'--el-color-primary': applicationDetail?.custom_theme?.theme_color, '--el-color-primary': applicationDetail?.custom_theme?.theme_color,
'--el-color-primary-light-9': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.1), '--el-color-primary-light-9': hexToRgba(
'--el-color-primary-light-6': hexToRgba(applicationDetail?.custom_theme?.theme_color, 0.4), applicationDetail?.custom_theme?.theme_color || '#3370FF',
0.1,
),
'--el-color-primary-light-6': hexToRgba(
applicationDetail?.custom_theme?.theme_color || '#3370FF',
0.4,
),
}" }"
> >
<div class="flex h-full w-full"> <div class="flex h-full w-full">
@ -157,7 +163,7 @@
collapsible 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 ellipsis" :title="rightPanelTitle">{{ 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">
@ -509,15 +515,14 @@ function closeExecutionDetail() {
.el-splitter-bar__dragger { .el-splitter-bar__dragger {
display: none; display: none;
} }
.execution-detail-panel { :deep(.execution-detail-panel) {
background: #ffffff; background: #ffffff;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
display: flex;
flex-direction: column;
.execution-detail-content { .execution-detail-content {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
height: calc(100% - 63px);
.execution-details { .execution-details {
padding: 16px; padding: 16px;
} }

View File

@ -374,46 +374,51 @@
</span> </span>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<template v-if="knowledgeDetail?.type === 0"> <template v-if="knowledgeDetail?.type === 0">
<span <el-tooltip
class="mr-4" effect="dark"
:content="$t('views.document.setting.cancelVectorization')"
placement="top"
v-if=" v-if="
([State.STARTED, State.PENDING] as Array<string>).includes( ([State.STARTED, State.PENDING] as Array<string>).includes(
getTaskState(row.status, TaskType.EMBEDDING), getTaskState(row.status, TaskType.EMBEDDING),
) )
" "
> >
<span class="mr-4">
<el-button <el-button
type="primary" type="primary"
text text
@click.stop="cancelTask(row, TaskType.EMBEDDING)" @click.stop="cancelTask(row, TaskType.EMBEDDING)"
:title="$t('views.document.setting.cancelVectorization')"
v-if="permissionPrecise.doc_vector(id)" v-if="permissionPrecise.doc_vector(id)"
> >
<el-icon><Close /></el-icon> <el-icon><Close /></el-icon>
</el-button> </el-button>
</span> </span>
<span class="mr-4" v-else> </el-tooltip>
<el-button <el-tooltip
type="primary" effect="dark"
text :content="$t('views.knowledge.setting.vectorization')"
@click.stop="refreshDocument(row)" placement="top"
:title="$t('views.knowledge.setting.vectorization')" v-else
v-if="permissionPrecise.doc_vector(id)"
> >
<span class="mr-4" v-if="permissionPrecise.doc_vector(id)">
<el-button type="primary" text @click.stop="refreshDocument(row)">
<AppIcon iconName="app-document-refresh" style="font-size: 16px"></AppIcon> <AppIcon iconName="app-document-refresh" style="font-size: 16px"></AppIcon>
</el-button> </el-button>
</span> </span>
<span class="mr-4"> </el-tooltip>
<el-button <el-tooltip
type="primary" effect="dark"
text :content="$t('common.setting')"
@click.stop="settingDoc(row)" placement="top"
:title="$t('common.setting')"
v-if="permissionPrecise.doc_edit(id)" v-if="permissionPrecise.doc_edit(id)"
> >
<span class="mr-4">
<el-button type="primary" text @click.stop="settingDoc(row)">
<el-icon><Setting /></el-icon> <el-icon><Setting /></el-icon>
</el-button> </el-button>
</span> </span>
</el-tooltip>
<span @click.stop> <span @click.stop>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button text type="primary"> <el-button text type="primary">
@ -481,44 +486,50 @@
</span> </span>
</template> </template>
<template v-if="knowledgeDetail?.type === 1 || knowledgeDetail?.type === 2"> <template v-if="knowledgeDetail?.type === 1 || knowledgeDetail?.type === 2">
<span class="mr-4"> <el-tooltip
<el-button effect="dark"
type="primary" :content="$t('views.knowledge.setting.sync')"
text placement="top"
@click.stop="syncDocument(row)"
:title="$t('views.knowledge.setting.sync')"
v-if="permissionPrecise.sync(id)" v-if="permissionPrecise.sync(id)"
> >
<span class="mr-4">
<el-button type="primary" text @click.stop="syncDocument(row)">
<el-icon><Refresh /></el-icon> <el-icon><Refresh /></el-icon>
</el-button> </el-button>
</span> </span>
<span class="mr-4"> </el-tooltip>
<el-button <el-tooltip
effect="dark"
:content="$t('views.document.setting.cancelVectorization')"
placement="top"
v-if=" v-if="
([State.STARTED, State.PENDING] as Array<string>).includes( ([State.STARTED, State.PENDING] as Array<string>).includes(
getTaskState(row.status, TaskType.EMBEDDING), getTaskState(row.status, TaskType.EMBEDDING),
) && permissionPrecise.doc_vector(id) ) && permissionPrecise.doc_vector(id)
" "
>
<span class="mr-4">
<el-button
type="primary" type="primary"
text text
@click.stop="cancelTask(row, TaskType.EMBEDDING)" @click.stop="cancelTask(row, TaskType.EMBEDDING)"
:title="$t('views.document.setting.cancelVectorization')"
> >
<el-icon><Close /></el-icon> <el-icon><Close /></el-icon>
</el-button> </el-button>
</span>
<el-button </el-tooltip>
v-else <el-tooltip
type="primary" effect="dark"
text :content="$t('views.knowledge.setting.vectorization')"
@click.stop="refreshDocument(row)" placement="top"
:title="$t('views.knowledge.setting.vectorization')" v-else="permissionPrecise.vector(id)"
v-if="permissionPrecise.vector(id)"
> >
<span class="mr-4">
<el-button type="primary" text @click.stop="refreshDocument(row)">
<AppIcon iconName="app-document-refresh" style="font-size: 16px"></AppIcon> <AppIcon iconName="app-document-refresh" style="font-size: 16px"></AppIcon>
</el-button> </el-button>
</span> </span>
</el-tooltip>
<span @click.stop> <span @click.stop>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button text type="primary"> <el-button text type="primary">
@ -526,13 +537,15 @@
</el-button> </el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Setting" @click="settingDoc(row)"
v-if="permissionPrecise.doc_edit(id)"
>{{
$t('common.setting')
}}</el-dropdown-item>
<el-dropdown-item <el-dropdown-item
v-if="permissionPrecise.doc_generate(id) && icon="Setting"
@click="settingDoc(row)"
v-if="permissionPrecise.doc_edit(id)"
>{{ $t('common.setting') }}</el-dropdown-item
>
<el-dropdown-item
v-if="
permissionPrecise.doc_generate(id) &&
([State.STARTED, State.PENDING] as Array<string>).includes( ([State.STARTED, State.PENDING] as Array<string>).includes(
getTaskState(row.status, TaskType.GENERATE_PROBLEM), getTaskState(row.status, TaskType.GENERATE_PROBLEM),
) )
@ -542,31 +555,38 @@
<el-icon><Connection /></el-icon> <el-icon><Connection /></el-icon>
{{ $t('views.document.setting.cancelGenerateQuestion') }} {{ $t('views.document.setting.cancelGenerateQuestion') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-else @click="openGenerateDialog(row)" <el-dropdown-item
v-else
@click="openGenerateDialog(row)"
v-if="permissionPrecise.doc_generate(id)" v-if="permissionPrecise.doc_generate(id)"
> >
<el-icon><Connection /></el-icon> <el-icon><Connection /></el-icon>
{{ $t('views.document.generateQuestion.title') }} {{ $t('views.document.generateQuestion.title') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click="openknowledgeDialog(row)" <el-dropdown-item
@click="openknowledgeDialog(row)"
v-if="permissionPrecise.doc_migrate(id)" v-if="permissionPrecise.doc_migrate(id)"
> >
<AppIcon iconName="app-migrate"></AppIcon> <AppIcon iconName="app-migrate"></AppIcon>
{{ $t('views.document.setting.migration') }} {{ $t('views.document.setting.migration') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click="exportDocument(row)" <el-dropdown-item
@click="exportDocument(row)"
v-if="permissionPrecise.doc_export(id)" v-if="permissionPrecise.doc_export(id)"
> >
<AppIcon iconName="app-export"></AppIcon> <AppIcon iconName="app-export"></AppIcon>
{{ $t('views.document.setting.export') }} Excel {{ $t('views.document.setting.export') }} Excel
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click="exportDocumentZip(row)" <el-dropdown-item
@click="exportDocumentZip(row)"
v-if="permissionPrecise.doc_export(id)" v-if="permissionPrecise.doc_export(id)"
> >
<AppIcon iconName="app-export"></AppIcon> <AppIcon iconName="app-export"></AppIcon>
{{ $t('views.document.setting.export') }} Zip {{ $t('views.document.setting.export') }} Zip
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item icon="Delete" @click.stop="deleteDocument(row)" <el-dropdown-item
icon="Delete"
@click.stop="deleteDocument(row)"
v-if="permissionPrecise.doc_delete(id)" v-if="permissionPrecise.doc_delete(id)"
> >
{{ $t('common.delete') }} {{ $t('common.delete') }}
@ -1025,12 +1045,12 @@ function updateData(documentId: string, data: any, msg: string) {
}) })
} }
function changeState(row: any) { async function changeState(row: any) {
const obj = { const obj = {
is_active: !row.is_active, is_active: !row.is_active,
} }
const str = !row.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess') const str = !row.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess')
currentMouseId.value && updateData(row.id, obj, str) await updateData(row.id, obj, str)
} }
function editName(val: string, id: string) { function editName(val: string, id: string) {

View File

@ -121,11 +121,11 @@ function cardLeave() {
show.value = subHovered.value show.value = subHovered.value
} }
function changeState(row: any) { async function changeState(row: any) {
const obj = { const obj = {
is_active: !row.is_active, is_active: !row.is_active,
} }
loadSharedApi({ type: 'paragraph', systemType: apiType.value }) await loadSharedApi({ type: 'paragraph', systemType: apiType.value })
.putParagraph(id, documentId, row.id, obj, changeStateloading) .putParagraph(id, documentId, row.id, obj, changeStateloading)
.then(() => { .then(() => {
emit('changeState', row.id) emit('changeState', row.id)

View File

@ -364,13 +364,13 @@ function handleSizeChange() {
getList() getList()
} }
function changeState(row: ChatUserItem) { async function changeState(row: ChatUserItem) {
const obj = { const obj = {
...row, ...row,
is_active: !row.is_active, is_active: !row.is_active,
} }
const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess') const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess')
loadPermissionApi('chatUser') await loadPermissionApi('chatUser')
.putUserManage(row.id, obj, loading) .putUserManage(row.id, obj, loading)
.then(() => { .then(() => {
getList() getList()

View File

@ -284,12 +284,12 @@ function getList() {
}) })
} }
function changeState(row: any) { async function changeState(row: any) {
const obj = { const obj = {
is_active: !row.is_active, is_active: !row.is_active,
} }
const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess') const str = obj.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess')
userManageApi await userManageApi
.putUserManage(row.id, obj, loading) .putUserManage(row.id, obj, loading)
.then((res) => { .then((res) => {
getList() getList()