diff --git a/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php b/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php index 38c7df8242..477543d5c4 100644 --- a/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php +++ b/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php @@ -1,11 +1,5 @@ - + setClientTheme('blue'); ?> - + +control->loadModel('im'); +$xxdStatus = $im->getXxdStatus(); +if(isset($app->config->xuanxuan->turnon) && $app->config->xuanxuan->turnon && $xxdStatus == 'online') +{ + $xuanConfig = new stdclass(); + $token = $im->userGetAuthToken($app->user->id, 'zentaoweb'); + $clientUrl = isset($app->config->webClientUrl) ? $app->config->webClientUrl : 'data/xuanxuan/web/index.html'; + $backendUrl = $im->getServer('zentao'); + + $xuanConfig->clientUrl = $clientUrl; + $xuanConfig->server = ($app->config->xuanxuan->https == 'on' ? 'https' : 'http') . '://' . parse_url($backendUrl, PHP_URL_HOST) . ':' . $app->config->xuanxuan->commonPort; + $xuanConfig->account = $app->user->account; + $xuanConfig->authKey = $token->token; + $xuanConfig->debug = $app->config->debug; +} +?> + + +getWebRoot() . 'data/xuanxuan/sdk/sdk.min.js'); ?> + + diff --git a/lib/zin/wg/chatbtn/v1.php b/lib/zin/wg/chatbtn/v1.php index 52c0bed9b1..f6dc89bfd0 100644 --- a/lib/zin/wg/chatbtn/v1.php +++ b/lib/zin/wg/chatbtn/v1.php @@ -7,39 +7,139 @@ class chatBtn extends wg public static function getPageCSS(): ?string { return << div {margin-bottom: 10px;} + #xuan-chat-view .unconfigured {top: 50px;} + + #reload-ai-chat.disabled {cursor: wait; color: #999!important;} CSS; } public static function getPageJS(): ?string { - $aiChatURL = createLink('ai', 'chat'); + global $app; + + $isAIConfigured = $app->control->loadModel('ai')->hasModelsAvailable(); + $hasAIChatPriv = commonModel::hasPriv('ai', 'chat'); + + $xuanUnconfiguredTip = sprintf($app->lang->index->chat->unconfiguredFormat, $app->lang->index->chat->chat, (common::hasPriv('setting', 'xuanxuan') ? sprintf($app->lang->index->chat->goConfigureFormat, helper::createLink('setting', 'xuanxuan'), $app->lang->index->chat->chat) : $app->lang->index->chat->contactAdminForHelp)); + $aiUnconfiguredTip = sprintf($app->lang->index->chat->unconfiguredFormat, $app->lang->index->chat->ai, (common::hasPriv('ai', 'models') ? sprintf($app->lang->index->chat->goConfigureFormat, helper::createLink('ai', 'models') . '#app=admin', $app->lang->index->chat->ai) : $app->lang->index->chat->contactAdminForHelp)); + $aiUnauthorizedTip = $app->lang->index->chat->unauthorized; + $aiChatURL = createLink('ai', 'chat'); + + $aiChatView = ""; + if(!$hasAIChatPriv) $aiChatView = "
$aiUnauthorizedTip
"; + if(!$isAIConfigured) $aiChatView = "
$aiUnconfiguredTip
"; + $chatContainer = << -
- + +
+
$xuanUnconfiguredTip
+
+
$aiChatView
HTML; + + $xuanDefaultOpener = ($hasAIChatPriv && $isAIConfigured) ? '' : 'if(window.xuan) $(`#chat-switch .chat-switch-item[data-value="chat"]`).trigger("click");'; + return << { - if(!$('#chat-container').length) - { - $('body').append(`{$chatContainer}`); - $('#ai-chat-frame').on('load', () => {window.toggleChatContainer();}); - return; - } + if(window.xuan) window.xuan[window.xuan.shown ? 'expand' : 'show'](); $('#chat-btn').toggleClass('active'); $('#chat-container').toggle(); - } - $(document).on('click', e => - { - if(!$('#chat-container').length || $('#chat-container').prop('style') && $('#chat-container').prop('style').display !== 'block') return; - if($(e.target).closest('#ai-chat-view,#chat-btn').length) return; - window.toggleChatContainer(); - }); + }; + + /* Setup xuan web chat. */ + window.setupXuan = () => { + /* Move xuan web client into #xuan-chat-view. */ + if(window.xuan && !document.querySelector('#xuan-chat-view #xx-embed-container')) + { + document.querySelector('#xuan-chat-view').prepend(document.querySelector('#xx-embed-container')); + + /* Switch to xuan chat by default if AI is not available. */ + $xuanDefaultOpener + + /* Update badge on chat. */ + window.xuan._options.onNotice = function(notice) + { + window.handleXuanNoticeChange(notice); + $('.chat-switch-item[data-value="chat"]').toggleClass('has-notice', !!notice.count); + }; + + /* Set style into xuan frame. */ + let tries = 0; + const xuanFrameWaitLoop = setInterval(function() + { + if(document.querySelector('#xx-embed-container iframe')) + { + clearInterval(xuanFrameWaitLoop); + tries = 0; + const chatsViewWaitLoop = setInterval(function() + { + if(document.querySelector('#xx-embed-container iframe').contentDocument.querySelector('.app-chats-menu')) + { + clearInterval(chatsViewWaitLoop); + document.querySelector('#xx-embed-container iframe').contentDocument.querySelector('.app-chats-menu').style.cssText = 'width: 330px !important; top: 48px;'; + document.querySelector('#xx-embed-container iframe').contentDocument.querySelector('.app-chats-cache').style.cssText = 'right: 330px !important;'; + document.querySelector('#xx-embed-container iframe').contentDocument.querySelector('.app-chats-menu-search').style.cssText = 'padding: 10px 8px !important;'; + document.querySelector('#xx-embed-container iframe').contentDocument.querySelector('.app-chats-menu-search .btn:first-child').style.cssText = 'display: none;'; + } + else + { + if(++tries > 20) clearInterval(chatsViewWaitLoop); + } + }, 200); + } + else + { + if(++tries > 20) clearInterval(xuanFrameWaitLoop); + } + }, 200); + } + }; + (() => { + /* Insert chat views. */ + $('body').append(`{$chatContainer}`); + + /* Handle switch events. */ + $('#chat-switch .chat-switch-item').on('click', e => + { + const target = $(e.target); + target.addClass('active').siblings().removeClass('active'); + $('#ai-chat-view').toggle(target.data('value') === 'ai'); + $('#xuan-chat-view').toggle(target.data('value') === 'chat'); + }); + + /* Handle clicking outside. */ + $(document).on('click', e => + { + if(!$('#chat-container').length || $('#chat-container').prop('style') && $('#chat-container').prop('style').display !== 'block') return; + if($(e.target).closest('#chat-switch,#xuan-chat-view>.unconfigured,#ai-chat-view,#chat-btn').length) return; + window.toggleChatContainer(); + }); + })(); JAVASCRIPT; } diff --git a/module/index/ui/index.html.php b/module/index/ui/index.html.php index 15ecc7c0a9..38f40a77b5 100644 --- a/module/index/ui/index.html.php +++ b/module/index/ui/index.html.php @@ -17,8 +17,6 @@ else $scoreNotice = ''; if($config->vision != 'lite') $scoreNotice = $this->loadModel('score')->getNotice(); -$shouldShowAIChat = hasPriv('ai', 'chat') && $this->loadModel('ai')->hasModelsAvailable(); - jsVar('scoreNotice', $scoreNotice); jsVar('edition', $config->edition); jsVar('vision', $config->vision); @@ -101,7 +99,7 @@ div setID('appsToolbar'), setClass('space-x-1'), hasPriv('search', 'index') ? globalSearch() : null, - $shouldShowAIChat ? chatBtn() : null, + chatBtn(), item ( setClass('ghost btn-zentao px-1'),