Карточка Агента Поддержки (#717)

This commit is contained in:
n1rwana 2022-11-08 00:36:07 +03:00 committed by GitHub
parent 882b2e5d39
commit 1eb74bbafd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 272 additions and 7 deletions

View file

@ -0,0 +1,39 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use openvk\Web\Models\Repositories\Users;
use openvk\Web\Models\RowModel;
class SupportAgent extends RowModel
{
protected $tableName = "support_names";
function getAgentId(): int
{
return $this->getRecord()->agent;
}
function getName(): ?string
{
return $this->getRecord()->name;
}
function getCanonicalName(): string
{
return $this->getName();
}
function getAvatarURL(): ?string
{
return $this->getRecord()->icon;
}
function isShowNumber(): int
{
return $this->getRecord()->numerate;
}
function getRealName(): string
{
return (new Users)->get($this->getAgentId())->getCanonicalName();
}
}

View file

@ -42,7 +42,7 @@ class TicketComment extends RowModel
$alias = $this->getSupportAlias(); $alias = $this->getSupportAlias();
if(!$alias) if(!$alias)
return OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["supportName"] . "" . $this->getAgentNumber(); return tr("helpdesk_agent") . " #" . $this->getAgentNumber();
$name = $alias->getName(); $name = $alias->getName();
if($alias->shouldAppendNumber()) if($alias->shouldAppendNumber())

View file

@ -0,0 +1,32 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
use openvk\Web\Models\Entities\{User, SupportAgent};
class SupportAgents
{
private $context;
private $tickets;
function __construct()
{
$this->context = DatabaseConnection::i()->getContext();
$this->agents = $this->context->table("support_names");
}
private function toAgent(?ActiveRow $ar)
{
return is_null($ar) ? NULL : new SupportAgent($ar);
}
function get(int $id): ?SupportAgent
{
return $this->toAgent($this->agents->where("agent", $id)->fetch());
}
function isExists(int $id): bool
{
return !is_null($this->get($id));
}
}

View file

@ -27,6 +27,13 @@ class TicketComments
else else
return NULL; return NULL;
} }
function getCountByAgent(int $agent_id, int $mark = NULL): int
{
$filter = ['user_id' => $agent_id, 'user_type' => 1];
$mark && $filter['mark'] = $mark;
return sizeof($this->comments->where($filter));
}
use \Nette\SmartObject; use \Nette\SmartObject;
} }

View file

@ -1,7 +1,7 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Presenters; namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{Ticket, TicketComment}; use openvk\Web\Models\Entities\{SupportAgent, Ticket, TicketComment};
use openvk\Web\Models\Repositories\{Tickets, Users, TicketComments}; use openvk\Web\Models\Repositories\{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;
@ -342,4 +342,58 @@ final class SupportPresenter extends OpenVKPresenter
$user->save(); $user->save();
$this->returnJson([ "success" => true ]); $this->returnJson([ "success" => true ]);
} }
function renderAgent(int $id): void
{
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
$support_names = new SupportAgents;
if(!$support_names->isExists($id))
$this->template->mode = "edit";
$this->template->agent_id = $id;
$this->template->mode = in_array($this->queryParam("act"), ["info", "edit"]) ? $this->queryParam("act") : "info";
$this->template->agent = $support_names->get($id) ?? NULL;
$this->template->counters = [
"all" => (new TicketComments)->getCountByAgent($id),
"good" => (new TicketComments)->getCountByAgent($id, 1),
"bad" => (new TicketComments)->getCountByAgent($id, 2)
];
if($id != $this->user->identity->getId())
if ($support_names->isExists($id))
$this->template->mode = "info";
else
$this->redirect("/support/agent" . $this->user->identity->getId());
}
function renderEditAgent(int $id): void
{
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
$this->assertNoCSRF();
$support_names = new SupportAgents;
$agent = $support_names->get($id);
if($agent)
if($agent->getAgentId() != $this->user->identity->getId()) $this->flashFail("err", tr("error"), tr("forbidden"));
if ($support_names->isExists($id)) {
$agent = $support_names->get($id);
$agent->setName($this->postParam("name") ?? tr("helpdesk_agent"));
$agent->setNumerate((int) $this->postParam("number") ?? NULL);
$agent->setIcon($this->postParam("avatar"));
$agent->save();
$this->flashFail("succ", "Успех", "Профиль отредактирован.");
} else {
$agent = new SupportAgent;
$agent->setAgent($this->user->identity->getId());
$agent->setName($this->postParam("name") ?? tr("helpdesk_agent"));
$agent->setNumerate((int) $this->postParam("number") ?? NULL);
$agent->setIcon($this->postParam("avatar"));
$agent->save();
$this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
}
}
} }

