mirror of
https://github.com/openvk/openvk
synced 2024-11-11 01:19:53 +03:00
Карточка Агента Поддержки (#717)
This commit is contained in:
parent
882b2e5d39
commit
1eb74bbafd
14 changed files with 272 additions and 7 deletions
39
Web/Models/Entities/SupportAgent.php
Normal file
39
Web/Models/Entities/SupportAgent.php
Normal 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();
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ class TicketComment extends RowModel
|
|||
|
||||
$alias = $this->getSupportAlias();
|
||||
if(!$alias)
|
||||
return OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["supportName"] . " №" . $this->getAgentNumber();
|
||||
return tr("helpdesk_agent") . " #" . $this->getAgentNumber();
|
||||
|
||||
$name = $alias->getName();
|
||||
if($alias->shouldAppendNumber())
|
||||
|
|
32
Web/Models/Repositories/SupportAgents.php
Normal file
32
Web/Models/Repositories/SupportAgents.php
Normal 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));
|
||||
}
|
||||
}
|
|
@ -27,6 +27,13 @@ class TicketComments
|
|||
else
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Entities\{Ticket, TicketComment};
|
||||
use openvk\Web\Models\Repositories\{Tickets, Users, TicketComments};
|
||||
use openvk\Web\Models\Entities\{SupportAgent, Ticket, TicketComment};
|
||||
use openvk\Web\Models\Repositories\{Tickets, Users, TicketComments, SupportAgents};
|
||||
use openvk\Web\Util\Telegram;
|
||||
use Chandler\Session\Session;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
@ -342,4 +342,58 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$user->save();
|
||||
$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", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
{var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
|
||||
<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="/support/tickets" class="link" n:if="$canAccessHelpdesk">Helpdesk
|
||||
<a href="/support/tickets" class="link" n:if="$canAccessHelpdesk">{_helpdesk}
|
||||
{if $helpdeskTicketNotAnsweredCount > 0}
|
||||
(<b>{$helpdeskTicketNotAnsweredCount}</b>)
|
||||
{/if}
|
||||
|
|
92
Web/Presenters/templates/Support/Agent.xml
Normal file
92
Web/Presenters/templates/Support/Agent.xml
Normal 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"> ({$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}
|
|
@ -66,7 +66,7 @@
|
|||
</div>
|
||||
{elseif ($comment->getUType() === 1)}
|
||||
<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)}
|
||||
<a href="{$comment->getUser()->getURL()}">
|
||||
<span class="nobold">
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
<a n:attr="id => ($isNew ? 'act_tab_a' : 'ki')" href="/support?act=new">{_support_new}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
{if $isNew}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
<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>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<a href="/support/agent{$thisUser->getId()}">Мой профиль</a>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{* BEGIN ELEMENTS DESCRIPTION *}
|
||||
|
|
|
@ -31,6 +31,10 @@ routes:
|
|||
handler: "Comment->makeComment"
|
||||
- url: "/support/delete/{num}"
|
||||
handler: "Support->delete"
|
||||
- url: "/support/agent{num}"
|
||||
handler: "Support->agent"
|
||||
- url: "/support/agent{num}/edit"
|
||||
handler: "Support->editAgent"
|
||||
- url: "/language"
|
||||
handler: "About->language"
|
||||
- url: "/language/{text}.js"
|
||||
|
|
15
install/sqls/00032-agent-card.sql
Normal file
15
install/sqls/00032-agent-card.sql
Normal 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;
|
|
@ -1186,8 +1186,18 @@
|
|||
"url_is_banned_title" = "Link to a suspicious site";
|
||||
"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_permission_removed_from_group" = "The permission has been removed from the group";
|
||||
"c_group_removed" = "The group has been deleted.";
|
||||
|
|
|
@ -1244,6 +1244,16 @@
|
|||
"url_is_banned_title" = "Ссылка на подозрительный сайт";
|
||||
"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 */
|
||||
|
||||
"c_user_removed_from_group" = "Пользователь был удалён из группы";
|
||||
|
|
Loading…
Reference in a new issue