feat:修复知识库问题1
parent
4c9ac22a7f
commit
9ed4f6edfc
|
|
@ -23,12 +23,14 @@ from django.utils.translation import gettext_lazy as _, gettext
|
|||
from openpyxl.cell.cell import ILLEGAL_CHARACTERS_RE
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.models import Chat, Application, ChatRecord
|
||||
from application.models import Chat, Application, ChatRecord, ChatUserType
|
||||
from common.database_model_manage.database_model_manage import DatabaseModelManage
|
||||
from common.db.search import get_dynamics_model, native_search, native_page_search, native_page_handler
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.utils.common import get_file_content
|
||||
from maxkb.conf import PROJECT_DIR
|
||||
from maxkb.settings import TIME_ZONE, edition
|
||||
from users.models import User
|
||||
|
||||
|
||||
class ApplicationChatResponseSerializers(serializers.Serializer):
|
||||
|
|
@ -147,6 +149,75 @@ class ApplicationChatQuerySerializers(serializers.Serializer):
|
|||
with_table_name=False)
|
||||
return self.append_feedback_content(result)
|
||||
|
||||
@staticmethod
|
||||
def format_user_display_name(nick_name, username):
|
||||
nick_name = (nick_name or '').strip()
|
||||
username = (username or '').strip()
|
||||
if nick_name and username and nick_name != username:
|
||||
return f'{nick_name}({username})'
|
||||
return nick_name or username or '游客'
|
||||
|
||||
@classmethod
|
||||
def build_asker(cls, user):
|
||||
return {
|
||||
'id': str(user.id),
|
||||
'email': getattr(user, 'email', ''),
|
||||
'phone': getattr(user, 'phone', ''),
|
||||
'nick_name': getattr(user, 'nick_name', ''),
|
||||
'username': getattr(user, 'username', ''),
|
||||
'display_name': cls.format_user_display_name(
|
||||
getattr(user, 'nick_name', ''),
|
||||
getattr(user, 'username', '')
|
||||
),
|
||||
'source': getattr(user, 'source', '')
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def normalize_asker(cls, asker):
|
||||
if isinstance(asker, dict):
|
||||
nick_name = asker.get('nick_name') or asker.get('name') or ''
|
||||
username = asker.get('username') or asker.get('user_name') or ''
|
||||
display_name = asker.get('display_name') or cls.format_user_display_name(nick_name, username)
|
||||
return {**asker, 'display_name': display_name, 'username': username or display_name}
|
||||
if asker:
|
||||
return {'username': str(asker), 'display_name': str(asker)}
|
||||
return {'username': '游客', 'display_name': '游客'}
|
||||
|
||||
@classmethod
|
||||
def fill_asker_display_name(cls, records):
|
||||
if not records:
|
||||
return records
|
||||
|
||||
platform_user_ids = [
|
||||
row.get('chat_user_id') for row in records
|
||||
if row.get('chat_user_type') == ChatUserType.PLATFORM_USER.value and row.get('chat_user_id')
|
||||
]
|
||||
chat_user_ids = [
|
||||
row.get('chat_user_id') for row in records
|
||||
if row.get('chat_user_type') == ChatUserType.CHAT_USER.value and row.get('chat_user_id')
|
||||
]
|
||||
platform_user_map = {
|
||||
str(user.id): user for user in QuerySet(User).filter(id__in=platform_user_ids)
|
||||
} if platform_user_ids else {}
|
||||
|
||||
chat_user_map = {}
|
||||
chat_user_model = DatabaseModelManage.get_model("chat_user")
|
||||
if chat_user_model and chat_user_ids:
|
||||
chat_user_map = {
|
||||
str(user.id): user for user in QuerySet(chat_user_model).filter(id__in=chat_user_ids)
|
||||
}
|
||||
|
||||
for row in records:
|
||||
chat_user_id = str(row.get('chat_user_id') or '')
|
||||
chat_user_type = row.get('chat_user_type')
|
||||
if chat_user_type == ChatUserType.PLATFORM_USER.value and chat_user_id in platform_user_map:
|
||||
row['asker'] = cls.build_asker(platform_user_map[chat_user_id])
|
||||
elif chat_user_type == ChatUserType.CHAT_USER.value and chat_user_id in chat_user_map:
|
||||
row['asker'] = cls.build_asker(chat_user_map[chat_user_id])
|
||||
else:
|
||||
row['asker'] = cls.normalize_asker(row.get('asker'))
|
||||
return records
|
||||
|
||||
@staticmethod
|
||||
def get_feedback_items(details):
|
||||
if not isinstance(details, dict):
|
||||
|
|
@ -163,6 +234,7 @@ class ApplicationChatQuerySerializers(serializers.Serializer):
|
|||
def append_feedback_content(cls, records):
|
||||
if not records:
|
||||
return records
|
||||
cls.fill_asker_display_name(records)
|
||||
chat_id_list = [row.get('id') for row in records if row.get('id') is not None]
|
||||
feedback_map = {}
|
||||
chat_records = QuerySet(ChatRecord).filter(chat_id__in=chat_id_list).order_by('create_time')
|
||||
|
|
@ -213,7 +285,7 @@ class ApplicationChatQuerySerializers(serializers.Serializer):
|
|||
"\n".join([
|
||||
f"{improve_paragraph_list[index].get('title')}\n{improve_paragraph_list[index].get('content')}"
|
||||
for index in range(len(improve_paragraph_list))]),
|
||||
row.get('asker').get('username'),
|
||||
ApplicationChatQuerySerializers.normalize_asker(row.get('asker')).get('display_name'),
|
||||
(row.get('message_tokens') or 0) + (row.get('answer_tokens') or 0), row.get('run_time'),
|
||||
str(row.get('create_time').astimezone(pytz.timezone(TIME_ZONE)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
if row.get('create_time') is not None else None)]
|
||||
|
|
@ -256,8 +328,9 @@ class ApplicationChatQuerySerializers(serializers.Serializer):
|
|||
('export_application_chat_ee.sql' if ['PE',
|
||||
'EE'].__contains__(
|
||||
edition) else 'export_application_chat.sql'))),
|
||||
with_table_name=False):
|
||||
with_table_name=False):
|
||||
|
||||
self.fill_asker_display_name(data_list)
|
||||
for item in data_list:
|
||||
row = [self.reset_value(v) for v in self.to_row(item)]
|
||||
worksheet.append(row)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ from common.exception.app_exception import ChatException
|
|||
from knowledge.models import Document
|
||||
from models_provider.models import Model
|
||||
from models_provider.tools import get_model_credential
|
||||
from users.models import User
|
||||
|
||||
|
||||
class ChatInfo:
|
||||
|
|
@ -99,14 +100,30 @@ class ChatInfo:
|
|||
chat_user_model = DatabaseModelManage.get_model("chat_user")
|
||||
if self.chat_user_type == ChatUserType.CHAT_USER.value and chat_user_model:
|
||||
chat_user = QuerySet(chat_user_model).filter(id=self.chat_user_id).first()
|
||||
if chat_user is None:
|
||||
return {'username': '游客'}
|
||||
return {
|
||||
'id': str(chat_user.id),
|
||||
'email': chat_user.email,
|
||||
'phone': chat_user.phone,
|
||||
'nick_name': chat_user.nick_name,
|
||||
'username': chat_user.username,
|
||||
'display_name': self.format_user_display_name(chat_user.nick_name, chat_user.username),
|
||||
'source': chat_user.source
|
||||
}
|
||||
elif self.chat_user_type == ChatUserType.PLATFORM_USER.value:
|
||||
user = QuerySet(User).filter(id=self.chat_user_id).first()
|
||||
if user is None:
|
||||
return {'username': '游客'}
|
||||
return {
|
||||
'id': str(user.id),
|
||||
'email': user.email,
|
||||
'phone': user.phone,
|
||||
'nick_name': user.nick_name,
|
||||
'username': user.username,
|
||||
'display_name': self.format_user_display_name(user.nick_name, user.username),
|
||||
'source': user.source
|
||||
}
|
||||
else:
|
||||
if asker:
|
||||
if isinstance(asker, dict):
|
||||
|
|
@ -117,6 +134,14 @@ class ChatInfo:
|
|||
self.chat_user = {'username': '游客'}
|
||||
return self.chat_user
|
||||
|
||||
@staticmethod
|
||||
def format_user_display_name(nick_name, username):
|
||||
nick_name = (nick_name or '').strip()
|
||||
username = (username or '').strip()
|
||||
if nick_name and username and nick_name != username:
|
||||
return f'{nick_name}({username})'
|
||||
return nick_name or username or '游客'
|
||||
|
||||
def to_base_pipeline_manage_params(self):
|
||||
self.get_application()
|
||||
self.get_chat_user()
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<h2 v-if="breadcrumbData?.length === 1" class="ellipsis" :title="breadcrumbData[0]?.name">
|
||||
{{ breadcrumbData[0]?.name }}
|
||||
<h2 v-if="breadcrumbData?.length === 1" class="ellipsis" :title="getFolderName(breadcrumbData[0])">
|
||||
{{ getFolderName(breadcrumbData[0]) }}
|
||||
</h2>
|
||||
<el-breadcrumb separator-icon="ArrowRight" style="line-height: normal" class="mt-4" v-else>
|
||||
<template v-if="breadcrumbData?.length > 3">
|
||||
<el-breadcrumb-item>
|
||||
<el-button link @click="handleClick(breadcrumbData[0])" :title="breadcrumbData[0].name">
|
||||
<span class="ellipsis"> {{ breadcrumbData[0].name }}</span>
|
||||
<el-button link @click="handleClick(breadcrumbData[0])" :title="getFolderName(breadcrumbData[0])">
|
||||
<span class="ellipsis"> {{ getFolderName(breadcrumbData[0]) }}</span>
|
||||
</el-button>
|
||||
</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>
|
||||
|
|
@ -15,19 +15,26 @@
|
|||
</el-button>
|
||||
</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>
|
||||
<h5 class="ml-4 ellipsis" :title="breadcrumbData[breadcrumbData.length - 1].name">
|
||||
{{ breadcrumbData[breadcrumbData.length - 1].name }}
|
||||
<h5
|
||||
class="ml-4 ellipsis"
|
||||
:title="getFolderName(breadcrumbData[breadcrumbData.length - 1])"
|
||||
>
|
||||
{{ getFolderName(breadcrumbData[breadcrumbData.length - 1]) }}
|
||||
</h5>
|
||||
</el-breadcrumb-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-breadcrumb-item v-for="(item, index) in breadcrumbData" :key="index">
|
||||
<h5 class="ml-4 ellipsis" v-if="index === breadcrumbData.length - 1" :title="item.name">
|
||||
{{ item.name }}
|
||||
<h5
|
||||
class="ml-4 ellipsis"
|
||||
v-if="index === breadcrumbData.length - 1"
|
||||
:title="getFolderName(item)"
|
||||
>
|
||||
{{ getFolderName(item) }}
|
||||
</h5>
|
||||
|
||||
<el-button v-else link @click="handleClick(item)" :title="item.name">
|
||||
<span class="ellipsis"> {{ item.name }}</span>
|
||||
<el-button v-else link @click="handleClick(item)" :title="getFolderName(item)">
|
||||
<span class="ellipsis"> {{ getFolderName(item) }}</span>
|
||||
</el-button>
|
||||
</el-breadcrumb-item>
|
||||
</template>
|
||||
|
|
@ -46,6 +53,10 @@ const props = defineProps({
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const breadcrumbData = computed(() => {
|
||||
|
|
@ -72,6 +83,19 @@ function getBreadcrumbData() {
|
|||
function handleClick(item: any) {
|
||||
emit('click', item)
|
||||
}
|
||||
|
||||
const rootFolderNameMap: Record<string, string> = {
|
||||
APPLICATION: 'AI应用',
|
||||
KNOWLEDGE: '知识库',
|
||||
TOOL: '工具',
|
||||
}
|
||||
|
||||
function getFolderName(item: any) {
|
||||
if (!item?.parent_id && item?.id === 'default' && props.source) {
|
||||
return rootFolderNameMap[props.source] || item?.name
|
||||
}
|
||||
return item?.name
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@
|
|||
class="flex align-center w-full custom-tree-node"
|
||||
>
|
||||
<AppIcon iconName="app-folder" style="font-size: 20px"></AppIcon>
|
||||
<span class="tree-label ml-8" :title="node.label">{{ i18n_name(node.label) }}</span>
|
||||
<span class="tree-label ml-8" :title="getFolderLabel(data, node)">
|
||||
{{ getFolderLabel(data, node) }}
|
||||
</span>
|
||||
|
||||
<div
|
||||
v-if="canOperation && MoreFilledPermission(node, data)"
|
||||
|
|
@ -197,6 +199,19 @@ const resourceType = computed(() => {
|
|||
}
|
||||
})
|
||||
|
||||
const rootFolderNameMap: Record<string, string> = {
|
||||
APPLICATION: 'AI应用',
|
||||
KNOWLEDGE: '知识库',
|
||||
TOOL: '工具',
|
||||
}
|
||||
|
||||
function getFolderLabel(data: any, node?: any) {
|
||||
if (!data?.parent_id && data?.id === 'default') {
|
||||
return rootFolderNameMap[props.source] || i18n_name(node?.label || data?.name)
|
||||
}
|
||||
return i18n_name(node?.label || data?.name)
|
||||
}
|
||||
|
||||
const permissionPrecise = computed(() => {
|
||||
return permissionMap[resourceType.value!]['workspace']
|
||||
})
|
||||
|
|
|
|||
|
|
@ -83,53 +83,6 @@
|
|||
{{ $t('layout.apiKey') }}
|
||||
</el-dropdown-item>
|
||||
</div>
|
||||
<el-dropdown-item
|
||||
style="padding: 0"
|
||||
@click.stop
|
||||
v-if="
|
||||
hasPermission(
|
||||
new ComplexPermission(
|
||||
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE, RoleConst.USER],
|
||||
[PermissionConst.SWITCH_LANGUAGE],
|
||||
[],
|
||||
'OR',
|
||||
),
|
||||
'OR',
|
||||
)
|
||||
"
|
||||
>
|
||||
<el-dropdown class="w-full" trigger="hover" placement="left-start">
|
||||
<div class="flex-between w-full" style="line-height: 22px; padding: 12px 11px">
|
||||
<span> {{ $t('layout.language') }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight/>
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu style="width: 180px">
|
||||
<el-dropdown-item
|
||||
v-for="(lang, index) in langList"
|
||||
:key="index"
|
||||
:value="lang.value"
|
||||
@click="changeLang(lang.value)"
|
||||
class="flex-between"
|
||||
>
|
||||
<span :class="lang.value === user.userInfo?.language ? 'primary' : ''">{{
|
||||
lang.label
|
||||
}}</span>
|
||||
|
||||
<el-icon
|
||||
:class="lang.value === user.userInfo?.language ? 'primary' : ''"
|
||||
v-if="lang.value === user.userInfo?.language"
|
||||
>
|
||||
<Check/>
|
||||
</el-icon>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</el-dropdown-item>
|
||||
<!-- <el-dropdown-item-->
|
||||
<!-- @click="openAbout"-->
|
||||
<!-- v-if="hasPermission([RoleConst.ADMIN, PermissionConst.ABOUT_READ], 'OR')"-->
|
||||
|
|
@ -159,7 +112,6 @@ import AboutDialog from './AboutDialog.vue'
|
|||
// import UserPwdDialog from '@/views/user-manage/component/UserPwdDialog.vue'
|
||||
import APIKeyDialog from './APIKeyDialog.vue'
|
||||
import {ComplexPermission} from '@/utils/permission/type'
|
||||
import {langList} from '@/locales/index'
|
||||
import {hasPermission} from '@/utils/permission'
|
||||
import {PermissionConst, RoleConst, EditionConst} from '@/utils/permission/data'
|
||||
|
||||
|
|
@ -170,11 +122,6 @@ const AboutDialogRef = ref()
|
|||
const APIKeyDialogRef = ref()
|
||||
const resetPasswordRef = ref<InstanceType<typeof ResetPassword>>()
|
||||
|
||||
// const { changeLocale } = useLocale()
|
||||
const changeLang = (lang: string) => {
|
||||
user.postUserLanguage(lang)
|
||||
// changeLocale(lang)
|
||||
}
|
||||
const openAbout = () => {
|
||||
AboutDialogRef.value?.open()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,33 +6,6 @@
|
|||
<div class="login-image" :style="{ backgroundImage: `url(${loginImage})` }"></div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="14" :lg="14" :xl="14" class="right-container flex-center">
|
||||
<el-dropdown trigger="click" type="primary" class="lang" v-if="lang">
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu style="width: 180px">
|
||||
<el-dropdown-item
|
||||
v-for="(lang, index) in langList"
|
||||
:key="index"
|
||||
:value="lang.value"
|
||||
@click="changeLang(lang.value)"
|
||||
class="flex-between"
|
||||
>
|
||||
<span :class="lang.value === user.getLanguage() ? 'primary' : ''">{{
|
||||
lang.label
|
||||
}}</span>
|
||||
|
||||
<el-icon
|
||||
:class="lang.value === user.getLanguage() ? 'primary' : ''"
|
||||
v-if="lang.value === user.getLanguage()"
|
||||
>
|
||||
<Check />
|
||||
</el-icon>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
<el-button>
|
||||
{{ currentLanguage }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||
</el-button>
|
||||
</el-dropdown>
|
||||
<slot></slot>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
|
@ -43,24 +16,13 @@
|
|||
import { computed } from 'vue'
|
||||
import { getThemeImg } from '@/utils/theme'
|
||||
import useStore from '@/stores'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
import { langList, localeConfigKey, getBrowserLang } from '@/locales/index'
|
||||
defineProps({
|
||||
lang: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
})
|
||||
const { user, theme } = useStore()
|
||||
|
||||
const changeLang = (lang: string) => {
|
||||
useLocalStorage(localeConfigKey, getBrowserLang()).value = lang
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
const currentLanguage = computed(() => {
|
||||
return langList.value?.filter((v: any) => v.value === user.getLanguage())?.[0]?.label
|
||||
})
|
||||
const { theme } = useStore()
|
||||
|
||||
const fileURL = computed(() => {
|
||||
if (theme.themeInfo?.loginImage) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import {useLocalStorage, usePreferredLanguages} from '@vueuse/core'
|
||||
import {computed} from 'vue'
|
||||
import {createI18n} from 'vue-i18n'
|
||||
|
||||
|
|
@ -16,21 +15,10 @@ const langModuleMap = new Map<string, object>()
|
|||
export const langCode: Array<string> = []
|
||||
|
||||
export const localeConfigKey = 'MaxKB-locale'
|
||||
|
||||
// 获取浏览器默认语言环境
|
||||
const languages = usePreferredLanguages()
|
||||
export const defaultLocale = 'zh-CN'
|
||||
|
||||
export function getBrowserLang() {
|
||||
const browserLang = navigator.language ? navigator.language : languages.value[0]
|
||||
let defaultBrowserLang = ''
|
||||
if (browserLang === 'zh-HK' || browserLang === 'zh-TW') {
|
||||
defaultBrowserLang = 'zh-Hant'
|
||||
} else if (browserLang === 'zh-CN') {
|
||||
defaultBrowserLang = 'zh-CN'
|
||||
} else {
|
||||
defaultBrowserLang = 'en-US'
|
||||
}
|
||||
return defaultBrowserLang
|
||||
return defaultLocale
|
||||
}
|
||||
|
||||
// 生成语言模块列表
|
||||
|
|
@ -59,8 +47,8 @@ const importMessages = computed(() => {
|
|||
|
||||
export const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: useLocalStorage(localeConfigKey, getBrowserLang()).value || getBrowserLang(),
|
||||
fallbackLocale: getBrowserLang(),
|
||||
locale: defaultLocale,
|
||||
fallbackLocale: defaultLocale,
|
||||
messages: importMessages.value,
|
||||
globalInjection: true
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import ChatAPI from '@/api/chat/chat'
|
|||
import type {ChatProfile, ChatUserProfile} from '@/api/type/chat'
|
||||
import type {LoginRequest} from '@/api/type/user'
|
||||
import type {Ref} from 'vue'
|
||||
import {getBrowserLang} from '@/locales/index'
|
||||
import {defaultLocale} from '@/locales/index'
|
||||
|
||||
interface ChatUser {
|
||||
// 用户id
|
||||
|
|
@ -28,7 +28,7 @@ const useChatUserStore = defineStore('chat-user', {
|
|||
}),
|
||||
actions: {
|
||||
getLanguage() {
|
||||
return localStorage.getItem(`${this.accessToken}-locale`) || getBrowserLang()
|
||||
return defaultLocale
|
||||
},
|
||||
setAccessToken(accessToken: string) {
|
||||
this.accessToken = accessToken
|
||||
|
|
@ -53,7 +53,7 @@ const useChatUserStore = defineStore('chat-user', {
|
|||
return ChatAPI.applicationProfile().then((ok) => {
|
||||
console.log('applicationProfile', ok.data)
|
||||
this.application = ok.data
|
||||
localStorage.setItem(`${this.accessToken}-locale`, ok.data?.language || this.getLanguage())
|
||||
localStorage.setItem(`${this.accessToken}-locale`, defaultLocale)
|
||||
})
|
||||
},
|
||||
isAuthentication() {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import UserApi from '@/api/user/user'
|
|||
import LoginApi from '@/api/user/login'
|
||||
import {useLocalStorage} from '@vueuse/core'
|
||||
|
||||
import {localeConfigKey, getBrowserLang} from '@/locales/index'
|
||||
import {defaultLocale, localeConfigKey} from '@/locales/index'
|
||||
import useThemeStore from './theme'
|
||||
import {defaultPlatformSetting} from '@/utils/theme'
|
||||
import useLoginStore from './login'
|
||||
|
|
@ -32,7 +32,7 @@ const useUserStore = defineStore('user', {
|
|||
}),
|
||||
actions: {
|
||||
getLanguage() {
|
||||
return localStorage.getItem('MaxKB-locale') || getBrowserLang()
|
||||
return defaultLocale
|
||||
},
|
||||
setWorkspaceId(workspace_id: string) {
|
||||
this.workspace_id = workspace_id
|
||||
|
|
@ -126,8 +126,7 @@ const useUserStore = defineStore('user', {
|
|||
this.setWorkspaceId(workspace_list[0].id)
|
||||
}
|
||||
this.workspace_list = workspace_list
|
||||
useLocalStorage<string>(localeConfigKey, 'en-US').value =
|
||||
ok?.data?.language || this.getLanguage()
|
||||
useLocalStorage<string>(localeConfigKey, defaultLocale).value = defaultLocale
|
||||
const theme = useThemeStore()
|
||||
theme.setTheme()
|
||||
return this.asyncGetProfile()
|
||||
|
|
@ -161,9 +160,9 @@ const useUserStore = defineStore('user', {
|
|||
},
|
||||
async postUserLanguage(lang: string, loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
LoginApi.postLanguage({language: lang}, loading)
|
||||
LoginApi.postLanguage({language: defaultLocale}, loading)
|
||||
.then(async (ok) => {
|
||||
useLocalStorage(localeConfigKey, 'en-US').value = lang
|
||||
useLocalStorage(localeConfigKey, defaultLocale).value = defaultLocale
|
||||
window.location.reload()
|
||||
resolve(ok)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,19 +7,6 @@
|
|||
width="550"
|
||||
>
|
||||
<el-form label-position="top" ref="displayFormRef" :model="form">
|
||||
<el-form-item>
|
||||
<span>{{
|
||||
$t('layout.language')
|
||||
}}</span>
|
||||
<el-select v-model="form.language" clearable>
|
||||
<el-option
|
||||
v-for="item in langList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-space direction="vertical" alignment="start" :size="2">
|
||||
<el-checkbox
|
||||
|
|
@ -51,7 +38,7 @@ import { ref, watch, computed } from 'vue'
|
|||
import { useRoute } from 'vue-router'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { MsgSuccess, MsgError } from '@/utils/message'
|
||||
import { langList, t } from '@/locales'
|
||||
import { defaultLocale, t } from '@/locales'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
|
||||
const route = useRoute()
|
||||
|
|
@ -71,7 +58,7 @@ const displayFormRef = ref()
|
|||
const form = ref<any>({
|
||||
show_source: false,
|
||||
show_exec: false,
|
||||
language: '',
|
||||
language: defaultLocale,
|
||||
})
|
||||
|
||||
const detail = ref<any>(null)
|
||||
|
|
@ -84,7 +71,7 @@ watch(dialogVisible, (bool) => {
|
|||
form.value = {
|
||||
show_source: false,
|
||||
show_exec: false,
|
||||
language: '',
|
||||
language: defaultLocale,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -92,7 +79,7 @@ const open = (data: any, content: any) => {
|
|||
detail.value = content
|
||||
form.value.show_source = data.show_source
|
||||
form.value.show_exec = data.show_exec
|
||||
form.value.language = data.language
|
||||
form.value.language = defaultLocale
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +88,7 @@ const submit = async (formEl: FormInstance | undefined) => {
|
|||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
loadSharedApi({ type: 'application', systemType: apiType.value })
|
||||
.putAccessToken(id as string, form.value, loading)
|
||||
.putAccessToken(id as string, { ...form.value, language: defaultLocale }, loading)
|
||||
.then(() => {
|
||||
emit('refresh')
|
||||
|
||||
|
|
|
|||
|
|
@ -197,19 +197,6 @@
|
|||
<el-color-picker v-model="xpackForm.custom_theme.header_font_color" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="w-full mb-8">
|
||||
<h5 class="mb-8">
|
||||
{{ $t('layout.language') }}
|
||||
</h5>
|
||||
<el-select v-model="xpackForm.language" clearable>
|
||||
<el-option
|
||||
v-for="item in langList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-row>
|
||||
<!-- 应用 LOGO -->
|
||||
<el-card shadow="never" class="mb-8">
|
||||
<div class="flex-between mb-8">
|
||||
|
|
@ -486,7 +473,7 @@ import { useRoute } from 'vue-router'
|
|||
import type { FormInstance, FormRules, UploadFiles } from 'element-plus'
|
||||
import { isAppIcon } from '@/utils/common'
|
||||
import { MsgSuccess, MsgError } from '@/utils/message'
|
||||
import { langList, t } from '@/locales'
|
||||
import { defaultLocale, t } from '@/locales'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
|
||||
|
|
@ -508,7 +495,7 @@ const emit = defineEmits(['refresh'])
|
|||
const defaultSetting = {
|
||||
show_source: false,
|
||||
show_exec: false,
|
||||
language: '',
|
||||
language: defaultLocale,
|
||||
show_history: true,
|
||||
draggable: true,
|
||||
show_guide: true,
|
||||
|
|
@ -541,7 +528,7 @@ const displayFormRef = ref()
|
|||
const xpackForm = ref<any>({
|
||||
show_source: false,
|
||||
show_exec: false,
|
||||
language: '',
|
||||
language: defaultLocale,
|
||||
icon: '',
|
||||
icon_url: '',
|
||||
show_history: true,
|
||||
|
|
@ -591,6 +578,7 @@ const customStyle = computed(() => {
|
|||
|
||||
function resetForm() {
|
||||
xpackForm.value = cloneDeep(defaultSetting)
|
||||
xpackForm.value.language = defaultLocale
|
||||
imgUrl.value = {
|
||||
avatar: '',
|
||||
float_icon: '',
|
||||
|
|
@ -618,7 +606,7 @@ const open = (data: any, content: any) => {
|
|||
xpackForm.value.show_source = data.show_source
|
||||
xpackForm.value.show_exec = data.show_exec
|
||||
xpackForm.value.show_history = data.show_history
|
||||
xpackForm.value.language = data.language
|
||||
xpackForm.value.language = defaultLocale
|
||||
xpackForm.value.draggable = data.draggable
|
||||
xpackForm.value.show_guide = data.show_guide
|
||||
imgUrl.value.avatar = data.avatar
|
||||
|
|
@ -664,6 +652,7 @@ const submit = async (formEl: FormInstance | undefined) => {
|
|||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const fd = new FormData()
|
||||
xpackForm.value.language = defaultLocale
|
||||
Object.keys(xpackForm.value).map((item) => {
|
||||
if (['custom_theme', 'float_location'].includes(item)) {
|
||||
fd.append(item, JSON.stringify(xpackForm.value[item]))
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@
|
|||
</template>
|
||||
<ContentContainer>
|
||||
<template #header>
|
||||
<FolderBreadcrumb :folderList="folderList" @click="folderClickHandle" />
|
||||
<FolderBreadcrumb
|
||||
:folderList="folderList"
|
||||
:source="SourceTypeEnum.APPLICATION"
|
||||
@click="folderClickHandle"
|
||||
/>
|
||||
</template>
|
||||
<template #search>
|
||||
<div class="flex">
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@
|
|||
</el-table-column>
|
||||
<el-table-column prop="asker" :label="$t('views.chatLog.table.user')">
|
||||
<template #default="{ row }">
|
||||
{{ row.asker?.username }}
|
||||
{{ getAskerDisplayName(row.asker) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('views.chatLog.table.recenTimes')" width="180">
|
||||
|
|
@ -487,6 +487,21 @@ const handleSelectionChange = (val: any[]) => {
|
|||
multipleSelection.value = val
|
||||
}
|
||||
|
||||
function getAskerDisplayName(asker: any) {
|
||||
if (!asker) {
|
||||
return '游客'
|
||||
}
|
||||
if (asker.display_name) {
|
||||
return asker.display_name
|
||||
}
|
||||
const nickName = asker.nick_name || asker.name || ''
|
||||
const username = asker.username || asker.user_name || ''
|
||||
if (nickName && username && nickName !== username) {
|
||||
return `${nickName}(${username})`
|
||||
}
|
||||
return nickName || username || '游客'
|
||||
}
|
||||
|
||||
function getList() {
|
||||
const obj: any = {
|
||||
start_time: daterange.value.start_time,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,12 @@
|
|||
<h2 v-if="folder.currentFolder?.id === 'share'">
|
||||
{{ $t('views.shared.shared_knowledge') }}
|
||||
</h2>
|
||||
<FolderBreadcrumb :folderList="folderList" @click="folderClickHandle" v-else />
|
||||
<FolderBreadcrumb
|
||||
:folderList="folderList"
|
||||
:source="SourceTypeEnum.KNOWLEDGE"
|
||||
@click="folderClickHandle"
|
||||
v-else
|
||||
/>
|
||||
</template>
|
||||
</KnowledgeListContainer>
|
||||
</LayoutContainer>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,12 @@
|
|||
<h2 v-if="folder.currentFolder?.id === 'share'">
|
||||
{{ $t('views.shared.shared_tool') }}
|
||||
</h2>
|
||||
<FolderBreadcrumb :folderList="folderList" @click="folderClickHandle" v-else />
|
||||
<FolderBreadcrumb
|
||||
:folderList="folderList"
|
||||
:source="SourceTypeEnum.TOOL"
|
||||
@click="folderClickHandle"
|
||||
v-else
|
||||
/>
|
||||
<el-divider direction="vertical" />
|
||||
<el-radio-group v-model="toolType" @change="radioChange" class="app-radio-button-group">
|
||||
<el-radio-button value="">{{ $t('views.tool.all') }}</el-radio-button>
|
||||
|
|
|
|||
Loading…
Reference in New Issue