View file

@ -138,7 +138,7 @@
{var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')} {var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
<div n:if="$canAccessAdminPanel || $canAccessHelpdesk || $menuLinksAvaiable" class="menu_divider"></div> <div n:if="$canAccessAdminPanel || $canAccessHelpdesk || $menuLinksAvaiable" class="menu_divider"></div>
<a href="/admin" class="link" n:if="$canAccessAdminPanel" title="{_admin} [Alt+Shift+A]" accesskey="a">{_admin}</a> <a href="/admin" class="link" n:if="$canAccessAdminPanel" title="{_admin} [Alt+Shift+A]" accesskey="a">{_admin}</a>
<a href="/support/tickets" class="link" n:if="$canAccessHelpdesk">Helpdesk <a href="/support/tickets" class="link" n:if="$canAccessHelpdesk">{_helpdesk}
{if $helpdeskTicketNotAnsweredCount > 0} {if $helpdeskTicketNotAnsweredCount > 0}
(<b>{$helpdeskTicketNotAnsweredCount}</b>) (<b>{$helpdeskTicketNotAnsweredCount}</b>)
{/if} {/if}

View file

@ -0,0 +1,92 @@
{extends "../@layout.xml"}
{block header}
{_helpdesk_agent_card}
{/block}
{block content}
{var $isInfo = $mode === "info"}
{var $isEdit = $mode === "edit"}
{if $agent != NULL}
<div class="left_small_block">
<img src="{$agent->getAvatarURL()}" style="width:100%;" />
<div class="profile_links">
<div n:if="$agent_id == $thisUser->getId()" id="profile_link" style="width: 194px;">
<a href="?act=edit" class="link">{_edit_page}</a>
</div>
</div>
</div>
<div class="right_big_block">
<div class="page_info">
<div class="accountInfo clearFix">
<a href="/id{$agent->getAgentId()}">
<div class="profileName" style="display: flex;">
<h2>{$agent->getCanonicalName()}</h2>
<span class="nobold">&nbsp; ({$agent->getRealName()})</span>
</div>
</a>
</div>
<div style="display: flex; justify-content: space-between; padding: 10px; font-size: 12px;">
<div style="text-align: center;">
<div>
<b style="color: green;">{$counters["good"]}</b>
</div>
<div>{_helpdesk_positive_answers}</div>
</div>
<div style="text-align: center;">
<div>
<b style="color: red;">{$counters["bad"]}</b>
</div>
<div>{_helpdesk_negative_answers}</div>
</div>
<div style="text-align: center;">
<div>
<b>{$counters["all"]}</b>
</div>
<div>{_helpdesk_all_answers}</div>
</div>
</div>
{if $isEdit}
<h4>{_edit}</h4>
<br/>
<form method="post" action="/support/agent{$agent_id}/edit">
<label for="name">{_helpdesk_showing_name}</label>
<input name="name" type="text" value="{$agent->getCanonicalName()}" placeholder="{_helpdesk_agent} #777" />
<br/><br/>
<label for="number">{_helpdesk_show_number}?</label>
{$agent->isShowNumber()}
<select name="number">
<option value="1" n:attr="selected => $agent->isShowNumber() === 1 ? true : false">{_yes}</option>
<option value="0" n:attr="selected => $agent->isShowNumber() === 0 ? true : false">{_no}</option>
</select>
<br/><br/>
<label for="number">{_avatar}</label>
<input name="avatar" type="text" value="{$agent->getAvatarURL()}" placeholder="{_helpdesk_avatar_url}" />
<input type="hidden" value="{$csrfToken}" name="hash" />
<br/><br/>
<input type="submit" class="button" value="{_save}" />
</form>
{/if}
</div>
</div>
{else}
<h4>Создать</h4>
<br/>
<form method="post" action="/support/agent{$agent_id}/edit">
<label for="name">{_helpdesk_showing_name}</label>
<input name="name" type="text" placeholder="{_helpdesk_agent} #777" />
<br/><br/>
<label for="number">{_helpdesk_show_number}?</span></label>
<select name="number">
<option value="1">{_yes}</option>
<option value="0">{_no}</option>
</select>
<br/><br/>
<label for="number">{_avatar}</label>
<input name="avatar" type="text" placeholder="{_helpdesk_avatar_url}" />
<input type="hidden" value="{$csrfToken}" name="hash" />
<input type="submit" class="button" value="{_save}" />
</form>
{/if}
{/block}

View file

@ -66,7 +66,7 @@
</div> </div>
{elseif ($comment->getUType() === 1)} {elseif ($comment->getUType() === 1)}
<div class="post-author"> <div class="post-author">
<a><b>{$comment->getAuthorName()}</b></a> <a n:attr="href => $thisUser->getChandlerUser()->can('write')->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0) ? '/support/agent' . $comment->getUser()->getId() : ''"><b>{$comment->getAuthorName()}</b></a>
{if $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)} {if $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)}
<a href="{$comment->getUser()->getURL()}"> <a href="{$comment->getUser()->getURL()}">
<span class="nobold"> <span class="nobold">

