Просмотр исходного кода

Merge branch 'feature/tickets' into develop

ideas
Charly 3 лет назад
Родитель
Сommit
3daa16f8a3
19 измененных файлов: 529 добавлений и 109 удалений
  1. +78
    -76
      Controller/AbstractAdminController.php
  2. +95
    -8
      Controller/Ticket/TicketAdminController.php
  3. +41
    -0
      Factory/Ticket/TicketFactory.php
  4. +23
    -0
      Factory/Ticket/TicketMessageFactory.php
  5. +96
    -0
      Form/Ticket/TicketFormType.php
  6. +6
    -18
      Form/Ticket/TicketMessageType.php
  7. +27
    -2
      Model/Ticket/TicketModel.php
  8. +3
    -1
      Resources/assets/app/adminlte/index/index.scss
  9. +4
    -0
      Resources/config/routes.yaml
  10. +10
    -2
      Resources/translations/admin.fr.yaml
  11. +83
    -0
      Resources/views/admin/ticket/detail.html.twig
  12. +1
    -0
      Resources/views/admin/ticket/index_email.html.twig
  13. +7
    -0
      Resources/views/admin/ticket/index_lastmessage.html.twig
  14. +10
    -0
      Resources/views/admin/ticket/index_status.html.twig
  15. +1
    -0
      Resources/views/admin/ticket/index_username.html.twig
  16. +19
    -0
      Resources/views/admin/ticket/new.html.twig
  17. +8
    -0
      Resources/views/adminlte/embed/infobox.html.twig
  18. +15
    -0
      Resources/views/adminlte/macro/badge.html.twig
  19. +2
    -2
      Resources/views/adminlte/macro/infobox.html.twig

+ 78
- 76
Controller/AbstractAdminController.php Просмотреть файл

@@ -50,22 +50,14 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;

