From c434ce5308c510ef9d7cec14a803f4f42e633581 Mon Sep 17 00:00:00 2001 From: Wangyuting <851424971@qq.com> Date: Tue, 25 Apr 2023 12:04:12 +0800 Subject: [PATCH 1/4] * Add my dashboard html for zin. --- module/block/js/dashboard.ui.js | 262 +++++++++++++++++++++++++++++ module/block/ui/dashboard.html.php | 65 +++++++ module/my/control.php | 2 +- 3 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 module/block/js/dashboard.ui.js create mode 100644 module/block/ui/dashboard.html.php diff --git a/module/block/js/dashboard.ui.js b/module/block/js/dashboard.ui.js new file mode 100644 index 0000000000..6dabc38d93 --- /dev/null +++ b/module/block/js/dashboard.ui.js @@ -0,0 +1,262 @@ +/** + * Delete block. + * + * @param int $index + * @access public + * @return void + */ +function deleteBlock(index) +{ + if(confirm(config.confirmRemoveBlock)) + { + $.getJSON(createLink('block', 'delete', 'index=' + index + '&module=' + module), function(data) + { + if(data.result != 'success') + { + alert(data.message); + return false; + } + else + { + window.location.reload(true); + } + }); + } +} + +/** + * Sort blocks. + * + * @param array $orders format is {'blockid' : 1, 'block1' : 2} + * @param function $callback + * @access public + * @return void + */ +function sortBlocks(newOrders, callback) +{ + $.getJSON(createLink('block', 'sort', 'orders=' + newOrders.join(',') + '&module=' + module), callback); +} + +/** + * Resize block + * @param string $blockId + * @param function $callback + * @access public + * @return void + */ +function resizeBlock(blockID, width, callback) +{ + $.getJSON(createLink('block', 'resize', 'id=' + blockID + '&type=horizontal&data=' + width), function(data) + { + callback && callback(); + refreshBlock($('#block' + blockID)); + }); +} + +/** + * refreshBlock + * + * @param object $panel + * @param function afterRefresh + * @access public + * @return void + */ +function refreshBlock($panel, afterRefresh) +{ + var url = $panel.data('url'); + $panel.addClass('load-indicator loading'); + $.ajax({url: url, dataType: 'html'}).done(function(data) + { + var $data = $(data); + if($data.hasClass('panel')) $panel.empty().append($data.children()); + else if($panel.find('#assigntomeBlock').length) $panel.find('#assigntomeBlock').empty().append($data.children()); + else + { + $panel.children('.panel-move-handler,style,script').remove(); + $panel.find('.panel-body,.empty-tip').first().replaceWith($data); + $panel.find('.iframe').initIframeModal(); + } + $panel.find('.progress-pie').progressPie(); + if($.isFunction(afterRefresh)) + { + afterRefresh.call(this, + { + result: true, + data: data, + $panel: $panel + }); + } + $panel.find('.tablesorter').sortTable(); + $panel.find('.chosen').chosen(); + $panel.children('.table-header-fixed').remove(); + initTableHeader($panel); + $(".sparkline").sparkline(); + }).fail(function() + { + $panel.addClass('panel-error'); + if($.isFunction(afterRefresh)) + { + afterRefresh.call(this, + { + result: false, + $panel: $panel + }); + } + }).always(function() + { + $panel.removeClass('load-indicator loading'); + }); +} + +/** + * Init table header + * @access public + * @return void + */ +function initTableHeader($wrapper) +{ + ($wrapper || $('#dashboard')).find('.panel-body > table.table-fixed-head').each(function() + { + var $table = $(this); + var $tabPane = $table.closest('.tab-pane'); + if ($tabPane.length && !$tabPane.hasClass('active')) + { + $('[data-tab][href="#' + $tabPane.attr('id') + '"]').one('shown.zui.tab', function() + { + initTableHeader($tabPane); + }); + return; + } + + var $panel = $tabPane.length ? $tabPane : $table.closest('.panel'); + + if(!$table.length || !$table.children('thead').length || ($panel.find('#assigntomeBlock').length && $panel.find('#assigntomeBlock > div').length > 1)) return; + var isFixed = $panel.find('.panel-body').height() < $table.outerHeight(); + + $panel.toggleClass('with-fixed-header', isFixed); + var $header = $panel.children('.table-header-fixed').toggle(isFixed); + if(!isFixed) + { + $table.find('thead').css('visibility', 'visible'); + return; + } + var tableWidth = $table.width(); + var $oldTableHead = $table.find('thead'); + var updateTh = function() + { + $header.find('thead').empty().append($oldTableHead.find('tr').clone()); + }; + if(!$header.length) + { + $header = $('
').css('right', $panel.width() - tableWidth - 20); + $oldTableHead.find('th').each(function(idx) + { + $(this).attr('data-idx', idx); + }); + $header.find('.table').addClass($table.attr('class')).append($oldTableHead.css('visibility', 'hidden').clone().css('visibility', 'visible')); + $panel.addClass('with-fixed-header').append($header); + var $heading = $panel.children('.panel-heading'); + if($heading.length) $header.css('top', $heading.outerHeight()); + if($table.hasClass('tablesorter')) + { + $header.on('mousedown mouseup', 'th[data-idx]', function(e) + { + var $th = $(this); + $oldTableHead.find('th[data-idx="' + $th.data('idx') + '"]').trigger(e); + if(e.type === 'mouseup') + { + setTimeout(updateTh, 10); + setTimeout(updateTh, 200); + } + }); + } + } + else + { + updateTh(); + } + + var timeoutCall = null; + $table.parent().off('scroll.initTableHeader').on('scroll.initTableHeader', function() + { + clearTimeout(timeoutCall); + var $tableContainer = $(this); + timeoutCall = setTimeout(function() { + $panel.toggleClass('table-scrolled', $tableContainer.scrollTop() > 0); + }, 200); + }); + }); +} + +/** + * Check refresh progress + * @param object $dashboard + * @access public + * @return void + */ +function checkRefreshProgress($dashboard, doneCallback) +{ + if($dashboard.find('.panel-loading').length) setTimeout(function() {checkRefreshProgress($dashboard, doneCallback);}, 500); + else doneCallback(); +} +/** + * Hidden block. + * + * @param index $index + * @access public + * @return void + */ +function hiddenBlock(index) +{ + $.getJSON(createLink('block', 'delete', 'index=' + index + '&module=' + module + '&type=hidden'), function(data) + { + if(data.result != 'success') + { + alert(data.message); + return false; + } + + $('#dashboard #block' + index).addClass('hidden'); + }) +} + +/** + * Block initialization. + * + * @access public + * @return void + */ +$(function() +{ + refreshBlock($('#block67')); + initTableHeader(); + $(window).on('resize', function() + { + initTableHeader(); + }); +}); + +/** + * Reload roadmap. + * + * @param int productID + * @param int roadMapID + * @access public + * @return void + */ +function reloadRoadmap(productID, roadMapID) +{ + $.ajax( + { + url: createLink('block', 'printScrumroadmapBlock', 'productID=' + productID + '&roadMapID=' + roadMapID), + dataType: "html", + async: false, + data: {productID: productID, roadMapID: roadMapID}, + type: 'post', + success: function(data) + { + $("#roadMap" + roadMapID).html(data); + $("#" + roadMapID).chosen(); + } + }) +} diff --git a/module/block/ui/dashboard.html.php b/module/block/ui/dashboard.html.php new file mode 100644 index 0000000000..69a2c3d74a --- /dev/null +++ b/module/block/ui/dashboard.html.php @@ -0,0 +1,65 @@ + $block) +{ + $blocks[] = + panel + ( + set('class', "{$block->block}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')), + set('data-id', $block->id), + set('data-name', $block->title), + set('data-order', $block->order), + set('data-url', $block->blockLink), + div + ( + set('class', 'panel-heading'), + div + ( + set('class', 'panel-title'), + $block->title + ), + nav + ( + set('class', 'panel-actions nav nav-default'), + dropdown + ( + icon + ( + set('class', 'icon icon-ellipsis-v') + ), + set::items + ([ + ['text' => $lang->block->refresh, 'url' => '', 'class' => 'refresh-panel'], + ['text' => $lang->edit, 'url' => $this->createLink("block", "admin", "id=$block->id&module=$module"), 'class' => 'refresh-panel'], + ['text' => $lang->block->hidden, 'url' => '', 'class' => 'refresh-panel'], + ['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "admin", "id=0&module=$module"), 'data-toggle' => 'modal'], + ['text' => $lang->block->reset, 'url' => '', 'class' => 'refresh-panel'], + ]), + ) + ) + ), + div + ( + set('class', 'panel-body scrollbar-hover') + ) + ); +} + +div +( + set('class', 'dashboard'), + set('id', 'dashboard'), + div + ( + set('class', 'row'), + div + ( + set('class', 'col-main'), + $blocks + ) + ) +); + +render(); diff --git a/module/my/control.php b/module/my/control.php index 38344fd394..f3fb45f883 100755 --- a/module/my/control.php +++ b/module/my/control.php @@ -33,7 +33,7 @@ class my extends control public function index() { $this->view->title = $this->lang->my->common; - $this->display(); + echo $this->fetch('block', 'dashboard', 'module=my'); } /** From 1d7ccc9e8cce9dd35f95891c2d500f915db76a54 Mon Sep 17 00:00:00 2001 From: Wangyuting <851424971@qq.com> Date: Tue, 25 Apr 2023 12:39:36 +0800 Subject: [PATCH 2/4] * Adjust block dashboard html. --- module/block/css/dashboard.ui.css | 36 ++++ module/block/js/dashboard.ui.js | 262 ----------------------------- module/block/ui/dashboard.html.php | 61 ++++++- 3 files changed, 92 insertions(+), 267 deletions(-) create mode 100644 module/block/css/dashboard.ui.css diff --git a/module/block/css/dashboard.ui.css b/module/block/css/dashboard.ui.css new file mode 100644 index 0000000000..37cd66eca9 --- /dev/null +++ b/module/block/css/dashboard.ui.css @@ -0,0 +1,36 @@ +body {padding-bottom: 20px;} +.nav > li > .btn {padding: 0 5px; line-height: 24px; margin: 3px; color: #3C4353;} +.nav > li > .btn.btn-primary {color: #fff;} +.nav .icon-more {font-size: 14px;} +.block-statistic .nav-stacked {overflow: auto; max-height: 220px;} +#dashboard .col-side {width: 450px; max-width: 450px;} +#dashboard .panel {margin-bottom: 20px; position: relative;} +#dashboard .panel-body {max-height: 400px; overflow: auto;} +#dashboard .panel-body.has-table {padding-top: 0;} +#dashboard .panel-move-handler {position: absolute; top: 0; left: 0; right: 50px; height: 40px; z-index: 10; cursor: move;} +#dashboard .panel-heading {cursor: move; padding-right: 75px;} +#dashboard .panel-actions {position: absolute; top: 0; right: 0; margin-right: 0; padding: 7px 8px} +#dashboard .panel-actions > a {padding: 0 5px; line-height: 22px;} +@media (min-width: 992px) +{ + #dashboard > .row {display: table; width: 100%; margin: 0;} + #dashboard > .row > .col-main, + #dashboard > .row > .col-side {display: table-cell; float: none; padding: 0; vertical-align: top;} + #dashboard > .row > .col-main {padding-right: 10px;} + #dashboard > .row > .col-side {padding-left: 10px;} +} +#dashboard.sortable-sorting .panel {margin-bottom: 10px; box-shadow: 0 1px 1px rgba(0,0,0,.075), 0 2px 6px 0 rgba(0,0,0,.075); height: 46px;} +#dashboard.sortable-sorting .panel > * {display: none;} +#dashboard.sortable-sorting .panel:before {display: block; content: attr(data-name); padding: 12px 20px; font-weight: bold; font-size: 14px; color: #3c4353; opacity: 1 !important; text-align: left; visibility: visible;} +#dashboard.sortable-sorting .panel.dragging {visibility: visible; background: transparent; background: rgba(0,0,0,.075); box-shadow: inset 0 2px 6px rgba(0,0,0,.075);} +#dashboard.sortable-sorting .panel.dragging:before {color: #bbb;} +#dashboard.sortable-sorting .panel.drag-shadow {box-shadow: 0 1px 3px rgba(0,0,0,.175), 0 3px 8px 0 rgba(0,0,0,.175);} + +#dashboard .block-sm .hide-in-sm {display: none;} +#dashboard .block-dynamic .panel-body {overflow-x: hidden;} +.modal-body {padding: 10px 20px 20px 20px;} + +#dashboard .block-scrumoverview .table {margin-bottom: 12px;} +#dashboard .block-scrumoverview .table thead tr th {padding-left: 0; text-align: right; border-bottom: unset;} +#dashboard .block-scrumoverview .table tbody tr td {padding-left: 0;} +#dashboard .block-scrumoverview .table tbody tr th {text-align: right;} diff --git a/module/block/js/dashboard.ui.js b/module/block/js/dashboard.ui.js index 6dabc38d93..e69de29bb2 100644 --- a/module/block/js/dashboard.ui.js +++ b/module/block/js/dashboard.ui.js @@ -1,262 +0,0 @@ -/** - * Delete block. - * - * @param int $index - * @access public - * @return void - */ -function deleteBlock(index) -{ - if(confirm(config.confirmRemoveBlock)) - { - $.getJSON(createLink('block', 'delete', 'index=' + index + '&module=' + module), function(data) - { - if(data.result != 'success') - { - alert(data.message); - return false; - } - else - { - window.location.reload(true); - } - }); - } -} - -/** - * Sort blocks. - * - * @param array $orders format is {'blockid' : 1, 'block1' : 2} - * @param function $callback - * @access public - * @return void - */ -function sortBlocks(newOrders, callback) -{ - $.getJSON(createLink('block', 'sort', 'orders=' + newOrders.join(',') + '&module=' + module), callback); -} - -/** - * Resize block - * @param string $blockId - * @param function $callback - * @access public - * @return void - */ -function resizeBlock(blockID, width, callback) -{ - $.getJSON(createLink('block', 'resize', 'id=' + blockID + '&type=horizontal&data=' + width), function(data) - { - callback && callback(); - refreshBlock($('#block' + blockID)); - }); -} - -/** - * refreshBlock - * - * @param object $panel - * @param function afterRefresh - * @access public - * @return void - */ -function refreshBlock($panel, afterRefresh) -{ - var url = $panel.data('url'); - $panel.addClass('load-indicator loading'); - $.ajax({url: url, dataType: 'html'}).done(function(data) - { - var $data = $(data); - if($data.hasClass('panel')) $panel.empty().append($data.children()); - else if($panel.find('#assigntomeBlock').length) $panel.find('#assigntomeBlock').empty().append($data.children()); - else - { - $panel.children('.panel-move-handler,style,script').remove(); - $panel.find('.panel-body,.empty-tip').first().replaceWith($data); - $panel.find('.iframe').initIframeModal(); - } - $panel.find('.progress-pie').progressPie(); - if($.isFunction(afterRefresh)) - { - afterRefresh.call(this, - { - result: true, - data: data, - $panel: $panel - }); - } - $panel.find('.tablesorter').sortTable(); - $panel.find('.chosen').chosen(); - $panel.children('.table-header-fixed').remove(); - initTableHeader($panel); - $(".sparkline").sparkline(); - }).fail(function() - { - $panel.addClass('panel-error'); - if($.isFunction(afterRefresh)) - { - afterRefresh.call(this, - { - result: false, - $panel: $panel - }); - } - }).always(function() - { - $panel.removeClass('load-indicator loading'); - }); -} - -/** - * Init table header - * @access public - * @return void - */ -function initTableHeader($wrapper) -{ - ($wrapper || $('#dashboard')).find('.panel-body > table.table-fixed-head').each(function() - { - var $table = $(this); - var $tabPane = $table.closest('.tab-pane'); - if ($tabPane.length && !$tabPane.hasClass('active')) - { - $('[data-tab][href="#' + $tabPane.attr('id') + '"]').one('shown.zui.tab', function() - { - initTableHeader($tabPane); - }); - return; - } - - var $panel = $tabPane.length ? $tabPane : $table.closest('.panel'); - - if(!$table.length || !$table.children('thead').length || ($panel.find('#assigntomeBlock').length && $panel.find('#assigntomeBlock > div').length > 1)) return; - var isFixed = $panel.find('.panel-body').height() < $table.outerHeight(); - - $panel.toggleClass('with-fixed-header', isFixed); - var $header = $panel.children('.table-header-fixed').toggle(isFixed); - if(!isFixed) - { - $table.find('thead').css('visibility', 'visible'); - return; - } - var tableWidth = $table.width(); - var $oldTableHead = $table.find('thead'); - var updateTh = function() - { - $header.find('thead').empty().append($oldTableHead.find('tr').clone()); - }; - if(!$header.length) - { - $header = $('
').css('right', $panel.width() - tableWidth - 20); - $oldTableHead.find('th').each(function(idx) - { - $(this).attr('data-idx', idx); - }); - $header.find('.table').addClass($table.attr('class')).append($oldTableHead.css('visibility', 'hidden').clone().css('visibility', 'visible')); - $panel.addClass('with-fixed-header').append($header); - var $heading = $panel.children('.panel-heading'); - if($heading.length) $header.css('top', $heading.outerHeight()); - if($table.hasClass('tablesorter')) - { - $header.on('mousedown mouseup', 'th[data-idx]', function(e) - { - var $th = $(this); - $oldTableHead.find('th[data-idx="' + $th.data('idx') + '"]').trigger(e); - if(e.type === 'mouseup') - { - setTimeout(updateTh, 10); - setTimeout(updateTh, 200); - } - }); - } - } - else - { - updateTh(); - } - - var timeoutCall = null; - $table.parent().off('scroll.initTableHeader').on('scroll.initTableHeader', function() - { - clearTimeout(timeoutCall); - var $tableContainer = $(this); - timeoutCall = setTimeout(function() { - $panel.toggleClass('table-scrolled', $tableContainer.scrollTop() > 0); - }, 200); - }); - }); -} - -/** - * Check refresh progress - * @param object $dashboard - * @access public - * @return void - */ -function checkRefreshProgress($dashboard, doneCallback) -{ - if($dashboard.find('.panel-loading').length) setTimeout(function() {checkRefreshProgress($dashboard, doneCallback);}, 500); - else doneCallback(); -} -/** - * Hidden block. - * - * @param index $index - * @access public - * @return void - */ -function hiddenBlock(index) -{ - $.getJSON(createLink('block', 'delete', 'index=' + index + '&module=' + module + '&type=hidden'), function(data) - { - if(data.result != 'success') - { - alert(data.message); - return false; - } - - $('#dashboard #block' + index).addClass('hidden'); - }) -} - -/** - * Block initialization. - * - * @access public - * @return void - */ -$(function() -{ - refreshBlock($('#block67')); - initTableHeader(); - $(window).on('resize', function() - { - initTableHeader(); - }); -}); - -/** - * Reload roadmap. - * - * @param int productID - * @param int roadMapID - * @access public - * @return void - */ -function reloadRoadmap(productID, roadMapID) -{ - $.ajax( - { - url: createLink('block', 'printScrumroadmapBlock', 'productID=' + productID + '&roadMapID=' + roadMapID), - dataType: "html", - async: false, - data: {productID: productID, roadMapID: roadMapID}, - type: 'post', - success: function(data) - { - $("#roadMap" + roadMapID).html(data); - $("#" + roadMapID).chosen(); - } - }) -} diff --git a/module/block/ui/dashboard.html.php b/module/block/ui/dashboard.html.php index 69a2c3d74a..018b6a8d80 100644 --- a/module/block/ui/dashboard.html.php +++ b/module/block/ui/dashboard.html.php @@ -1,13 +1,59 @@ $block) { - $blocks[] = - panel + $mainBlocks[] = + div ( - set('class', "{$block->block}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')), + set('class', "panel rounded shadow ring-0 canvas {$block->block}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')), + set('data-id', $block->id), + set('data-name', $block->title), + set('data-order', $block->order), + set('data-url', $block->blockLink), + div + ( + set('class', 'panel-heading'), + div + ( + set('class', 'panel-title'), + $block->title + ), + nav + ( + set('class', 'panel-actions nav nav-default'), + dropdown + ( + icon + ( + set('class', 'icon icon-ellipsis-v') + ), + set::items + ([ + ['text' => $lang->block->refresh, 'url' => '', 'class' => 'refresh-panel'], + ['text' => $lang->edit, 'url' => $this->createLink("block", "admin", "id=$block->id&module=$module"), 'class' => 'refresh-panel'], + ['text' => $lang->block->hidden, 'url' => '', 'class' => 'refresh-panel'], + ['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "admin", "id=0&module=$module"), 'data-toggle' => 'modal'], + ['text' => $lang->block->reset, 'url' => '', 'class' => 'refresh-panel'], + ]), + ) + ) + ), + div + ( + set('class', 'panel-body scrollbar-hover') + ) + ); +} + +$sideBlocks = array(); +foreach($shortBlocks as $index => $block) +{ + $sideBlocks[] = + div + ( + set('class', "panel rounded shadow ring-0 canvas {$block->block}" . (isset($block->params->color) ? 'panel-' . $block->params->color : '')), set('data-id', $block->id), set('data-name', $block->title), set('data-order', $block->order), @@ -57,7 +103,12 @@ div div ( set('class', 'col-main'), - $blocks + $mainBlocks + ), + div + ( + set('class', 'col-side'), + $sideBlocks ) ) ); From f8d08dd5a9d8773eff01add50a564d85c9b20314 Mon Sep 17 00:00:00 2001 From: dingguodong Date: Tue, 25 Apr 2023 13:07:04 +0800 Subject: [PATCH 3/4] * Turn on the strict mode od MySQL. --- config/config.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.php b/config/config.php index 4095dbba33..aec4c336dc 100644 --- a/config/config.php +++ b/config/config.php @@ -64,12 +64,12 @@ $config->slaveDB = new stdclass(); $config->db->persistant = false; // 是否为持续连接。 Pconnect or not. $config->db->driver = 'mysql'; // 目前只支持MySQL数据库。Must be MySQL. Don't support other database server yet. $config->db->encoding = 'UTF8'; // 数据库编码。 Encoding of database. -$config->db->strictMode = false; // 关闭MySQL的严格模式。 Turn off the strict mode of MySQL. +$config->db->strictMode = true; // 默认开启MySQL的严格模式。 Turn on the strict mode of MySQL. $config->db->prefix = 'zt_'; // 数据库表名前缀。 The prefix of the table name. $config->slaveDB->persistant = false; $config->slaveDB->driver = 'mysql'; $config->slaveDB->encoding = 'UTF8'; -$config->slaveDB->strictMode = false; +$config->slaveDB->strictMode = true; /* 可用域名后缀列表。Domain postfix lists. */ $config->domainPostfix = "|com|com.cn|com.hk|com.tw|com.vc|edu.cn|es|"; From ba16f459926c47e42a0b4d8fba55c08c9f96e7f8 Mon Sep 17 00:00:00 2001 From: dingguodong Date: Tue, 25 Apr 2023 13:25:03 +0800 Subject: [PATCH 4/4] * Check whether user is locked and reset locked datetime. --- module/user/model.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/user/model.php b/module/user/model.php index b9e74bb02a..dc22a23e53 100644 --- a/module/user/model.php +++ b/module/user/model.php @@ -1399,7 +1399,7 @@ class userModel extends model if($this->session->{"{$account}.loginLocked"} and (time() - strtotime($this->session->{"{$account}.loginLocked"})) <= $this->config->user->lockMinutes * 60) return true; $user = $this->dao->select('locked')->from(TABLE_USER)->where('account')->eq($account)->fetch(); - if(empty($user)) return false; + if(empty($user) or is_null($user->locked)) return false; if((time() - strtotime($user->locked)) > $this->config->user->lockMinutes * 60) return false; return true; @@ -1414,7 +1414,7 @@ class userModel extends model */ public function cleanLocked($account) { - $this->dao->update(TABLE_USER)->set('fails')->eq(0)->set('locked')->eq('0000-00-00 00:00:00')->where('account')->eq($account)->exec(); + $this->dao->update(TABLE_USER)->set('fails')->eq(0)->set('locked = null')->where('account')->eq($account)->exec(); unset($_SESSION['loginFails']); unset($_SESSION["{$account}.loginLocked"]);