-
-
-`
- }
-
- function getHighestZIndexValue() {
- try {
- let maxZIndex = -Infinity
- let foundAny = false
-
- const allElements = document.all || document.querySelectorAll('*')
-
- for (let i = 0; i < allElements.length; i++) {
- const element = allElements[i]
-
- if (!element || element.nodeType !== 1) continue
-
- const styles = window.getComputedStyle(element)
-
- const position = styles.position
- if (position === 'static') continue
-
- const zIndex = styles.zIndex
- let zIndexValue
-
- if (zIndex === 'auto') {
- zIndexValue = 0
- } else {
- zIndexValue = parseInt(zIndex, 10)
- if (isNaN(zIndexValue)) continue
- }
-
- foundAny = true
-
- // 快速返回:如果找到很大的z-index,很可能就是最大值
- /* if (zIndexValue > 10000) {
- return zIndexValue;
- } */
-
- if (zIndexValue > maxZIndex) {
- maxZIndex = zIndexValue
- }
- }
- return foundAny ? maxZIndex : 0
- } catch (error) {
- console.warn('获取最高z-index时出错,返回默认值0:', error)
- return 0
- }
- }
-
- /**
- * 初始化引导
- * @param {*} root
- */
- const initGuide = (root) => {
- root.insertAdjacentHTML('beforeend', guideHtml)
- const button = root.querySelector('.sqlbot-assistant-button')
- const close_icon = root.querySelector('.sqlbot-assistant-close')
- const close_func = () => {
- root.removeChild(root.querySelector('.sqlbot-assistant-tips'))
- root.removeChild(root.querySelector('.sqlbot-assistant-mask'))
- localStorage.setItem('sqlbot_assistant_mask_tip', true)
- }
- button.onclick = close_func
- close_icon.onclick = close_func
- }
- const initChat = (root, data) => {
- // 添加对话icon
- root.insertAdjacentHTML('beforeend', chatButtonHtml(data))
- // 添加对话框
- root.insertAdjacentHTML('beforeend', getChatContainerHtml(data))
- // 按钮元素
- const chat_button = root.querySelector('.sqlbot-assistant-chat-button')
- let chat_button_img = root.querySelector('.sqlbot-assistant-chat-button > svg')
- if (data.float_icon) {
- chat_button_img = root.querySelector('.sqlbot-assistant-chat-button > img')
- }
- 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`;
- }
- resizeImg()
- window.addEventListener('resize', resizeImg);
- // 对话框元素
- const chat_container = root.querySelector('#sqlbot-assistant-chat-container')
- // 引导层
- const mask_content = root.querySelector('.sqlbot-assistant-mask > .sqlbot-assistant-content')
- const mask_tips = root.querySelector('.sqlbot-assistant-tips')
- chat_button_img.onload = (event) => {
- if (mask_content) {
- mask_content.style.width = chat_button_img.width + 'px'
- mask_content.style.height = chat_button_img.height + 'px'
- if (data.x_type == 'left') {
- mask_tips.style.marginLeft =
- (chat_button_img.naturalWidth > 500 ? 500 : chat_button_img.naturalWidth) - 64 + 'px'
- } else {
- mask_tips.style.marginRight =
- (chat_button_img.naturalWidth > 500 ? 500 : chat_button_img.naturalWidth) - 64 + 'px'
- }
- }
- }
-
- const viewport = root.querySelector('.sqlbot-assistant-openviewport')
- const closeviewport = root.querySelector('.sqlbot-assistant-closeviewport')
- const close_func = () => {
- chat_container.style['display'] =
- chat_container.style['display'] == 'block' ? 'none' : 'block'
- chat_button.style['display'] = chat_container.style['display'] == 'block' ? 'none' : 'block'
- }
- close_icon = chat_container.querySelector('.sqlbot-assistant-chat-close')
- chat_button.onclick = close_func
- close_icon.onclick = close_func
- const viewport_func = () => {
- if (chat_container.classList.contains('sqlbot-assistant-enlarge')) {
- chat_container.classList.remove('sqlbot-assistant-enlarge')
- viewport.classList.remove('sqlbot-assistant-viewportnone')
- closeviewport.classList.add('sqlbot-assistant-viewportnone')
- } else {
- chat_container.classList.add('sqlbot-assistant-enlarge')
- viewport.classList.add('sqlbot-assistant-viewportnone')
- closeviewport.classList.remove('sqlbot-assistant-viewportnone')
- }
- }
- if (data.float_icon_drag) {
- chat_button.setAttribute('draggable', 'true')
-
- let startX = 0
- let startY = 0
- const img = new Image()
- img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='
- chat_button.addEventListener('dragstart', (e) => {
- startX = e.clientX - chat_button.offsetLeft
- startY = e.clientY - chat_button.offsetTop
- e.dataTransfer.setDragImage(img, 0, 0)
- })
-
- chat_button.addEventListener('drag', (e) => {
- if (e.clientX && e.clientY) {
- const left = e.clientX - startX
- const top = e.clientY - startY
-
- const maxX = window.innerWidth - chat_button.offsetWidth
- const maxY = window.innerHeight - chat_button.offsetHeight
-
- chat_button.style.left = Math.min(Math.max(0, left), maxX) + 'px'
- chat_button.style.top = Math.min(Math.max(0, top), maxY) + 'px'
- }
- })
-
- let touchStartX = 0
- let touchStartY = 0
-
- chat_button.addEventListener('touchstart', (e) => {
- touchStartX = e.touches[0].clientX - chat_button.offsetLeft
- touchStartY = e.touches[0].clientY - chat_button.offsetTop
- e.preventDefault()
- })
-
- chat_button.addEventListener('touchmove', (e) => {
- const left = e.touches[0].clientX - touchStartX
- const top = e.touches[0].clientY - touchStartY
-
- const maxX = window.innerWidth - chat_button.offsetWidth
- const maxY = window.innerHeight - chat_button.offsetHeight
-
- chat_button.style.left = Math.min(Math.max(0, left), maxX) + 'px'
- chat_button.style.top = Math.min(Math.max(0, top), maxY) + 'px'
-
- e.preventDefault()
- })
- }
- /* const drag = (e) => {
- if (['touchmove', 'touchstart'].includes(e.type)) {
- chat_button.style.top = e.touches[0].clientY - chat_button_img.clientHeight / 2 + 'px'
- chat_button.style.left = e.touches[0].clientX - chat_button_img.clientHeight / 2 + 'px'
- } else {
- chat_button.style.top = e.y - chat_button_img.clientHeight / 2 + 'px'
- chat_button.style.left = e.x - chat_button_img.clientHeight / 2 + 'px'
- }
- chat_button.style.width = chat_button_img.clientHeight + 'px'
- chat_button.style.height = chat_button_img.clientHeight + 'px'
- }
- if (data.float_icon_drag) {
- chat_button.setAttribute('draggable', 'true')
- chat_button.addEventListener('drag', drag)
- chat_button.addEventListener('dragover', (e) => {
- e.preventDefault()
- })
- chat_button.addEventListener('dragend', drag)
- chat_button.addEventListener('touchstart', drag)
- chat_button.addEventListener('touchmove', drag)
- } */
- viewport.onclick = viewport_func
- closeviewport.onclick = viewport_func
- }
- /**
- * 第一次进来的引导提示
- */
- function initsqlbot_assistant(data) {
- const sqlbot_div = document.createElement('div')
- const root = document.createElement('div')
- const sqlbot_root_id = 'sqlbot-assistant-root-' + data.id
- root.id = sqlbot_root_id
- initsqlbot_assistantStyle(sqlbot_div, sqlbot_root_id, data)
- sqlbot_div.appendChild(root)
- document.body.appendChild(sqlbot_div)
- const sqlbot_assistant_mask_tip = localStorage.getItem('sqlbot_assistant_mask_tip')
- if (sqlbot_assistant_mask_tip == null && data.show_guide) {
- initGuide(root)
- }
- initChat(root, data)
- }
-
- // 初始化全局样式
- function initsqlbot_assistantStyle(root, sqlbot_assistantId, data) {
- const maxZIndex = getHighestZIndexValue()
- const zIndex = Math.max((maxZIndex || 0) + 1, 10000)
- const maskZIndex = zIndex + 1
- style = document.createElement('style')
- style.type = 'text/css'
- style.innerText = `
- /* 放大 */
- #sqlbot-assistant .sqlbot-assistant-enlarge {
- width: 50%!important;
- height: 100%!important;
- bottom: 0!important;
- right: 0 !important;
- }
- @media only screen and (max-width: 768px){
- #sqlbot-assistant .sqlbot-assistant-enlarge {
- width: 100%!important;
- height: 100%!important;
- right: 0 !important;
- bottom: 0!important;
- }
- }
-
- /* 引导 */
-
- #sqlbot-assistant .sqlbot-assistant-mask {
- position: fixed;
- z-index: ${maskZIndex};
- background-color: transparent;
- height: 100%;
- width: 100%;
- top: 0;
- left: 0;
- }
- #sqlbot-assistant .sqlbot-assistant-mask .sqlbot-assistant-content {
- width: 64px;
- height: 64px;
- box-shadow: 1px 1px 1px 9999px rgba(0,0,0,.6);
- position: absolute;
- ${data.x_type}: ${data.x_val}px;
- ${data.y_type}: ${data.y_val}px;
- z-index: ${maskZIndex};
- }
- #sqlbot-assistant .sqlbot-assistant-tips {
- position: fixed;
- ${data.x_type}:calc(${data.x_val}px + 75px);
- ${data.y_type}: calc(${data.y_val}px + 0px);
- padding: 22px 24px 24px;
- border-radius: 6px;
- color: #ffffff;
- font-size: 14px;
- background: #3370FF;
- z-index: ${maskZIndex};
- }
- #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-arrow {
- position: absolute;
- background: #3370FF;
- width: 10px;
- height: 10px;
- pointer-events: none;
- transform: rotate(45deg);
- box-sizing: border-box;
- /* left */
- ${data.x_type}: -5px;
- ${data.y_type}: 33px;
- border-left-color: transparent;
- border-bottom-color: transparent
- }
- #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-title {
- font-size: 20px;
- font-weight: 500;
- margin-bottom: 8px;
- }
- #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-button {
- text-align: right;
- margin-top: 24px;
- }
- #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-button button {
- border-radius: 4px;
- background: #FFF;
- padding: 3px 12px;
- color: #3370FF;
- cursor: pointer;
- outline: none;
- border: none;
- }
- #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-button button::after{
- border: none;
- }
- #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-close {
- position: absolute;
- right: 20px;
- top: 20px;
- cursor: pointer;
-
- }
- #sqlbot-assistant-chat-container {
- width: 460px;
- height: 640px;
- display:none;
- }
- @media only screen and (max-width: 768px) {
- #sqlbot-assistant-chat-container {
- width: 100%;
- height: 70%;
- right: 0 !important;
- }
- }
-
- #sqlbot-assistant .sqlbot-assistant-chat-button{
- position: fixed;
- ${data.x_type}: ${data.x_val}px;
- ${data.y_type}: ${data.y_val}px;
- cursor: pointer;
- z-index: ${zIndex};
- }
- #sqlbot-assistant #sqlbot-assistant-chat-container{
- z-index: ${zIndex};
- position: relative;
- border-radius: 8px;
- //border: 1px solid #ffffff;
- background: linear-gradient(188deg, rgba(235, 241, 255, 0.20) 39.6%, rgba(231, 249, 255, 0.20) 94.3%), #EFF0F1;
- box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.10);
- position: fixed;bottom: 16px;right: 16px;overflow: hidden;
- }
-
- .ed-overlay-dialog {
- margin-top: 50px;
- }
- .ed-drawer {
- margin-top: 50px;
- }
-
- #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate{
- top: 18px;
- right: 15px;
- position: absolute;
- display: flex;
- align-items: center;
- line-height: 18px;
- }
- #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-chat-close{
- margin-left:15px;
- cursor: pointer;
- }
- #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-openviewport{
-
- cursor: pointer;
- }
- #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-closeviewport{
-
- cursor: pointer;
- }
- #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-viewportnone{
- display:none;
- }
- #sqlbot-assistant #sqlbot-assistant-chat-container #sqlbot-assistant-chat-iframe-${data.id} {
- height:100%;
- width:100%;
- border: none;
- }
- #sqlbot-assistant #sqlbot-assistant-chat-container {
- animation: appear .4s ease-in-out;
- }
- @keyframes appear {
- from {
- height: 0;;
- }
-
- to {
- height: 600px;
- }
- }`.replaceAll('#sqlbot-assistant ', `#${sqlbot_assistantId} `)
- root.appendChild(style)
- }
- function getParam(src, key) {
- const url = new URL(src)
- return url.searchParams.get(key)
- }
- function parsrCertificate(config) {
- const certificateList = config.certificate
- if (!certificateList?.length) {
- return null
- }
- const list = certificateList.map((item) => formatCertificate(item)).filter((item) => !!item)
- return JSON.stringify(list)
- }
- function isEmpty(obj) {
- return obj == null || typeof obj == 'undefined'
- }
- function formatCertificate(item) {
- const { type, source, target, target_key, target_val } = item
- let source_val = null
- if (type.toLocaleLowerCase() == 'localstorage') {
- source_val = localStorage.getItem(source)
- }
- if (type.toLocaleLowerCase() == 'sessionstorage') {
- source_val = sessionStorage.getItem(source)
- }
- if (type.toLocaleLowerCase() == 'cookie') {
- source_val = getCookie(source)
- }
- if (type.toLocaleLowerCase() == 'custom') {
- source_val = source
- }
- if (isEmpty(source_val)) {
- return null
- }
- return {
- target,
- key: target_key || source,
- value: (target_val && eval(target_val)) || source_val,
- }
- }
- function getCookie(key) {
- if (!key || !document.cookie) {
- return null
- }
- const cookies = document.cookie.split(';')
- for (let i = 0; i < cookies.length; i++) {
- const cookie = cookies[i].trim()
-
- if (cookie.startsWith(key + '=')) {
- return decodeURIComponent(cookie.substring(key.length + 1))
- }
- }
- return null
- }
- function registerMessageEvent(id, data) {
- const iframe = document.getElementById(`sqlbot-assistant-chat-iframe-${id}`)
- const url = iframe.src
- const eventName = 'sqlbot_assistant_event'
- window.addEventListener('message', (event) => {
- if (event.data?.eventName === eventName) {
- if (event.data?.messageId !== id) {
- return
- }
- if (event.data?.busi == 'ready' && event.data?.ready) {
- params = {
- eventName,
- messageId: id,
- hostOrigin: window.location.origin,
- }
- if (data.type === 1) {
- const certificate = parsrCertificate(data)
- params['busi'] = 'certificate'
- params['certificate'] = certificate
- }
- const contentWindow = iframe.contentWindow
- contentWindow.postMessage(params, url)
- }
- }
- })
- }
- function loadScript(src, id) {
- const domain_url = getDomain(src)
- const online = getParam(src, 'online')
- const userFlag = getParam(src, 'userFlag')
- const history = getParam(src, 'history')
- let url = `${domain_url}/api/v1/system/assistant/info/${id}`
- if (domain_url.includes('5173')) {
- url = url.replace('5173', '8000')
- }
- fetch(url)
- .then((response) => response.json())
- .then((res) => {
- if (!res.data) {
- throw new Error(res)
- }
- const data = res.data
- const config_json = data.configuration
- let tempData = Object.assign(defaultData, data)
- if (tempData.configuration) {
- delete tempData.configuration
- }
- if (config_json) {
- const config = JSON.parse(config_json)
- if (config) {
- delete config.id
- tempData = Object.assign(tempData, config)
- }
- }
- tempData['id'] = id
- tempData['domain_url'] = domain_url
-
- if (tempData['float_icon'] && !tempData['float_icon'].startsWith('http://')) {
- tempData['float_icon'] =
- `${domain_url}/api/v1/system/assistant/picture/${tempData['float_icon']}`
-
- if (domain_url.includes('5173')) {
- tempData['float_icon'] = tempData['float_icon'].replace('5173', '8000')
- }
- }
-
- tempData['online'] = online && online.toString().toLowerCase() == 'true'
- tempData['userFlag'] = userFlag
- tempData['history'] = history
- initsqlbot_assistant(tempData)
- registerMessageEvent(id, tempData)
- })
- .catch((e) => {
- showMsg('嵌入失败', e.message)
- })
- }
- function getDomain(src) {
- return src.substring(0, src.indexOf('/assistant.js'))
- }
- function init() {
- const sqlbotScripts = document.querySelectorAll(`script[id^="${script_id_prefix}"]`)
- const scriptsArray = Array.from(sqlbotScripts)
- const src_list = scriptsArray.map((script) => script.src)
- src_list.forEach((src) => {
- const id = getParam(src, 'id')
- window.sqlbot_assistant_handler[id] = window.sqlbot_assistant_handler[id] || {}
- window.sqlbot_assistant_handler[id]['id'] = id
- const propName = script_id_prefix + id + '-state'
- if (window[propName]) {
- return true
- }
- window[propName] = true
- loadScript(src, id)
- expposeGlobalMethods(id)
- })
- }
-
- function showMsg(title, content) {
- // 检查并创建容器(如果不存在)
- let container = document.getElementById('messageContainer')
- if (!container) {
- container = document.createElement('div')
- container.id = 'messageContainer'
- container.style.position = 'fixed'
- container.style.bottom = '20px'
- container.style.right = '20px'
- container.style.zIndex = '1000'
- document.body.appendChild(container)
- } else {
- // 如果容器已存在,先移除旧弹窗
- const oldMessage = container.querySelector('div')
- if (oldMessage) {
- oldMessage.style.transform = 'translateX(120%)'
- oldMessage.style.opacity = '0'
- setTimeout(() => {
- container.removeChild(oldMessage)
- }, 300)
- }
- }
-
- // 创建弹窗元素
- const messageBox = document.createElement('div')
- messageBox.style.width = '240px'
- messageBox.style.minHeight = '100px'
- messageBox.style.background = 'linear-gradient(135deg, #ff6b6b, #ff8e8e)'
- messageBox.style.borderRadius = '8px'
- messageBox.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)'
- messageBox.style.padding = '15px'
- messageBox.style.color = 'white'
- messageBox.style.fontFamily = 'Arial, sans-serif'
- messageBox.style.display = 'flex'
- messageBox.style.flexDirection = 'column'
- messageBox.style.transform = 'translateX(120%)'
- messageBox.style.transition = 'transform 0.3s ease-out'
- messageBox.style.opacity = '0'
- messageBox.style.transition = 'opacity 0.3s ease, transform 0.3s ease'
- messageBox.style.overflow = 'hidden'
-
- // 创建标题元素
- const titleElement = document.createElement('div')
- titleElement.style.fontSize = '18px'
- titleElement.style.fontWeight = 'bold'
- titleElement.style.marginBottom = '10px'
- titleElement.style.borderBottom = '1px solid rgba(255, 255, 255, 0.3)'
- titleElement.style.paddingBottom = '8px'
- titleElement.textContent = title
-
- // 创建内容元素
- const contentElement = document.createElement('div')
- contentElement.style.fontSize = '14px'
- contentElement.style.flexGrow = '1'
- contentElement.style.overflow = 'auto'
- contentElement.textContent = content
-
- // 组装元素
- messageBox.appendChild(titleElement)
- messageBox.appendChild(contentElement)
-
- // 添加到容器
- container.appendChild(messageBox)
-
- // 触发显示动画
- setTimeout(() => {
- messageBox.style.transform = 'translateX(0)'
- messageBox.style.opacity = '1'
- }, 10)
-
- // 3秒后自动隐藏
- setTimeout(() => {
- messageBox.style.transform = 'translateX(120%)'
- messageBox.style.opacity = '0'
- setTimeout(() => {
- container.removeChild(messageBox)
- // 如果容器是空的,也移除容器
- if (container.children.length === 0) {
- document.body.removeChild(container)
- }
- }, 300)
- }, 5000)
- }
-
- /* function hideMsg() {
- const container = document.getElementById('messageContainer');
- if (container) {
- const messageBox = container.querySelector('div');
- if (messageBox) {
- messageBox.style.transform = 'translateX(120%)';
- messageBox.style.opacity = '0';
- setTimeout(() => {
- container.removeChild(messageBox);
- // 如果容器是空的,也移除容器
- if (container.children.length === 0) {
- document.body.removeChild(container);
- }
- }, 300);
- }
- }
- } */
-
- function updateParam(target_url, key, newValue) {
- try {
- const url = new URL(target_url)
- const [hashPath, hashQuery] = url.hash.split('?')
- let searchParams
- if (hashQuery) {
- searchParams = new URLSearchParams(hashQuery)
- } else {
- searchParams = url.searchParams
- }
- searchParams.set(key, newValue)
- if (hashQuery) {
- url.hash = `${hashPath}?${searchParams.toString()}`
- } else {
- url.search = searchParams.toString()
- }
- return url.toString()
- } catch (e) {
- console.error('Invalid URL:', target_url)
- return target_url
- }
- }
- function expposeGlobalMethods(id) {
- window.sqlbot_assistant_handler[id]['setOnline'] = (online) => {
- if (online != null && typeof online != 'boolean') {
- throw new Error('The parameter can only be of type boolean')
- }
- const iframe = document.getElementById(`sqlbot-assistant-chat-iframe-${id}`)
- if (iframe) {
- const url = iframe.src
- const eventName = 'sqlbot_assistant_event'
- const params = {
- busi: 'setOnline',
- online,
- 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')
- }
- const iframe = document.getElementById(`sqlbot-assistant-chat-iframe-${id}`)
- if (iframe) {
- const url = iframe.src
- let new_url = updateParam(url, 't', Date.now())
- if (online != null) {
- new_url = updateParam(new_url, 'online', online)
- }
- if (userFlag != null) {
- new_url = updateParam(new_url, 'userFlag', userFlag)
- }
- iframe.src = 'about:blank'
- setTimeout(() => {
- iframe.src = new_url
- }, 500)
- }
- }
- window.sqlbot_assistant_handler[id]['destroy'] = () => {
- const sqlbot_root_id = 'sqlbot-assistant-root-' + id
- const container_div = document.getElementById(sqlbot_root_id)
- if (container_div) {
- const root_div = container_div.parentNode
- if (root_div?.parentNode) {
- root_div.parentNode.removeChild(root_div)
- }
- }
-
- const scriptDom = document.getElementById(`sqlbot-assistant-float-script-${id}`)
- if (scriptDom) {
- scriptDom.parentNode.removeChild(scriptDom)
- }
- const propName = script_id_prefix + id + '-state'
- if (window[propName]) {
- delete window[propName]
- }
- delete window.sqlbot_assistant_handler[id]
- }
- window.sqlbot_assistant_handler[id]['setHistory'] = (show) => {
- if (show != null && typeof show != 'boolean') {
- throw new Error('The parameter can only be of type boolean')
- }
- const iframe = document.getElementById(`sqlbot-assistant-chat-iframe-${id}`)
- if (iframe) {
- const url = iframe.src
- const eventName = 'sqlbot_assistant_event'
- const params = {
- busi: 'setHistory',
- show,
- eventName,
- messageId: id,
- }
- const contentWindow = iframe.contentWindow
- contentWindow.postMessage(params, url)
- }
- }
- window.sqlbot_assistant_handler[id]['createConversation'] = (param) => {
- const iframe = document.getElementById(`sqlbot-assistant-chat-iframe-${id}`)
- if (iframe) {
- const url = iframe.src
- const eventName = 'sqlbot_assistant_event'
- const params = {
- busi: 'createConversation',
- param,
- eventName,
- messageId: id,
- }
- const contentWindow = iframe.contentWindow
- contentWindow.postMessage(params, url)
- }
- }
- }
- // window.addEventListener('load', init)
- const executeWhenReady = (fn) => {
- if (
- document.readyState === 'complete' ||
- (document.readyState !== 'loading' && !document.documentElement.doScroll)
- ) {
- setTimeout(fn, 0)
- } else {
- const onReady = () => {
- document.removeEventListener('DOMContentLoaded', onReady)
- window.removeEventListener('load', onReady)
- fn()
- }
- document.addEventListener('DOMContentLoaded', onReady)
- window.addEventListener('load', onReady)
- }
- }
-
- executeWhenReady(init)
-})()
diff --git a/frontend/public/swagger-ui-bundle.js b/frontend/public/swagger-ui-bundle.js
index cdbe29ace..dcfadae0b 100644
--- a/frontend/public/swagger-ui-bundle.js
+++ b/frontend/public/swagger-ui-bundle.js
@@ -41749,7 +41749,8 @@
const s = new Error(a.statusText || `response status is ${a.status}`)
// if (a.status === 401 && a.statusText === 'Unauthorized') {
if (a.status === 401) {
- location.href = location.pathname.replace('/docs', '/') + '#/401?title=unauthorized&target=docs'
+ location.href =
+ location.pathname.replace('/docs', '/') + '#/401?title=unauthorized&target=docs'
return a
}
throw ((s.status = a.status), (s.statusCode = a.status), (s.response = a), s)
@@ -56482,8 +56483,15 @@
const a = o.getConfigs().withCredentials
o.fn.fetch.withCredentials = a
})
+ function getTokenKey() {
+ var pathname = window.location.pathname.replace('docs', '')
+ var match = pathname.match(/^\/([^\/]+)/)
+ var prefix = match ? `${match[1]}_` : 'sqlbot_v1_'
+ return `${prefix}user.token`
+ }
function get_token() {
- var tokenCache = localStorage.getItem('user.token')
+ var token_key = getTokenKey()
+ var tokenCache = localStorage.getItem(token_key)
if (!tokenCache) {
return null
}
diff --git a/frontend/src/api/assistant.ts b/frontend/src/api/assistant.ts
index bb955e09f..b883976f0 100644
--- a/frontend/src/api/assistant.ts
+++ b/frontend/src/api/assistant.ts
@@ -6,6 +6,6 @@ export const assistantApi = {
add: (data: any) => request.post('/system/assistant', data),
edit: (data: any) => request.put('/system/assistant', data),
delete: (id: number) => request.delete(`/system/assistant/${id}`),
- query: (id: number) => request.get(`/system/assistant/${id}`),
+ // query: (id: number) => request.get(`/system/assistant/${id}`),
validate: (data: any) => request.get('/system/assistant/validator', { params: data }),
}
diff --git a/frontend/src/api/chat.ts b/frontend/src/api/chat.ts
index 2a5870632..4a52187ee 100644
--- a/frontend/src/api/chat.ts
+++ b/frontend/src/api/chat.ts
@@ -474,7 +474,7 @@ export const chatApi = {
return request.post('/chat/rename', { id: chat_id, brief: brief })
},
deleteChat: (id: number | undefined, brief: any): Promise
=> {
- return request.delete(`/chat/${id}/${brief}`)
+ return request.delete(`/chat/${id}`, { data: { id: id, brief: brief } })
},
analysis: (record_id: number | undefined, controller?: AbortController) => {
return request.fetchStream(`/chat/record/${record_id}/analysis`, {}, controller)
diff --git a/frontend/src/api/embedded.ts b/frontend/src/api/embedded.ts
index 0733088ae..2e51008ae 100644
--- a/frontend/src/api/embedded.ts
+++ b/frontend/src/api/embedded.ts
@@ -5,7 +5,7 @@ export const getAdvancedApplicationList = () =>
request.get('/system/assistant/advanced_application')
export const updateAssistant = (data: any) => request.put('/system/assistant', data)
export const saveAssistant = (data: any) => request.post('/system/assistant', data)
-export const getOne = (id: any) => request.get(`/system/assistant/${id}`)
+// export const getOne = (id: any) => request.get(`/system/assistant/${id}`)
export const delOne = (id: any) => request.delete(`/system/assistant/${id}`)
export const dsApi = (id: any) => request.get(`/datasource/ws/${id}`)
diff --git a/frontend/src/api/system.ts b/frontend/src/api/system.ts
index f9ed3ec10..4d56fecb1 100644
--- a/frontend/src/api/system.ts
+++ b/frontend/src/api/system.ts
@@ -27,6 +27,8 @@ export const modelApi = {
query: (id: number) => request.get(`/system/aimodel/${id}`),
setDefault: (id: number) => request.put(`/system/aimodel/default/${id}`),
check: (data: any) => request.fetchStream('/system/aimodel/status', data),
- platform: (id: number) => request.get(`/system/platform/org/${id}`),
+ platform: (id: number, lazy?: number, pid?: string) =>
+ request.post(`/system/platform/org/${id}`, { lazy, pid }),
userSync: (data: any) => request.post(`/system/platform/user/sync`, data),
+ list_by_ws: () => request.get(`/system/aimodel/list/by_ws`),
}
diff --git a/frontend/src/api/workspace.ts b/frontend/src/api/workspace.ts
index 5298045b5..46637678c 100644
--- a/frontend/src/api/workspace.ts
+++ b/frontend/src/api/workspace.ts
@@ -15,3 +15,12 @@ export const workspaceDelete = (id: any) => request.delete(`/system/workspace/${
export const workspaceList = () => request.get('/system/workspace')
export const workspaceDetail = (id: any) => request.get(`/system/workspace/${id}`)
export const uwsOption = (params: any) => request.get('system/workspace/uws/option', { params })
+
+export const workspaceModelMapping = (aiModelId: any) =>
+ request.get(`/system/aimodel/${aiModelId}/ws_mapping`)
+export const workspaceModelMappingUpdate = (aiModelId: any, data: any) =>
+ request.put(`/system/aimodel/${aiModelId}/ws_mapping`, data)
+export const workspaceModelMappingAdd = (aiModelId: any, data: any) =>
+ request.post(`/system/aimodel/${aiModelId}/ws_mapping`, data)
+export const workspaceModelMappingDelete = (aiModelId: any, data: any) =>
+ request.delete(`/system/aimodel/${aiModelId}/ws_mapping`, { data })
diff --git a/frontend/src/assets/datasource/icon_hive.png b/frontend/src/assets/datasource/icon_hive.png
new file mode 100644
index 000000000..51b996f5e
Binary files /dev/null and b/frontend/src/assets/datasource/icon_hive.png differ
diff --git a/frontend/src/assets/datasource/icon_sqlite.png b/frontend/src/assets/datasource/icon_sqlite.png
new file mode 100644
index 000000000..1a198d0b4
Binary files /dev/null and b/frontend/src/assets/datasource/icon_sqlite.png differ
diff --git a/frontend/src/assets/svg/chart/icon-thousand-separator.svg b/frontend/src/assets/svg/chart/icon-thousand-separator.svg
new file mode 100644
index 000000000..670e86901
--- /dev/null
+++ b/frontend/src/assets/svg/chart/icon-thousand-separator.svg
@@ -0,0 +1,6 @@
+
diff --git a/frontend/src/assets/svg/icon_block_outlined.svg b/frontend/src/assets/svg/icon_block_outlined.svg
new file mode 100644
index 000000000..ffefda2c0
--- /dev/null
+++ b/frontend/src/assets/svg/icon_block_outlined.svg
@@ -0,0 +1,11 @@
+
diff --git a/frontend/src/assets/svg/icon_describe_outlined.svg b/frontend/src/assets/svg/icon_describe_outlined.svg
new file mode 100644
index 000000000..7dc0951b4
--- /dev/null
+++ b/frontend/src/assets/svg/icon_describe_outlined.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/src/assets/svg/workspace-white.svg b/frontend/src/assets/svg/workspace-white.svg
new file mode 100644
index 000000000..7e9cac0a5
--- /dev/null
+++ b/frontend/src/assets/svg/workspace-white.svg
@@ -0,0 +1,5 @@
+
diff --git a/frontend/src/components/Language-selector/index.vue b/frontend/src/components/Language-selector/index.vue
index 8b21e4904..7ba9b37cf 100644
--- a/frontend/src/components/Language-selector/index.vue
+++ b/frontend/src/components/Language-selector/index.vue
@@ -34,6 +34,7 @@ const userStore = useUserStore()
const languageOptions = computed(() => [
{ value: 'en', label: t('common.english') },
{ value: 'zh-CN', label: t('common.simplified_chinese') },
+ { value: 'zh-TW', label: t('common.traditional_chinese') },
{ value: 'ko-KR', label: t('common.korean') },
])
diff --git a/frontend/src/components/drawer-filter/src/DrawerEnumFilter.vue b/frontend/src/components/drawer-filter/src/DrawerEnumFilter.vue
index a7cae5c5d..262b5c710 100644
--- a/frontend/src/components/drawer-filter/src/DrawerEnumFilter.vue
+++ b/frontend/src/components/drawer-filter/src/DrawerEnumFilter.vue
@@ -84,7 +84,7 @@ useEmitt({
padding: 1px 6px;
background: var(--deTextPrimary5, #f5f6f7);
color: var(--deTextPrimary, #1f2329);
- border-radius: 4px;
+ border-radius: 6px;
cursor: pointer;
display: inline-block;
margin-bottom: 12px;
diff --git a/frontend/src/components/filter-text/src/FilterText.vue b/frontend/src/components/filter-text/src/FilterText.vue
index 4eedaa269..d423543d4 100644
--- a/frontend/src/components/filter-text/src/FilterText.vue
+++ b/frontend/src/components/filter-text/src/FilterText.vue
@@ -181,7 +181,7 @@ watch(
.arrow-filter:hover {
background: rgba(31, 35, 41, 0.1);
- border-radius: 4px;
+ border-radius: 6px;
}
.ed-icon-arrow-right.arrow-filter {
diff --git a/frontend/src/components/layout/Apikey.vue b/frontend/src/components/layout/Apikey.vue
index d55e37a16..ee17bd56c 100644
--- a/frontend/src/components/layout/Apikey.vue
+++ b/frontend/src/components/layout/Apikey.vue
@@ -38,7 +38,7 @@ const handleAdd = () => {
const pwd = ref('**********')
const toApiDoc = () => {
console.log('Add API Key')
- const url = '/docs'
+ const url = './docs'
window.open(url, '_blank')
}
diff --git a/frontend/src/components/layout/Person.vue b/frontend/src/components/layout/Person.vue
index a683ab1dc..a58a02afb 100644
--- a/frontend/src/components/layout/Person.vue
+++ b/frontend/src/components/layout/Person.vue
@@ -58,6 +58,10 @@ const languageList = computed(() => [
name: '简体中文',
value: 'zh-CN',
},
+ {
+ name: '繁體中文',
+ value: 'zh-TW',
+ },
{
name: '한국인',
value: 'ko-KR',
@@ -341,7 +345,7 @@ const logout = async () => {
position: relative;
cursor: pointer;
margin: 0 4px;
- border-radius: 4px;
+ border-radius: 6px;
&:hover {
background-color: #1f23291a;
}
@@ -378,7 +382,7 @@ const logout = async () => {
padding-right: 8px;
margin-bottom: 2px;
position: relative;
- border-radius: 4px;
+ border-radius: 6px;
cursor: pointer;
&:not(.empty):hover {
background: #1f23291a;
diff --git a/frontend/src/components/layout/Workspace.vue b/frontend/src/components/layout/Workspace.vue
index 1f76e92ad..456c083cd 100644
--- a/frontend/src/components/layout/Workspace.vue
+++ b/frontend/src/components/layout/Workspace.vue
@@ -198,7 +198,7 @@ onMounted(async () => {
padding-right: 8px;
margin-bottom: 2px;
position: relative;
- border-radius: 4px;
+ border-radius: 6px;
cursor: pointer;
&:not(.empty):hover {
background: #1f23291a;
diff --git a/frontend/src/components/layout/index.vue b/frontend/src/components/layout/index.vue
index f83ef983a..4a0097e41 100644
--- a/frontend/src/components/layout/index.vue
+++ b/frontend/src/components/layout/index.vue
@@ -362,7 +362,7 @@ onMounted(() => {
column-gap: 12px;
align-items: center;
padding: 8px 16px;
- border-radius: 4px;
+ border-radius: 6px;
cursor: pointer;
border: none;
font-weight: 500;
@@ -493,7 +493,7 @@ onMounted(() => {
column-gap: 12px;
align-items: center;
padding: 8px 16px;
- border-radius: 4px;
+ border-radius: 6px;
cursor: pointer;
border: none;
font-weight: 500;
diff --git a/frontend/src/entity/supplier.ts b/frontend/src/entity/supplier.ts
index cd672f9d8..bd4ddc971 100644
--- a/frontend/src/entity/supplier.ts
+++ b/frontend/src/entity/supplier.ts
@@ -276,7 +276,7 @@ export const supplierList: Array<{
{ name: 'doubao-1-5-pro-32k-character-250715' },
{ name: 'kimi-k2-250711' },
{ name: 'deepseek-v3-250324' },
- { name: 'deepseek-r1' },
+ { name: 'deepseek-v4-pro-260425' },
],
},
},
@@ -290,11 +290,7 @@ export const supplierList: Array<{
0: {
api_domain: 'https://api.minimax.io/v1',
common_args: [{ key: 'temperature', val: 0.7, type: 'number', range: '[0, 1]' }],
- model_options: [
- { name: 'MiniMax-M2.7' },
- { name: 'MiniMax-M2.5' },
- { name: 'MiniMax-M2.5-highspeed' },
- ],
+ model_options: [{ name: 'MiniMax-M3' }, { name: 'MiniMax-M2.7' }],
},
},
},
diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index 298e91bb0..4cdef7da8 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -32,12 +32,24 @@
"enter_variable_name": "Please Enter Variable Name",
"enter_variable_value": "Please Enter Variable Value"
},
+ "authorized_space": {
+ "authorized_space": "Authorized Space",
+ "authorized_space_list": "Authorized Space List",
+ "select_space": "Select Space",
+ "modify_authorized_space": "Modify Authorized Space",
+ "workspaces_authorized": "Authorized {num} Workspaces",
+ "number_of_members": "Number of Members",
+ "delete_selected_workspaces": "Are you sure you want to delete the selected {msg} workspaces?",
+ "delete_workspace": "Are you sure you want to delete the workspace: {msg}?",
+ "no_workspace": "No Workspaces"
+ },
"sync": {
- "records":"Displaying {num} records out of {total}",
- "confirm_upload":"Confirm Upload",
- "field_details":"Field Details",
+ "records": "Displaying {num} records out of {total}",
+ "confirm_upload": "Confirm Upload",
+ "field_details": "Field Details",
"integration": "Platform integration needs to be enabled.",
"the_existing_user": "If the user already exists, overwrite the existing user.",
+ "lazy_load": "Lazy Load",
"sync_users": "Sync Users",
"sync_wechat_users": "Sync WeChat Users",
"sync_dingtalk_users": "Sync DingTalk Users",
@@ -64,12 +76,16 @@
"context_record_count": "Context Record Count",
"context_record_count_hint": "Number of user question rounds",
"model_thinking_process": "Expand Model Thinking Process",
+ "hide_model_thinking_process": "Hide Model Thinking Process",
"rows_of_data": "Limit 1000 Rows of Data",
- "third_party_platform_settings": "Third-Party Platform Settings",
- "by_third_party_platform": "Automatic User Creation by Third-Party Platform",
- "platform_user_organization": "Third-Party Platform Workspace",
+ "third_party_platform_settings": "Authentication Settings",
+ "by_third_party_platform": "Automatic User Creation",
+ "platform_user_organization": "Default Workspace",
"platform_user_roles": "Third-Party Platform User Roles",
"excessive_data_volume": "Disabling the 1000-row data limit may cause system lag due to excessive data volume.",
+ "sqlbot_name": "Data Query Assistant Name",
+ "show_sql": "Allow Viewing SQL Statements",
+ "show_log": "Show Execution Log",
"prompt": "Prompt",
"disabling_successfully": "Disabling Successfully",
"closed_by_default": "In the Question Count window, control whether the model thinking process is expanded or closed by default.",
@@ -175,6 +191,7 @@
"system_manage": "System Management",
"update_success": "Update",
"save_success": "Save Successful",
+ "operation_success": "Operation successful",
"next": "Next",
"save": "Save",
"logout": "Logout",
@@ -395,9 +412,13 @@
"timeout": "Connection Timeout(second)",
"address": "Address",
"low_version": "Compatible with lower versions",
- "ssl": "Enable SSL"
+ "ssl": "Enable SSL",
+ "file_path": "File Path",
+ "pool_size": "Connection Pool Size"
},
- "sync_fields": "Sync Fields"
+ "sync_fields": "Sync Fields",
+ "sync_fields_success": "Sync fields successfully",
+ "sync_fields_failed": "Sync fields failed"
},
"datasource": {
"recommended_question": "Recommended Question",
@@ -565,6 +586,7 @@
"member_feng_yibudao": "Do you want to remove the member: {msg}?",
"select_member": "Select member",
"selected_2_people": "Selected: {msg} people",
+ "selected_number": "Selected: {msg} items",
"clear": "Clear",
"historical_dialogue": "No historical dialogue",
"rename_a_workspace": "Rename a workspace",
@@ -665,6 +687,10 @@
"application_name": "Application name",
"application_description": "Application description",
"cross_domain_settings": "Cross-domain settings",
+ "enableCustomModel": "Use specified model",
+ "useModel": "Use model",
+ "defaultModel": "Default model",
+ "customModel": "Specified model",
"third_party_address": "Please enter the embedded third party address,multiple items separated by semicolons",
"set_to_private": "Set as private",
"set_to_public": "Set as public",
@@ -715,7 +741,7 @@
"display_settings": "Display Settings",
"header_text_color": "Header Text Color",
"app_logo": "App Logo",
- "maximum_size_10mb": "Recommended size: 32 x 32, supports JPG, PNG, and SVG, maximum size: 10MB",
+ "maximum_size_10mb": "Recommended size: 32 x 32, supports JPG, PNG, maximum size: 10MB",
"replace": "Replace",
"default_icon_position": "Default Icon Position",
"draggable_position": "Draggable Position",
@@ -764,6 +790,8 @@
"no_data": "No Data",
"loading_data": "Loading ...",
"show_error_detail": "Show error info",
+ "thousands_separator_setting": "Thousands Separator Setting",
+ "thousands_separator_display": "Apply Thousands Separator Display",
"log": {
"GENERATE_SQL": "Generate SQL",
"GENERATE_CHART": "Generate Chart Structure",
@@ -828,11 +856,11 @@
"website_logo": "Website Logo",
"tab": "Tab",
"replace_image": "Replace Image",
- "larger_than_200kb": "Logo displayed at the top of the website: Recommended size: 48 x 48 pixels, supports JPG, PNG, and SVG, and no larger than 200KB",
+ "larger_than_200kb": "Logo displayed at the top of the website: Recommended size: 48 x 48 pixels, supports JPG, PNG, and no larger than 200KB",
"login_logo": "System Logo",
- "larger_than_200kb_de": "Logo on the right side of the login page: Recommended size: 204 x 52 pixels, supports JPG, PNG, and SVG, and no larger than 200KB",
+ "larger_than_200kb_de": "Logo on the right side of the login page: Recommended size: 204 x 52 pixels, supports JPG, PNG, and no larger than 200KB",
"login_background_image": "Login Background Image",
- "larger_than_5mb": "Background image on the left: Recommended size: 576 x 900 for vector images, 1152 x 1800 for bitmap images, supports JPG, PNG, and SVG, and no larger than 5MB",
+ "larger_than_5mb": "Background image on the left: Recommended size: 576 x 900 for vector images, 1152 x 1800 for bitmap images, supports JPG, PNG, and no larger than 5MB",
"website_name": "Website Name",
"on_webpage_tabs": "Platform name displayed on webpage tabs",
"welcome_message": "Display a welcome message",
diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts
index df718e652..c06dfcd98 100644
--- a/frontend/src/i18n/index.ts
+++ b/frontend/src/i18n/index.ts
@@ -1,16 +1,42 @@
import { createI18n } from 'vue-i18n'
import en from './en.json'
import zhCN from './zh-CN.json'
+import zhTw from './zh-TW.json'
import koKR from './ko-KR.json'
import elementEnLocale from 'element-plus-secondary/es/locale/lang/en'
import elementZhLocale from 'element-plus-secondary/es/locale/lang/zh-cn'
+import elementTwLocale from 'element-plus-secondary/es/locale/lang/zh-tw'
import { useCache } from '@/utils/useCache'
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'
}
@@ -23,6 +49,10 @@ const messages = {
...zhCN,
el: elementZhLocale,
},
+ 'zh-TW': {
+ ...zhTw,
+ el: elementTwLocale,
+ },
'ko-KR': {
...koKR,
el: elementKoLocale,
@@ -40,6 +70,7 @@ export const i18n = createI18n({
const elementLocales = {
en: elementEnLocale,
'zh-CN': elementZhLocale,
+ 'zh-TW': elementTwLocale,
'ko-KR': elementKoLocale,
} as const
diff --git a/frontend/src/i18n/ko-KR.json b/frontend/src/i18n/ko-KR.json
index 317588668..100efe262 100644
--- a/frontend/src/i18n/ko-KR.json
+++ b/frontend/src/i18n/ko-KR.json
@@ -32,12 +32,24 @@
"enter_variable_name": "변수 이름을 입력하세요",
"enter_variable_value": "변수 값을 입력하세요"
},
+ "authorized_space": {
+ "authorized_space": "권한 있는 공간",
+ "authorized_space_list": "권한 있는 공간 목록",
+ "select_space": "공간 선택",
+ "modify_authorized_space": "권한 있는 공간 수정",
+ "workspaces_authorized": "{num}개의 권한 있는 작업 공간",
+ "number_of_members": "회원 수",
+ "delete_selected_workspaces": "선택한 {msg}개의 작업 공간을 삭제하시겠습니까?",
+ "delete_workspace": "작업 공간을 삭제하시겠습니까: {msg}?",
+ "no_workspace": "작업 공간 없음"
+ },
"sync": {
"records": "{total}개 중 {num}개의 레코드 표시",
"confirm_upload": "업로드 확인",
"field_details": "필드 세부 정보",
"integration": "플랫폼 통합을 활성화해야 합니다.",
"the_existing_user": "해당 사용자가 이미 존재하는 경우 기존 사용자를 덮어씁니다.",
+ "lazy_load": "지연 로딩",
"sync_users": "사용자 동기화",
"sync_wechat_users": "위챗 사용자 동기화",
"sync_dingtalk_users": "딩톡 사용자 동기화",
@@ -64,12 +76,16 @@
"context_record_count": "컨텍스트 기록 수",
"context_record_count_hint": "사용자 질문 라운드 수",
"model_thinking_process": "모델 사고 프로세스 확장",
+ "hide_model_thinking_process": "모델 사고 과정 숨기기",
"rows_of_data": "데이터 1,000행 제한",
- "third_party_platform_settings": "타사 플랫폼 설정",
- "by_third_party_platform": "타사 플랫폼에 의한 자동 사용자 생성",
- "platform_user_organization": "제3자 플랫폼 작업 공간",
+ "third_party_platform_settings": "로그인 인증 설정",
+ "by_third_party_platform": "자동 사용자 생성",
+ "platform_user_organization": "기본 작업 공간",
"platform_user_roles": "타사 플랫폼 사용자 역할",
"excessive_data_volume": "1,000행 데이터 제한을 비활성화하면 과도한 데이터 양으로 인해 시스템 지연이 발생할 수 있습니다.",
+ "sqlbot_name": "데이터 질의 도우미 이름",
+ "show_sql": "SQL 문 보기 허용",
+ "show_log": "실행 로그 표시",
"prompt": "프롬프트",
"disabling_successfully": "비활성화 완료",
"closed_by_default": "질문 수 창에서 모델 사고 프로세스를 기본적으로 확장할지 또는 닫을지 여부를 제어합니다.",
@@ -175,6 +191,7 @@
"system_manage": "시스템 관리",
"update_success": "업데이트 성공",
"save_success": "저장 성공",
+ "operation_success": "작업 성공",
"next": "다음 단계",
"save": "저장",
"logout": "로그아웃",
@@ -395,9 +412,13 @@
"timeout": "연결 시간 초과(초)",
"address": "주소",
"low_version": "낮은 버전 호환",
- "ssl": "SSL 활성화"
+ "ssl": "SSL 활성화",
+ "file_path": "파일 경로",
+ "pool_size": "연결 풀 크기"
},
- "sync_fields": "동기화된 테이블 구조"
+ "sync_fields": "동기화된 테이블 구조",
+ "sync_fields_success": "테이블 구조 동기화 성공",
+ "sync_fields_failed": "테이블 구조 동기화 실패"
},
"datasource": {
"recommended_question": "추천 질문",
@@ -565,6 +586,7 @@
"member_feng_yibudao": "멤버를 제거하시겠습니까: {msg}?",
"select_member": "멤버 선택",
"selected_2_people": "선택됨: {msg}명",
+ "selected_number": "선택됨: {msg}개",
"clear": "지우기",
"historical_dialogue": "과거 대화가 없습니다",
"rename_a_workspace": "작업 공간 이름 바꾸기",
@@ -665,6 +687,10 @@
"application_name": "애플리케이션 이름",
"application_description": "애플리케이션 설명",
"cross_domain_settings": "교차 도메인 설정",
+ "enableCustomModel": "지정된 모델 사용",
+ "useModel": "사용 모델",
+ "defaultModel": "기본 모델",
+ "customModel": "지정 모델",
"third_party_address": "임베디드할 제3자 주소를 입력하십시오, 여러 항목을 세미콜론으로 구분",
"set_to_private": "비공개로 설정",
"set_to_public": "공개로 설정",
@@ -715,7 +741,7 @@
"display_settings": "표시 설정",
"header_text_color": "헤더 텍스트 색상",
"app_logo": "애플리케이션 로고",
- "maximum_size_10mb": "권장 크기 32 x 32, JPG, PNG, SVG 지원, 크기 10MB 이하",
+ "maximum_size_10mb": "권장 크기 32 x 32, JPG, PNG 지원, 크기 10MB 이하",
"replace": "교체",
"default_icon_position": "아이콘 기본 위치",
"draggable_position": "드래그 가능한 위치",
@@ -764,6 +790,8 @@
"no_data": "데이터가 없습니다",
"loading_data": "로딩 중 ...",
"show_error_detail": "구체적인 정보 보기",
+ "thousands_separator_setting": "천 단위 구분 기호 설정",
+ "thousands_separator_display": "천 단위 구분 기호 표시 적용",
"log": {
"GENERATE_SQL": "SQL 생성",
"GENERATE_CHART": "차트 구조 생성",
@@ -828,11 +856,11 @@
"website_logo": "웹사이트 로고",
"tab": "페이지 탭",
"replace_image": "이미지 교체",
- "larger_than_200kb": "상단 웹사이트에 표시되는 로고, 권장 크기 48 x 48, JPG, PNG, SVG 지원, 크기 200KB 이하",
+ "larger_than_200kb": "상단 웹사이트에 표시되는 로고, 권장 크기 48 x 48, JPG, PNG 지원, 크기 200KB 이하",
"login_logo": "시스템 로고",
- "larger_than_200kb_de": "로그인 페이지 오른쪽 로고, 권장 크기 204*52, JPG, PNG, SVG 지원, 크기 200KB 이하",
+ "larger_than_200kb_de": "로그인 페이지 오른쪽 로고, 권장 크기 204*52, JPG, PNG 지원, 크기 200KB 이하",
"login_background_image": "로그인 배경 이미지",
- "larger_than_5mb": "왼쪽 배경 이미지, 벡터 이미지 권장 크기 576*900, 비트맵 권장 크기 1152*1800; JPG, PNG, SVG 지원, 크기 5MB 이하",
+ "larger_than_5mb": "왼쪽 배경 이미지, 벡터 이미지 권장 크기 576*900, 비트맵 권장 크기 1152*1800; JPG, PNG 지원, 크기 5MB 이하",
"website_name": "웹사이트 이름",
"on_webpage_tabs": "웹페이지 탭에 표시되는 플랫폼 이름",
"welcome_message": "환영 메시지 표시",
@@ -954,4 +982,4 @@
"to_doc": "API 보기",
"trigger_limit": "최대 {0}개의 API 키 생성 지원"
}
-}
\ No newline at end of file
+}
diff --git a/frontend/src/i18n/zh-CN.json b/frontend/src/i18n/zh-CN.json
index 953c12509..9f5cc9b24 100644
--- a/frontend/src/i18n/zh-CN.json
+++ b/frontend/src/i18n/zh-CN.json
@@ -32,12 +32,24 @@
"enter_variable_name": "请输入变量名称",
"enter_variable_value": "请输入变量值"
},
+ "authorized_space": {
+ "authorized_space": "授权空间",
+ "authorized_space_list": "授权空间列表",
+ "select_space": "选择空间",
+ "modify_authorized_space": "修改授权空间",
+ "workspaces_authorized": "已授权 {num} 个工作空间",
+ "number_of_members": "成员数量",
+ "delete_selected_workspaces": "是否移除选中的 {msg} 个工作空间?",
+ "delete_workspace": "是否移除工作空间:{msg}?",
+ "no_workspace": "暂无工作空间"
+ },
"sync": {
- "records":"显示 {num} 条数据,共 {total} 条",
- "confirm_upload":"确定上传",
- "field_details":"字段详情",
+ "records": "显示 {num} 条数据,共 {total} 条",
+ "confirm_upload": "确定上传",
+ "field_details": "字段详情",
"integration": "需开启平台对接",
"the_existing_user": "若用户已存在,覆盖旧用户",
+ "lazy_load": "懒加载",
"sync_users": "同步用户",
"sync_wechat_users": "同步企业微信用户",
"sync_dingtalk_users": "同步钉钉用户",
@@ -64,12 +76,16 @@
"context_record_count": "上下文记录数",
"context_record_count_hint": "用户提问轮数",
"model_thinking_process": "展开模型思考过程",
+ "hide_model_thinking_process": "隐藏模型思考过程",
"rows_of_data": "限制 1000 行数据",
- "third_party_platform_settings": "第三方平台设置",
- "by_third_party_platform": "第三方自动创建用户",
- "platform_user_organization": "第三方平台工作空间",
+ "third_party_platform_settings": "登录认证设置",
+ "by_third_party_platform": "自动创建用户",
+ "platform_user_organization": "默认工作空间",
"platform_user_roles": "第三方平台用户角色",
"excessive_data_volume": "关闭1000行的数据限制后,数据量过大,可能会造成系统卡顿",
+ "sqlbot_name": "问数小助手名称",
+ "show_sql": "允许查看SQL语句",
+ "show_log": "显示执行日志",
"prompt": "提示",
"disabling_successfully": "关闭成功",
"closed_by_default": "在问数窗口中,控制模型思考过程默认展开或者关闭",
@@ -175,6 +191,7 @@
"system_manage": "系统管理",
"update_success": "更新成功",
"save_success": "保存成功",
+ "operation_success": "操作成功",
"next": "下一步",
"save": "保存",
"logout": "退出登录",
@@ -395,9 +412,13 @@
"timeout": "连接超时(秒)",
"address": "地址",
"low_version": "兼容低版本",
- "ssl": "启用 SSL"
+ "ssl": "启用 SSL",
+ "file_path": "文件路径",
+ "pool_size": "连接池大小"
},
- "sync_fields": "同步表结构"
+ "sync_fields": "同步表结构",
+ "sync_fields_success": "同步表结构成功",
+ "sync_fields_failed": "同步表结构失败"
},
"datasource": {
"recommended_question": "推荐问题",
@@ -565,6 +586,7 @@
"member_feng_yibudao": "是否移除成员:{msg}?",
"select_member": "选择成员",
"selected_2_people": "已选:{msg} 人",
+ "selected_number": "已选:{msg} 个",
"clear": "清空",
"historical_dialogue": "暂无历史对话",
"rename_a_workspace": "重命名工作空间",
@@ -665,6 +687,10 @@
"application_name": "应用名称",
"application_description": "应用描述",
"cross_domain_settings": "跨域设置",
+ "enableCustomModel": "使用指定大模型",
+ "useModel": "使用模型",
+ "defaultModel": "默认模型",
+ "customModel": "指定模型",
"third_party_address": "请输入嵌入的第三方地址,多个以分号分割",
"set_to_private": "设为私有",
"set_to_public": "设为公共",
@@ -715,7 +741,7 @@
"display_settings": "显示设置",
"header_text_color": "头部文本颜色",
"app_logo": "应用 Logo",
- "maximum_size_10mb": "建议尺寸 32 x 32,支持 JPG、PNG、SVG,大小不超过 10MB",
+ "maximum_size_10mb": "建议尺寸 32 x 32,支持 JPG、PNG,大小不超过 10MB",
"replace": "替换",
"default_icon_position": "图标默认位置",
"draggable_position": "可拖拽位置",
@@ -764,6 +790,8 @@
"no_data": "暂无数据",
"loading_data": "加载中...",
"show_error_detail": "查看具体信息",
+ "thousands_separator_setting": "千分位符设置",
+ "thousands_separator_display": "应用千分位符展示",
"log": {
"GENERATE_SQL": "生成 SQL",
"GENERATE_CHART": "生成图表结构",
@@ -828,11 +856,11 @@
"website_logo": "网站 Logo",
"tab": "页签",
"replace_image": "替换图片",
- "larger_than_200kb": "顶部网站显示的 Logo,建议尺寸 48 x 48,支持 JPG、PNG、SVG,大小不超过 200KB",
+ "larger_than_200kb": "顶部网站显示的 Logo,建议尺寸 48 x 48,支持 JPG、PNG,大小不超过 200KB",
"login_logo": "系统 Logo",
- "larger_than_200kb_de": "登录页面右侧 Logo,建议尺寸 204*52,支持 JPG、PNG、SVG,大小不超过 200KB",
+ "larger_than_200kb_de": "登录页面右侧 Logo,建议尺寸 204*52,支持 JPG、PNG,大小不超过 200KB",
"login_background_image": "登录背景图",
- "larger_than_5mb": "左侧背景图,矢量图建议尺寸 576*900,位图建议尺寸 1152*1800;支持 JPG、PNG、SVG,大小不超过 5M",
+ "larger_than_5mb": "左侧背景图,矢量图建议尺寸 576*900,位图建议尺寸 1152*1800;支持 JPG、PNG,大小不超过 5M",
"website_name": "网站名称",
"on_webpage_tabs": "显示在网页 Tab 的平台名称",
"welcome_message": "显示欢迎语",
diff --git a/frontend/src/i18n/zh-TW.json b/frontend/src/i18n/zh-TW.json
new file mode 100644
index 000000000..b64649f9a
--- /dev/null
+++ b/frontend/src/i18n/zh-TW.json
@@ -0,0 +1,985 @@
+{
+ "menu": {
+ "add_interface_credentials": "請新增介面憑證",
+ "Data Q&A": "智慧問數",
+ "Data Connections": "資料來源",
+ "Dashboard": "儀表板",
+ "AI Model Configuration": "模型配置",
+ "Details": "詳情"
+ },
+ "variables": {
+ "please_select_date": "請選擇日期",
+ "number_variable_error": "請輸入正確的數值範圍",
+ "built_in": "已內建",
+ "normal_value": "一般值",
+ "cannot_be_empty": "變數值不能為空",
+ "1_to_100": "{name}數值範圍 {min}~{max}",
+ "1_to_100_de": "{name}日期範圍 {min}~{max}",
+ "system_variables": "系統變數",
+ "variables": "變數",
+ "system": "系統",
+ "search_variables": "搜尋變數",
+ "add_variable": "新增變數",
+ "variable_name": "變數名稱",
+ "variable_type": "變數類型",
+ "variable_value": "變數值",
+ "edit_variable": "編輯變數",
+ "no_variables_yet": "暫無變數",
+ "please_enter_value": "請輸入數值",
+ "date": "日期",
+ "start_date": "開始日期",
+ "end_date": "結束日期",
+ "enter_variable_name": "請輸入變數名稱",
+ "enter_variable_value": "請輸入變數值"
+ },
+ "authorized_space": {
+ "authorized_space": "授權空間",
+ "authorized_space_list": "授權空間列表",
+ "select_space": "選擇空間",
+ "modify_authorized_space": "修改授權空間",
+ "workspaces_authorized": "已授權 {num} 個工作空間",
+ "number_of_members": "成員數量",
+ "delete_selected_workspaces": "是否移除選中的 {msg} 個工作空間?",
+ "delete_workspace": "是否移除工作空間:{msg}?",
+ "no_workspace": "暫無工作空間"
+ },
+ "sync": {
+ "records": "顯示 {num} 筆資料,共 {total} 筆",
+ "confirm_upload": "確定上傳",
+ "field_details": "欄位詳情",
+ "integration": "需開啟平台對接",
+ "the_existing_user": "若使用者已存在,覆蓋舊使用者",
+ "lazy_load": "懶加載",
+ "sync_users": "同步使用者",
+ "sync_wechat_users": "同步企業微信使用者",
+ "sync_dingtalk_users": "同步釘釘使用者",
+ "sync_lark_users": "同步飛書使用者",
+ "sync_complete": "同步完成",
+ "synced_10_users": "成功同步 {num} 個使用者",
+ "failed_3_users": "成功同步 {success} 個使用者,同步失敗 {failed} 個使用者,",
+ "download_failure_list": "下載失敗列表",
+ "sync_failed": "同步失敗",
+ "failed_10_users": "同步失敗 {num} 個使用者,",
+ "continue_syncing": "繼續同步",
+ "return_to_view": "返回查看"
+ },
+ "parameter": {
+ "execution_details": "執行詳情",
+ "overview": "概覽",
+ "tokens_required": "消耗 Tokens",
+ "time_execution": "耗時",
+ "export_notes": "匯出備註",
+ "import_notes": "匯入備註",
+ "memo": "備註更新規則:根據表名和欄位名稱匹配,如果匹配則更新表備註和欄位備註;如果匹配不上,備註保持不變。",
+ "parameter_configuration": "參數配置",
+ "question_count_settings": "問數設定",
+ "context_record_count": "上下文記錄數",
+ "context_record_count_hint": "使用者提問輪數",
+ "model_thinking_process": "展開模型思考過程",
+ "hide_model_thinking_process": "隱藏模型思考過程",
+ "rows_of_data": "限制 1000 列資料",
+ "third_party_platform_settings": "登入認證設定",
+ "by_third_party_platform": "自動建立使用者",
+ "platform_user_organization": "預設工作區",
+ "platform_user_roles": "第三方平台使用者角色",
+ "excessive_data_volume": "關閉1000列的資料限制後,資料量過大,可能會造成系統卡頓",
+ "sqlbot_name": "問數小助手名稱",
+ "show_sql": "允許查看SQL語句",
+ "show_log": "顯示執行日誌",
+ "prompt": "提示",
+ "disabling_successfully": "關閉成功",
+ "closed_by_default": "在問數視窗中,控制模型思考過程預設展開或者關閉",
+ "and_platform_integration": "登入認證相關",
+ "login_settings": "登入設定",
+ "default_login": "預設登入方式"
+ },
+ "prompt": {
+ "default_password": "預設密碼:{msg}",
+ "no_sql_sample": "暫無 SQL 範例",
+ "add_sql_sample": "新增 SQL 範例",
+ "no_prompt_words": "暫無提示詞",
+ "customize_prompt_words": "自訂提示詞",
+ "ask_sql": "問數 SQL",
+ "data_analysis": "資料分析",
+ "data_prediction": "資料預測",
+ "add_prompt_word": "新增提示詞",
+ "prompt_word_name": "提示詞名稱",
+ "prompt_word_content": "提示詞內容",
+ "training_data_details": "訓練資料詳情",
+ "selected_prompt_words": "是否刪除選中的 {msg} 筆提示詞?",
+ "replaced_with": "請輸入提示詞,範例:回傳姓名時,只顯示姓氏,名字用*代替",
+ "loss_exercise_caution": "若輸入刪除資料庫、資料表或修改表結構等高風險的操作指令,可能導致資料永久遺失,請務必謹慎!",
+ "edit_prompt_word": "編輯提示詞",
+ "all_236_terms": "是否匯出全部 {msg} 筆{type}提示詞?",
+ "export_hint": "是否匯出全部{type}提示詞?",
+ "prompt_word_name_de": "是否刪除提示詞:{msg}?",
+ "disable_field": "停用欄位",
+ "to_disable_it": "該欄位已配置表關聯關係,若停用後,關聯關係將失效,確定停用?"
+ },
+ "training": {
+ "effective_data_sources": "生效資料來源",
+ "all_data_sources": "所有資料來源",
+ "partial_data_sources": "部分資料來源",
+ "add_it_here": "拖曳左側表名,新增到這裡",
+ "table_relationship_management": "表關係管理",
+ "system_management": "系統管理",
+ "data_training": "SQL 範例庫",
+ "problem_description": "問題描述",
+ "sample_sql": "範例 SQL",
+ "search_problem": "搜尋問題",
+ "add_training_data": "新增範例 SQL",
+ "training_data_details": "範例 SQL 詳情",
+ "training_data_items": "是否刪除選中的 {msg} 筆範例 SQL?",
+ "sql_statement": "SQL 語句",
+ "edit_training_data": "編輯範例 SQL",
+ "all_236_terms": "是否匯出全部 {msg} 筆範例 SQL?",
+ "export_hint": "是否匯出全部範例 SQL?",
+ "sales_this_year": "是否刪除範例 SQL:{msg}?",
+ "upload_success": "匯入成功",
+ "upload_failed": "匯入成功 {success} 筆,失敗 {fail} 筆,失敗資訊詳見:{fail_info}"
+ },
+ "professional": {
+ "cannot_be_repeated": "術語名稱,同義詞不能重複",
+ "code_for_debugging": "複製以下程式碼進行除錯",
+ "full_screen_mode": "全螢幕模式",
+ "editing_terminology": "編輯術語",
+ "professional_terminology": "術語配置",
+ "term_name": "術語名稱",
+ "term_description": "術語描述",
+ "search_term": "搜尋術語",
+ "no_term": "暫無術語",
+ "create_new_term": "新建術語",
+ "export_all": "全部匯出",
+ "professional_term_details": "專業術語詳情",
+ "business_term": "業務術語",
+ "synonyms": "同義詞",
+ "all_236_terms": "是否匯出全部 {msg} 筆術語?",
+ "export_hint": "是否匯出全部術語?",
+ "export": "匯出",
+ "selected_2_terms": "是否刪除選中的 {msg} 筆術語?",
+ "selected_2_terms_de": "是否匯出選中的 {msg} 筆術語?",
+ "the_term_gmv": "是否刪除術語:{msg}?"
+ },
+ "common": {
+ "start_time": "開始時間",
+ "end_time": "結束時間",
+ "require": "必填",
+ "zoom_in": "放大",
+ "zoom_out": "縮小",
+ "the_default_model": "已是預設模型",
+ "as_default_model": "設為預設模型",
+ "no_model_yet": "暫無模型",
+ "intelligent_questioning_platform": "歡迎使用 SQLBot 智慧問數平台",
+ "login": "帳號登入",
+ "login_": "登入",
+ "confirm2": "確定",
+ "excessive_tables_selected": "選擇資料表過量",
+ "to_continue_saving": "選擇的資料表數量為:{msg},已超出30,可能會導致操作逾時或者無回應,是否繼續儲存?",
+ "proceed_with_caution": "刪除後無法復原,請謹慎操作。",
+ "sales_in_2024": "是否刪除對話:{msg}?",
+ "limited_to_30": "資料表數量限制30",
+ "enter_your_password": "請輸入密碼",
+ "your_account_email_address": "請輸入帳號/郵箱",
+ "the_correct_password": "請輸入正確的密碼",
+ "input_content": "請輸入內容",
+ "may_not_exist": "暫無結果,使用者可能不存在",
+ "empty": "",
+ "back": "返回",
+ "confirm": "確認",
+ "cancel": "取消",
+ "search": "查詢",
+ "system_manage": "系統管理",
+ "update_success": "更新成功",
+ "save_success": "儲存成功",
+ "operation_success": "操作成功",
+ "next": "下一步",
+ "save": "儲存",
+ "logout": "登出",
+ "please_input": "請輸入{msg}",
+ "switch_success": "切換成功",
+ "result_count": "個結果",
+ "clear_filter": "清空條件",
+ "reset": "重設",
+ "simplified_chinese": "簡體中文",
+ "korean": "한국어",
+ "traditional_chinese": "繁體中文",
+ "help": "說明",
+ "language": "語言",
+ "english": "English",
+ "re_upload": "重新上傳",
+ "not_exceed_50mb": "支援 XLS、XLSX、CSV 格式,檔案大小不超過 50MB",
+ "excel_file_type_limit": "僅支援 XLS、XLSX 格式",
+ "click_to_select_file": "點擊選擇檔案",
+ "upload_hint_first": "先",
+ "upload_hint_download_template": "下載範本",
+ "upload_hint_end": ",按要求填寫後上傳。",
+ "continue_to_upload": "繼續匯入",
+ "reset_password": "重設密碼",
+ "password_reset_successful": "重設密碼成功",
+ "or": "或者",
+ "refresh": "重新整理",
+ "input_limit": "長度在 {0} 到 {1} 個字元",
+ "file_size_limit_error": "檔案大小超出限制(最大{limit})"
+ },
+ "dashboard": {
+ "open_dashboard": "開啟儀表板",
+ "add_dashboard_name_tips": "請輸入儀表板名稱",
+ "existing_dashboard": "存量儀表板",
+ "add_success": "新增成功",
+ "no_data": "沒有找到相關內容",
+ "new_tab": "新建Tab",
+ "length_limit64": "欄位長度需要在1-64之間",
+ "sort_column": "排序欄位",
+ "sort_type": "排序方式",
+ "time": "時間",
+ "sort_asc": "升序",
+ "sort_desc": "降序",
+ "name_repeat": "儀表板名稱已被使用",
+ "rich_text_tips": "雙擊輸入文字內容",
+ "exit_preview": "退出預覽",
+ "no_chat": "暫無對話",
+ "today": "今日",
+ "this_week": "本週",
+ "earlier": "更早",
+ "add_component_tips": "從頂部工具列中選擇元件,新增到這裡建立儀表板",
+ "add_view": "新增圖表",
+ "delete_dashboard_warn": "是否刪除儀表板:{0}",
+ "rename_dashboard": "重新命名儀表板",
+ "dashboard_name": "儀表板名稱",
+ "select_dashboard_tips": "請在左側選擇儀表板",
+ "no_dashboard": "暫無儀表板",
+ "no_dashboard_info": "暫無內容,點擊下列按鈕進行新增",
+ "search": "搜尋",
+ "time_asc": "按時間升序",
+ "time_desc": "按時間降序",
+ "name_asc": "按名稱升序",
+ "name_desc": "按名稱降序",
+ "select_dashboard": "請選擇儀表板",
+ "name": "名稱",
+ "view": "圖表",
+ "text": "富文字",
+ "preview": "預覽",
+ "creator": "建立人",
+ "dashboard_id": "儀表板ID",
+ "create_time": "建立時間",
+ "updater": "更新人",
+ "update_time": "更新時間",
+ "edit": "編輯",
+ "edit_title": "編輯標題",
+ "length_1_64_characters": "名稱欄位長度1-64個字元",
+ "rename": "重新命名",
+ "delete": "刪除",
+ "delete_tips": "刪除後,此目錄的所有資源都會被刪除,請謹慎操作。",
+ "undo": "復原",
+ "reduction": "復原",
+ "folder": "目錄",
+ "dashboard": "儀表板",
+ "delete_warning": "確定要刪除嗎?",
+ "delete_resource_warn": "確定刪除該{0}嗎?",
+ "delete_success": "刪除成功",
+ "new_folder": "新建目錄",
+ "new_dashboard": "新建儀表板",
+ "add_chart": "新增圖表",
+ "chart_selected": "已選{0}"
+ },
+ "qa": {
+ "retrieve_error": "暫無內容",
+ "retrieve_again": "重新取得",
+ "recently": "最近",
+ "recommend": "推薦",
+ "quick_question": "快捷提問",
+ "new_chat": "新建對話",
+ "start_sqlbot": "開啟問數",
+ "title": "智慧問數",
+ "placeholder": "請輸入您的問題",
+ "ask": "提問",
+ "loading": "載入中...",
+ "no_data": "暫無資料",
+ "error": "發生錯誤,請稍後再試",
+ "question_placeholder": "按下 Enter 提交問題, 或使用 Ctrl + Enter 換行",
+ "greeting": "你好,我是SQLBot,很高興為你服務",
+ "hint_description": "我可以查詢資料、產生圖表、分析資料、預測資料等,請選擇一個資料來源,開啟智慧問數吧~",
+ "select_datasource": "選擇資料來源",
+ "view_more": "查看更多",
+ "selected_datasource": "已選擇資料來源",
+ "empty_datasource": "資料來源為空,請新建後再開啟智慧問數!",
+ "datasource_not_exist": "資料來源不存在",
+ "guess_u_ask": "猜你想問:",
+ "continue_to_ask": "繼續提問:",
+ "data_analysis": "資料分析",
+ "data_predict": "資料預測",
+ "data_regenerated": "重新產生",
+ "chat_search": "搜尋",
+ "thinking": "思考中",
+ "thinking_step": "思考過程",
+ "ask_again": "重新產生",
+ "today": "今天",
+ "week": "7天內",
+ "earlier": "更早以前",
+ "no_time": "沒有時間",
+ "rename_conversation_title": "重新命名對話標題",
+ "conversation_title": "對話標題",
+ "copied": "已複製",
+ "ask_failed": "問數失敗"
+ },
+ "ds": {
+ "title": "資料來源",
+ "local_excelcsv": "本機 Excel/CSV",
+ "add": "新增資料來源",
+ "delete": "刪除資料來源",
+ "name": "資料來源名稱",
+ "type": "資料來源類型",
+ "status": "狀態",
+ "pieces_in_total": "顯示 {ms} 筆資料",
+ "actions": "操作",
+ "test_connection": "測試連線",
+ "check": "驗證",
+ "connection_success": "連線成功",
+ "connection_failed": "連線失敗,請檢查配置",
+ "Search Datasource": "搜尋資料來源",
+ "tables": "資料表",
+ "no_data_tip": "暫無資料,請從左側選擇資料表",
+ "comment": "註解",
+ "table_schema": "表結構",
+ "previous": "上一步",
+ "preview": "資料預覽",
+ "preview_tip": "預覽100筆資料",
+ "field": {
+ "name": "欄位名",
+ "type": "類型",
+ "comment": "註解",
+ "custom_comment": "自訂註解",
+ "status": "狀態"
+ },
+ "edit": {
+ "table_comment": "編輯表註解",
+ "field_comment": "編輯欄位註解",
+ "table_comment_label": "表註解",
+ "field_comment_label": "欄位註解"
+ },
+ "form": {
+ "title": {
+ "add": "新增資料來源",
+ "edit": "編輯資料來源",
+ "choose_tables": "選擇資料表"
+ },
+ "base_info": "基本資訊",
+ "choose_tables": "選擇資料表",
+ "name": "名稱",
+ "description": "描述",
+ "host": "主機名/IP位址",
+ "port": "連接埠",
+ "username": "使用者名稱",
+ "password": "密碼",
+ "database": "資料庫",
+ "connect_mode": "連線方式",
+ "service_name": "服務名",
+ "extra_jdbc": "額外的資料庫連線配置",
+ "schema": "模式",
+ "get_schema": "取得模式",
+ "file": "檔案",
+ "upload_tip": "僅支援 .xls, .xlsx, .csv 格式,大小不超過50MB",
+ "version_tip": {
+ "sqlServer": "支援版本: 2012+",
+ "oracle": "支援版本: 12+",
+ "mysql": "支援版本: 5.6+",
+ "pg": "支援版本: 9.6+"
+ },
+ "selected": "已選擇: {0}/{1}",
+ "validate": {
+ "name_required": "請輸入名稱",
+ "name_length": "長度應在1到50個字元之間",
+ "type_required": "請選擇資料庫類型",
+ "host_required": "請輸入主機位址",
+ "port_required": "請輸入連接埠號",
+ "database_required": "請輸入資料庫名",
+ "mode_required": "請選擇連線方式",
+ "schema_required": "請輸入模式名"
+ },
+ "mode": {
+ "sid": "SID",
+ "service_name": "服務名"
+ },
+ "support_version": "支援版本",
+ "upload": {
+ "button": "上傳",
+ "tip": "僅支援 .xls, .xlsx, .csv 格式,檔案小於 50MB."
+ },
+ "connect": {
+ "success": "連線成功",
+ "failed": "連線失敗"
+ },
+ "timeout": "連線逾時(秒)",
+ "address": "位址",
+ "low_version": "相容低版本",
+ "ssl": "啟用 SSL",
+ "file_path": "文件路徑",
+ "pool_size": "連線池大小"
+ },
+ "sync_fields": "同步表結構",
+ "sync_fields_success": "同步表結構成功",
+ "sync_fields_failed": "同步表結構失敗"
+ },
+ "datasource": {
+ "recommended_question": "推薦問題",
+ "recommended_repetitive_tips": "存在重複問題",
+ "recommended_problem_tips": "自訂配置至少一個問題,每個問題2-200個字元",
+ "recommended_problem_configuration": "推薦問題配置",
+ "problem_generation_method": "問題產生方式",
+ "ai_automatic_generation": "AI 自動產生",
+ "user_defined": "使用者自訂",
+ "question_tips": "請輸入推薦問題",
+ "add_question": "新增問題",
+ "data_source_yet": "暫無資料來源",
+ "search_by_name": "透過名稱搜尋",
+ "search": "搜尋",
+ "all_types": "全部類型",
+ "new_data_source": "新建資料來源",
+ "open_query": "開啟問數",
+ "edit": "編輯",
+ "source_connection_failed": "資料來源連線失敗",
+ "confirm": "確定",
+ "copy": "複製",
+ "the_original_one": "確認恢復為初始密碼嗎?",
+ "incorrect_email_format": "郵箱格式不對",
+ "enabled_status": "啟用狀態",
+ "custom_notes": "自訂備註",
+ "field_type": "欄位類型",
+ "field_name": "欄位名稱",
+ "relevant_content_found": "沒有找到相關內容",
+ "please_enter": "請輸入",
+ "Please_select": "請選擇",
+ "table_notes": "表備註",
+ "field_notes": "欄位備註",
+ "select_all": "全選",
+ "mysql_data_source": "修改 {msg} 資料來源",
+ "configuration_information": "配置資訊",
+ "data_source": "是否刪除資料來源:{msg}?",
+ "operate_with_caution": "被刪除後,將無法對該資料來源進行智慧問數,請謹慎操作。",
+ "data_source_de": "無法刪除資料來源:{msg}",
+ "cannot_be_deleted": "儀表板的圖表使用了該資料來源,不可刪除。",
+ "got_it": "知道了",
+ "field_original_notes": "欄位原始備註",
+ "field_notes_1": "欄位備註",
+ "no_table": "暫無資料表",
+ "go_add": "去新增",
+ "get_schema": "取得Schema"
+ },
+ "model": {
+ "int": "整數",
+ "float": "小數",
+ "string": "字串",
+ "default_model": "預設模型",
+ "model_type": "模型類型",
+ "basic_model": "基礎模型",
+ "set_successfully": "設定成功",
+ "operate_with_caution": "系統預設模型被取代後,智慧問數的結果將會受到影響,請謹慎操作。",
+ "system_default_model": "是否設定 {msg} 為系統預設模型?",
+ "ai_model_configuration": "AI 模型配置",
+ "system_default_model_de": "系統預設模型",
+ "relevant_results_found": "沒有找到相關結果",
+ "add_model": "新增模型",
+ "select_supplier": "選擇供應商",
+ "the_basic_model": "請給基礎模型設定一個名稱",
+ "the_basic_model_de": "請選擇基礎模型",
+ "length_max_error": "{msg}長度不能超過{max}個字元",
+ "model_name": "模型名稱",
+ "custom_model_name": "自訂的模型名稱",
+ "enter_to_add": "清單中未列出的模型,直接輸入模型名稱,Enter 即可新增",
+ "api_domain_name": "API 網域",
+ "advanced_settings": "進階設定",
+ "model_parameters": "模型參數",
+ "add": "新增",
+ "parameters": "參數",
+ "display_name": "顯示名稱",
+ "parameter_value": "參數值",
+ "text": "文字",
+ "number": "數值",
+ "parameter_type": "參數類型",
+ "verification_successful": "驗證成功",
+ "del_default_tip": "無法刪除模型: {msg}",
+ "del_default_warn": "該模型為系統預設模型,請先設定其他模型為系統預設模型,再刪除此模型。",
+ "del_warn_tip": "是否刪除模型: {msg}?",
+ "check_failed": "模型無效【{msg}】",
+ "default_miss": "尚未設定預設大語言模型,因此無法開啟問數,請聯繫管理員設定。",
+ "default_miss_admin": "尚未設定預設大語言模型,因此無法開啟問數。",
+ "to_config": "去設定"
+ },
+ "user": {
+ "workspace": "工作區",
+ "creation_time": "建立時間",
+ "user_source": "使用者來源",
+ "phone_number": "手機號",
+ "email": "郵箱",
+ "user_status": "使用者狀態",
+ "account": "帳號",
+ "name": "姓名",
+ "selected_2_items": "已選 {msg} 筆",
+ "name_account_email": "搜尋姓名、帳號、郵箱",
+ "user_management": "使用者管理",
+ "filter": "篩選",
+ "batch_import": "批次匯入",
+ "add_users": "新增使用者",
+ "selected_2_users": "是否刪除選中的 {msg} 個使用者?",
+ "filter_conditions": "篩選條件",
+ "enable": "啟用",
+ "disable": "停用",
+ "local_creation": "本機建立",
+ "lark": "飛書",
+ "larksuite": "國際飛書",
+ "dingtalk": "釘釘",
+ "wecom": "企業微信",
+ "1240_results": "{msg} 個結果 ",
+ "clear_conditions": "清空條件",
+ "disabled": "已停用",
+ "enabled": "已啟用",
+ "edit_user": "編輯使用者",
+ "del_user": "是否刪除使用者: {msg}?",
+ "del_key": "是否刪除key: {msg}?",
+ "please_first": "請先",
+ "download_the_template": "下載範本",
+ "required_and_upload": ",按要求填寫後上傳",
+ "file": "檔案",
+ "upload_file": "上傳檔案",
+ "xls_format_files": "僅支援xlsx、xls格式的檔案",
+ "import": "匯入",
+ "change_file": "更換檔案",
+ "data_import_completed": "資料匯入完成",
+ "notes_import_completed": "備註匯入完成",
+ "imported_100_data": "成功匯入資料 {msg} 筆",
+ "return_to_view": "返回查看",
+ "continue_importing": "繼續匯入",
+ "import_20_can": "成功匯入資料 {msg} 筆,匯入失敗 {loss} 筆,可 ",
+ "download_error_report": "下載錯誤報告",
+ "modify_and_re_import": ",修改後重新匯入",
+ "data_import_failed": "資料匯入失敗",
+ "failed_100_can": "匯入失敗 {msg} 筆,可",
+ "change_password": "修改密碼",
+ "new_password": "新密碼",
+ "confirm_password": "確認密碼",
+ "old_password": "舊密碼",
+ "title": "使用者管理",
+ "upgrade_pwd": {
+ "title": "修改密碼",
+ "old_pwd": "舊密碼",
+ "new_pwd": "新密碼",
+ "confirm_pwd": "確認密碼",
+ "two_pwd_not_match": "兩次輸入的密碼不一致",
+ "pwd_format_error": "8-20位且至少一位大寫字母、小寫字母、數字、特殊字元"
+ }
+ },
+ "workspace": {
+ "relevant_content_found": "找不到相關內容",
+ "add_workspace": "新增工作區",
+ "administrator": "管理員",
+ "ordinary_member": "一般成員",
+ "people": "人",
+ "name_username_email": "搜尋姓名、使用者名稱、郵箱",
+ "add_member": "新增成員",
+ "member_type": "成員類型",
+ "workspace_name": "工作區名稱",
+ "no_user": "暫無使用者",
+ "remove": "移除",
+ "selected_2_members": "是否移除選中的 {msg} 個成員?",
+ "removed_successfully": "移除成功",
+ "workspace_de_workspace": "是否刪除工作區:{msg}?",
+ "member_feng_yibudao": "是否移除成員:{msg}?",
+ "select_member": "選擇成員",
+ "selected_2_people": "已選:{msg} 人",
+ "selected_number": "已選:{msg} 個",
+ "clear": "清空",
+ "historical_dialogue": "暫無歷史對話",
+ "rename_a_workspace": "重新命名工作區",
+ "return_to_workspace": "返回工作區",
+ "there_are": "有 ",
+ "2_dashboards": "{msg} 個儀表板",
+ "smart_data_centers": "{msg} 個智慧問數",
+ "confirm_to_delete": "資料來源刪除後,相關的問數不可繼續提問,儀表板中的圖表無法正常顯示,請謹慎操作!",
+ "id_account_to_add": "搜尋使用者名稱/帳號新增",
+ "find_user": "尋找使用者",
+ "add_successfully": "新增成功",
+ "member_management": "成員管理",
+ "permission_configuration": "權限配置",
+ "set": "設定",
+ "operate_with_caution": "刪除後,該工作區下的使用者將被移除,所有資源也將被刪除,請謹慎操作。"
+ },
+ "permission": {
+ "search_field": "搜尋欄位",
+ "search_rule_group": "搜尋規則組",
+ "add_rule_group": "新增規則組",
+ "permission_rule": "權限規則",
+ "restricted_user": "受限使用者",
+ "set_rule": "設定規則",
+ "set_user": "設定使用者",
+ "2": "{msg} 個",
+ "238_people": "{msg} 人",
+ "no_permission_rule": "暫無權限規則",
+ "set_permission_rule": "設定權限規則",
+ "basic_information": "基本資訊",
+ "rule_group_name": "規則組名稱",
+ "rule_name": "規則名稱",
+ "type": "類型",
+ "data_source": "資料來源",
+ "data_table": "資料表",
+ "select_restricted_user": "選擇受限使用者",
+ "rule_group_1": "是否刪除規則組:{msg}?",
+ "no_rule": "暫無規則",
+ "row_permission": "列權限",
+ "column_permission": "欄位權限",
+ "rule_rule_1": "是否刪除規則:{msg}?",
+ "no_content": "暫無內容",
+ "edit_column_permission": "編輯欄位權限",
+ "edit_row_permission": "編輯列權限",
+ "add_column_permission": "新增欄位權限",
+ "add_row_permission": "新增列權限",
+ "no_fields_yet": "暫無欄位",
+ "filter_eq": "等於",
+ "filter_not_eq": "不等於",
+ "filter_lt": "小於",
+ "filter_le": "小於等於",
+ "filter_gt": "大於",
+ "filter_ge": "大於等於",
+ "filter_null": "為空",
+ "filter_not_null": "不為空",
+ "filter_empty": "空字串",
+ "filter_not_empty": "非空字串",
+ "filter_include": "包含",
+ "filter_not_include": "不包含",
+ "conditional_filtering": "條件篩選",
+ "add_conditions": "新增條件",
+ "add_relationships": "新增關係",
+ "cannot_be_empty_": "過濾欄位不能為空",
+ "cannot_be_empty_de_ruler": "規則條件不能為空",
+ "filter_value_can_null": "過濾值不能為空",
+ "filter_like": "包含",
+ "filter_not_like": "不包含",
+ "filter_in": "屬於",
+ "filter_not_in": "不屬於",
+ "enter_a_question": "請輸入問題",
+ "new_conversation": "新對話",
+ "send": "傳送",
+ "stop_replying": "停止回覆",
+ "i_am_sqlbot": "你好,我是SQLBot",
+ "predict_data_etc": "我可以查詢資料、產生圖表、分析資料、預測資料等。",
+ "intelligent_data_query": "趕快開啟智慧問數吧~"
+ },
+ "embedded": {
+ "delete_10_apps": "是否刪除 {msg} 個應用?",
+ "click_to_show": "點擊顯示",
+ "click_to_hide": "點擊隱藏",
+ "your_app_secret": "確定更新 APP Secret 嗎?",
+ "proceed_with_caution": "重設後現有的 App Secret 將會失效,請謹慎操作。",
+ "password_length": "密碼長度",
+ "edit_app": "編輯應用",
+ "embedded_management": "嵌入式管理",
+ "embedded_assistant": "小助手嵌入",
+ "embedded_page": "頁面嵌入",
+ "no_application": "暫無應用",
+ "create_application": "建立應用",
+ "basic_application": "基礎應用",
+ "advanced_application": "進階應用",
+ "embed_third_party": "嵌入第三方",
+ "support_is_required": "適用於無需資料驗證的場景,只需將嵌入式程式碼內嵌到第三方的程式碼中,無需做額外的支援",
+ "data_permissions_etc": "適用於需要資料驗證的場景,需要第三方系統提供資料來源介面、使用者介面資料權限等",
+ "create_basic_application": "建立基礎應用",
+ "set_data_source": "設定資料來源",
+ "basic_information": "基本資訊",
+ "application_name": "應用名稱",
+ "application_description": "應用描述",
+ "cross_domain_settings": "跨網域設定",
+ "enableCustomModel": "使用指定模型",
+ "useModel": "使用模型",
+ "defaultModel": "預設模型",
+ "customModel": "指定模型",
+ "third_party_address": "請輸入嵌入的第三方位址,多個以分號分割",
+ "set_to_private": "設為私有",
+ "set_to_public": "設為公共",
+ "public": "公共",
+ "private": "私有",
+ "configure_interface": "配置介面",
+ "interface_url": "介面 URL",
+ "format_is_incorrect": "格式不對{msg}",
+ "domain_format_incorrect": ",http或https開頭,不能以 / 結尾,多個網域名稱以分號(半形)分隔",
+ "interface_url_incorrect": ",請填寫相對路徑,以/開頭,或者絕對路徑以http或https開頭",
+ "aes_enable": "開啟 AES 加密",
+ "aes_enable_tips": "加密欄位 (host, user, password, dataBase, schema) 均採用 AES-CBC-PKCS5Padding 加密方式",
+ "bit": "位",
+ "creating_advanced_applications": "建立進階應用",
+ "credential_acquisition_method": "憑證取得方式",
+ "table_notes": "表備註",
+ "system_credential_type": "來源系統憑證類型",
+ "credential_name": "憑證名稱",
+ "target_credential_location": "目標憑證位置",
+ "target_credential_name": "目標憑證名稱",
+ "target_credential": "目標憑證",
+ "edit_advanced_applications": "編輯進階應用",
+ "edit_basic_applications": "編輯基礎應用",
+ "delete": "是否刪除: {msg}?",
+ "code_to_embed": "複製以下程式碼進行嵌入",
+ "floating_window_mode": "浮窗模式",
+ "copy_successful": "複製成功",
+ "copy_failed": "複製失敗",
+ "open_the_query": "公共的資料來源,允許所有使用者開啟問數;私有資料來源,登入狀態的使用者可以開啟問數",
+ "add_interface_credentials": "新增介面憑證",
+ "edit_interface_credentials": "編輯介面憑證",
+ "duplicate_name": "重複名稱",
+ "duplicate_name_": "重複姓名",
+ "duplicate_account": "重複帳號",
+ "duplicate_email": "重複郵箱",
+ "repeating_parameters": "重複參數",
+ "interface_credentials": "介面憑證",
+ "no_credentials_yet": "暫無憑證",
+ "intelligent_customer_service": "SQLBot 智慧客服",
+ "enter_a_question": "請輸入問題",
+ "new_conversation": "新建對話",
+ "send": "傳送",
+ "stop_replying": "停止回答",
+ "i_am_sqlbot": "你好,我是 SQLBot",
+ "predict_data_etc": "我可以查詢資料、產生圖表、檢測資料異常、預測資料等",
+ "intelligent_data_query": "趕快開啟智慧問數吧~",
+ "origin_format_error": "格式錯誤,http或https開頭,不能以 / 結尾",
+ "display_settings": "顯示設定",
+ "header_text_color": "頭部文字顏色",
+ "app_logo": "應用 Logo",
+ "maximum_size_10mb": "建議尺寸 32 x 32,支援 JPG、PNG,大小不超過 10MB",
+ "replace": "取代",
+ "default_icon_position": "圖示預設位置",
+ "draggable_position": "可拖曳位置",
+ "up": "上",
+ "down": "下",
+ "left": "左",
+ "right": "右",
+ "welcome_description": "歡迎語描述",
+ "data_analysis_now": "我可以查詢資料、產生圖表、檢測資料異常、預測資料等趕快開啟智慧問數吧~",
+ "window_entrance_icon": "浮窗入口圖示",
+ "preview_error": "目前頁面禁止使用 Iframe 嵌入!",
+ "assistant_app": "小助手應用",
+ "auto_select_ds": "自動選擇資料來源"
+ },
+ "chat": {
+ "type": "圖表類型",
+ "chart_type": {
+ "table": "明細表",
+ "bar": "橫條圖",
+ "column": "柱狀圖",
+ "line": "折線圖",
+ "pie": "圓餅圖"
+ },
+ "hide_label": "隱藏標籤",
+ "show_label": "顯示標籤",
+ "sort_asc": "升序",
+ "sort_desc": "降序",
+ "sort_none": "不排序",
+ "show_sql": "檢視SQL",
+ "export_to": "匯出為",
+ "excel": "Excel",
+ "picture": "圖片",
+ "add_to_dashboard": "新增到儀表板",
+ "full_screen": "全螢幕",
+ "exit_full_screen": "退出全螢幕",
+ "sql_generation": "產生SQL",
+ "chart_generation": "產生圖表",
+ "inference_process": "思考過程",
+ "thinking": "思考中",
+ "data_analysis": "資料分析",
+ "data_predict": "資料預測",
+ "data_over_limit": "資料量過大,僅展示前{0}筆資料",
+ "ds_is_invalid": "資料來源無效",
+ "error": "錯誤",
+ "exec-sql-err": "執行SQL失敗",
+ "no_data": "暫無資料",
+ "loading_data": "載入中...",
+ "show_error_detail": "檢視具體資訊",
+ "thousands_separator_setting": "千分位符設定",
+ "thousands_separator_display": "套用千分位符顯示",
+ "log": {
+ "GENERATE_SQL": "產生 SQL",
+ "GENERATE_CHART": "產生圖表結構",
+ "ANALYSIS": "分析",
+ "PREDICT_DATA": "預測",
+ "GENERATE_SQL_WITH_PERMISSIONS": "拼接 SQL 列權限",
+ "CHOOSE_DATASOURCE": "匹配資料來源",
+ "GENERATE_DYNAMIC_SQL": "產生動態 SQL",
+ "CHOOSE_TABLE": "匹配資料表 (Schema)",
+ "FILTER_TERMS": "匹配術語",
+ "FILTER_SQL_EXAMPLE": "匹配 SQL 範例",
+ "FILTER_CUSTOM_PROMPT": "匹配自訂提示詞",
+ "EXECUTE_SQL": "執行 SQL",
+ "GENERATE_PICTURE": "產生圖片"
+ },
+ "log_system": "對話範本",
+ "log_question": "本次提問",
+ "log_answer": "AI 回答",
+ "log_history": "歷史記錄",
+ "find_term_title": "匹配到 {0} 個術語",
+ "find_sql_sample_title": "匹配到 {0} 個SQL範例",
+ "find_custom_prompt_title": "匹配到 {0} 個自訂提示詞",
+ "query_count_title": "查詢到 {0} 筆資料",
+ "generate_picture_success": "已產生圖片"
+ },
+ "about": {
+ "title": "關於",
+ "auth_to": "授權給",
+ "invalid_license": "License 無效",
+ "update_license": "更新 License",
+ "expiration_time": "過期時間",
+ "expirationed": "(已過期)",
+ "auth_num": "授權數量",
+ "version": "版本",
+ "version_num": "版本號",
+ "standard": "社區版",
+ "enterprise": "企業版",
+ "professional": "專業版",
+ "embedded": "嵌入式版",
+ "support": "取得技術支援",
+ "update_success": "更新成功,請重新登入",
+ "serial_no": "序號",
+ "remark": "備註",
+ "back_community": "還原至社區版",
+ "confirm_tips": "確定還原至社區版?"
+ },
+ "license": {
+ "error_tips": "是否重新整理頁面?",
+ "offline_tips": "服務已下線,請聯繫管理員重啟服務!"
+ },
+ "system": {
+ "system_settings": "系統設定",
+ "appearance_settings": "外觀設定",
+ "authentication_settings": "登入認證",
+ "platform_display_theme": "平台顯示主題",
+ "default_turquoise": "預設 (松石綠)",
+ "tech_blue": "科技藍",
+ "custom": "自訂",
+ "platform_login_settings": "平台登入設定",
+ "page_preview": "頁面預覽",
+ "restore_default": "恢復預設",
+ "website_logo": "網站 Logo",
+ "tab": "頁籤",
+ "replace_image": "取代圖片",
+ "larger_than_200kb": "頂部網站顯示的 Logo,建議尺寸 48 x 48,支援 JPG、PNG,大小不超過 200KB",
+ "login_logo": "系統 Logo",
+ "larger_than_200kb_de": "登入頁面右側 Logo,建議尺寸 204*52,支援 JPG、PNG,大小不超過 200KB",
+ "login_background_image": "登入背景圖",
+ "larger_than_5mb": "左側背景圖,向量圖建議尺寸 576*900,點陣圖建議尺寸 1152*1800;支援 JPG、PNG,大小不超過 5M",
+ "website_name": "網站名稱",
+ "on_webpage_tabs": "顯示在網頁 Tab 的平台名稱",
+ "welcome_message": "顯示歡迎語",
+ "the_product_logo": "產品 Logo 下的 歡迎語",
+ "screen_customization_supported": "預設為 SQLBot 登入介面,支援自訂設定",
+ "screen_customization_settings": "預設為 SQLBot 平台介面,支援自訂設定",
+ "platform_settings": "平台設定",
+ "help_documentation": "說明文件",
+ "show_about": "顯示關於",
+ "abort_update": "放棄更新",
+ "save_and_apply": "儲存並套用",
+ "setting_successfully": "設定成功",
+ "customize_theme_color": "自訂主題色"
+ },
+ "platform": {
+ "title": "平台對接",
+ "status_open": "已開啟",
+ "status_close": "已關閉",
+ "access_in": "接入",
+ "can_enable_it": "測試連線有效後,可開啟"
+ },
+ "authentication": {
+ "invalid": "無效",
+ "valid": "有效",
+ "cas_settings": "CAS 設定",
+ "callback_domain_name": "回調位址",
+ "callback_domain_name_error": "回調位址必須是目前的存取網域名稱",
+ "field_mapping": "使用者屬性對應",
+ "field_mapping_placeholder": "例如:{'{'}\"account\": \"saml2Account\", \"name\": \"saml2Name\", \"email\": \"email\"{'}'}",
+ "incorrect_please_re_enter": "格式錯誤,請重新填寫",
+ "in_json_format": "請輸入json格式",
+ "authorize_url": "授權位址",
+ "client_id": "用戶端 ID",
+ "client_secret": "用戶端密鑰",
+ "redirect_url": "回調位址",
+ "logout_redirect_url": "登出回調位址",
+ "logout_redirect_url_placeholder": "登出後預設跳轉至 SQLBot 登入頁面,可自訂設定登出後跳轉位址",
+ "oauth2_settings": "OAuth2 設定",
+ "scope": "授權範圍",
+ "userinfo_url": "使用者資訊位址",
+ "token_url": "權杖位址",
+ "revoke_url": "撤銷位址",
+ "oauth2_field_mapping_placeholder": "例如:{'{'}\"account\": \"oauth2Account\", \"name\": \"oauth2Name\", \"email\": \"email\"{'}'}",
+ "token_auth_method": "Token 認證方式",
+ "userinfo_auth_method": "使用者資訊認證方式",
+ "oidc_settings": "OIDC 設定",
+ "metadata_url": "中繼資料位址",
+ "realm": "領域",
+ "oidc_field_mapping_placeholder": "例如:{'{'}\"account\": \"oidcAccount\", \"name\": \"oidcName\", \"email\": \"email\"{'}'}",
+ "ldap_settings": "LDAP 設定",
+ "server_address": "伺服器位址",
+ "server_address_placeholder": "例如:ldap://ldap.example.com:389",
+ "bind_dn": "繫結 DN",
+ "bind_dn_placeholder": "例如:cn=admin,dc=example,dc=com",
+ "bind_pwd": "繫結密碼",
+ "ou": "使用者 OU",
+ "ou_placeholder": "例如:ou=users,dc=example,dc=com",
+ "user_filter": "使用者過濾器",
+ "user_filter_placeholder": "例如:uid 或 uid {0} email, 多屬性以 {1} 分割",
+ "ldap_field_mapping_placeholder": "例如:{'{'}\"account\": \"ldapAccount\", \"name\": \"ldapName\", \"email\": \"mail\"{'}'}",
+ "be_turned_on": "測試連線有效後,可開啟"
+ },
+ "login": {
+ "default_login": "預設",
+ "ldap_login": "LDAP 登入",
+ "account_login": "帳號登入",
+ "other_login": "其他登入方式",
+ "pwd_invalid_error": "密碼已過期請聯繫管理員修改或重設",
+ "pwd_exp_tips": "密碼在 {0} 天後過期,請盡快修改密碼",
+ "qr_code": "QR Code",
+ "platform_disable": "{0}設定未開啟!",
+ "input_account": "請輸入帳號",
+ "redirect_2_auth": "正在跳轉至 {0} 認證,{1} 秒...",
+ "redirect_immediately": "立即跳轉",
+ "permission_invalid": "認證無效【目前帳號權限不夠】",
+ "scan_qr_login": "掃碼登入",
+ "no_auth_error": "未認證,即將跳轉登入頁面,{0} 秒..."
+ },
+ "supplier": {
+ "alibaba_cloud_bailian": "阿里雲百煉",
+ "qianfan_model": "千帆大模型",
+ "deepseek": "DeepSeek",
+ "tencent_hunyuan": "騰訊混元",
+ "iflytek_spark": "訊飛星火",
+ "gemini": "Gemini",
+ "openai": "OpenAI",
+ "kimi": "Kimi",
+ "tencent_cloud": "騰訊雲",
+ "volcano_engine": "火山引擎",
+ "minimax": "MiniMax",
+ "generic_openai": "通用OpenAI"
+ },
+ "modelType": {
+ "llm": "大語言模型"
+ },
+ "audit": {
+ "system_log": "操作日誌",
+ "search_log": "搜尋日誌",
+ "operation_type": "操作類型",
+ "operation_details": "操作詳情",
+ "operation_user_name": "操作使用者",
+ "operation_status": "操作狀態",
+ "user_name": "操作日誌",
+ "oid_name": "工作區",
+ "ip_address": "IP 位址",
+ "create_time": "建立時間",
+ "no_log": "暫無日誌",
+ "all_236_terms": "是否匯出全部 {msg} 筆日誌?",
+ "export_hint": "是否匯出全部日誌?",
+ "export": "匯出",
+ "success": "成功",
+ "failed": "失敗",
+ "failed_info": "操作失敗詳情",
+ "opt_time": "操作時間"
+ },
+ "api_key": {
+ "info_tips": "API Key 是您存取 SQLBot API 的密鑰,具有帳戶的完全權限,請您務必妥善保管!不要以任何方式公開 API Key 到外部渠道,避免被他人利用造成安全威脅。",
+ "create": "建立",
+ "to_doc": "檢視 API",
+ "trigger_limit": "最多支援建立 {0} 個 API Key"
+ }
+}
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index f81e9fcbe..08c414c1a 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -1,3 +1,7 @@
+import 'core-js/features/object/has-own'
+// @ts-ignore: css-has-pseudo/browser lacks official type definitions
+import cssHasPseudo from 'css-has-pseudo/browser'
+
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import './style.less'
@@ -7,6 +11,26 @@ import { i18n } from './i18n'
import VueDOMPurifyHTML from 'vue-dompurify-html'
// import 'element-plus/dist/index.css'
+cssHasPseudo(document)
+
+function supportsFlexGap() {
+ const flex = document.createElement('div')
+ flex.style.display = 'flex'
+ flex.style.flexDirection = 'column'
+ flex.style.rowGap = '1px'
+
+ flex.appendChild(document.createElement('div'))
+ flex.appendChild(document.createElement('div'))
+
+ document.body.appendChild(flex)
+ const isSupported = flex.scrollHeight === 1
+ document.body.removeChild(flex)
+
+ return isSupported
+}
+
+document.documentElement.setAttribute('data-no-flex-gap', String(!supportsFlexGap()))
+
const app = createApp(App)
const pinia = createPinia()
diff --git a/frontend/src/stores/appearance.ts b/frontend/src/stores/appearance.ts
index 2093f300a..ed368a7dc 100644
--- a/frontend/src/stores/appearance.ts
+++ b/frontend/src/stores/appearance.ts
@@ -315,7 +315,7 @@ const setLinkIcon = (linkWeb?: string) => {
if (linkWeb) {
link['href'] = baseUrl + linkWeb
} else {
- link['href'] = '/LOGO-fold.svg'
+ link['href'] = `${location.pathname}LOGO-fold.svg`
}
}
}
diff --git a/frontend/src/stores/assistant.ts b/frontend/src/stores/assistant.ts
index 754d00a11..45474fcbd 100644
--- a/frontend/src/stores/assistant.ts
+++ b/frontend/src/stores/assistant.ts
@@ -1,10 +1,6 @@
import { defineStore } from 'pinia'
import { store } from './index'
import { chatApi, ChatInfo } from '@/api/chat'
-import { useCache } from '@/utils/useCache'
-
-const { wsCache } = useCache()
-const flagKey = 'sqlbit-assistant-flag'
type Resolver = (value: T | PromiseLike) => void
type Rejecter = (reason?: any) => void
interface PendingRequest {
@@ -16,7 +12,6 @@ interface AssistantState {
id: string
token: string
assistant: boolean
- flag: number
type: number
certificate: string
online: boolean
@@ -35,7 +30,6 @@ export const AssistantStore = defineStore('assistant', {
id: '',
token: '',
assistant: false,
- flag: 0,
type: 0,
certificate: '',
online: false,
@@ -61,9 +55,6 @@ export const AssistantStore = defineStore('assistant', {
getAssistant(): boolean {
return this.assistant
},
- getFlag(): number {
- return this.flag
- },
getType(): number {
return this.type
},
@@ -176,14 +167,6 @@ export const AssistantStore = defineStore('assistant', {
setAssistant(assistant: boolean) {
this.assistant = assistant
},
- setFlag(flag: number) {
- if (wsCache.get(flagKey)) {
- this.flag = wsCache.get(flagKey)
- } else {
- this.flag = flag
- wsCache.set(flagKey, flag)
- }
- },
setPageEmbedded(embedded?: boolean) {
this.pageEmbedded = !!embedded
},
@@ -208,7 +191,6 @@ export const AssistantStore = defineStore('assistant', {
return chat
},
clear() {
- wsCache.delete(flagKey)
this.$reset()
},
},
diff --git a/frontend/src/stores/chatConfig.ts b/frontend/src/stores/chatConfig.ts
index a4ad4def9..478547826 100644
--- a/frontend/src/stores/chatConfig.ts
+++ b/frontend/src/stores/chatConfig.ts
@@ -4,21 +4,41 @@ import { request } from '@/utils/request.ts'
import { formatArg } from '@/utils/utils.ts'
interface ChatConfig {
+ sqlbot_name: string
expand_thinking_block: boolean
+ hide_thinking_block: boolean
limit_rows: boolean
+ show_sql: boolean
+ show_log: boolean
}
export const chatConfigStore = defineStore('chatConfigStore', {
state: (): ChatConfig => {
return {
+ sqlbot_name: 'SQLBot',
expand_thinking_block: false,
+ hide_thinking_block: false,
limit_rows: true,
+ show_sql: true,
+ show_log: true,
}
},
getters: {
+ getSQLBotName(): string {
+ return this.sqlbot_name
+ },
getExpandThinkingBlock(): boolean {
return this.expand_thinking_block
},
+ getHideThinkingBlock(): boolean {
+ return this.hide_thinking_block
+ },
+ getShowSQL(): boolean {
+ return this.show_sql
+ },
+ getShowLog(): boolean {
+ return this.show_log
+ },
getLimitRows(): boolean {
return this.limit_rows
},
@@ -28,12 +48,26 @@ export const chatConfigStore = defineStore('chatConfigStore', {
request.get('/system/parameter/chat').then((res: any) => {
if (res) {
res.forEach((item: any) => {
+ if (item.pkey === 'chat.hide_thinking_block') {
+ this.hide_thinking_block = formatArg(item.pval)
+ }
if (item.pkey === 'chat.expand_thinking_block') {
this.expand_thinking_block = formatArg(item.pval)
}
+ if (item.pkey === 'chat.show_sql') {
+ this.show_sql = formatArg(item.pval)
+ }
+ if (item.pkey === 'chat.show_log') {
+ this.show_log = formatArg(item.pval)
+ }
if (item.pkey === 'chat.limit_rows') {
this.limit_rows = formatArg(item.pval)
}
+ if (item.pkey === 'chat.sqlbot_name') {
+ if (item.pval && item.pval.trim().length > 0) {
+ this.sqlbot_name = item.pval
+ }
+ }
})
}
})
diff --git a/frontend/src/stores/user.ts b/frontend/src/stores/user.ts
index 356a8619e..b72e061d7 100644
--- a/frontend/src/stores/user.ts
+++ b/frontend/src/stores/user.ts
@@ -177,6 +177,8 @@ export const UserStore = defineStore('user', {
language = 'zh-CN'
} else if (language === 'zh_CN') {
language = 'zh-CN'
+ } else if (language === 'zh_TW') {
+ language = 'zh-TW'
} else if (language === 'ko_KR') {
language = 'ko-KR'
}
diff --git a/frontend/src/style.less b/frontend/src/style.less
index 9f9be7f4a..0d1d9263b 100644
--- a/frontend/src/style.less
+++ b/frontend/src/style.less
@@ -1,3 +1,23 @@
+/* ==========================================
+ 老旧浏览器 Flex Gap 完美物理隔离补丁
+ ========================================== */
+
+/* 1. 当浏览器【不支持 flex gap】时,激活此特定命名空间 */
+:root[data-no-flex-gap='true'] .flex-gap-fallback {
+ display: flex;
+}
+
+/* 2. 仅对标记了该 class 的容器下的【相邻子元素】水平方向加间距 */
+:root[data-no-flex-gap='true'] .flex-gap-fallback > * + * {
+ margin-left: var(--gap-size, 16px); /* 默认 16px,可通过变量动态修改 */
+}
+
+/* 3. 如果需要处理垂直排列(flex-direction: column) */
+:root[data-no-flex-gap='true'] .flex-gap-fallback.flex-col > * + * {
+ margin-left: 0;
+ margin-top: var(--gap-size, 16px);
+}
+
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
@@ -25,12 +45,15 @@
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
--ed-border-radius-base: 6px !important;
--ed-border-color: #d9dcdf !important;
+}
+
+:root:root {
--ed-color-primary-light-7: #d2f1e9 !important;
--ed-border-color: #d9dcdf !important;
- --ed-border-radius-base: 6px !important;
--ed-disabled-border-color: #d9dcdf !important;
--ed-border-color-light: #dee0e3 !important;
--ed-border-color-lighter: #dee0e3 !important;
+ --ed-border-radius-base: 6px !important;
}
a {
@@ -85,7 +108,7 @@ body {
.list-item_primary {
height: 40px;
- border-radius: 4px;
+ border-radius: 6px;
padding: 8px 12px;
cursor: pointer;
display: flex;
@@ -227,7 +250,11 @@ strong {
.ed-select__popper {
padding: 0 4px !important;
.ed-select-dropdown__item {
- border-radius: 4px;
+ border-radius: 6px;
+ }
+
+ .ed-select-dropdown__list {
+ padding: 4px 0 !important;
}
}
@@ -380,16 +407,6 @@ strong {
line-height: 22px;
}
-.ed-pager li.number.number.number {
- &:hover {
- background-color: var(--ed-color-primary-60);
- }
-
- &:active {
- background-color: var(--ed-color-primary-80);
- }
-}
-
.ed-table.ed-table.ed-table {
--ed-table-border-color: #1f232926;
}
@@ -432,3 +449,32 @@ strong {
.datetime-variables.datetime-variables {
color: #3370ff;
}
+
+.ed-tree-node__content {
+ border-radius: 6px;
+}
+
+.login-content {
+ /* 针对 Webkit 浏览器的自动填充样式重置 */
+ input:-webkit-autofill,
+ input:-webkit-autofill:hover,
+ input:-webkit-autofill:focus,
+ input:-webkit-autofill:active {
+ /* 1. 使用足够大的内阴影来覆盖背景色,把 #ffffff 替换成你输入框原本的背景色 */
+ -webkit-box-shadow: 0 0 0px 1000px #ffffff inset !important;
+
+ /* 2. 由于常规的 color 属性也会失效,需要用这个属性修改文字颜色 */
+ -webkit-text-fill-color: #333333 !important;
+
+ /* 3. 保留光标的正常颜色 */
+ caret-color: #333333;
+ }
+}
+
+.ed-popper.is-pure:has(.ed-select-dropdown) {
+ padding: 0 !important;
+
+ .ed-select-dropdown {
+ padding: 0 4px !important;
+ }
+}
diff --git a/frontend/src/utils/useCache.ts b/frontend/src/utils/useCache.ts
index c7cda2afa..256da2142 100644
--- a/frontend/src/utils/useCache.ts
+++ b/frontend/src/utils/useCache.ts
@@ -1,13 +1,50 @@
import WebStorageCache from 'web-storage-cache'
-type CacheType = 'sessionStorage' | 'localStorage'
+type CacheType = 'localStorage' | 'sessionStorage'
+
+const getPathPrefix = () => {
+ const pathname = window.location.pathname
+ // eslint-disable-next-line no-useless-escape
+ const match = pathname.match(/^\/([^\/]+)/)
+ return match ? `${match[1]}_` : 'sqlbot_v1_'
+}
export const useCache = (type: CacheType = 'localStorage') => {
- const wsCache: WebStorageCache = new WebStorageCache({
- storage: type,
+ const originalCache = new WebStorageCache({ storage: type })
+ const prefix = getPathPrefix()
+
+ const methodsNeedKeyPrefix = new Set(['get', 'delete', 'touch', 'add', 'replace'])
+
+ const wrappedCache = new Proxy(originalCache, {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ get(target, prop, _receiver) {
+ const originalMethod = target[prop as keyof typeof target]
+
+ if (typeof originalMethod !== 'function') {
+ return originalMethod
+ }
+
+ if (methodsNeedKeyPrefix.has(prop as string)) {
+ return function (this: any, key: string, ...args: any[]) {
+ // 自动加上前缀
+ const scopedKey = `${prefix}${key}`
+ return (originalMethod as (...args: any[]) => any).apply(target, [scopedKey, ...args])
+ }
+ }
+
+ if (prop === 'set') {
+ return function (this: any, key: string, value: any, ...args: any[]) {
+ const scopedKey = `${prefix}${key}`
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
+ return (originalMethod as Function).apply(target, [scopedKey, value, ...args])
+ }
+ }
+
+ return originalMethod.bind(target)
+ },
})
return {
- wsCache,
+ wsCache: wrappedCache,
}
}
diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts
index 65aa4fed3..01eb57390 100644
--- a/frontend/src/utils/utils.ts
+++ b/frontend/src/utils/utils.ts
@@ -50,7 +50,7 @@ export const getBrowserLocale = () => {
}
if (language.toLowerCase().startsWith('zh')) {
const temp = language.toLowerCase().replace('_', '-')
- return temp === 'zh' ? 'zh-CN' : temp === 'zh-cn' ? 'zh-CN' : 'tw'
+ return temp === 'zh' ? 'zh-CN' : temp === 'zh-cn' ? 'zh-CN' : 'zh-TW'
}
return language
}
diff --git a/frontend/src/views/chat/ChatCreator.vue b/frontend/src/views/chat/ChatCreator.vue
index 831ab3950..aab5ae298 100644
--- a/frontend/src/views/chat/ChatCreator.vue
+++ b/frontend/src/views/chat/ChatCreator.vue
@@ -75,6 +75,11 @@ function selectDsInDialog(ds: any) {
innerDs.value = ds.id
}
+function selectDsDirectlyInDialog(ds: any) {
+ innerDs.value = ds.id
+ confirmSelectDs()
+}
+
function confirmSelectDs() {
if (innerDs.value) {
if (assistantStore.getType == 1) {
@@ -207,6 +212,7 @@ defineExpose({
:is-selected="ele.id === innerDs"
:description="ele.description"
@select-ds="selectDsInDialog(ele)"
+ @select-ds-directly="selectDsDirectlyInDialog(ele)"
>
diff --git a/frontend/src/views/chat/ChatList.vue b/frontend/src/views/chat/ChatList.vue
index c2a98aa3b..33799afc5 100644
--- a/frontend/src/views/chat/ChatList.vue
+++ b/frontend/src/views/chat/ChatList.vue
@@ -200,7 +200,7 @@ const handleConfirmPassword = () => {
-
+
{
display: flex;
flex-direction: column;
+ --gap-size: 16px;
gap: 16px;
.group {
@@ -399,7 +400,7 @@ const handleConfirmPassword = () => {
diff --git a/frontend/src/views/dashboard/canvas/CanvasCore.vue b/frontend/src/views/dashboard/canvas/CanvasCore.vue
index 7fe3a84a7..6a58d220f 100644
--- a/frontend/src/views/dashboard/canvas/CanvasCore.vue
+++ b/frontend/src/views/dashboard/canvas/CanvasCore.vue
@@ -727,7 +727,11 @@ function startResize(e: MouseEvent, point: string, item: CanvasItem, index: numb
infoBox.value.point = point
}
-function containerClick() {
+function containerClick(e?: MouseEvent) {
+ // Ignore clicks that originate inside a component so interacting with component
+ // content (e.g. selecting/copying cells in an S2 table) does not clear the
+ // current selection. Only blank-canvas clicks deselect.
+ if ((e?.target as HTMLElement)?.closest?.('.item')) return
// remove current component info
dashboardStore.setCurComponent(null)
}
diff --git a/frontend/src/views/dashboard/canvas/CanvasShape.vue b/frontend/src/views/dashboard/canvas/CanvasShape.vue
index f49de87fb..a498b3590 100644
--- a/frontend/src/views/dashboard/canvas/CanvasShape.vue
+++ b/frontend/src/views/dashboard/canvas/CanvasShape.vue
@@ -52,7 +52,11 @@ const props = defineProps({
const { draggable } = toRefs(props)
const shapeClick = (e: MouseEvent) => {
- e.stopPropagation()
+ // Do not stopPropagation here: the click must reach window so components that
+ // rely on a window-level click listener (e.g. the S2 table copy interaction,
+ // which only enables Cmd/Ctrl+C when the last click landed on its canvas) work
+ // inside the editor. Deselection is handled by containerClick ignoring clicks
+ // that originate inside a component.
e.preventDefault()
}
diff --git a/frontend/src/views/dashboard/canvas/ComponentBar.vue b/frontend/src/views/dashboard/canvas/ComponentBar.vue
index bd6ac78b2..b2480804c 100644
--- a/frontend/src/views/dashboard/canvas/ComponentBar.vue
+++ b/frontend/src/views/dashboard/canvas/ComponentBar.vue
@@ -115,7 +115,7 @@ const doDeleteComponent = (e: MouseEvent) => {
+
+
diff --git a/frontend/src/views/system/model/Model.vue b/frontend/src/views/system/model/Model.vue
index 76f514058..47da0cd49 100644
--- a/frontend/src/views/system/model/Model.vue
+++ b/frontend/src/views/system/model/Model.vue
@@ -16,8 +16,11 @@ import { getModelTypeName } from '@/entity/CommonEntity.ts'
import { useI18n } from 'vue-i18n'
import { get_supplier } from '@/entity/supplier'
import { highlightKeyword } from '@/utils/xss'
+import AuthorizedWorkspaceDialogForModel from '@/views/system/workspace/AuthorizedWorkspaceDialogForModel.vue'
+import AuthorizedWorkspaceDraw from '@/views/system/workspace/AuthorizedWorkspaceDraw.vue'
interface Model {
+ ws_mapping_count: number | undefined
name: string
model_type: string
base_model: string
@@ -249,6 +252,16 @@ const deleteHandler = (item: any) => {
})
}
+const AuthorizedWorkspaceDialogForModelRef = ref()
+const AuthorizedWorkspaceDrawRef = ref()
+
+const handleAuthorizedSpace = (item: any) => {
+ AuthorizedWorkspaceDialogForModelRef.value.open(item.id)
+}
+const handleEditWorkspaceList = (item: any) => {
+ AuthorizedWorkspaceDrawRef.value.open(item.id)
+}
+
const clickModel = (ele: any) => {
activeStep.value = 1
supplierChang(ele)
@@ -387,6 +400,7 @@ const submit = (item: any) => {
:ref="(el: any) => setCardRef(el, index)"
:key="ele.id"
:name="ele.name"
+ :num="ele.ws_mapping_count"
:supplier="ele.supplier"
:model-type="getModelTypeName(ele['model_type'])"
:base-model="ele['base_model']"
@@ -394,6 +408,8 @@ const submit = (item: any) => {
@edit="handleEditModel(ele)"
@del="deleteHandler"
@default="handleDefault(ele)"
+ @authorized-space="handleAuthorizedSpace(ele)"
+ @edit-workspace-list="handleEditWorkspaceList(ele)"
>
@@ -468,6 +484,8 @@ const submit = (item: any) => {
+
+
diff --git a/frontend/src/views/system/workspace/AuthorizedWorkspaceDialogForModelAdd.vue b/frontend/src/views/system/workspace/AuthorizedWorkspaceDialogForModelAdd.vue
new file mode 100644
index 000000000..4f1fc4ba6
--- /dev/null
+++ b/frontend/src/views/system/workspace/AuthorizedWorkspaceDialogForModelAdd.vue
@@ -0,0 +1,349 @@
+
+
+ {{ $t('authorized_space.select_space') }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('datasource.select_all') }}
+
+
+
+
+
+
+
+
+ {{ space.name }}
+
+
+
+
+
+
+
+
+ {{ $t('workspace.selected_number', { msg: checkTableList.length }) }}
+
+
+
+ {{ $t('workspace.clear') }}
+
+
+
+
+
+
+
+
{{
+ ele.name
+ }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t('common.cancel') }}
+
+ {{ $t('common.confirm2') }}
+
+
+
+
+
+
+
diff --git a/frontend/src/views/system/workspace/AuthorizedWorkspaceDraw.vue b/frontend/src/views/system/workspace/AuthorizedWorkspaceDraw.vue
new file mode 100644
index 000000000..808eb16ac
--- /dev/null
+++ b/frontend/src/views/system/workspace/AuthorizedWorkspaceDraw.vue
@@ -0,0 +1,521 @@
+
+
+
+
+
+ {{ $t('authorized_space.workspaces_authorized', { num: filteredList.length }) }}
+
+
+
+
+
+
+ {{ $t('authorized_space.authorized_space') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('datasource.select_all') }}
+
+
+
+
+ {{
+ $t('user.selected_2_items', { msg: multipleSelectionAll.length })
+ }}
+
+ {{ $t('common.cancel') }}
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/views/system/workspace/index.vue b/frontend/src/views/system/workspace/index.vue
index da3519cd4..303c888e6 100644
--- a/frontend/src/views/system/workspace/index.vue
+++ b/frontend/src/views/system/workspace/index.vue
@@ -701,7 +701,7 @@ const handleCurrentChange = (val: number) => {
display: flex;
align-items: center;
padding-left: 8px;
- border-radius: 4px;
+ border-radius: 6px;
cursor: pointer;
padding-right: 8px;
margin-bottom: 2px;
@@ -876,7 +876,7 @@ const handleCurrentChange = (val: number) => {