View file

@ -22,7 +22,6 @@
<a n:attr="id => ($isNew ? 'act_tab_a' : 'ki')" href="/support?act=new">{_support_new}</a> <a n:attr="id => ($isNew ? 'act_tab_a' : 'ki')" href="/support?act=new">{_support_new}</a>
</div> </div>
</div> </div>
<br /> <br />
{if $isNew} {if $isNew}

View file

@ -18,6 +18,9 @@
<div n:attr="id => ($act === 'closed' ? 'activetabs' : 'ki')" class="tab"> <div n:attr="id => ($act === 'closed' ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($act === 'closed' ? 'act_tab_a' : 'ki')" href="?act=closed">{_support_closed}</a> <a n:attr="id => ($act === 'closed' ? 'act_tab_a' : 'ki')" href="?act=closed">{_support_closed}</a>
</div> </div>
<div class="tab">
<a href="/support/agent{$thisUser->getId()}">Мой профиль</a>
</div>
{/block} {/block}
{* BEGIN ELEMENTS DESCRIPTION *} {* BEGIN ELEMENTS DESCRIPTION *}

View file

@ -31,6 +31,10 @@ routes:
handler: "Comment->makeComment" handler: "Comment->makeComment"
- url: "/support/delete/{num}" - url: "/support/delete/{num}"
handler: "Support->delete" handler: "Support->delete"
- url: "/support/agent{num}"
handler: "Support->agent"
- url: "/support/agent{num}/edit"
handler: "Support->editAgent"
- url: "/language" - url: "/language"
handler: "About->language" handler: "About->language"
- url: "/language/{text}.js" - url: "/language/{text}.js"

View file

@ -0,0 +1,15 @@
CREATE TABLE `support_names` (
`id` bigint(20) UNSIGNED NOT NULL,
`agent` bigint(20) UNSIGNED NOT NULL,
`name` varchar(512) COLLATE utf8mb4_unicode_ci NOT NULL,
`icon` varchar(1024) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`numerate` tinyint(1) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `support_names`
ADD PRIMARY KEY (`id`);
ALTER TABLE `support_names`
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

View file

@ -1186,8 +1186,18 @@
"url_is_banned_title" = "Link to a suspicious site"; "url_is_banned_title" = "Link to a suspicious site";
"url_is_banned_proceed" = "Follow the link"; "url_is_banned_proceed" = "Follow the link";
/* Chandler */ /* Helpdesk */
"helpdesk" = "Support";
"helpdesk_agent" = "Support Agent";
"helpdesk_agent_card" = "Agent Card";
"helpdesk_positive_answers" = "positive answers";
"helpdesk_negative_answers" = "negative answers";
"helpdesk_all_answers" = "all answers";
"helpdesk_showing_name" = "Display name";
"helpdesk_show_number" = "Show the number";
"helpdesk_avatar_url" = "Link to the avatar";
/* Chandler */
"c_user_removed_from_group" = "The user has been removed from the group"; "c_user_removed_from_group" = "The user has been removed from the group";
"c_permission_removed_from_group" = "The permission has been removed from the group"; "c_permission_removed_from_group" = "The permission has been removed from the group";
"c_group_removed" = "The group has been deleted."; "c_group_removed" = "The group has been deleted.";

View file

@ -1244,6 +1244,16 @@
"url_is_banned_title" = "Ссылка на подозрительный сайт"; "url_is_banned_title" = "Ссылка на подозрительный сайт";
"url_is_banned_proceed" = "Перейти по ссылке"; "url_is_banned_proceed" = "Перейти по ссылке";
/* Helpdesk */
"helpdesk" = "Поддержка";
"helpdesk_agent" = "Агент Поддержки";
"helpdesk_agent_card" = "Карточка агента";
"helpdesk_positive_answers" = "положительных ответов";
"helpdesk_negative_answers" = "отрицательных ответов";
"helpdesk_all_answers" = "всего ответов";
"helpdesk_showing_name" = "Отображаемое имя";
"helpdesk_show_number" = "Показывать номер";
"helpdesk_avatar_url" = "Ссылка на аватарку";
/* Chandler */ /* Chandler */
"c_user_removed_from_group" = "Пользователь был удалён из группы"; "c_user_removed_from_group" = "Пользователь был удалён из группы";