abstract class AbstractAdminController extends EaAbstractCrudController
{
protected $session;
protected $request;
protected $em;
protected $translatorAdmin;

public function __construct(
SessionInterface $session,
RequestStack $request,
EntityManagerInterface $em,
TranslatorAdmin $translatorAdmin
)
public static function getSubscribedServices()
{
$this->session = $session;
$this->request = $request;
$this->em = $em;
$this->translatorAdmin = $translatorAdmin;
return array_merge(parent::getSubscribedServices(), [
'session' => SessionInterface::class,
'request' => RequestStack::class,
'em' => EntityManagerInterface::class,
'translator_admin' => TranslatorAdmin::class,
]);
}

public function configureActions(Actions $actions): Actions
@@ -87,7 +79,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController
$actionsArray[Crud::PAGE_INDEX] = [
Action::NEW => [
'icon' => 'plus',
'label' => $this->translatorAdmin->transAction('create'),
'label' => $this->get('translator_admin')->transAction('create'),
'add_class' => 'btn-sm'
],
Action::EDIT => [
@@ -96,43 +88,51 @@ abstract class AbstractAdminController extends EaAbstractCrudController
'label' => false,
'html_attributes' => array(
'data-toggle' => 'tooltip',
'title' => $this->translatorAdmin->transAction('edit')
'title' => $this->get('translator_admin')->transAction('edit')
)
],
Action::DETAIL => [
'icon' => 'eye',
'add_class' => 'btn btn-sm btn-success',
'label' => false,
'html_attributes' => array(
'data-toggle' => 'tooltip',
'title' => $this->get('translator_admin')->transAction('detail')
)
],
Action::DELETE => [
'icon' => 'trash',
'dropdown' => true,
'label' => $this->translatorAdmin->transAction('delete')
'label' => $this->get('translator_admin')->transAction('delete')
],
Action::BATCH_DELETE => [
'class' => 'btn btn-sm btn-danger',
'icon' => 'trash',
'label' => $this->translatorAdmin->transAction('delete')
'label' => $this->get('translator_admin')->transAction('delete')
],
];

/* Boutons des actions dans l'édition */

$actionSaveAndReturn = [
'add_class' => 'float-right',
'icon' => 'check',
'label' => $this->translatorAdmin->transAction('save_and_return')
'label' => $this->get('translator_admin')->transAction('save_and_return')
];
$actionIndex = [
'icon' => 'chevron-left',
'class' => 'btn btn-link',
'label' => $this->translatorAdmin->transAction('back_index')
'label' => $this->get('translator_admin')->transAction('back_index')
];

$actionsArray[Crud::PAGE_EDIT] = [
Action::SAVE_AND_CONTINUE => [
'class' => 'btn btn-info float-right',
'label' => $this->translatorAdmin->transAction('save_and_continue')
'label' => $this->get('translator_admin')->transAction('save_and_continue')
],
Action::DELETE => [
'icon' => 'trash',
'class' => 'btn btn-outline-danger action-delete',
'label' => $this->translatorAdmin->transAction('delete')
'label' => $this->get('translator_admin')->transAction('delete')
],
Action::SAVE_AND_RETURN => $actionSaveAndReturn,
Action::INDEX => $actionIndex,
@@ -141,7 +141,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController
$actionsArray[Crud::PAGE_NEW] = [
Action::SAVE_AND_ADD_ANOTHER => [
'class' => 'btn btn-info float-right',
'label' => $this->translatorAdmin->transAction('save_and_add_another')
'label' => $this->get('translator_admin')->transAction('save_and_add_another')
],
Action::SAVE_AND_RETURN => $actionSaveAndReturn,
Action::INDEX => $actionIndex,
@@ -152,7 +152,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController
$actions->add(Crud::PAGE_NEW, Action::INDEX);

if ($this->isInstanceOf(SortableInterface::class)) {
$sortAction = Action::new('sort', $this->translatorAdmin->transAction('sort'), 'fa fa-sort')
$sortAction = Action::new('sort', $this->get('translator_admin')->transAction('sort'), 'fa fa-sort')
->linkToCrudAction('sort')
->setCssClass('btn btn-sm btn-success')
->createAsGlobalAction();
@@ -164,7 +164,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController
if ($this->isInstanceOf(TreeInterface::class)) {
$indexChildAction = Action::new(
'index_children',
$this->translatorAdmin->transAction('index_children'),
$this->get('translator_admin')->transAction('index_children'),
'fa fa-list'
)
->linkToCrudAction(Action::INDEX)
@@ -175,7 +175,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController

$backParentAction = Action::new(
'index_parent',
$this->translatorAdmin->transAction('index_parent'),
$this->get('translator_admin')->transAction('index_parent'),
'fa fa-chevron-left'
)
->linkToCrudAction(Action::INDEX)
@@ -192,37 +192,40 @@ abstract class AbstractAdminController extends EaAbstractCrudController

foreach ($actionsArray as $crudActionName => $actionsStyle) {
foreach ($actionsStyle as $actionName => $button) {
$actions->update(
$crudActionName,
$actionName,
function (Action $action) use ($button) {
if (isset($button['add_class'])) {
$action->addCssClass($button['add_class']);
}

if (isset($button['class'])) {
$action->setCssClass($button['class']);
}

if (isset($button['icon'])) {
$action->setIcon('fa fa-' . $button['icon']);
// si l'action existe
if ($actions->getAsDto('actions')->getAction($crudActionName, $actionName)) {
$actions->update(
$crudActionName,
$actionName,
function (Action $action) use ($button) {
if (isset($button['add_class'])) {
$action->addCssClass($button['add_class']);
}

if (isset($button['class'])) {
$action->setCssClass($button['class']);
}

if (isset($button['icon'])) {
$action->setIcon('fa fa-' . $button['icon']);
}

if (isset($button['label'])) {
$action->setLabel($button['label']);
}

if (isset($button['dropdown']) && $button['dropdown']) {
$action->addCssClass('in-dropdown');
}

if (isset($button['html_attributes']) && $button['html_attributes']) {
$action->setHtmlAttributes($button['html_attributes']);
}

return $action;
}

if (isset($button['label'])) {
$action->setLabel($button['label']);
}

if (isset($button['dropdown']) && $button['dropdown']) {
$action->addCssClass('in-dropdown');
}

if (isset($button['html_attributes']) && $button['html_attributes']) {
$action->setHtmlAttributes($button['html_attributes']);
}

return $action;
}
);
);
}
}
}

@@ -254,12 +257,12 @@ abstract class AbstractAdminController extends EaAbstractCrudController
$entityClass = $this->getEntityFqcn();
$paramListMaxResults = 'listMaxResults';
$paramSessionListMaxResults = $entityClass . '-' . $paramListMaxResults;
$requestListMaxResults = $this->request->getCurrentRequest()->get($paramListMaxResults);
$requestListMaxResults = $this->get('request')->getCurrentRequest()->get($paramListMaxResults);

if ($requestListMaxResults) {
$this->session->set($paramSessionListMaxResults, $requestListMaxResults);
$this->get('session')->set($paramSessionListMaxResults, $requestListMaxResults);
}
$maxResults = $this->session->get($paramSessionListMaxResults) ? $this->session->get(
$maxResults = $this->get('session')->get($paramSessionListMaxResults) ? $this->get('session')->get(
$paramSessionListMaxResults
) : 30;

@@ -390,16 +393,16 @@ abstract class AbstractAdminController extends EaAbstractCrudController
}

public function createIndexQueryBuilder(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): QueryBuilder {
$queryBuilder = parent::createIndexQueryBuilder(
$searchDto,
$entityDto,
$fields,
$filters
$searchDto,
$entityDto,
$fields,
$filters
);

if ($this->isInstanceOf(TreeInterface::class)) {
@@ -417,13 +420,12 @@ abstract class AbstractAdminController extends EaAbstractCrudController
}

public function createSortQueryBuilder(
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
SearchDto $searchDto,
EntityDto $entityDto,
FieldCollection $fields,
FilterCollection $filters
): QueryBuilder {

$queryBuilder = $this->createIndexQueryBuilder($searchDto,$entityDto,$fields,$filters);
$queryBuilder = $this->createIndexQueryBuilder($searchDto, $entityDto, $fields, $filters);

return $queryBuilder;
}
@@ -434,7 +436,7 @@ abstract class AbstractAdminController extends EaAbstractCrudController

// on vide le flash bag si édition en ajax (notification déjà affichée en Javascript)
if ($context->getRequest()->isXmlHttpRequest()) {
$this->session->getFlashBag()->clear();
$this->get('session')->getFlashBag()->clear();
}

return $response;

+ 95
- 8
Controller/Ticket/TicketAdminController.php Просмотреть файл

@@ -3,17 +3,44 @@
namespace Lc\SovBundle\Controller\Ticket;

use App\Entity\Ticket\Ticket;
use App\Entity\Ticket\TicketMessage;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityPersistedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeCrudActionEvent;
use EasyCorp\Bundle\EasyAdminBundle\Event\BeforeEntityPersistedEvent;
use EasyCorp\Bundle\EasyAdminBundle\Exception\ForbiddenActionException;
use EasyCorp\Bundle\EasyAdminBundle\Exception\InsufficientEntityPermissionException;
use EasyCorp\Bundle\EasyAdminBundle\Factory\EntityFactory;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
use Lc\SovBundle\Factory\Ticket\TicketFactory;
use Lc\SovBundle\Field\StatusField;
use Lc\SovBundle\Form\Ticket\TicketFormType;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Controller\AbstractAdminController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

abstract class TicketAdminController extends AbstractAdminController
class TicketAdminController extends AbstractAdminController
{
protected $ticketFactory;

public function __construct(TicketFactory $ticketFactory)
{
$this->ticketFactory = $ticketFactory;
}

public static function getEntityFqcn(): string
{
@@ -22,16 +49,23 @@ abstract class TicketAdminController extends AbstractAdminController

public function configureFields(string $pageName): iterable
{

return [
TextField::new('id')->hideOnForm(),
DateField::new('createdAt')->setFormat('short')->hideOnForm(),
TextField::new('visitorFirstName')->hideOnForm(),
TextField::new('visitorLastName')->hideOnForm(),
TextField::new('visitorEmail')->hideOnForm(),
IntegerField::new('id')
->hideOnForm(),
DateField::new('createdAt')->setFormat('short')
->hideOnForm(),
TextField::new('visitorFirstName')
->setTemplatePath('@LcSov/admin/ticket/index_username.html.twig')
->hideOnForm(),
TextField::new('visitorEmail')
->setTemplatePath('@LcSov/admin/ticket/index_email.html.twig')
->hideOnForm(),
AssociationField::new('user')
->hideOnIndex(),
TextField::new('subject'),
TextField::new('lastMessage')
->setTemplatePath('@LcSov/admin/ticket/index_lastmessage.html.twig')
->hideOnForm(),
ChoiceField::new('type')
->autocomplete()
->setChoices(
@@ -40,7 +74,60 @@ abstract class TicketAdminController extends AbstractAdminController
'entity.Ticket.fields.typeOptions.' . Ticket::TYPE_TECHNICAL_PROBLEM => Ticket::TYPE_TECHNICAL_PROBLEM,
]
),
StatusField::new('status')->setRequired(false)->hideOnForm(),
ChoiceField::new('status')
->autocomplete()
->setChoices(
[
'entity.Ticket.fields.statusOptions.' . Ticket::TICKET_STATUS_OPEN => Ticket::TICKET_STATUS_OPEN,
'entity.Ticket.fields.statusOptions.' . Ticket::TICKET_STATUS_BEING_PROCESSED => Ticket::TICKET_STATUS_BEING_PROCESSED,
'entity.Ticket.fields.statusOptions.' . Ticket::TICKET_STATUS_CLOSED => Ticket::TICKET_STATUS_CLOSED,
]
)
->setTemplatePath('@LcSov/admin/ticket/index_status.html.twig')
->hideOnForm(),
];
}

public function configureCrud(Crud $crud): Crud
{
$crud
->overrideTemplate('crud/detail', '@LcSov/admin/ticket/detail.html.twig');

return parent::configureCrud($crud);
}

public function configureActions(Actions $actions): Actions
{
$actions
->add(Crud::PAGE_INDEX, Action::DETAIL)
->remove(Crud::PAGE_INDEX, Action::EDIT);
return parent::configureActions($actions);
}

public function new(AdminContext $context)
{
$ticket = $this->ticketFactory->create();
$form = $this->createForm(TicketFormType::class, $ticket);

$form->handleRequest($context->getRequest());
if ($form->isSubmitted() && $form->isValid()) {
$ticket = $form->getData();

foreach($ticket->getTicketMessages() as $ticketMessage){
$this->get('em')->persist($ticketMessage);
}

$this->get('em')->persist($ticket);
$this->get('em')->flush();

return $this->redirectToRoute('admin_dashboard');
}

return $this->render(
'@LcSov/admin/ticket/new.html.twig',
[
'form' => $form->createView(),
]
);
}
}

+ 41
- 0
Factory/Ticket/TicketFactory.php Просмотреть файл

@@ -0,0 +1,41 @@
<?php

namespace Lc\SovBundle\Factory\Ticket;

use App\Entity\Ticket\Ticket;
use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Ticket\TicketInterface;

class TicketFactory extends AbstractFactory
{
protected $ticketMessageFactory;

public function __construct(EntityManagerInterface $em, TicketMessageFactory $ticketMessageFactory)
{
$this->ticketMessageFactory = $ticketMessageFactory;

parent::__construct($em);
}

public function getEntityClass()
{
return TicketInterface::class;
}

public function create($params = array())
{
if (!isset($params['status'])) {
$params['status'] = Ticket::TICKET_STATUS_OPEN;
}

$ticket = parent::create($params);

if (!isset($params['ticketMessages'])) {
$ticket->addTicketMessage($this->ticketMessageFactory->create());
}

return $ticket;
}

}

+ 23
- 0
Factory/Ticket/TicketMessageFactory.php Просмотреть файл

@@ -0,0 +1,23 @@
<?php

namespace Lc\SovBundle\Factory\Ticket;

use Lc\SovBundle\Factory\AbstractFactory;
use Lc\SovBundle\Model\Ticket\TicketMessageInterface;

class TicketMessageFactory extends AbstractFactory
{
public function getEntityClass()
{
return TicketMessageInterface::class;
}

public function create($params = array())
{
if (!isset($params['status'])) {
$params['status'] = 1;
}

return parent::create($params);
}
}

+ 96
- 0
Form/Ticket/TicketFormType.php Просмотреть файл

@@ -0,0 +1,96 @@
<?php

namespace Lc\SovBundle\Form\Ticket;

use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Model\Ticket\TicketInterface;
use Lc\SovBundle\Model\Ticket\TicketModel;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Translation\TranslatorAdmin;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TicketFormType extends AbstractType
{

protected $em;
protected $translatorAdmin;

public function __construct(EntityManager $em, TranslatorAdmin $translatorAdmin)
{
$this->em = $em;
$this->translatorAdmin = $translatorAdmin;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
$entityName = $this->em->getEntityName(TicketInterface::class);

$builder->add(
'user',
EntityType::class,
[
'class' => $this->em->getEntityName(UserInterface::class),
]
);

$builder->add(
'subject',
TextType::class
);

$builder->add(
'type',
ChoiceType::class,
[
'label' => 'Type',
'choices' => [
$this->translatorAdmin->transField(
'typeOptions.' . TicketModel::TYPE_TECHNICAL_PROBLEM,
$entityName
) => TicketModel::TYPE_TECHNICAL_PROBLEM,
$this->translatorAdmin->transField(
'typeOptions.' . TicketModel::TYPE_GENERAL_QUESTION,
$entityName
) => TicketModel::TYPE_TECHNICAL_PROBLEM,
],
]
);

$builder->add(
'ticketMessages',
CollectionType::class,
[
'entry_type' => TicketMessageType::class,
'allow_add' => false,
]
);

$builder->add(
'submit',
SubmitType::class,
[
'label' => $this->translatorAdmin->transAction('save')
]
);
}

/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => $this->em->getEntityName(TicketInterface::class),
]
);
}
}

+ 6
- 18
Form/Ticket/TicketMessageType.php Просмотреть файл

@@ -2,10 +2,9 @@

namespace Lc\SovBundle\Form\Ticket;

use Doctrine\ORM\EntityManagerInterface;
use Lc\SovBundle\Doctrine\EntityManager;
use Lc\SovBundle\Model\Ticket\TicketMessageInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -14,7 +13,7 @@ class TicketMessageType extends AbstractType
{
protected $em;

public function __construct(EntityManagerInterface $em)
public function __construct(EntityManager $em)
{
$this->em = $em;
}
@@ -24,28 +23,17 @@ class TicketMessageType extends AbstractType
$builder->add(
'message',
TextareaType::class,
array(
[
'required' => true
)
)
->add(
'add',
SubmitType::class,
array(
'label' => 'action.send',
'attr' => array(
'class' => 'btn btn-primary float-right'
)
)
);
]
);
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'data_class' => $this->em->getClassMetadata(TicketMessageInterface::class)->getName(),
'translation_domain' => 'lcshop'
'data_class' => $this->em->getEntityName(TicketMessageInterface::class),
]
);
}

+ 27
- 2
Model/Ticket/TicketModel.php Просмотреть файл

@@ -77,7 +77,7 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac
protected $visitorToken;

/**
* @ORM\OneToMany(targetEntity="Lc\SovBundle\Model\Ticket\TicketMessageInterface", mappedBy="ticket", orphanRemoval=true)
* @ORM\OneToMany(targetEntity="Lc\SovBundle\Model\Ticket\TicketMessageInterface", mappedBy="ticket", orphanRemoval=true, cascade={"persist", "remove"})
* @ORM\OrderBy({"id" = "ASC"})
*/
protected $ticketMessages;
@@ -101,12 +101,37 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac
}
}

