feat: Add language options to the embed

This commit is contained in:
fit2cloud-chenyw
2026-07-13 14:03:51 +08:00
committed by fit2cloud-chenyw
parent c8b5346d54
commit c4110f6a69
5 changed files with 147 additions and 8 deletions
+28 -5
View File
@@ -1,4 +1,4 @@
; (function () {
;(function () {
window.sqlbot_assistant_handler = window.sqlbot_assistant_handler || {}
const defaultData = {
id: '1',
@@ -74,6 +74,9 @@
if (data.history) {
srcUrl += `&history=${data.history}`
}
if (data.lang) {
srcUrl += `&lang=${data.lang}`
}
return `
<div id="sqlbot-assistant-chat-container">
<iframe id="sqlbot-assistant-chat-iframe-${data.id}" allow="microphone;clipboard-read 'src'; clipboard-write 'src'" src="${srcUrl}"></iframe>
@@ -171,12 +174,12 @@
}
chat_button_img.style.display = 'block'
function resizeImg() {
const rate = window.outerWidth / window.innerWidth;
chat_button_img.style.width = `${30 * (1 / rate)}px`;
chat_button_img.style.height = `${30 * (1 / rate)}px`;
const rate = window.outerWidth / window.innerWidth
chat_button_img.style.width = `${30 * (1 / rate)}px`
chat_button_img.style.height = `${30 * (1 / rate)}px`
}
resizeImg()
window.addEventListener('resize', resizeImg);
window.addEventListener('resize', resizeImg)
// 对话框元素
const chat_container = root.querySelector('#sqlbot-assistant-chat-container')
// 引导层
@@ -567,6 +570,7 @@
const online = getParam(src, 'online')
const userFlag = getParam(src, 'userFlag')
const history = getParam(src, 'history')
const lang = getParam(src, 'lang')
let url = `${domain_url}/api/v1/system/assistant/info/${id}`
if (domain_url.includes('5173')) {
url = url.replace('5173', '8000')
@@ -605,6 +609,7 @@
tempData['online'] = online && online.toString().toLowerCase() == 'true'
tempData['userFlag'] = userFlag
tempData['history'] = history
tempData['lang'] = lang
initsqlbot_assistant(tempData)
registerMessageEvent(id, tempData)
})
@@ -776,6 +781,24 @@
contentWindow.postMessage(params, url)
}
}
window.sqlbot_assistant_handler[id]['setLang'] = (lang) => {
if (lang != null && typeof lang != 'string') {
throw new Error('The parameter can only be of type string')
}
const iframe = document.getElementById(`sqlbot-assistant-chat-iframe-${id}`)
if (iframe) {
const url = iframe.src
const eventName = 'sqlbot_assistant_event'
const params = {
busi: 'setLang',
lang,
eventName,
messageId: id,
}
const contentWindow = iframe.contentWindow
contentWindow.postMessage(params, url)
}
}
window.sqlbot_assistant_handler[id]['refresh'] = (online, userFlag) => {
if (online != null && typeof online != 'boolean') {
throw new Error('The parameter can only be of type boolean')
+24
View File
@@ -12,7 +12,31 @@ import { getBrowserLocale } from '@/utils/utils'
const elementKoLocale = elementEnLocale
const { wsCache } = useCache()
const isEmbeddedRoute = () => {
const hash = window.location.hash
if (!hash) return false
const hashPath = hash.substring(1).split('?')[0]
return ['/assistant', '/embeddedPage', '/embeddedCommon'].includes(hashPath)
}
const getUrlLang = () => {
try {
const hash = window.location.hash
if (!hash) return null
const hashQuery = hash.substring(1).split('?')[1]
if (!hashQuery) return null
return new URLSearchParams(hashQuery).get('lang')
} catch {
return null
}
}
const getDefaultLocale = () => {
// 嵌入式页面的 URL lang 参数(第三种国际化渠道),优先级最高
const urlLang = getUrlLang()
if (urlLang && isEmbeddedRoute()) {
return urlLang
}
return wsCache.get('user.language') || getBrowserLocale() || 'zh-CN'
}
+17 -1
View File
@@ -30,6 +30,13 @@ const divLoading = ref(true)
const eventName = 'sqlbot_embedded_event'
const busiFlag = ref('ds')
const setParamLanguage = () => {
const lang = route.query.lang
if (lang) {
userStore.setLanguage(lang as string)
}
}
const isWsAdmin = computed(() => {
return userStore.isAdmin || userStore.isSpaceAdmin
})
@@ -49,13 +56,21 @@ const communicationCb = async (event: any) => {
assistantStore.setType(type)
assistantStore.setToken(certificate)
assistantStore.setAssistant(true)
await userStore.info()
try {
await userStore.info()
} catch (e) {
console.error('Failed to fetch user info in common embedded:', e)
}
setParamLanguage()
loading.value = false
return
}
if (event.data?.hostOrigin) {
assistantStore.setHostOrigin(event.data?.hostOrigin)
}
if (event.data?.busi == 'setLang') {
userStore.setLanguage(event.data.lang)
}
}
}
@@ -82,6 +97,7 @@ const registerReady = (assistantId: any) => {
}
onBeforeMount(async () => {
setParamLanguage()
const assistantId = route.query.id
if (!assistantId) {
ElMessage.error('Miss embedded id, please check embedded url')
+42 -1
View File
@@ -31,7 +31,16 @@
</div>
</template>
<script setup lang="ts">
import { onBeforeMount, nextTick, onBeforeUnmount, ref, onMounted, reactive, computed } from 'vue'
import {
onBeforeMount,
nextTick,
onBeforeUnmount,
ref,
onMounted,
reactive,
computed,
watch,
} from 'vue'
import ChatComponent from '@/views/chat/index.vue'
import { request } from '@/utils/request'
import LOGO from '@/assets/svg/logo-custom_small.svg'
@@ -42,6 +51,9 @@ import { assistantApi } from '@/api/assistant'
import { useAssistantStore } from '@/stores/assistant'
import { setCurrentColor } from '@/utils/utils'
import { useI18n } from 'vue-i18n'
import { i18n } from '@/i18n'
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
const { t } = useI18n()
const assistantStore = useAssistantStore()
@@ -92,6 +104,9 @@ const communicationCb = async (event: any) => {
if (event.data?.busi == 'createConversation') {
createChat()
}
if (event.data?.busi == 'setLang') {
userStore.setLanguage(event.data.lang)
}
}
}
const setFormatOnline = (text?: any) => {
@@ -128,6 +143,24 @@ const customSet = reactive({
theme: '#1CBA90',
header_font_color: '#1F2329',
}) as { [key: string]: any }
// 记录哪些字段被服务端 API 配置覆盖过,避免被 locale watcher 覆盖
const configuredKeys = new Set<string>()
// 监听 locale 变化,动态更新未被子定义覆盖的翻译字段
watch(
() => i18n.global.locale.value,
() => {
if (!configuredKeys.has('welcome')) {
customSet.welcome = t('embedded.i_am_sqlbot')
}
if (!configuredKeys.has('welcome_desc')) {
customSet.welcome_desc = t('embedded.data_analysis_now')
}
},
{ immediate: true }
)
const logo = ref()
const basePath = import.meta.env.VITE_API_BASE_URL
const baseUrl = basePath + '/system/assistant/picture/'
@@ -140,7 +173,14 @@ const setPageHeaderFontColor = (val: any) => {
const ele = document.querySelector('body') as HTMLElement
ele.style.setProperty('--ed-text-color-primary', val)
}
const setParamLanguage = () => {
const lang = route.query.lang
if (lang) {
userStore.setLanguage(lang as string)
}
}
onBeforeMount(async () => {
setParamLanguage()
const assistantId = route.query.id
if (!assistantId) {
ElMessage.error('Miss assistant id, please check assistant url')
@@ -197,6 +237,7 @@ onBeforeMount(async () => {
![null, undefined].includes(rawData[key])
) {
customSet[key] = rawData[key]
configuredKeys.add(key)
}
}
+36 -1
View File
@@ -22,6 +22,7 @@ import { assistantApi } from '@/api/assistant'
import { useAssistantStore } from '@/stores/assistant'
import { useAppearanceStoreWithOut } from '@/stores/appearance'
import { useI18n } from 'vue-i18n'
import { i18n } from '@/i18n'
import { request } from '@/utils/request'
import { setCurrentColor } from '@/utils/utils'
import { useUserStore } from '@/stores/user'
@@ -41,6 +42,24 @@ const customSet = reactive({
theme: '#1CBA90',
header_font_color: '#1F2329',
}) as { [key: string]: any }
// 记录哪些字段被服务端 API 配置覆盖过,避免被 locale watcher 覆盖
const configuredKeys = new Set<string>()
// 监听 locale 变化,动态更新未被子定义覆盖的翻译字段
watch(
() => i18n.global.locale.value,
() => {
if (!configuredKeys.has('welcome')) {
customSet.welcome = t('embedded.i_am_sqlbot')
}
if (!configuredKeys.has('welcome_desc')) {
customSet.welcome_desc = t('embedded.data_analysis_now')
}
},
{ immediate: true }
)
const logo = ref()
const basePath = import.meta.env.VITE_API_BASE_URL
const baseUrl = basePath + '/system/assistant/picture/'
@@ -65,7 +84,12 @@ const communicationCb = async (event: any) => {
if (type === 4) {
assistantStore.setToken(certificate)
assistantStore.setAssistant(true)
await userStore.info()
try {
await userStore.info()
} catch (e) {
console.error('Failed to fetch user info in embedded page:', e)
}
setParamLanguage()
loading.value = false
return
}
@@ -84,6 +108,9 @@ const communicationCb = async (event: any) => {
if (event.data?.busi == 'createConversation') {
createChat()
}
if (event.data?.busi == 'setLang') {
userStore.setLanguage(event.data.lang)
}
}
}
@@ -132,8 +159,15 @@ const setPageCustomColor = (val: any) => {
setCurrentColor(val, ele)
}
const setParamLanguage = () => {
const lang = route.query.lang
if (lang) {
userStore.setLanguage(lang as string)
}
}
onBeforeMount(async () => {
const assistantId = route.query.id
setParamLanguage()
if (!assistantId) {
ElMessage.error('Miss embedded id, please check embedded url')
return
@@ -193,6 +227,7 @@ onBeforeMount(async () => {
![null, undefined].includes(rawData[key])
) {
customSet[key] = rawData[key]
configuredKeys.add(key)
}
}