334 lines
17 KiB
Plaintext
334 lines
17 KiB
Plaintext
{*+**********************************************************************************
|
||
* The contents of this file are subject to the vtiger CRM Public License Version 1.1
|
||
* ("License"); You may not use this file except in compliance with the License
|
||
* The Original Code is: vtiger CRM Open Source
|
||
* The Initial Developer of the Original Code is vtiger.
|
||
* Portions created by vtiger are Copyright (C) vtiger.
|
||
* All Rights Reserved.
|
||
************************************************************************************}
|
||
{strip}
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>{vtranslate($PAGETITLE, $QUALIFIED_MODULE)}</title>
|
||
<link rel="SHORTCUT ICON" href="layouts/v7/skins/images/favicon.ico">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/todc/css/bootstrap.min.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/todc/css/docs.min.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/todc/css/todc-bootstrap.min.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/font-awesome/css/font-awesome.min.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/jquery/select2/select2.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/select2-bootstrap/select2-bootstrap.css'>
|
||
<link type='text/css' rel='stylesheet' href='libraries/bootstrap/js/eternicode-bootstrap-datepicker/css/datepicker3.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/jquery/jquery-ui-1.11.3.custom/jquery-ui.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/vt-icons/style.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/animate/animate.min.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/jquery/malihu-custom-scrollbar/jquery.mCustomScrollbar.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/jquery/jquery.qtip.custom/jquery.qtip.css'>
|
||
<link type='text/css' rel='stylesheet' href='layouts/v7/lib/jquery/daterangepicker/daterangepicker.css'>
|
||
{*Salesplatform.ru begin PBXManager porting*}
|
||
<link type='text/css' rel='stylesheet' href='libraries/jquery/pnotify/jquery.pnotify.default.css'>
|
||
{*Salesplatform.ru end PBXManager porting*}
|
||
<input type="hidden" id="inventoryModules" value={ZEND_JSON::encode($INVENTORY_MODULES)}>
|
||
|
||
{assign var=V7_THEME_PATH value=Vtiger_Theme::getv7AppStylePath($SELECTED_MENU_CATEGORY)}
|
||
{if strpos($V7_THEME_PATH,".less")!== false}
|
||
<link type="text/css" rel="stylesheet/less" href="{vresource_url($V7_THEME_PATH)}" media="screen" />
|
||
{else}
|
||
<link type="text/css" rel="stylesheet" href="{vresource_url($V7_THEME_PATH)}" media="screen" />
|
||
{/if}
|
||
|
||
{foreach key=index item=cssModel from=$STYLES}
|
||
<link type="text/css" rel="{$cssModel->getRel()}" href="{vresource_url($cssModel->getHref())}" media="{$cssModel->getMedia()}" />
|
||
{/foreach}
|
||
|
||
{* For making pages - print friendly *}
|
||
<style type="text/css">
|
||
@media print {
|
||
.noprint { display:none; }
|
||
}
|
||
</style>
|
||
<script type="text/javascript">var __pageCreationTime = (new Date()).getTime();</script>
|
||
<script src="{vresource_url('layouts/v7/lib/jquery/jquery.min.js')}"></script>
|
||
<script src="{vresource_url('layouts/v7/lib/jquery/jquery-migrate-1.0.0.js')}"></script>
|
||
|
||
<script type="text/javascript">
|
||
var _META = { 'module': "{$MODULE}", view: "{$VIEW}", 'parent': "{$PARENT_MODULE}", 'notifier':"{$NOTIFIER_URL}", 'app':"{$SELECTED_MENU_CATEGORY}" };
|
||
{if $EXTENSION_MODULE}
|
||
var _EXTENSIONMETA = { 'module': "{$EXTENSION_MODULE}", view: "{$EXTENSION_VIEW}"};
|
||
{/if}
|
||
var _USERMETA;
|
||
{if $CURRENT_USER_MODEL}
|
||
_USERMETA = { 'id' : "{$CURRENT_USER_MODEL->get('id')}", 'menustatus' : "{$CURRENT_USER_MODEL->get('leftpanelhide')}",
|
||
'currency' : "{$USER_CURRENCY_SYMBOL}", 'currencySymbolPlacement' : "{$CURRENT_USER_MODEL->get('currency_symbol_placement')}",
|
||
'currencyGroupingPattern' : "{$CURRENT_USER_MODEL->get('currency_grouping_pattern')}", 'truncateTrailingZeros' : "{$CURRENT_USER_MODEL->get('truncate_trailing_zeros')}"};
|
||
{/if}
|
||
</script>
|
||
|
||
{* AI Drawer - подключение внешних файлов только для авторизованных пользователей *}
|
||
{if $CURRENT_USER_MODEL}
|
||
<link rel="stylesheet" href="layouts/v7/resources/css/ai-drawer.css?v=2.1">
|
||
<script src="layouts/v7/resources/js/ai-drawer-simple.js?v=2.8"></script>
|
||
<script src="ai_drawer_improvements.js"></script>
|
||
<script type="text/javascript">
|
||
{literal}
|
||
// Простая функция для редактирования в Nextcloud
|
||
function editInNextcloud(recordId, fileName) {
|
||
console.log('🎯 Opening file in Nextcloud:', recordId, fileName);
|
||
|
||
// Проверяем расширение
|
||
const ext = fileName.split('.').pop().toLowerCase();
|
||
if (!['docx', 'xlsx', 'pptx'].includes(ext)) {
|
||
alert('Файл ' + fileName + ' не поддерживается для редактирования. Поддерживаются: docx, xlsx, pptx');
|
||
return;
|
||
}
|
||
|
||
// Отправляем запрос к нашему API
|
||
const apiUrl = `crm_extensions/nextcloud_api.php?record=${encodeURIComponent(recordId)}&fileName=${encodeURIComponent(fileName)}`;
|
||
fetch(apiUrl, {
|
||
method: 'GET'
|
||
})
|
||
.then(response => {
|
||
console.log('📥 Response status:', response.status);
|
||
return response.json();
|
||
})
|
||
.then(json => {
|
||
console.log('📋 JSON response:', json);
|
||
if (json.success && json.data && json.data.urls) {
|
||
// Сначала пробуем файловый менеджер, потом прямой редактор
|
||
const filesManagerUrl = json.data.urls.files_manager;
|
||
const collaboraUrl = json.data.urls.collabora_id;
|
||
const onlyofficeUrl = json.data.urls.onlyoffice_id;
|
||
|
||
if (filesManagerUrl) {
|
||
console.log('🎯 Opening files manager:', filesManagerUrl);
|
||
window.open(filesManagerUrl, '_blank');
|
||
} else if (collaboraUrl) {
|
||
console.log('🎯 Opening Collabora:', collaboraUrl);
|
||
window.open(collaboraUrl, '_blank');
|
||
} else if (onlyofficeUrl) {
|
||
console.log('🎯 Opening OnlyOffice:', onlyofficeUrl);
|
||
window.open(onlyofficeUrl, '_blank');
|
||
} else {
|
||
console.error('❌ No valid URLs found');
|
||
alert('Ошибка: Не удалось получить URL для редактирования');
|
||
}
|
||
} else {
|
||
console.error('❌ Invalid response structure:', json);
|
||
alert('Ошибка: ' + (json.error || 'Не удалось получить URL для редактирования. Проверьте консоль для деталей.'));
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('❌ Error:', error);
|
||
alert('❌ Ошибка: ' + error.message);
|
||
});
|
||
}
|
||
|
||
// Алиас для совместимости с FilePreview.tpl
|
||
function openNextcloudEditor(recordId, fileName) {
|
||
console.log('🔄 openNextcloudEditor called, redirecting to editInNextcloud');
|
||
return editInNextcloud(recordId, fileName);
|
||
}
|
||
|
||
// Делаем функции глобальными для доступа из шаблонов
|
||
window.editInNextcloud = editInNextcloud;
|
||
window.openNextcloudEditor = openNextcloudEditor;
|
||
|
||
|
||
// Тестовая функция для отладки
|
||
function testEditButton(recordId, fileName) {
|
||
console.log('🧪 TEST: testEditButton called with:', recordId, fileName);
|
||
console.log('🧪 TEST: typeof editInNextcloud:', typeof editInNextcloud);
|
||
console.log('🧪 TEST: typeof window.editInNextcloud:', typeof window.editInNextcloud);
|
||
|
||
if (typeof editInNextcloud === 'function') {
|
||
console.log('✅ Функция editInNextcloud найдена, вызываем...');
|
||
editInNextcloud(recordId, fileName);
|
||
} else {
|
||
console.log('❌ Функция editInNextcloud НЕ найдена!');
|
||
alert('❌ Функция editInNextcloud не найдена!\n\nRecord ID: ' + recordId + '\nFile Name: ' + fileName);
|
||
}
|
||
}
|
||
window.testEditButton = testEditButton;
|
||
{/literal}
|
||
</script>
|
||
<script type="text/javascript">
|
||
{literal}
|
||
// Инициализация нового AI Drawer только для авторизованных пользователей
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
try {
|
||
console.log('AI Drawer: Initializing new version');
|
||
// Инициализируем новый AI Drawer
|
||
if (typeof AIDrawer !== 'undefined') {
|
||
window.aiDrawerInstance = new AIDrawer();
|
||
console.log('AI Drawer: New version initialized successfully');
|
||
|
||
// Отслеживаем смену URL для обновления истории
|
||
let currentURL = window.location.href;
|
||
const urlObserver = setInterval(function() {
|
||
if (window.location.href !== currentURL) {
|
||
currentURL = window.location.href;
|
||
console.log('AI Drawer: URL changed, refreshing history');
|
||
if (window.aiDrawerInstance && typeof window.aiDrawerInstance.refreshPreloadedHistory === 'function') {
|
||
// Обновляем историю с небольшой задержкой чтобы страница успела загрузиться
|
||
setTimeout(() => {
|
||
window.aiDrawerInstance.refreshPreloadedHistory();
|
||
}, 1000);
|
||
}
|
||
}
|
||
}, 1000);
|
||
|
||
// Также слушаем события навигации
|
||
window.addEventListener('popstate', function() {
|
||
console.log('AI Drawer: Popstate event, refreshing history');
|
||
if (window.aiDrawerInstance && typeof window.aiDrawerInstance.refreshPreloadedHistory === 'function') {
|
||
setTimeout(() => {
|
||
window.aiDrawerInstance.refreshPreloadedHistory();
|
||
}, 1000);
|
||
}
|
||
});
|
||
|
||
} else {
|
||
console.error('AI Drawer: AIDrawer class not found');
|
||
}
|
||
} catch (error) {
|
||
console.error('AI Drawer: Initialization error:', error);
|
||
}
|
||
});
|
||
{/literal}
|
||
</script>
|
||
{/if}
|
||
|
||
<!-- Nextcloud Editor Integration -->
|
||
<script type="text/javascript">
|
||
function testEditButton(recordId, fileName) {
|
||
console.log("🚀 Nextcloud Editor:", recordId, fileName);
|
||
|
||
// Простая версия для начала
|
||
var editUrl = "https://office.klientprav.tech/apps/files/?dir=/CRM_Active_Files";
|
||
var editorWindow = window.open(editUrl, "nextcloud_editor", "width=1200,height=800");
|
||
|
||
if (editorWindow) {
|
||
alert("✅ Открываю Nextcloud для файла: " + fileName + "\n\nПерейдите в папку CRM_Active_Files и найдите ваш файл для редактирования.");
|
||
} else {
|
||
alert("❌ Всплывающие окна заблокированы. Откройте Nextcloud вручную:\n" + editUrl);
|
||
}
|
||
}
|
||
|
||
console.log("✅ Nextcloud Editor функция загружена");
|
||
|
||
// Умная функция для редактирования с автозагрузкой файла
|
||
function openNextcloudEditorSmart(recordId, fileName) {
|
||
console.log("🚀 Smart Editor для:", recordId, fileName);
|
||
|
||
// Показываем индикатор
|
||
var loadingDiv = document.createElement("div");
|
||
loadingDiv.id = "nextcloud-smart-loading";
|
||
loadingDiv.innerHTML = '<div style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 99999; display: flex; align-items: center; justify-content: center;"><div style="background: white; padding: 40px; border-radius: 15px; text-align: center;"><i class="fa fa-cloud-upload fa-3x" style="color: #28a745;"></i><h3>Подготавливаю файл</h3><p>Загружаю ' + fileName + ' в Nextcloud...</p></div></div>';
|
||
document.body.appendChild(loadingDiv);
|
||
|
||
fetch("/crm_extensions/file_storage/api/simple_edit.php", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ record_id: recordId, file_name: fileName })
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
var loading = document.getElementById("nextcloud-smart-loading");
|
||
if (loading) document.body.removeChild(loading);
|
||
|
||
if (data.success) {
|
||
var win = window.open(data.edit_url, "nextcloud_editor", "width=1200,height=800");
|
||
if (win) {
|
||
alert("✅ Nextcloud открыт!\n\n" + data.message);
|
||
} else {
|
||
alert("❌ Всплывающие окна заблокированы");
|
||
}
|
||
} else {
|
||
alert("❌ Ошибка: " + data.error);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
var loading = document.getElementById("nextcloud-smart-loading");
|
||
if (loading) document.body.removeChild(loading);
|
||
alert("❌ Ошибка API: " + error.message);
|
||
});
|
||
}
|
||
body: JSON.stringify({ record_id: recordId, file_name: fileName })
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
// Убираем индикатор
|
||
var loading = document.getElementById("nextcloud-smart-loading");
|
||
if (loading) document.body.removeChild(loading);
|
||
|
||
if (data.success) {
|
||
// Открываем редактор
|
||
var win = window.open(data.edit_url, "nextcloud_editor", "width=1200,height=800,scrollbars=yes,resizable=yes");
|
||
if (win) {
|
||
alert("✅ Файл подготовлен и загружен в Nextcloud!\n\nФайл: " + fileName + "\n\nОткрывается редактор...");
|
||
} else {
|
||
alert("❌ Всплывающие окна заблокированы.\n\nОткройте ссылку:\n" + data.edit_url);
|
||
}
|
||
} else {
|
||
alert("❌ Ошибка: " + data.error);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
// Убираем индикатор
|
||
var loading = document.getElementById("nextcloud-smart-loading");
|
||
if (loading) document.body.removeChild(loading);
|
||
|
||
console.error("API Error:", error);
|
||
alert("❌ Ошибка подключения: " + error.message);
|
||
});
|
||
}
|
||
</script>
|
||
</head>
|
||
<body data-skinpath="{Vtiger_Theme::getBaseThemePath()}" data-language="{$LANGUAGE}"{if $CURRENT_USER_MODEL} data-user-decimalseparator="{$CURRENT_USER_MODEL->get('currency_decimal_separator')}" data-user-dateformat="{$CURRENT_USER_MODEL->get('date_format')}"
|
||
data-user-groupingseparator="{$CURRENT_USER_MODEL->get('currency_grouping_separator')}" data-user-numberofdecimals="{$CURRENT_USER_MODEL->get('no_of_currency_decimals')}" data-user-hourformat="{$CURRENT_USER_MODEL->get('hour_format')}"
|
||
data-user-calendar-reminder-interval="{$CURRENT_USER_MODEL->getCurrentUserActivityReminderInSeconds()}"{/if}>
|
||
{if $CURRENT_USER_MODEL}<input type="hidden" id="start_day" value="{$CURRENT_USER_MODEL->get('dayoftheweek')}" />{/if}
|
||
{* SalesPlatform.ru begin #5116 fixed localization *}
|
||
<input type="hidden" name="locale" value='{json_encode($LOCALE)}'>
|
||
{* SalesPlatform.ru end *}
|
||
{*
|
||
<!-- AI Drawer HTML - ЗАКОММЕНТИРОВАНО для предотвращения дублирования -->
|
||
<!-- JavaScript создает AI Drawer динамически, поэтому статический HTML не нужен -->
|
||
{if $CURRENT_USER_MODEL}
|
||
<div class="ai-drawer font-normal">
|
||
<div class="ai-drawer-header">
|
||
<span>AI Ассистент</span>
|
||
<button type="button" class="ai-drawer-close">×</button>
|
||
</div>
|
||
<div class="ai-font-controls">
|
||
<label>Размер шрифта:</label>
|
||
<button type="button" class="font-btn" data-size="small">Мелкий</button>
|
||
<button type="button" class="font-btn active" data-size="normal">Обычный</button>
|
||
<button type="button" class="font-btn" data-size="large">Крупный</button>
|
||
<button type="button" class="font-btn" data-size="extra-large">Очень крупный</button>
|
||
</div>
|
||
<div class="ai-avatar-controls">
|
||
<label>Аватарка ассистента:</label>
|
||
<button type="button" class="avatar-btn active" data-type="default">🤖</button>
|
||
<button type="button" class="avatar-btn" data-type="friendly">😊</button>
|
||
<button type="button" class="avatar-btn" data-type="helpful">💡</button>
|
||
<button type="button" class="avatar-btn" data-type="smart">🧠</button>
|
||
</div>
|
||
<div class="ai-drawer-content">
|
||
<div class="ai-chat-messages"></div>
|
||
<div class="ai-chat-input-container">
|
||
<textarea class="ai-chat-input" placeholder="Задайте вопрос AI ассистенту..."></textarea>
|
||
<button class="ai-send-btn">Отправить</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button type="button" class="ai-drawer-toggle">AI</button>
|
||
{/if}
|
||
*}
|
||
|
||
<div id="page">
|
||
<div id="pjaxContainer" class="hide noprint"></div>
|
||
<div id="messageBar" class="hide"></div> |