public function getUserInfosTicket()
{
$user = $this->getUser();
if ($user) {
return '#' . $user->getId() . ' ' . $user->getName() . ' ' . $user->getEmail();
} else {
return strtoupper($this->getVisitorLastname()) . ' ' . $this->getVisitorFirstname(
) . ' ' . $this->getVisitorEmail();
}
}

public function getEmail()
{
if ($this->getUser()) {
return $this->getUser()->getEmail();
} else {
return $this->getVisitorEmail();
}
}

public function getVisitorInfos()
{
return strtoupper($this->getVisitorLastname()) . ' ' . $this->getVisitorFirstname(
) . ' (' . $this->getVisitorEmail() . ')';
}

public function getLastMessage()
{
return $this->getTicketMessages()->last();
}

public function getType(): ?string
{
return $this->type;
@@ -121,7 +146,7 @@ abstract class TicketModel extends AbstractLightEntity implements TicketInterfac

public function getTypeLabel(): string
{
return 'field.Ticket.typeOptions.' . $this->getType();
return 'entity.Ticket.fields.typeOptions.' . $this->getType();
}

public function getStatus(): ?string

+ 3
- 1
Resources/assets/app/adminlte/index/index.scss Просмотреть файл

@@ -1,6 +1,8 @@

table.table {
.dropdown-actions {
display: inline-block ;
}
.actions {
white-space: nowrap;
}
}

+ 4
- 0
Resources/config/routes.yaml Просмотреть файл

@@ -26,3 +26,7 @@ sov_admin_setting_global:
path: /admin/setting/global
controller: Lc\SovBundle\Controller\Setting\SettingAdminController::manageGlobal

sov_admin_create_ticket:
path: /admin/ticket/create
controller: Lc\SovBundle\Controller\Ticket\TicketAdminController::create


+ 10
- 2
Resources/translations/admin.fr.yaml Просмотреть файл

@@ -27,6 +27,7 @@ action:
sort: Ordonner
delete: Supprimer
change: Changer
detail: Voir
index_children: Afficher les enfants
index_parent: Retour au parent
back_index: Retour à la liste
@@ -51,6 +52,8 @@ entity:
label: Page
label_plurial: Pages
Ticket:
label: Ticket
label_plurial: Tickets
fields:
visitorFirstName: Nom
visitorLastName: Prénom
@@ -60,11 +63,16 @@ entity:
typeOptions:
general-question: Questions générales
technical-problem: Problème technique
lastMessage: Dernier message
statusOptions:
open: Ouvert
being-processed: En attente
closed: Fermé

default:
fields:
id: Id
createdAt: Created at
createdAt: Créé à
user: Utilisateur
firstname: Prénom
lastname: Nom
@@ -73,7 +81,7 @@ entity:
position: Position
description: Description
file: Fichier
status: Statut
status: Status
email: Email
value: Valeur
metaTitle: Meta title

+ 83
- 0
Resources/views/admin/ticket/detail.html.twig Просмотреть файл

@@ -0,0 +1,83 @@
{% extends '@LcSov/adminlte/layout.html.twig' %}
{% import '@LcSov/adminlte/macro/infobox.html.twig' as macro %}

{% block content_title %}
{{ 'detail'|lc_trans_admin_title(ea.getEntity().getFqcn(), {id: ea.getEntity().getInstance().getId()}) }}
{% endblock %}

{% block main %}
{{ dump() }}
<div class="row">
<div class="col-4">
{% embed '@LcSov/adminlte/embed/infobox.html.twig' %}
{% block color %}blue{% endblock %}
{% block icon %}fa fa-toggle-on{% endblock %}
{% block title %}Status{% endblock %}
{% block content %}
{{ entity.instance.status }}
{% endblock %}
{% endembed %}

{% embed '@LcSov/adminlte/embed/infobox.html.twig' %}
{% block color %}blue{% endblock %}
{% block icon %}fa fa-user{% endblock %}
{% block title %}Utilisateur{% endblock %}
{% block content %}
{{ entity.instance.getUserInfosTicket() }}
{% endblock %}
{% endembed %}

{{ macro.infobox('Date',entity.instance.createdAt|date('d/m/Y'), "yellow", "fa fa-calendar") }}
{{ macro.infobox('Catégorie',entity.instance.getTypeLabel()|trans({},'admin'), "green", "fa fa-archive") }}
</div>
<div class="col-8">
{% embed '@LcSov/adminlte/embed/card.html.twig' %}
{% block css %}card-primary{% endblock %}
{% block header %}
<h3 class="card-title">
Liste des messages
</h3>
{% endblock header %}

{% block body_wrapper %}
<div class="card-body row">
<div class="col-12 direct-chat-primary">
{% for message in entity.instance.ticketMessages %}
<div class="direct-chat-msg {{ message.answerByAdmin ? 'right' }}">
<div class="direct-chat-infos clearfix">
<div class="direct-chat-name {{ message.answerByAdmin ? 'float-right' : 'float-left' }}">
{{ message.createdBy }}
</div>
<div class="direct-chat-timestamp {{ message.answerByAdmin ? 'float-left' : 'float-right' }}">
{{ message.createdAt|date('d/m/Y H:i') }}
</div>
</div>
{% if message.answerByAdmin %}
<div class="direct-chat-img align-items-center">
<i class="fa fa-user-circle" style="font-size: 2rem; color: red"></i>
</div>
{% else %}
<div class="direct-chat-img align-items-center">
<i class="fa fa-user-circle" style="font-size: 2rem"></i>
</div>
{% endif %}
<div class="direct-chat-text">
<p>{{ message.message|nl2br }}</p>
{% if message.imageFilename is not null %}
<i>Photo jointe au message : </i> <br/>
<a href="{{ lc_liip(message.imageFilename, 'big') }}"
data-toggle="lightbox">
<img src="{{ lc_liip(message.imageFilename, 'thumb') }}"
alt="Illustration ticket"/>
</a>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
{% endembed %}
</div>
</div>
{% endblock %}

+ 1
- 0
Resources/views/admin/ticket/index_email.html.twig Просмотреть файл

@@ -0,0 +1 @@
{{ entity.instance.getEmail() }}

+ 7
- 0
Resources/views/admin/ticket/index_lastmessage.html.twig Просмотреть файл

@@ -0,0 +1,7 @@
{% set ticketMessage = entity.instance.getLastMessage() %}
{% if ticketMessage.answerByAdmin != true %}
<span class="badge badge-danger">
New
</span>
{% endif %}
{{ ticketMessage.createdAt|date('d/m/Y H:i') }} par {{ ticketMessage.createdBy }} {{ ticketMessage.message }}

+ 10
- 0
Resources/views/admin/ticket/index_status.html.twig Просмотреть файл

@@ -0,0 +1,10 @@
{% import "@LcSov/adminlte/macro/badge.html.twig" as macro %}

{% set status = entity.instance.status %}
{% if status == 'open' %}
{{ macro.badge_success(('entity.Ticket.fields.statusOptions.'~entity.instance.status)|trans({},'admin')) }}
{% elseif status == 'being-processed' %}
{{ macro.badge_warning(('entity.Ticket.fields.statusOptions.'~entity.instance.status)|trans({},'admin')) }}
{% elseif status == 'closed' %}
{{ macro.badge_danger(('entity.Ticket.fields.statusOptions.'~entity.instance.status)|trans({},'admin')) }}
{% endif %}

+ 1
- 0
Resources/views/admin/ticket/index_username.html.twig Просмотреть файл

@@ -0,0 +1 @@
{{ entity.instance.getUsername() }}

+ 19
- 0
Resources/views/admin/ticket/new.html.twig Просмотреть файл

@@ -0,0 +1,19 @@
{% extends '@LcSov/adminlte/layout.html.twig' %}

{% block content_title %}
{# {{ 'ticket.profile'|lc_trans_admin_title }}#}
Créer un ticket
{% endblock %}

{% block main %}
<div class="col-8">
{% embed '@LcSov/adminlte/embed/card.html.twig' %}
{% block header_wrapper %}{% endblock %}
{% block body %}
{% form_theme form '@LcSov/adminlte/crud/form_theme.html.twig' %}
{{ form(form) }}
{% endblock %}
{% block footer_wrapper %}{% endblock %}
{% endembed %}
</div>
{% endblock main %}

+ 8
- 0
Resources/views/adminlte/embed/infobox.html.twig Просмотреть файл

@@ -0,0 +1,8 @@
<div class="info-box">
<!-- Apply any bg-* class to to the icon to color it -->
<span class="info-box-icon bg-{% block color %}{% endblock %}"><i class="{% block icon %}{% endblock %}"></i></span>
<div class="info-box-content">
<span class="info-box-text">{% block title %}{% endblock %}</span>
<span class="info-box-number">{% block content %}{% endblock %}</span>
</div>
</div>

+ 15
- 0
Resources/views/adminlte/macro/badge.html.twig Просмотреть файл

@@ -0,0 +1,15 @@
{% macro badge_success(title) %}
{{ _self.badge('success', title) }}
{% endmacro %}

{% macro badge_warning(title) %}
{{ _self.badge('warning', title) }}
{% endmacro %}

{% macro badge_danger(title) %}
{{ _self.badge('danger', title) }}
{% endmacro %}

{% macro badge(status, title) %}
<span class="badge badge-{{ status }}">{{ title }}</span>
{% endmacro %}

+ 2
- 2
Resources/views/adminlte/macro/infobox.html.twig Просмотреть файл

@@ -1,10 +1,10 @@
{% macro infobox(title, number, color, icon) %}
{% macro infobox(title, content, color, icon) %}
<div class="info-box">
<!-- Apply any bg-* class to to the icon to color it -->
<span class="info-box-icon bg-{{ color }}"><i class="{{ icon }}"></i></span>
<div class="info-box-content">
<span class="info-box-text">{{ title }}</span>
<span class="info-box-number">{{ number }}</span>
<span class="info-box-number">{{ content }}</span>
</div>
<!-- /.info-box-content -->
</div>

Загрузка…
Отмена
Сохранить