diff --git a/actions.php b/actions.php index 5dadf67e6..734066ef3 100644 --- a/actions.php +++ b/actions.php @@ -3,6 +3,8 @@ include_once __DIR__.'/core.php'; use Models\Note; +use Models\Checklist; +use Models\User; if (empty($structure) || empty($structure['enabled'])) { die(tr('Accesso negato')); @@ -105,8 +107,8 @@ elseif (filter('op') == 'add_nota') { flash()->info(tr('Nota interna aggiunta correttamente!')); } -// Aggiunta nota interna -elseif (filter('op') == 'remove_nota') { +// Rimozione nota interna +elseif (filter('op') == 'delete_nota') { $id_nota = post('id_nota'); $nota = Note::find($id_nota); @@ -115,6 +117,39 @@ elseif (filter('op') == 'remove_nota') { flash()->info(tr('Nota interna aggiunta correttamente!')); } +// Rimozione checklist +elseif (filter('op') == 'add_check') { + $content = post('content'); + $parent_id = post('parent') ?: null; + + $assigned_user = User::find(post('assigned_user')); + + $check = Checklist::build($user, $assigned_user, $structure, $id_record, $content, $parent_id); +} + +// Rimozione checklist +elseif (filter('op') == 'delete_check') { + $check_id = post('check_id'); + $check = Checklist::find($check_id); + + $check->delete(); +} + +// Gestione check per le checklist +elseif (filter('op') == 'toggle_check') { + $check_id = post('check_id'); + $check = Checklist::find($check_id); + + if (!empty($check)) { + $check->checked_at = $check->checked_at ? null : date('Y-m-d H:i:s'); + $check->save(); + + echo json_encode([ + 'checked_at' => timestampFormat($check->checked_at) ?: null, + ]); + } +} + // Invio email elseif (post('op') == 'send-email') { $id_template = post('template'); diff --git a/ajax.php b/ajax.php index 29e4a42ba..00402a238 100644 --- a/ajax.php +++ b/ajax.php @@ -54,6 +54,11 @@ switch (get('op')) { break; + case 'checklists': + echo '{( "name": "checklists", "id_module": "'.$id_module.'", "id_record": "'.$id_record.'", "id_plugin": "'.$id_plugin.'" )}'; + + break; + case 'active_users': $posizione = get('id_module'); if (isset($id_record)) { diff --git a/assets/src/css/style.css b/assets/src/css/style.css index 19ba34325..6024921be 100644 --- a/assets/src/css/style.css +++ b/assets/src/css/style.css @@ -826,7 +826,7 @@ input.small-width { margin-bottom: 5px; } -.skin-default .nav.navbar-nav li a{ +.skin-default .nav.navbar-nav li a{ color: #FFFFFF; } .skin-default .nav.navbar-nav li a:hover{ @@ -845,8 +845,48 @@ input.small-width { hyphens: auto; } - .request .morelink{ color: #fff; font-weight: bold; } + +/* Checklist */ +ul.checklist { + list-style-type: none; + margin: 0; + padding: 0; +} + +ul.checklist li { + cursor: pointer; + position: relative; + padding: 12px 8px 12px 10px; + font-size: 18px; + transition: 0.2s; + + /* make the list items unselectable */ + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +ul.checklist li:hover { + background: #ddd; +} + +ul.checklist li.checked { + background: #eee; +} + +ul.checklist li.checked > .check-text { + text-decoration: line-through; +} + +ul.checklist li > .check-icon { + display: none; +} + +ul.checklist li.checked > .check-icon { + display: inline-block; +} diff --git a/assets/src/js/supersearch.js b/assets/src/js/supersearch.js new file mode 100644 index 000000000..6622b9232 --- /dev/null +++ b/assets/src/js/supersearch.js @@ -0,0 +1,86 @@ +$(document).ready(function () { + $('#supersearch').keyup(function () { + $(document).ajaxStop(); + + if ($(this).val() == '') { + $(this).removeClass('wait'); + } else { + $(this).addClass('wait'); + } + }); + + $.widget("custom.supersearch", $.ui.autocomplete, { + _create: function () { + this._super(); + this.widget().menu("option", "items", "> :not(.ui-autocomplete-category)"); + }, + _renderMenu: function (ul, items) { + if (items[0].value == undefined) { + $('#supersearch').removeClass('wait'); + ul.html(''); + } else { + var that = this, + currentCategory = ""; + + ul.addClass('ui-autocomplete-scrollable'); + ul.css('z-index', '999'); + + $.each(items, function (index, item) { + + if (item.category != currentCategory) { + ul.append("
  • " + item.category + "
  • "); + currentCategory = item.category; + } + + that._renderItemData(ul, item); + }); + } + }, + _renderItem: function (ul, item) { + return $("
  • ") + .append("" + item.value + "
    " + item.label + "
    ") + .appendTo(ul); + } + }); + + // Configurazione supersearch + var $super = $('#supersearch').supersearch({ + minLength: 3, + select: function (event, ui) { + location.href = ui.item.link; + }, + source: function (request, response) { + $.ajax({ + url: globals.rootdir + '/ajax_search.php', + dataType: "json", + data: { + term: request.term + }, + + complete: function (jqXHR) { + $('#supersearch').removeClass('wait'); + }, + + success: function (data) { + if (data == null) { + response($.map(['a'], function (item) { + return false; + })); + } else { + response($.map(data, function (item) { + labels = (item.labels).toString(); + labels = labels.replace('
    ,', '
    '); + + return { + label: labels, + category: item.category, + link: item.link, + value: item.title + } + })); + } + } + }); + } + }); +}); diff --git a/editor.php b/editor.php index 2450d85e1..58a43a23a 100755 --- a/editor.php +++ b/editor.php @@ -333,7 +333,7 @@ if (empty($record) || !$has_access) { if ($user->is_admin || $utente->id == $user->id) { echo ' - '; } diff --git a/lib/functions.js b/lib/functions.js index 3ad4f2ba3..0b4e38adf 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -280,7 +280,7 @@ $(document).ready(function () { removeHash(); } }); - + // Nel caso la navigazione sia da mobile, disabilito il ritorno al punto precedente if (!isMobile.any()) { // Salvo lo scroll per riportare qui l'utente al reload @@ -1034,6 +1034,7 @@ function start_datepickers() { }); }); } + // Select function start_superselect() { // Statico @@ -1790,3 +1791,14 @@ function removeHash() { function replaceAll(str, find, replace) { return str.replace(new RegExp(find, "g"), replace); } + +function restart_input() { + start_datepickers(); + start_inputmask(); + + $('.superselect, .superselectajax').select2().select2("destroy"); + start_superselect(); + + // Autosize per le textarea + autosize($('.autosize')); +} diff --git a/lib/init.js b/lib/init.js index 25f5d4620..5f401bfa4 100644 --- a/lib/init.js +++ b/lib/init.js @@ -23,9 +23,6 @@ $(document).ready(function () { }); }); - // Autosize per le textarea - autosize($('.autosize')); - if ($('form').length) { $('form').not('.no-check').parsley(); } @@ -34,8 +31,6 @@ $(document).ready(function () { this.$element.removeClass('parsley-success'); }); - start_datepickers(); - // Aggiunta nell'URL del nome tab su cui tornare dopo il submit // Blocco del pulsante di submit dopo il primo submit $("form").submit(function () { @@ -65,6 +60,5 @@ $(document).ready(function () { return false; }); - start_superselect(); - start_inputmask(); + restart_input(); }); diff --git a/modules/interventi/edit.php b/modules/interventi/edit.php index 27f44f63b..415b8a6b1 100644 --- a/modules/interventi/edit.php +++ b/modules/interventi/edit.php @@ -94,7 +94,7 @@ $_SESSION['superselect']['idsede_destinazione'] = $record['idsede_destinazione']
    {[ "type": "timestamp", "label": "", "name": "data_richiesta", "required": 1, "value": "$data_richiesta$", "readonly": "" ]}
    - +
    {[ "type": "timestamp", "label": "", "name": "data_scadenza", "required": 0, "value": "$data_scadenza$", "readonly": "" ]}
    @@ -286,6 +286,8 @@ include $structure->filepath('ajax_righe.php'); +{( "name": "checklists", "id_module": "$id_module$", "id_record": "$id_record$" )} + {( "name": "filelist_and_upload", "id_module": "$id_module$", "id_record": "$id_record$", )} @@ -355,15 +357,15 @@ include $structure->filepath('ajax_righe.php'); //session_set('superselect,idzona', $(this).selectData().idzona, 0); } }); - + $('#codice_cig, #codice_cup').bind("keyup change", function(e) { - + if ($('#codice_cig').val() == '' && $('#codice_cup').val() == '' ){ $('#id_documento_fe').prop('required', false); }else{ $('#id_documento_fe').prop('required', true); } - + }); diff --git a/modules/utenti/ajax/select.php b/modules/utenti/ajax/select.php index 767995528..077fc0cb8 100644 --- a/modules/utenti/ajax/select.php +++ b/modules/utenti/ajax/select.php @@ -4,7 +4,7 @@ include_once __DIR__.'/../../../core.php'; switch ($resource) { case 'anagrafiche_utenti': - $query = 'SELECT `an_anagrafiche`.`idanagrafica` AS id, `an_anagrafiche`.`ragione_sociale` AS "descrizione", `an_tipianagrafiche`.`descrizione` AS optgroup FROM `an_tipianagrafiche` INNER JOIN `an_tipianagrafiche_anagrafiche` ON `an_tipianagrafiche`.`idtipoanagrafica`=`an_tipianagrafiche_anagrafiche`.`idtipoanagrafica` INNER JOIN `an_anagrafiche` ON `an_anagrafiche`.`idanagrafica`=`an_tipianagrafiche_anagrafiche`.`idanagrafica` |where| ORDER BY `optgroup` ASC'; + $query = 'SELECT `an_anagrafiche`.`idanagrafica` AS id, `an_anagrafiche`.`ragione_sociale` AS descrizione, `an_tipianagrafiche`.`descrizione` AS optgroup FROM `an_tipianagrafiche` INNER JOIN `an_tipianagrafiche_anagrafiche` ON `an_tipianagrafiche`.`idtipoanagrafica`=`an_tipianagrafiche_anagrafiche`.`idtipoanagrafica` INNER JOIN `an_anagrafiche` ON `an_anagrafiche`.`idanagrafica`=`an_tipianagrafiche_anagrafiche`.`idanagrafica` |where| ORDER BY `optgroup` ASC'; $where[] = 'an_anagrafiche.deleted_at IS NULL'; @@ -44,5 +44,54 @@ switch ($resource) { ]; } + break; + + case 'utenti': + $query = "SELECT zz_users.id AS id, if(`an_anagrafiche`.`idanagrafica` IS NOT NULL, CONCAT(`an_anagrafiche`.`ragione_sociale`, ' (', zz_users.username, ')'), zz_users.username) AS descrizione, `an_tipianagrafiche`.`descrizione` AS optgroup + FROM zz_users + LEFT JOIN `an_anagrafiche` ON `an_anagrafiche`.`idanagrafica` = `zz_users`.`idanagrafica` + INNER JOIN `an_tipianagrafiche_anagrafiche` ON `an_anagrafiche`.`idanagrafica`=`an_tipianagrafiche_anagrafiche`.`idanagrafica` + INNER JOIN `an_tipianagrafiche` ON `an_tipianagrafiche`.`idtipoanagrafica`=`an_tipianagrafiche_anagrafiche`.`idtipoanagrafica` + |where| ORDER BY `optgroup` ASC"; + + $where[] = 'an_anagrafiche.deleted_at IS NULL'; + + foreach ($elements as $element) { + $filter[] = 'zz_users.id='.prepare($element); + } + + if (!empty($search)) { + $search_fields[] = 'an_anagrafiche.ragione_sociale LIKE '.prepare('%'.$search.'%'); + $search_fields[] = 'zz_users.username LIKE '.prepare('%'.$search.'%'); + } + + if (!empty($search_fields)) { + $where[] = '('.implode(' OR ', $search_fields).')'; + } + + if (!empty($filter)) { + $where[] = '('.implode(' OR ', $filter).')'; + } + + $wh = ''; + if (count($where) != 0) { + $wh = 'WHERE '.implode(' AND ', $where); + } + $query = str_replace('|where|', $wh, $query); + + $rs = $dbo->fetchArray($query); + foreach ($rs as $r) { + if ($prev != $r['optgroup']) { + $results[] = ['text' => $r['optgroup'], 'children' => []]; + $prev = $r['optgroup']; + } + + $results[count($results) - 1]['children'][] = [ + 'id' => $r['id'], + 'text' => $r['descrizione'], + 'descrizione' => $r['descrizione'], + ]; + } + break; } diff --git a/src/HTMLBuilder/HTMLBuilder.php b/src/HTMLBuilder/HTMLBuilder.php index 275a2e197..4dc19ccb8 100644 --- a/src/HTMLBuilder/HTMLBuilder.php +++ b/src/HTMLBuilder/HTMLBuilder.php @@ -75,6 +75,7 @@ class HTMLBuilder protected static $managers = [ 'list' => [ 'filelist_and_upload' => Manager\FileManager::class, + 'checklists' => Manager\ChecklistManager::class, 'button' => Manager\ButtonManager::class, 'csrf' => Manager\CSRFManager::class, 'custom_fields' => Manager\FieldManager::class, diff --git a/src/HTMLBuilder/Manager/ChecklistManager.php b/src/HTMLBuilder/Manager/ChecklistManager.php new file mode 100644 index 000000000..a84d0a54c --- /dev/null +++ b/src/HTMLBuilder/Manager/ChecklistManager.php @@ -0,0 +1,263 @@ +checklists($options['id_record']); + + $list = []; + foreach ($checklists as $checklist) { + $list [] = [ + 'id' => $checklist->id, + 'text' => $checklist->content, + ]; + } + + $result = ' +
    +
    +

    '.tr('Checklist').'

    +
    +
    +
    + '.tr('Caricamento...').' +
    '; + + // Form per la creazione di una nuova checklist + if (!$options['readonly']) { + $result .= ' +
    +
    + {[ "type": "text", "placeholder": "'.tr('Contenuto').'", "name": "content", "class": "unblockable", "required": 1 ]} +
    + +
    + {[ "type": "select", "placeholder": "'.tr('Genitore').'", "name": "parent", "class": "unblockable", "values": '.json_encode($list).' ]} +
    + +
    + {[ "type": "select", "placeholder": "'.tr('Utente').'", "name": "assigned_user", "class": "unblockable", "ajax-source": "utenti", "required": 1 ]} +
    + +
    + +
    +
    +
    '; + } + + $result .= ' +
      '; + + foreach ($checklists as $checklist) { + $result .= $this->renderChecklist($checklist); + } + + $result .= ' +
    +
    +
    '; + + $result .= ' + + +'; + + return $result; + } + + protected function renderChecklist(Checklist $checklist, $level = 0) + { + $result = ' +
  • + '.str_repeat(' ', $level * 8).' + + + '.$checklist->content.' + +
    + '.timestampFormat($checklist->checked_at).' + +
    +
  • + '; + + return $result; + } +} diff --git a/src/HTMLBuilder/Manager/FileManager.php b/src/HTMLBuilder/Manager/FileManager.php index be2f50dfb..9332d5d5b 100644 --- a/src/HTMLBuilder/Manager/FileManager.php +++ b/src/HTMLBuilder/Manager/FileManager.php @@ -241,7 +241,6 @@ function show_'.$attachment_id.'() { } function reload_'.$attachment_id.'() { - $("#'.$attachment_id.'").load(globals.rootdir + "/ajax.php?op=list_attachments&id_module='.$options['id_module'].'&id_record='.$options['id_record'].'&id_plugin='.$options['id_plugin'].'", function() { $("#loading_'.$attachment_id.'").addClass("hide"); }); diff --git a/src/Models/Checklist.php b/src/Models/Checklist.php new file mode 100644 index 000000000..f56bdf594 --- /dev/null +++ b/src/Models/Checklist.php @@ -0,0 +1,71 @@ +user()->associate($user); + $model->assignedUser()->associate($assigned_user); + + if ($structure instanceof Module) { + $model->module()->associate($structure); + } elseif ($structure instanceof Plugin) { + $model->plugin()->associate($structure); + } + + $model->id_record = $id_record; + $model->id_parent = $id_parent; + $model->content = $contenuto; + + $model->save(); + + return $model; + } + + /* Relazioni Eloquent */ + + public function user() + { + return $this->belongsTo(User::class, 'id_utente'); + } + + public function assignedUser() + { + return $this->belongsTo(User::class, 'id_utente_assegnato'); + } + + public function plugin() + { + return $this->belongsTo(Plugin::class, 'id_plugin'); + } + + public function module() + { + return $this->belongsTo(Module::class, 'id_module'); + } +} diff --git a/src/Models/Module.php b/src/Models/Module.php index 0a2f108c5..9379e9a2d 100644 --- a/src/Models/Module.php +++ b/src/Models/Module.php @@ -5,10 +5,11 @@ namespace Models; use Auth; use Common\Model; use Illuminate\Database\Eloquent\Builder; +use Traits\Components\ChecklistTrait; +use Traits\Components\NoteTrait; +use Traits\Components\UploadTrait; use Traits\ManagerTrait; -use Traits\NoteTrait; use Traits\StoreTrait; -use Traits\UploadTrait; class Module extends Model { @@ -16,11 +17,11 @@ class Module extends Model use UploadTrait; use StoreTrait; use NoteTrait; + use ChecklistTrait; protected $table = 'zz_modules'; protected $main_folder = 'modules'; - protected $upload_identifier = 'id_module'; - protected $note_identifier = 'id_module'; + protected $component_identifier = 'id_module'; protected $variables = []; diff --git a/src/Models/Plugin.php b/src/Models/Plugin.php index 7315ff2e4..63723f0cd 100644 --- a/src/Models/Plugin.php +++ b/src/Models/Plugin.php @@ -5,10 +5,11 @@ namespace Models; use App; use Common\Model; use Illuminate\Database\Eloquent\Builder; +use Traits\Components\ChecklistTrait; +use Traits\Components\NoteTrait; +use Traits\Components\UploadTrait; use Traits\ManagerTrait; -use Traits\NoteTrait; use Traits\StoreTrait; -use Traits\UploadTrait; class Plugin extends Model { @@ -18,11 +19,11 @@ class Plugin extends Model getUploadDirectoryAttribute as protected defaultUploadDirectory; } use NoteTrait; + use ChecklistTrait; protected $table = 'zz_plugins'; protected $main_folder = 'plugins'; - protected $upload_identifier = 'id_plugin'; - protected $note_identifier = 'id_plugin'; + protected $component_identifier = 'id_plugin'; protected $appends = [ 'permission', diff --git a/src/Traits/Components/ChecklistTrait.php b/src/Traits/Components/ChecklistTrait.php new file mode 100644 index 000000000..b3490261d --- /dev/null +++ b/src/Traits/Components/ChecklistTrait.php @@ -0,0 +1,13 @@ +hasMany(Checklist::class, $this->component_identifier)->where('id_record', $id_record)->whereNull('id_parent')->orderBy('created_at')->get(); + } +} diff --git a/src/Traits/Components/NoteTrait.php b/src/Traits/Components/NoteTrait.php new file mode 100644 index 000000000..d3951a04a --- /dev/null +++ b/src/Traits/Components/NoteTrait.php @@ -0,0 +1,13 @@ +hasMany(Note::class, $this->component_identifier)->where('id_record', $id_record)->orderBy('created_at')->get(); + } +} diff --git a/src/Traits/UploadTrait.php b/src/Traits/Components/UploadTrait.php similarity index 77% rename from src/Traits/UploadTrait.php rename to src/Traits/Components/UploadTrait.php index 65934a303..8738122f4 100644 --- a/src/Traits/UploadTrait.php +++ b/src/Traits/Components/UploadTrait.php @@ -1,6 +1,6 @@ hasMany(Upload::class, $this->upload_identifier)->where('id_record', $id_record)->get(); + return $this->hasMany(Upload::class, $this->component_identifier)->where('id_record', $id_record)->get(); } } diff --git a/src/Traits/HierarchyTrait.php b/src/Traits/HierarchyTrait.php new file mode 100644 index 000000000..ef786bea0 --- /dev/null +++ b/src/Traits/HierarchyTrait.php @@ -0,0 +1,33 @@ +hasMany(self::class, self::$parent_identifier); + } + + public function parent() + { + return $this->belongsTo(self::class, self::$parent_identifier); + } + + public function allParents() + { + return $this->parent()->with('allParents'); + } + + public function allChildren() + { + return $this->children()->with('allChildren'); + } + + public static function getHierarchy() + { + return self::with('allChildren') + ->whereNull(self::$parent_identifier) + ->get(); + } +} diff --git a/src/Traits/NoteTrait.php b/src/Traits/NoteTrait.php deleted file mode 100644 index 786df5fe6..000000000 --- a/src/Traits/NoteTrait.php +++ /dev/null @@ -1,13 +0,0 @@ -hasMany(Note::class, $this->note_identifier)->where('id_record', $id_record)->orderBy('created_at')->get(); - } -} diff --git a/update/2_4_11.sql b/update/2_4_11.sql index 9a777e188..e25a46323 100644 --- a/update/2_4_11.sql +++ b/update/2_4_11.sql @@ -203,3 +203,35 @@ CREATE TABLE IF NOT EXISTS `zz_notes` ( FOREIGN KEY (`id_plugin`) REFERENCES `zz_plugins`(`id`) ON DELETE CASCADE, FOREIGN KEY (`id_utente`) REFERENCES `zz_users`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB; + +-- Sistema di checklists +CREATE TABLE IF NOT EXISTS `zz_checklists` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `id_module` int(11), + `id_plugin` int(11), + `id_record` int(11) NOT NULL, + `id_utente` int(11) NOT NULL, + `id_utente_assegnato` int(11) NOT NULL, + `checked_at` TIMESTAMP, + `content` TEXT, + `id_parent` int(11), + PRIMARY KEY (`id`), + FOREIGN KEY (`id_module`) REFERENCES `zz_modules`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`id_plugin`) REFERENCES `zz_plugins`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`id_utente`) REFERENCES `zz_users`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`id_utente_assegnato`) REFERENCES `zz_users`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`id_parent`) REFERENCES `zz_checklists`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS `zz_checklist_templates` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `id_module` int(11), + `id_plugin` int(11), + `id_record` int(11) NOT NULL, + `content` TEXT, + `id_parent` int(11), + PRIMARY KEY (`id`), + FOREIGN KEY (`id_module`) REFERENCES `zz_modules`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`id_plugin`) REFERENCES `zz_plugins`(`id`) ON DELETE CASCADE, + FOREIGN KEY (`id_parent`) REFERENCES `zz_checklist_templates`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB;