mirror of
https://github.com/openvk/openvk
synced 2024-12-23 00:51:03 +03:00
Шаблоны в Поддержке
This commit is contained in:
parent
a2384cc231
commit
541be355e3
14 changed files with 607 additions and 14 deletions
40
Web/Models/Entities/SupportTemplate.php
Normal file
40
Web/Models/Entities/SupportTemplate.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities;
|
||||||
|
use openvk\Web\Models\Repositories\SupportTemplatesDirs;
|
||||||
|
use openvk\Web\Models\Repositories\Users;
|
||||||
|
use openvk\Web\Models\RowModel;
|
||||||
|
|
||||||
|
class SupportTemplate extends RowModel
|
||||||
|
{
|
||||||
|
protected $tableName = "support_templates";
|
||||||
|
|
||||||
|
function getId(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOwner(): ?User
|
||||||
|
{
|
||||||
|
return (new Users)->get($this->getRecord()->owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDir(): ?SupportTemplateDir
|
||||||
|
{
|
||||||
|
return (new SupportTemplatesDirs)->get($this->getRecord()->dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPublic(): bool
|
||||||
|
{
|
||||||
|
return $this->getDir()->isPublic();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getText(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->text;
|
||||||
|
}
|
||||||
|
}
|
40
Web/Models/Entities/SupportTemplateDir.php
Normal file
40
Web/Models/Entities/SupportTemplateDir.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Entities;
|
||||||
|
use openvk\Web\Models\Repositories\SupportTemplates;
|
||||||
|
use openvk\Web\Models\Repositories\Users;
|
||||||
|
use openvk\Web\Models\RowModel;
|
||||||
|
|
||||||
|
class SupportTemplateDir extends RowModel
|
||||||
|
{
|
||||||
|
protected $tableName = "support_templates_dirs";
|
||||||
|
|
||||||
|
function getId(): int
|
||||||
|
{
|
||||||
|
return $this->getRecord()->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOwner(): ?User
|
||||||
|
{
|
||||||
|
return (new Users)->get($this->getRecord()->owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPublic(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->getRecord()->is_public;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getText(): string
|
||||||
|
{
|
||||||
|
return $this->getRecord()->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTemplates(): \Traversable
|
||||||
|
{
|
||||||
|
return (new SupportTemplates)->getListByDirId($this->getId());
|
||||||
|
}
|
||||||
|
}
|
33
Web/Models/Repositories/SupportTemplates.php
Normal file
33
Web/Models/Repositories/SupportTemplates.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use openvk\Web\Models\Entities\{SupportTemplate, SupportAgent};
|
||||||
|
|
||||||
|
class SupportTemplates
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $templates;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DatabaseConnection::i()->getContext();
|
||||||
|
$this->templates = $this->context->table("support_templates");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toTemplate(?ActiveRow $ar): ?SupportTemplate
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : new SupportTemplate($ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?SupportTemplate
|
||||||
|
{
|
||||||
|
return $this->toTemplate($this->templates->get($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListByDirId(int $dir_id): \Traversable
|
||||||
|
{
|
||||||
|
foreach ($this->templates->where(["dir" => $dir_id, "deleted" => 0]) as $template)
|
||||||
|
yield new SupportTemplate($template);
|
||||||
|
}
|
||||||
|
}
|
33
Web/Models/Repositories/SupportTemplatesDirs.php
Normal file
33
Web/Models/Repositories/SupportTemplatesDirs.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace openvk\Web\Models\Repositories;
|
||||||
|
use Nette\Database\Table\ActiveRow;
|
||||||
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
use openvk\Web\Models\Entities\{SupportTemplateDir};
|
||||||
|
|
||||||
|
class SupportTemplatesDirs
|
||||||
|
{
|
||||||
|
private $context;
|
||||||
|
private $dirs;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->context = DatabaseConnection::i()->getContext();
|
||||||
|
$this->dirs = $this->context->table("support_templates_dirs");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toDir(?ActiveRow $ar): ?SupportTemplateDir
|
||||||
|
{
|
||||||
|
return is_null($ar) ? NULL : new SupportTemplateDir($ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(int $id): ?SupportTemplateDir
|
||||||
|
{
|
||||||
|
return $this->toDir($this->dirs->get($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getList(int $uid): \Traversable
|
||||||
|
{
|
||||||
|
foreach ($this->dirs->where("(owner=$uid OR is_public=1) AND deleted=0") as $dir)
|
||||||
|
yield new SupportTemplateDir($dir);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,12 @@
|
||||||
<?php declare(strict_types=1);
|
<?php declare(strict_types=1);
|
||||||
namespace openvk\Web\Presenters;
|
namespace openvk\Web\Presenters;
|
||||||
use openvk\Web\Models\Entities\{SupportAgent, Ticket, TicketComment};
|
use openvk\Web\Models\Entities\{SupportAgent, SupportTemplate, SupportTemplateDir, Ticket, TicketComment};
|
||||||
use openvk\Web\Models\Repositories\{Tickets, Users, TicketComments, SupportAgents};
|
use openvk\Web\Models\Repositories\{SupportTemplates,
|
||||||
|
SupportTemplatesDirs,
|
||||||
|
Tickets,
|
||||||
|
Users,
|
||||||
|
TicketComments,
|
||||||
|
SupportAgents};
|
||||||
use openvk\Web\Util\Telegram;
|
use openvk\Web\Util\Telegram;
|
||||||
use Chandler\Session\Session;
|
use Chandler\Session\Session;
|
||||||
use Chandler\Database\DatabaseConnection;
|
use Chandler\Database\DatabaseConnection;
|
||||||
|
@ -210,7 +215,6 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
$this->template->ticket = $ticket;
|
$this->template->ticket = $ticket;
|
||||||
$this->template->comments = $ticketComments;
|
$this->template->comments = $ticketComments;
|
||||||
$this->template->id = $id;
|
$this->template->id = $id;
|
||||||
$this->template->fastAnswers = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["fastAnswers"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAnswerTicketReply(int $id): void
|
function renderAnswerTicketReply(int $id): void
|
||||||
|
@ -396,4 +400,233 @@ final class SupportPresenter extends OpenVKPresenter
|
||||||
$this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
|
$this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderGetTemplatesDirs(): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
|
||||||
|
$dirs = [];
|
||||||
|
foreach ((new SupportTemplatesDirs)->getList($this->user->identity->getId()) as $dir) {
|
||||||
|
$dirs[] = ["id" => $dir->getId(), "title" => $dir->getTitle()];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->returnJson(["success" => true, "dirs" => $dirs]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderGetTemplatesInDir(int $dirId): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
|
||||||
|
$dir = (new SupportTemplatesDirs)->get($dirId);
|
||||||
|
|
||||||
|
if (!$dir || $dir->getOwner()->getId() !== $this->user->identity->getId() && !$dir->isPublic()) {
|
||||||
|
$this->returnJson(["success" => false, "error" => tr("forbidden")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$templates = [];
|
||||||
|
foreach ($dir->getTemplates() as $template) {
|
||||||
|
$templateData = [
|
||||||
|
"id" => $template->getId(),
|
||||||
|
"title" => $template->getTitle(),
|
||||||
|
"text" => $template->getText(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($this->queryParam("tid")) {
|
||||||
|
$ticket = (new Tickets)->get((int) $this->queryParam("tid"));
|
||||||
|
$ticket_user = $ticket->getUser();
|
||||||
|
$replacements = [
|
||||||
|
"{user_name}" => $ticket_user->getFirstName(),
|
||||||
|
"{last_name}" => $ticket_user->getLastName(),
|
||||||
|
"{unban_time}" => $ticket_user->getUnbanTime(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($ticket->getId()) {
|
||||||
|
foreach ($replacements as $search => $replace) {
|
||||||
|
$templateData["text"] = str_replace($search, $replace, $templateData["text"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$templates[] = $templateData;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->returnJson(["success" => true, "templates" => $templates]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCreateTemplatesDir(): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
$this->assertNoCSRF();
|
||||||
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
|
$dir = new SupportTemplateDir;
|
||||||
|
$dir->setTitle($this->postParam("title"));
|
||||||
|
$dir->setOwner($this->user->identity->getId());
|
||||||
|
$dir->setIs_Public(!empty($this->postParam("is_public")));
|
||||||
|
$dir->save();
|
||||||
|
|
||||||
|
$this->flashFail("succ", tr("changes_saved"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTemplates(): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
|
||||||
|
$mode = in_array($this->queryParam("act"), ["dirs", "list", "create_dir", "create_template", "edit_dir", "edit_template"]) ? $this->queryParam("act") : "dirs";
|
||||||
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
|
$this->assertNoCSRF();
|
||||||
|
|
||||||
|
if ($mode === "create_dir" || $mode === "edit_dir") {
|
||||||
|
$dirId = (int) $this->queryParam("dir");
|
||||||
|
$dir = ($mode === "create_dir") ? new SupportTemplateDir : (new SupportTemplatesDirs)->get($dirId);
|
||||||
|
|
||||||
|
if ($mode === "edit_dir" && (!$dir || $dir->isDeleted())) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === "edit_dir" && $dir->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$dir->setTitle($this->postParam("title"));
|
||||||
|
$dir->setOwner($this->user->identity->getId());
|
||||||
|
$dir->setIs_Public(!empty($this->postParam("is_public")));
|
||||||
|
$dir->save();
|
||||||
|
|
||||||
|
if ($mode === "create_dir") {
|
||||||
|
$this->redirect("/support/templates?act=list&dir=" . $dir->getId());
|
||||||
|
} else {
|
||||||
|
$this->flashFail("succ", tr("changes_saved"));
|
||||||
|
}
|
||||||
|
} else if ($mode === "create_template" || $mode === "edit_template") {
|
||||||
|
$templateId = (int) $this->queryParam("id");
|
||||||
|
$template = ($mode === "create_template") ? new SupportTemplate : (new SupportTemplates)->get($templateId);
|
||||||
|
if (!$template || $template->isDeleted()) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === "edit_template" && $template->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$dirId = ($mode === "create_template") ? (int) $this->queryParam("dir") : $template->getDir()->getId();
|
||||||
|
$dir = (new SupportTemplatesDirs)->get($dirId);
|
||||||
|
|
||||||
|
if ($mode === "create_template" && $dir->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$dir || $dir->isDeleted()) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dir->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$template->setOwner($this->user->identity->getId());
|
||||||
|
$template->setDir($dir->getId());
|
||||||
|
$template->setTitle($this->postParam("title"));
|
||||||
|
$template->setText($this->postParam("text"));
|
||||||
|
$template->save();
|
||||||
|
|
||||||
|
if ($mode === "create_template") {
|
||||||
|
$this->redirect("/support/templates?act=list&dir=" . $dirId . "&id=" . $template->getId());
|
||||||
|
} else {
|
||||||
|
$this->flashFail("succ", tr("changes_saved"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->template->mode = $mode;
|
||||||
|
|
||||||
|
if (!$this->queryParam("dir")) {
|
||||||
|
$dirs = (new SupportTemplatesDirs)->getList($this->user->identity->getId());
|
||||||
|
$this->template->dirs = $dirs;
|
||||||
|
$this->template->dirsCount = count($dirs);
|
||||||
|
|
||||||
|
if ($mode === "edit_template") {
|
||||||
|
$templateId = (int) $this->queryParam("id");
|
||||||
|
$template = (new SupportTemplates)->get($templateId);
|
||||||
|
|
||||||
|
if (!$template || $template->isDeleted()) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($template->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->template->dir = $template->getDir();
|
||||||
|
$this->template->activeTemplate = $template;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$dirId = (int) $this->queryParam("dir");
|
||||||
|
$dir = (new SupportTemplatesDirs)->get($dirId);
|
||||||
|
|
||||||
|
if (!$dir || $dir->isDeleted()) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === "edit_dir" && $dir->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === "create_template" && $dir->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->template->dir = $dir;
|
||||||
|
$templates = $dir->getTemplates();
|
||||||
|
$this->template->templates = $templates;
|
||||||
|
$this->template->templatesCount = count($templates);
|
||||||
|
$this->template->selectedTemplate = (int) $this->queryParam("id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDeleteDir(int $id): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
$dir = (new SupportTemplatesDirs)->get($id);
|
||||||
|
|
||||||
|
if (!$dir || $dir->isDeleted()) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dir->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$templates = $dir->getTemplates();
|
||||||
|
|
||||||
|
foreach ($templates as $template) {
|
||||||
|
$template->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$dir->delete();
|
||||||
|
|
||||||
|
$this->redirect("/support/templates");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDeleteTemplate(int $id): void
|
||||||
|
{
|
||||||
|
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||||
|
$template = (new SupportTemplates)->get($id);
|
||||||
|
|
||||||
|
if (!$template || $template->isDeleted()) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($template->getOwner()->getId() !== $this->user->identity->getId()) {
|
||||||
|
$this->flashFail("err", tr("forbidden"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$dir = $template->getDir()->getId();
|
||||||
|
$template->delete();
|
||||||
|
|
||||||
|
$this->redirect("/support/templates?act=list&dir=$dir");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,8 @@
|
||||||
<option value="0">{_support_status_0}</option>
|
<option value="0">{_support_status_0}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div n:if="!is_null($fastAnswers)" style="float: right;">
|
<div style="float: right;">
|
||||||
<a class="button" href="javascript:showSupportFastAnswerDialog(fastAnswers)">{_fast_answers}</a>
|
<a class="button" href="javascript:getTemplatesDirs({$ticket->getId()}, true)">{_fast_answers}</a>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
</form>
|
</form>
|
||||||
|
@ -123,10 +123,9 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const fastAnswers = [
|
function toggleTemplateTextShow(id) {
|
||||||
{foreach $fastAnswers as $answer}
|
const elem = document.getElementById('template-text-' + id);
|
||||||
{$answer},
|
elem.style.display = (elem.style.display === "none" ? "block" : "none");
|
||||||
{/foreach}
|
}
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
<div class="tab">
|
<div class="tab">
|
||||||
<a href="/support/agent{$thisUser->getId()}">Мой профиль</a>
|
<a href="/support/agent{$thisUser->getId()}">Мой профиль</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab">
|
||||||
|
<a href="/support/templates">{_support_my_templates}</a>
|
||||||
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{* BEGIN ELEMENTS DESCRIPTION *}
|
{* BEGIN ELEMENTS DESCRIPTION *}
|
||||||
|
|
93
Web/Presenters/templates/Support/Templates.xml
Normal file
93
Web/Presenters/templates/Support/Templates.xml
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
{extends "../@layout.xml"}
|
||||||
|
|
||||||
|
{block header}
|
||||||
|
<div n:if="$mode === 'dirs'">{_support_my_templates}</div>
|
||||||
|
<div n:if="$mode === 'list'"><a href="/support/templates">{_support_my_templates}</a> > {$dir->getTitle()}</div>
|
||||||
|
<div n:if="$mode === 'create_dir'"><a href="/support/templates">{_support_my_templates}</a> > {_support_create_templates_dir}</div>
|
||||||
|
<div n:if="$mode === 'create_template'">
|
||||||
|
<a href="/support/templates">{_support_my_templates}</a>
|
||||||
|
> <a href="/support/templates?act=list&dir={$dir->getId()}">{$dir->getTitle()}</a>
|
||||||
|
> {_support_create_template}
|
||||||
|
</div>
|
||||||
|
<div n:if="$mode === 'edit_dir'">
|
||||||
|
<a href="/support/templates">{_support_my_templates}</a>
|
||||||
|
> <a href="/support/templates?act=list&dir={$dir->getId()}">{$dir->getTitle()}</a>
|
||||||
|
> {_edit}
|
||||||
|
</div>
|
||||||
|
<div n:if="$mode === 'edit_template'">
|
||||||
|
<a href="/support/templates">{_support_my_templates}</a>
|
||||||
|
> <a href="/support/templates?act=list&dir={$dir->getId()}">{$dir->getTitle()}</a>
|
||||||
|
> <a href="/support/templates?act=list&dir={$dir->getId()}&id={$activeTemplate->getId()}">{$activeTemplate->getTitle()}</a>
|
||||||
|
> {_edit}
|
||||||
|
</div>
|
||||||
|
{/block}
|
||||||
|
|
||||||
|
{block content}
|
||||||
|
<div n:if="$mode === 'dirs'">
|
||||||
|
<div>
|
||||||
|
<a class="button" href="/support/templates?act=create_dir">{_support_create_templates_dir}</a>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<div n:if="$dirsCount <= 0" style="padding: 32px">
|
||||||
|
<center>{_no_data_description}</center>
|
||||||
|
</div>
|
||||||
|
<div n:foreach="$dirs as $dir">
|
||||||
|
<a href="/support/templates?act=list&dir={$dir->getId()}">
|
||||||
|
<h4 style="padding: 8px;">
|
||||||
|
{$dir->getTitle()}
|
||||||
|
<a n:if="$dir->getOwner()->getId() === $thisUser->getId()" href="/support/templates?act=edit_dir&dir={$dir->getId()}">({_edit})</a>
|
||||||
|
</h4>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div n:if="$mode === 'list'">
|
||||||
|
<div n:if="$dir->getOwner()->getId() === $thisUser->getId()">
|
||||||
|
<a class="button" href="/support/templates?act=create_template&dir={$dir->getId()}">{_support_create_template}</a>
|
||||||
|
<a class="button" href="/support/templates_dir{$dir->getId()}/delete">{_support_remove_templates_dir_1} <b>{_support_remove_templates_dir_2}</b></a>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<div n:if="$templatesCount <= 0" style="padding: 32px">
|
||||||
|
<center>{_no_data_description}</center>
|
||||||
|
</div>
|
||||||
|
<div n:foreach="$templates as $template">
|
||||||
|
<h4 style="padding: 8px; cursor: pointer;" onclick="toggleTemplateTextShow({$template->getId()})">
|
||||||
|
{$template->getTitle()}
|
||||||
|
<a n:if="$template->getOwner()->getId() === $thisUser->getId()" href="/support/templates?act=edit_template&id={$template->getId()}">({_edit})</a>
|
||||||
|
</h4>
|
||||||
|
<div id="template-text-{$template->getId()}" style="display: none; padding: 8px; white-space: pre-wrap;">{$template->getText()}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div n:if="$mode === 'create_dir' || $mode === 'edit_dir'">
|
||||||
|
<form method="post">
|
||||||
|
<input type="text" placeholder="{_support_templates_dir_name}" name="title" n:attr="value => $mode === 'edit_dir' ? $dir->getTitle() : ''" />
|
||||||
|
<input type="checkbox" value="1" name="is_public" n:attr="checked => $mode === 'edit_dir' ? $dir->isPublic() : false"/> {_support_public_templates_dir}
|
||||||
|
<input type="hidden" value="{$csrfToken}" name="hash"/>
|
||||||
|
<input type="submit" n:attr="value => ($mode === 'create_dir' ? tr(create) : tr(save))" class="button" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div n:if="$mode === 'create_template' || $mode === 'edit_template'">
|
||||||
|
<form method="post">
|
||||||
|
<input n:attr="value => $mode === 'edit_template' ? $activeTemplate->getTitle() : ''" type="text" placeholder="{_support_template_name}" name="title"/>
|
||||||
|
<textarea style="resize: vertical;" name="text" placeholder="{_support_template_text}">{$mode === 'edit_template' ? $activeTemplate->getText() : ''}</textarea>
|
||||||
|
<ul>
|
||||||
|
<li><b>{="{user_name}"}</b> — {_support_template_replacement_user_name}</li>
|
||||||
|
<li><b>{="{last_name}"}</b> — {_support_template_replacement_last_name}</li>
|
||||||
|
<li><b>{="{unban_time}"}</b> — {_support_template_replacement_unban_time}</li>
|
||||||
|
</ul>
|
||||||
|
<input type="hidden" value="{$csrfToken}" name="hash"/>
|
||||||
|
<input type="submit" n:attr="value => ($mode === 'create_template' ? tr(create) : tr(save))" class="button" />
|
||||||
|
<a n:if="$mode === 'edit_template'" class="button" href="/support/template{$activeTemplate->getId()}/delete">{_delete}</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function toggleTemplateTextShow(id, scrollTo) {
|
||||||
|
if (!scrollTo) scrollTo = false;
|
||||||
|
|
||||||
|
const elem = document.getElementById('template-text-' + id);
|
||||||
|
elem.style.display = (elem.style.display === 'none' ? 'inherit' : 'none');
|
||||||
|
if (scrollTo) elem.scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTemplateTextShow({$selectedTemplate}, true)
|
||||||
|
</script>
|
||||||
|
{/block}
|
|
@ -35,6 +35,18 @@ routes:
|
||||||
handler: "Support->agent"
|
handler: "Support->agent"
|
||||||
- url: "/support/agent{num}/edit"
|
- url: "/support/agent{num}/edit"
|
||||||
handler: "Support->editAgent"
|
handler: "Support->editAgent"
|
||||||
|
- url: "/al_helpdesk/get_templates_dirs"
|
||||||
|
handler: "Support->getTemplatesDirs"
|
||||||
|
- url: "/al_helpdesk/td{num}/templates"
|
||||||
|
handler: "Support->getTemplatesInDir"
|
||||||
|
- url: "/al_helpdesk/create_templates_dir"
|
||||||
|
handler: "Support->createTemplatesDir"
|
||||||
|
- url: "/support/templates"
|
||||||
|
handler: "Support->templates"
|
||||||
|
- url: "/support/templates_dir{num}/delete"
|
||||||
|
handler: "Support->deleteDir"
|
||||||
|
- url: "/support/template{num}/delete"
|
||||||
|
handler: "Support->deleteTemplate"
|
||||||
- url: "/language"
|
- url: "/language"
|
||||||
handler: "About->language"
|
handler: "About->language"
|
||||||
- url: "/language/{text}.js"
|
- url: "/language/{text}.js"
|
||||||
|
|
|
@ -344,6 +344,57 @@ function supportFastAnswerDialogOnClick(answer) {
|
||||||
answerInput.focus();
|
answerInput.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTemplatesDirs(tid) {
|
||||||
|
$.ajax("/al_helpdesk/get_templates_dirs").done((response) => {
|
||||||
|
console.log(response, response.success);
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
const dirsHtml = response.dirs.length > 0 ? response.dirs.map((dir) => `
|
||||||
|
<li style="cursor: pointer;" onclick="getTemplatesInDir(${dir.id}, ${tid})">
|
||||||
|
<h4 style="padding: 8px;">${dir.title}</h4>
|
||||||
|
</li>
|
||||||
|
`).join("") : `<center>${tr("no_data_description")}</center>`;
|
||||||
|
|
||||||
|
const managementLink = `<a href="/support/templates" target="_blank" class="button">${tr("edit")}</a>`;
|
||||||
|
if (document.getElementsByClassName('ovk-diag-body').length === 0) {
|
||||||
|
MessageBox(tr("fast_answers"), `${managementLink}<ul style="padding-inline-start: 8px; overflow-y: auto; max-height: 70vh;">${dirsHtml}</ul>`, [tr("close")], [
|
||||||
|
Function.noop
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
document.getElementsByClassName('ovk-diag-body')[0].innerHTML = `${managementLink}<ul style="padding-inline-start: 8px; overflow-y: auto; max-height: 70vh;">${dirsHtml}</ul>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTemplatesInDir(dir, ticket) {
|
||||||
|
$.ajax(`/al_helpdesk/td${dir}/templates?tid=${ticket}`).done((response) => {
|
||||||
|
console.log(response, response.success);
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
let html = "";
|
||||||
|
|
||||||
|
response.templates.forEach((template) => {
|
||||||
|
html += '\
|
||||||
|
<li onclick="toggleTemplateTextShow(' + template.id + ')" style="cursor: pointer;" onclick="toggleTemplateTextShow(' + template.id + ')">\
|
||||||
|
<h4 style="padding: 8px;">' + template.title + '</h4>\
|
||||||
|
<div id="template-text-' + template.id +'" style="color: #000; white-space: pre-wrap; display: none;">\
|
||||||
|
' + template.text + '\
|
||||||
|
<br/><br/><button class="button" onclick="document.getElementById(`answer_text`).value=`' + template.text.replaceAll("\"", """) + '`">' + tr("support_apply_template") + '</button>\
|
||||||
|
</div>\
|
||||||
|
</li>';
|
||||||
|
});
|
||||||
|
|
||||||
|
const templatesListHtml = response.templates.length > 0
|
||||||
|
? `<a href="javascript:getTemplatesDirs(${ticket}, false)">< ${tr("paginator_back")}</a><ul style="padding-inline-start: 8px; overflow-y: auto; max-height: 70vh;">${html}</ul>`
|
||||||
|
: `<center>${tr("no_data_description")}</center>`;
|
||||||
|
|
||||||
|
document.getElementsByClassName("ovk-diag-body")[0].innerHTML = templatesListHtml;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function ovk_proc_strtr(string, length = 0) {
|
function ovk_proc_strtr(string, length = 0) {
|
||||||
const newString = string.substring(0, length);
|
const newString = string.substring(0, length);
|
||||||
return newString + (string !== newString ? "…" : "");
|
return newString + (string !== newString ? "…" : "");
|
||||||
|
|
33
install/sqls/00038-support-templates.sql
Normal file
33
install/sqls/00038-support-templates.sql
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
CREATE TABLE `support_templates_dirs`
|
||||||
|
(
|
||||||
|
`id` bigint(20) UNSIGNED NOT NULL,
|
||||||
|
`owner` bigint(20) UNSIGNED NOT NULL,
|
||||||
|
`is_public` tinyint(1) NOT NULL DEFAULT 0,
|
||||||
|
`title` tinytext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`deleted` tinyint(1) NOT NULL DEFAULT 0
|
||||||
|
) ENGINE = InnoDB
|
||||||
|
DEFAULT CHARSET = utf8mb4;
|
||||||
|
|
||||||
|
ALTER TABLE `support_templates_dirs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
ALTER TABLE `support_templates_dirs`
|
||||||
|
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
CREATE TABLE `support_templates`
|
||||||
|
(
|
||||||
|
`id` bigint(20) UNSIGNED NOT NULL,
|
||||||
|
`owner` bigint(20) UNSIGNED NOT NULL,
|
||||||
|
`dir` bigint(20) UNSIGNED NOT NULL,
|
||||||
|
`title` tinytext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`text` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`deleted` tinyint(1) NOT NULL DEFAULT 0
|
||||||
|
) ENGINE = InnoDB
|
||||||
|
DEFAULT CHARSET = utf8mb4;
|
||||||
|
|
||||||
|
ALTER TABLE `support_templates`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
ALTER TABLE `support_templates`
|
||||||
|
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT;
|
|
@ -913,6 +913,20 @@
|
||||||
"banned_in_support_1" = "Sorry, <b>$1</b>, but now you can't create tickets.";
|
"banned_in_support_1" = "Sorry, <b>$1</b>, but now you can't create tickets.";
|
||||||
"banned_in_support_2" = "And the reason for this is simple: <b>$1</b>. Unfortunately, this time we had to take away this opportunity from you forever.";
|
"banned_in_support_2" = "And the reason for this is simple: <b>$1</b>. Unfortunately, this time we had to take away this opportunity from you forever.";
|
||||||
|
|
||||||
|
"support_my_templates" = "My templates";
|
||||||
|
"support_create_templates_dir" = "Create folder";
|
||||||
|
"support_create_template" = "Create template";
|
||||||
|
"support_public_templates_dir" = "Other agents can use";
|
||||||
|
"support_remove_templates_dir_1" = "Delete folder";
|
||||||
|
"support_remove_templates_dir_2" = "with templates";
|
||||||
|
"support_templates_dir_name" = "Folder name";
|
||||||
|
"support_template_replacement_user_name" = "User's first name";
|
||||||
|
"support_template_replacement_last_name" = "User's last name";
|
||||||
|
"support_template_replacement_unban_time" = "User's unban time";
|
||||||
|
"support_template_text" = "Template Text";
|
||||||
|
"support_template_name" = "Template Name";
|
||||||
|
"support_apply_template" = "Use";
|
||||||
|
|
||||||
/* Invite */
|
/* Invite */
|
||||||
|
|
||||||
"invite" = "Invite";
|
"invite" = "Invite";
|
||||||
|
|
|
@ -841,6 +841,19 @@
|
||||||
"ticket_changed_comment" = "Изменения вступят силу через несколько секунд.";
|
"ticket_changed_comment" = "Изменения вступят силу через несколько секунд.";
|
||||||
"banned_in_support_1" = "Извините, <b>$1</b>, но теперь вам нельзя создавать обращения.";
|
"banned_in_support_1" = "Извините, <b>$1</b>, но теперь вам нельзя создавать обращения.";
|
||||||
"banned_in_support_2" = "А причина этому проста: <b>$1</b>. К сожалению, на этот раз нам пришлось отобрать у вас эту возможность навсегда.";
|
"banned_in_support_2" = "А причина этому проста: <b>$1</b>. К сожалению, на этот раз нам пришлось отобрать у вас эту возможность навсегда.";
|
||||||
|
"support_my_templates" = "Мои шаблоны";
|
||||||
|
"support_create_templates_dir" = "Создать папку";
|
||||||
|
"support_create_template" = "Создать шаблон";
|
||||||
|
"support_public_templates_dir" = "Видят другие агенты";
|
||||||
|
"support_remove_templates_dir_1" = "Удалить папку";
|
||||||
|
"support_remove_templates_dir_2" = "вместе с шаблонами";
|
||||||
|
"support_templates_dir_name" = "Название папки с шаблонами";
|
||||||
|
"support_template_replacement_user_name" = "Имя пользователя";
|
||||||
|
"support_template_replacement_last_name" = "Фамилия пользователя";
|
||||||
|
"support_template_replacement_unban_time" = "Время разблокировки";
|
||||||
|
"support_template_text" = "Текст шаблона";
|
||||||
|
"support_template_name" = "Название шаблона";
|
||||||
|
"support_apply_template" = "Применить";
|
||||||
|
|
||||||
/* Invite */
|
/* Invite */
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,6 @@ openvk:
|
||||||
support:
|
support:
|
||||||
supportName: "Agent"
|
supportName: "Agent"
|
||||||
adminAccount: 1 # Change this ok
|
adminAccount: 1 # Change this ok
|
||||||
fastAnswers:
|
|
||||||
- "This is a list of quick answers to common questions for support. Post your responses here and agents can send it quickly with just 3 clicks"
|
|
||||||
- "There can be as many answers as you want, but it is best to have a maximum of 10.\n\nYou can also remove all answers from the list to disable this feature"
|
|
||||||
- "Good luck filling! If you are a regular support agent, inform the administrator that he forgot to fill the config"
|
|
||||||
messages:
|
messages:
|
||||||
strict: false
|
strict: false
|
||||||
wall:
|
wall:
|
||||||
|
|
Loading…
Reference in a new issue