UI обращений, WebSocket и исправление DnD
- Канбан: шире контейнер, колонки minmax(300px), больше высота списков и колонок, брейкпоинт 1100px. - WebSocket: настраиваемый префикс support_ws_base (occ) и data-support-ws-base; корректная сборка пути /ws/tickets/… - Устранён ReferenceError: clientChatDndBound до инициализации при открытии создания обращения.
This commit is contained in:
+29
-11
@@ -5,6 +5,7 @@
|
|||||||
const username = root.dataset.username;
|
const username = root.dataset.username;
|
||||||
const serverAddress = root.dataset.serverAddress;
|
const serverAddress = root.dataset.serverAddress;
|
||||||
const apiBase = root.dataset.supportApiBase;
|
const apiBase = root.dataset.supportApiBase;
|
||||||
|
const supportWsBaseOverride = (root.dataset.supportWsBase || "").trim();
|
||||||
|
|
||||||
const RASTER_IMAGE_EXT = new Set(["jpg", "jpeg", "png", "gif", "webp", "bmp", "tif", "tiff", "heic", "heif"]);
|
const RASTER_IMAGE_EXT = new Set(["jpg", "jpeg", "png", "gif", "webp", "bmp", "tif", "tiff", "heic", "heif"]);
|
||||||
const RASTER_IMAGE_MIME = new Set([
|
const RASTER_IMAGE_MIME = new Set([
|
||||||
@@ -149,10 +150,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function wsUrlForTicket(ticketNumber) {
|
function wsUrlForTicket(ticketNumber) {
|
||||||
|
const tail = `/tickets/${encodeURIComponent(ticketNumber)}`;
|
||||||
|
if (supportWsBaseOverride) {
|
||||||
|
try {
|
||||||
|
const raw = supportWsBaseOverride.replace(/\/$/, "");
|
||||||
|
const u = new URL(raw.includes("://") ? raw : `wss://${raw}`);
|
||||||
|
const wsProto = u.protocol === "https:" ? "wss:" : u.protocol === "http:" ? "ws:" : u.protocol;
|
||||||
|
let path = (u.pathname || "").replace(/\/$/, "");
|
||||||
|
if (path === "" || path === "/") {
|
||||||
|
path = "/ws";
|
||||||
|
}
|
||||||
|
return `${wsProto}//${u.host}${path}${tail}`;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const u = new URL(apiBase);
|
const u = new URL(apiBase);
|
||||||
const wsProto = u.protocol === "https:" ? "wss:" : "ws:";
|
const wsProto = u.protocol === "https:" ? "wss:" : "ws:";
|
||||||
return `${wsProto}//${u.host}/ws/tickets/${encodeURIComponent(ticketNumber)}`;
|
return `${wsProto}//${u.host}/ws${tail}`;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -311,25 +327,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style>
|
||||||
.f7support-wrap { padding: 16px; font-family: sans-serif; max-width: min(1200px, 100%); box-sizing: border-box; }
|
.f7support-wrap { padding: 16px; font-family: sans-serif; max-width: min(1680px, 100%); width: 100%; box-sizing: border-box; }
|
||||||
.f7support-error { color: #b00020; min-height: 1.25em; margin: 8px 0; }
|
.f7support-error { color: #b00020; min-height: 1.25em; margin: 8px 0; }
|
||||||
.f7support-main { margin-top: 12px; }
|
.f7support-main { margin-top: 12px; width: 100%; }
|
||||||
.f7-board {
|
.f7-board {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(300px, 1fr));
|
||||||
gap: 12px;
|
gap: 16px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 1100px) {
|
||||||
.f7-board { grid-template-columns: 1fr; }
|
.f7-board { grid-template-columns: 1fr; }
|
||||||
}
|
}
|
||||||
.f7-column {
|
.f7-column {
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
padding: 10px;
|
padding: 12px;
|
||||||
min-height: 200px;
|
min-height: min(52vh, 560px);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -339,8 +356,8 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 160px;
|
min-height: min(42vh, 420px);
|
||||||
max-height: min(56vh, 520px);
|
max-height: min(72vh, 820px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.f7-ticket-card {
|
.f7-ticket-card {
|
||||||
@@ -645,6 +662,8 @@
|
|||||||
const createModal = document.getElementById("create-ticket-modal");
|
const createModal = document.getElementById("create-ticket-modal");
|
||||||
const chatModal = document.getElementById("chat-modal");
|
const chatModal = document.getElementById("chat-modal");
|
||||||
|
|
||||||
|
let clientChatDndBound = false;
|
||||||
|
|
||||||
bindClientChatDnDOnce();
|
bindClientChatDnDOnce();
|
||||||
|
|
||||||
function showError(message) {
|
function showError(message) {
|
||||||
@@ -682,7 +701,6 @@
|
|||||||
updatePendingFileUi();
|
updatePendingFileUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
let clientChatDndBound = false;
|
|
||||||
function bindClientChatDnDOnce() {
|
function bindClientChatDnDOnce() {
|
||||||
if (clientChatDndBound) return;
|
if (clientChatDndBound) return;
|
||||||
clientChatDndBound = true;
|
clientChatDndBound = true;
|
||||||
|
|||||||
@@ -6,20 +6,22 @@ namespace OCA\F7Support\Controller;
|
|||||||
|
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
|
use OCP\IConfig;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use OCP\IURLGenerator;
|
use OCP\IURLGenerator;
|
||||||
use OCP\IUserSession;
|
use OCP\IUserSession;
|
||||||
use OCP\Util;
|
use OCP\Util;
|
||||||
|
|
||||||
class PageController extends Controller {
|
class PageController extends Controller {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
string $AppName,
|
string $AppName,
|
||||||
IRequest $request,
|
IRequest $request,
|
||||||
private IUserSession $userSession,
|
private IUserSession $userSession,
|
||||||
private IURLGenerator $urlGenerator
|
private IURLGenerator $urlGenerator,
|
||||||
) {
|
private IConfig $config,
|
||||||
parent::__construct($AppName, $request);
|
) {
|
||||||
}
|
parent::__construct($AppName, $request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
@@ -30,19 +32,23 @@ class PageController extends Controller {
|
|||||||
$baseUrl = $this->urlGenerator->getBaseUrl();
|
$baseUrl = $this->urlGenerator->getBaseUrl();
|
||||||
$serverHost = parse_url($baseUrl, PHP_URL_HOST) ?: 'localhost';
|
$serverHost = parse_url($baseUrl, PHP_URL_HOST) ?: 'localhost';
|
||||||
|
|
||||||
$supportApiBase = 'https://support.f7cloud.ru';
|
$supportApiBase = 'https://support.f7cloud.ru';
|
||||||
$supportParts = parse_url($supportApiBase);
|
$supportParts = parse_url($supportApiBase);
|
||||||
$supportApiOrigin = ($supportParts['scheme'] ?? 'https') . '://' . ($supportParts['host'] ?? '');
|
$supportApiOrigin = ($supportParts['scheme'] ?? 'https') . '://' . ($supportParts['host'] ?? '');
|
||||||
|
|
||||||
Util::addStyle('f7support', 'f7support');
|
// Optional full WebSocket URL prefix, e.g. wss://support.f7cloud.ru/api/ws (path before /tickets/{id})
|
||||||
Util::addScript('f7support', 'main');
|
$supportWsBase = $this->config->getAppValue('f7support', 'support_ws_base', '');
|
||||||
|
|
||||||
return new TemplateResponse('f7support', 'main', [
|
Util::addStyle('f7support', 'f7support');
|
||||||
'username' => $user ? $user->getUID() : '',
|
Util::addScript('f7support', 'main');
|
||||||
'serverAddress' => $serverHost,
|
|
||||||
'supportApiBase' => $supportApiBase,
|
return new TemplateResponse('f7support', 'main', [
|
||||||
'supportApiOrigin' => $supportApiOrigin,
|
'username' => $user ? $user->getUID() : '',
|
||||||
]);
|
'serverAddress' => $serverHost,
|
||||||
|
'supportApiBase' => $supportApiBase,
|
||||||
|
'supportApiOrigin' => $supportApiOrigin,
|
||||||
|
'supportWsBase' => $supportWsBase,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
data-username="<?php p($_['username']); ?>"
|
data-username="<?php p($_['username']); ?>"
|
||||||
data-server-address="<?php p($_['serverAddress']); ?>"
|
data-server-address="<?php p($_['serverAddress']); ?>"
|
||||||
data-support-api-base="<?php p($_['supportApiBase']); ?>"
|
data-support-api-base="<?php p($_['supportApiBase']); ?>"
|
||||||
|
data-support-ws-base="<?php p($_['supportWsBase'] ?? ''); ?>"
|
||||||
data-messages-poll-ms="5000">
|
data-messages-poll-ms="5000">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user