This commit is contained in:
tianshujie
2021-08-25 15:19:35 +08:00
29 changed files with 357 additions and 103 deletions
+51
View File
@@ -0,0 +1,51 @@
<?php
/**
* 禅道API的issue资源类
* 版本V1
*
* The issue entry point of zentaopms
* Version 1
*/
class issueEntry extends Entry
{
public function get($issueID)
{
$control = $this->loadController('issue', 'view');
$control->view($issueID);
$data = $this->getData();
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
if(isset($data->status) and $data->status == 'success') $this->send(200, $this->format($data->data->issue, 'createdDate:time,editedDate:time,assignedDate:time'));
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
$this->sendError(400, 'error');
}
public function put($issueID)
{
$oldIssue = $this->loadModel('issue')->getByID($issueID);
/* Set $_POST variables. */
$fields = 'type,title,severity,pri,assignedTo,deadline,desc';
$this->batchSetPost($fields, $oldIssue);
$control = $this->loadController('issue', 'edit');
$control->edit($issueID);
$data = $this->getData();
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
$issue = $this->issue->getByID($issueID);
$this->send(200, $this->format($issue, 'createdDate:time,editedDate:time,assignedDate:time'));
}
public function delete($issueID)
{
$control = $this->loadController('issue', 'delete');
$control->delete($issueID, 'true');
$this->getData();
$this->sendSuccess(200, 'success');
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
/**
* 禅道API的issues资源类
* 版本V1
*
* The issues entry point of zentaopms
* Version 1
*/
class issuesEntry extends entry
{
public function get()
{
$control = $this->loadController('my', 'issue');
$control->issue($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(!isset($data->status)) return $this->sendError(400, 'error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
$pager = $data->data->pager;
$result = array();
foreach($data->data->issues as $issue)
{
$result[] = $this->format($issue, 'createdDate:time,editedDate:time,assignedDate:time');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'issues' => $result));
}
public function post($projectID = 0)
{
if((int) $projectID <= 0) $this->sendError(400, 'The id of project is wrong.');
$fields = 'type,title,severity,pri,assignedTo,deadline,desc';
$this->batchSetPost($fields);
$control = $this->loadController('issue', 'create');
$this->requireFields('type,title,severity');
$control->create($projectID);
$data = $this->getData();
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
if(isset($data->result) and!isset($data->id)) return $this->sendError(400, $data->message);
$issue = $this->loadModel('issue')->getByID($data->id);
$this->send(201, $this->format($issue, 'createdDate:time,editedDate:time,assignedDate:time'));
}
}
+2 -1
View File
@@ -222,7 +222,8 @@ $filter->project->task->cookie['projectTaskOrder'] = 'reg::orderBy';
$filter->project->task->cookie['windowWidth'] = 'int';
$filter->project->export->cookie['checkedItem'] = 'reg::checked';
$filter->projectstory->story->cookie['storyModuleParam'] = 'int';
$filter->projectstory->story->cookie['storyModuleParam'] = 'int';
$filter->projectstory->story->cookie['pagerProductBrowse'] = 'int';
$filter->qa->default->cookie['lastProduct'] = 'int';
$filter->qa->default->cookie['preBranch'] = 'int';
+4
View File
@@ -55,4 +55,8 @@ $routes['/projects/:project/risks'] = 'risks';
$routes['/risks'] = 'risks';
$routes['/risks/:id'] = 'risk';
$routes['/projects/:project/questions'] = 'issues';
$routes['/questions'] = 'issues';
$routes['/questions/:id'] = 'issue';
$config->routes = $routes;
+2 -1
View File
@@ -897,7 +897,8 @@ class baseControl
foreach($data as $key => $value)
{
if(!is_string($value)) continue;
$data[$key] = urlencode($value);
/* Retain ["] for json encode when value is jsoned string. */
$data[$key] = str_replace('%22', '"', urlencode($value));
}
print(urldecode(json_encode($data)));
+109
View File
@@ -211,6 +211,115 @@ class html extends baseHTML
$value = str_replace("'", '&#039;', $value);
return "<input type='number' name='$name' {$id} value='$value' $attrib />\n";
}
/**
* Convert a string to a uni code
*
* @param string $string
* @return int
*/
static public function stringToCode($string)
{
$stringLength = strlen($string);
if($stringLength == 0) return 0;
$code = 0;
for($i = 0; $i < $stringLength; ++$i)
{
$code += ($i + 1) * ord($string[$i]);
}
return $code;
}
/**
* Create user avatar.
*
* @param string|object|array $user User object or user avatar address or user account
* @param string|int $size Avatar size, can be a number or preset sizes: "xs", "sm", "", "lg", "xl", default is ""
* @param string $className Avatar element class name, default is "avatar-circle"
* @param string $attrib Extra attributes on avatar element
* @param string $tag Avatar element tag name, default is "div"
* @static
* @access public
* @return string
*/
static public function avatar($user, $size = '', $className = 'avatar-circle', $attrib = '', $tag = 'div')
{
if(is_string($user))
{
$userObj = new stdClass();
if(strlen($user) > 1) $userObj->avatar = $user;
else $userObj->account = $user;
$user = $userObj;
}
else if(is_array($user))
{
$userObj = new stdClass();
$userObj->avatar = $user['avatar'];
$userObj->account = $user['account'];
$user = $userObj;
}
$hasImage = !empty($user->avatar);
$extraClassName = $hasImage ? ' has-img' : ' has-text';
$style = '';
if($size)
{
if(is_numeric($size)) $style .= "width: $size" . "px; height: $size" . "px; line-height: $size" . 'px;';
$extraClassName .= " avatar-$size";
}
if(!$hasImage)
{
$colorHue = (html::stringToCode($user->account) * 43) % 360;
$style .= "background: hsl($colorHue, 100%, 58%);";
}
if(!empty($style)) $style = "style='$style'";
$html = "<$tag class='avatar$extraClassName $className' $attrib $style>";
if($hasImage) $html .= html::image($user->avatar);
else $html .= '<span>' . strtoupper($user->account[0]) . '</span>';
$html .= "</$tag>";
return $html;
}
/**
* Create a small user avatar.
*
* @param string|object $user User object or user avatar address or user account
* @param string $className Avatar element class name, default is "avatar-circle"
* @param string $attrib Extra attributes on avatar element
* @param string $tag Avatar element tag name, default is "div"
* @static
* @access public
* @return string
*/
static public function smallAvatar($user, $className = 'avatar-circle', $attrib = '', $tag = 'div')
{
return html::avatar($user, 'sm', $className, $attrib, $tag);
}
/**
* Create a large user avatar.
*
* @param string|object $user User object or user avatar address or user account
* @param string $className Avatar element class name, default is "avatar-circle"
* @param string $attrib Extra attributes on avatar element
* @param string $tag Avatar element tag name, default is "div"
* @static
* @access public
* @return string
*/
static public function largeAvatar($user, $className = 'avatar-circle', $attrib = '', $tag = 'div')
{
return html::avatar($user, 'lg', $className, $attrib, $tag);
}
}
/**
@@ -23,7 +23,7 @@
#cards .project-detail .progress-text-left .progress-text {width: 50px; left: -50px;}
#cards .panel-heading {cursor: pointer;}
#cards .project-stages-container {margin: 0 0 -16px 0; padding: 0 4px; height: 46px; overflow-x: auto; position: relative;}
#cards .project-stages:after {content: ' '; width: 30px; display: block; right: -16px; top: 16px; bottom: -6px; z-index: 1; background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%); position: absolute;}
#cards .project-stages:after {content: ' '; width: 30px; display: block; right: -5px; top: 16px; bottom: -5px; z-index: 1; background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%); position: absolute;}
#cards .project-stages-row {position: relative; height: 30px; z-index: 0;}
#cards .project-stage-item {white-space: nowrap; position: absolute; top: 0; min-width: 48px; padding-top: 13px; color: #838A9D;}
#cards .project-stage-item > div {white-space: nowrap; overflow: visible; text-align: center; text-overflow: ellipsis;}
@@ -73,7 +73,7 @@
<span><i class='icon icon-clock'></i> <?php printf($lang->project->hoursUnit, $project->estimate); ?></span>
</div>
<?php if($config->systemMode == 'new'):?>
<?php if($project->model === 'waterfall'): ?>
<?php if($project->model !== 'waterfall'): ?>
<div class='project-detail project-stages'>
<?php
$projectProjects = array();
+2 -6
View File
@@ -281,9 +281,7 @@ class commonModel extends model
$isGuest = $app->user->account == 'guest';
echo "<a class='dropdown-toggle' data-toggle='dropdown'>";
echo "<div id='main-avatar' class='avatar avatar bg-secondary avatar-circle'>";
echo !empty($app->user->avatar) ? html::image($app->user->avatar) : strtoupper($app->user->account[0]);
echo "</div>\n";
echo html::avatar($app->user);
echo '</a>';
echo "<ul class='dropdown-menu pull-right'>";
if(!$isGuest)
@@ -291,9 +289,7 @@ class commonModel extends model
$noRole = (!empty($app->user->role) && isset($lang->user->roleList[$app->user->role])) ? '' : ' no-role';
echo '<li class="user-profile-item">';
echo "<a href='" . helper::createLink('my', 'profile', '', '', true) . "' data-width='600' class='iframe $noRole'" . '>';
echo "<div id='menu-avatar' class='avatar avatar bg-secondary avatar-circle'>";
echo $app->user->avatar ? html::image($app->user->avatar) : strtoupper($app->user->account[0]);
echo "</div>\n";
echo html::avatar($app->user, '', 'avatar-circle', 'id="menu-avatar"');
echo '<div class="user-profile-name">' . (empty($app->user->realname) ? $app->user->account : $app->user->realname) . '</div>';
if(isset($lang->user->roleList[$app->user->role])) echo '<div class="user-profile-role">' . $lang->user->roleList[$app->user->role] . '</div>';
echo '</a></li><li class="divider"></li>';
+31 -2
View File
@@ -1,9 +1,24 @@
/**
* Load modules by libID.
*
* @param int $libID
* @access public
* @return void
*/
function loadModules(libID)
{
link = createLink('doc', 'ajaxGetModules', 'libID=' + libID);
$('#moduleBox').load(link, function(){$('#moduleBox').find('select').chosen()});
}
/**
* Toggle acl.
*
* @param string $acl
* @param string $type
* @access public
* @return void
*/
function toggleAcl(acl, type)
{
if(acl == 'custom')
@@ -27,6 +42,13 @@ function toggleAcl(acl, type)
}
}
/**
* Load doc module by libID.
*
* @param int $libID
* @access public
* @return void
*/
function loadDocModule(libID)
{
link = createLink('doc', 'ajaxGetChild', 'libID=' + libID);
@@ -38,6 +60,13 @@ function loadDocModule(libID)
});
}
/**
* Set cookie of browse type and reload.
*
* @param type $type
* @access public
* @return void
*/
function setBrowseType(type)
{
$.cookie('browseType', type, {expires:config.cookieLife, path:config.webRoot});
@@ -46,7 +75,7 @@ function setBrowseType(type)
$(document).ready(function()
{
/* hide #module chosen dropdown on #lib dropdown show */
/* Hide #module chosen dropdown on #lib dropdown show */
$('#lib').on('chosen:showing_dropdown', function()
{
$('#module').trigger('chosen:close');
@@ -85,7 +114,7 @@ $(document).ready(function()
var NAME = 'zui.splitRow'; // model name
/* The SplitRow model class */
/* The SplitRow model class. */
var SplitRow = function(element, options)
{
var that = this;
+2 -2
View File
@@ -21,7 +21,7 @@ $(function()
$('.ke-toolbar .ke-outline:last').after("<span data-name='unlink' class='ke-outline' title='Markdown' onclick='toggleEditor(\"markdown\")' style='font-size: unset; line-height: unset;'>Markdown</span>");
}
$(document).on("mousedown", 'span[data-name="fullscreen"]', function()
$(document).on("mouseup", 'span[data-name="fullscreen"]', function()
{
if($(this).hasClass('ke-selected'))
{
@@ -35,7 +35,7 @@ $(function()
}
});
$(document).on("mousedown", 'a[title="Fullscreen"],.icon-columns', function()
$(document).on("mouseup", 'a[title="Fullscreen"],.icon-columns', function()
{
setTimeout(function()
{
+2 -2
View File
@@ -33,7 +33,7 @@ $(function()
/* Automatically save document contents. */
setInterval("saveTempContent()", 60 * 1000);
$(document).on("mousedown", 'span[data-name="fullscreen"]', function()
$(document).on("mouseup", 'span[data-name="fullscreen"]', function()
{
if(config.onlybody == 'no')
{
@@ -50,7 +50,7 @@ $(function()
}
});
$(document).on("mousedown", 'a[title="Fullscreen"],.icon-columns', function()
$(document).on("mouseup", 'a[title="Fullscreen"],.icon-columns', function()
{
if(config.onlybody == 'no')
{
+3 -3
View File
@@ -1875,10 +1875,10 @@ class docModel extends model
if($doc->type == 'project') $objectID = $doc->project;
if($doc->type == 'execution') $objectID = $doc->execution;
$app = $this->app->openApp;
if($app != 'doc') $app = $objectID ? $doc->type : 'doc';
$tab = $this->app->openApp;
if($tab != 'doc') $tab = $objectID ? $doc->type : 'doc';
$html .= '<li>' . html::a(inlink('objectLibs', "type={$doc->type}&objectID=$objectID&libID={$doc->lib}&docID={$doc->id}"), "<i class='icon icon-file-text'></i> " . $doc->title, '', "data-app='$app' title='{$doc->title}'") . '</li>';
$html .= '<li>' . html::a(inlink('objectLibs', "type={$doc->type}&objectID=$objectID&libID={$doc->lib}&docID={$doc->id}"), "<i class='icon icon-file-text'></i> " . $doc->title, '', "data-app='$tab' title='{$doc->title}'") . '</li>';
}
$collectionCount = $this->dao->select('count(id) as count')->from(TABLE_DOC)
+1 -1
View File
@@ -358,7 +358,7 @@ class executionModel extends model
->batchcheck($this->config->execution->create->requiredFields, 'notempty')
->checkIF($sprint->begin != '', 'begin', 'date')
->checkIF($sprint->end != '', 'end', 'date')
->checkIF($sprint->end != '', 'end', 'gt', $sprint->begin)
->checkIF($sprint->end != '', 'end', 'ge', $sprint->begin)
->checkIF(!empty($sprint->code), 'code', 'unique')
->exec();
+11 -3
View File
@@ -190,10 +190,13 @@ class gitlab extends control
*/
public function checkToken()
{
if(strpos($this->post->url, 'http') !== 0) return $this->send(array('result' => 'fail', 'message' => array('url' => array($this->lang->gitlab->hostError))));
if(!$this->post->token) return $this->send(array('result' => 'fail', 'message' => array('token' => array($this->lang->gitlab->tokenError))));
$gitlabURL = trim($this->post->url);
$token = trim($this->post->token);
$user = $this->gitlab->apiGetCurrentUser($this->post->url, $this->post->token);
if(strpos($gitlabURL, 'http') !== 0) return $this->send(array('result' => 'fail', 'message' => array('url' => array($this->lang->gitlab->hostError))));
if(!$token) return $this->send(array('result' => 'fail', 'message' => array('token' => array($this->lang->gitlab->tokenError))));
$user = $this->gitlab->apiGetCurrentUser($gitlabURL, $token);
if(!is_object($user)) return $this->send(array('result' => 'fail', 'message' => array('url' => array($this->lang->gitlab->hostError))));
if(!isset($user->is_admin) or !$user->is_admin) return $this->send(array('result' => 'fail', 'message' => array('token' => array($this->lang->gitlab->tokenError))));
@@ -256,6 +259,11 @@ class gitlab extends control
$gitlabID = $repo->gitlab;
$projectID = $repo->project;
$gitlab = $this->gitlab->getByID($gitlabID);
$user = $this->gitlab->apiGetCurrentUser($gitlab->url, $gitlab->token);
if(!isset($user->is_admin) or !$user->is_admin) die(js::alert($this->lang->gitlab->tokenLimit) . js::locate($this->createLink('gitlab', 'edit', array('gitlabID' => $gitlabID))));
if($_POST)
{
$executionList = $this->post->executionList;
+1
View File
@@ -40,6 +40,7 @@ $lang->gitlab->placeholder->token = "Please fill in the access token of an accou
$lang->gitlab->noImportableIssues = "There are currently no issues available for import.";
$lang->gitlab->tokenError = "The current token is not admin rights.";
$lang->gitlab->tokenLimit = "The current token has no admin privilege. Please regenerate one with admin user in GitLab.";
$lang->gitlab->hostError = "Invalid GitLab service address.";
$lang->gitlab->bindUserError = "Can not bind users repeatedly %s";
$lang->gitlab->importIssueError = "The execution to which this issue belongs is not selected.";
+6 -3
View File
@@ -5,8 +5,11 @@ table+table {border-top: 1px solid #eee;}
.row td {width: 33%; text-align: left; font-weight: 700;}
.main-actions {margin: 5px 0 10px 0; text-align: center;}
.user-title {margin: 10px 10px -10px 10px; font-size: 14px; font-weight: bold; padding-left: 10px;}
.avatar {display: inline-block; width: 50px; height: 50px; line-height: 50px;}
#avatarForm {width: 100%; height: 100%;}
.avatar .btn-avatar {padding: 0; vertical-align: revert; border: 0; background-color: auto; color: #fff; font-size: 20px;}
.user-name {margin-left: 15px; font-weight: bold;}
.user-name, .user-role {line-height: 50px; font-size: 16px; vertical-align: top;}
#avatarUpload {display: inline-block; width: 50px; height: 50px; position: relative;}
#avatarForm {position: absolute; top: 0; left: 0; right: 0; bottom: 0;}
#avatarUploadBtn {display: block; position: absolute; top: 0; left: 0; right: 0; bottom: 0;}
#avatarUploadBtn {opacity: 0; color: #fff; border-radius: 50%; line-height: 50px;}
#avatarUploadBtn:hover {opacity: 1; background-color: rgba(0,0,0,.5);}
+2
View File
@@ -22,6 +22,8 @@ $(document).ready(function()
window.parent.$('#main-avatar, #menu-avatar').html('<img src="' + avatar + '"/>');
window.parent.$('#mainContent>.cell>.main-header>.avatar').html('<img src="' + avatar + '"/>');
window.parent.$('#mainContent .avatar-' + account).html('<img src="' + avatar + '"/>');
$('#avatarUploadBtn').tooltip();
});
function uploadAvatar()
+1 -1
View File
@@ -29,7 +29,7 @@
</p>
</div>
<?php else:?>
<form class='main-table' id='projectForm' method='post' data-ride='table' data-checkable='false'>
<form id='projectForm' method='post' data-ride='table' data-checkable='false'>
<table class='table table-fixed' id='docList'>
<thead>
<tr>
+4 -4
View File
@@ -16,13 +16,13 @@
<div id='mainContent'>
<div class='cell'>
<div class='main-header text-center'>
<span class="avatar avatar bg-secondary avatar-circle">
<div id="avatarUpload">
<?php echo html::avatar($user, 50); ?>
<form method='post' class='form-ajax' action=<?php echo inlink('uploadAvatar');?> id='avatarForm' enctype='multipart/form-data'>
<input type="file" name="files" id="files" class="form-control hidden">
<?php $avatar = $user->avatar ? html::image($user->avatar) : strtoupper($user->account[0]);?>
<?php echo html::a('javascript:void(0);', $avatar, '', "class='btn-avatar' id='avatarUploadBtn' data-placement='right'");?>
<?php echo html::a('javascript:void(0);', '<i class="icon icon-pencil icon-2x"></i>', '', "class='btn-avatar' id='avatarUploadBtn' data-toggle='tooltip' data-container='body' data-placement='bottom' title='{$lang->my->uploadAvatar}'");?>
</form>
</span>
</div>
<span class='user-name'><?php echo $user->realname;?></span>
<span class='user-role'><?php echo zget($lang->user->roleList, $user->role, '');?></span>
</div>
+2
View File
@@ -76,6 +76,7 @@ class pipelineModel extends model
->add('private',md5(rand(10,113450)))
->add('createdBy', $this->app->user->account)
->add('createdDate', helper::now())
->trim('token')
->skipSpecial('url,token,account,password')
->get();
if($type == 'gitlab') $pipeline->url = rtrim($pipeline->url, '/');
@@ -104,6 +105,7 @@ class pipelineModel extends model
$pipeline = fixer::input('post')
->add('editedBy', $this->app->user->account)
->add('editedDate', helper::now())
->trim('token')
->skipSpecial('url,token,account,password')
->get();
+3 -5
View File
@@ -13,7 +13,7 @@
<th class='text-right w-100px'><?php common::printOrderLink('budget', $orderBy, $vars, $lang->project->budget);?></th>
<th class='w-100px'><?php common::printOrderLink('begin', $orderBy, $vars, $lang->project->begin);?></th>
<th class='w-100px'><?php common::printOrderLink('end', $orderBy, $vars, $lang->project->end);?></th>
<th class='w-70px'><?php echo $lang->project->progress;?></th>
<th class='w-60px'><?php echo $lang->project->progress;?></th>
<th class='text-center w-180px'><?php echo $lang->actions;?></th>
</tr>
</thead>
@@ -62,9 +62,7 @@
<td class='c-status'><span class="status-program status-<?php echo $program->status?>"><?php echo zget($lang->project->statusList, $program->status, '');?></span></td>
<td>
<?php if(!empty($program->PM)):?>
<div class="avatar bg-secondary avatar-circle avatar-<?php echo $program->PM;?>">
<?php echo !empty($usersAvatar[$program->PM]) ? html::image($usersAvatar[$program->PM]) : strtoupper($program->PM[0]);?>
</div>
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$program->PM], 'account' => $program->PM)); ?>
<?php $userID = isset($PMList[$program->PM]) ? $PMList[$program->PM]->id : '';?>
<?php $userName = zget($users, $program->PM);?>
<?php echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");?>
@@ -76,7 +74,7 @@
<td><?php echo $program->end == LONG_TIME ? $lang->program->longTime : $program->end;?></td>
<td>
<?php if(isset($progressList[$program->id])):?>
<div class='progress-pie' data-doughnut-size='90' data-color='#3CB371' data-value='<?php echo $progressList[$program->id]?>' data-width='24' data-height='24' data-back-color='#e8edf3'>
<div class='progress-pie' data-doughnut-size='85' data-color='#00DA88' data-value='<?php echo $progressList[$program->id]?>' data-width='26' data-height='26' data-back-color='#e8edf3'>
<div class='progress-info'><?php echo $progressList[$program->id];?></div>
</div>
<?php endif;?>
+41 -41
View File
@@ -29,7 +29,7 @@
#cards .project-infos > span + span {margin-left: 15px;}
#cards .project-infos > .budget {max-width: 75px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#cards .project-detail {position: absolute; top: 75px; left: 16px; right: 16px; font-size: 12px;}
#cards .project-footer {position: absolute; bottom: 5px;}
#cards .project-footer {position: absolute; bottom: 10px; right: 10px; left: 15px;}
#cards .pager {margin: 0; float: right;}
#cards .pager .btn {border: none}
#cards .panel .label-wait {background: #EFEFEF !important; color: #838A9D;}
@@ -40,16 +40,18 @@
#cards .project-infos .text-red {color: #F85A40 !important;}
#cards .project-detail .progress-pie {width: 24px; position: absolute; top: 18px;}
#cards .project-detail .leftTasks, .totalLeft {display:block; margin-top: 8px;}
#cards .project-members {float: left;}
#cards .project-members .avatar {display: inline-block; width: 25px; height: 25px; line-height: 25px; margin-right: 1px;}
#cards .project-members a:not(:first-child) {margin-left: -5px;}
#cards .totalMembers{display: inline-block; margin-left: 6px; position: absolute; bottom: 8px;}
#cards .project-actions {float: right;}
#cards .project-actions .menu-actions {padding-right: 20px;}
#cards .project-actions ul {min-width: 35px; padding: 5px 6px;}
#cards .project-actions .dropdown-hover:hover>.dropdown-menu ul,
#cards .project-actions .open>.dropdown-menu ul {display: flex;}
#cards .menu-actions .btn.btn-action {margin-bottom: -3px !important; margin-right: 5px;}
#cards .project-members {float: left; height: 24px; line-height: 24px;}
#cards .project-members > a {display: inline-block; height: 24px;}
#cards .project-members > a + a {margin-left: -5px;}
#cards .project-members > a > .avatar {display: inline-block; width: 24px; height: 24px; line-height: 24px; margin-right: 1px;}
#cards .project-members > span {display: inline-block; color: transparent; width: 2px; height: 2px; background-color: #8990a2; position: relative; border-radius: 50%; top: 3px; margin: 0 3px;}
#cards .project-members > span:before,
#cards .project-members > span:after {content: ''; display: block; position: absolute; width: 2px; height: 2px; background-color: #8990a2; top: 0; border-radius: 50%}
#cards .project-members > span:before {left: -4px;}
#cards .project-members > span:after {right: -4px;}
#cards .project-members-total {display: inline-block; margin-left: 6px; position: relative; top: 3px}
#cards .project-actions {position: absolute; right: -8px; bottom: -5px; white-space: nowrap;}
#cards .project-actions .dropdown-menu {padding: 5px 6px; top: -5px; right: 30px;}
#cards .icon-ellipsis-v {font-size: 13px;}
#cards .teamTitle {margin-bottom: 30px;}
</style>
@@ -138,41 +140,39 @@
</div>
</div>
</div>
<div class='project-footer table-row'>
<div class='project-footer'>
<?php $titleClass = ($project->teamCount == 0 and !$canActions) ? 'teamTitle' : '';?>
<?php $count = 0;?>
<div class="<?php echo $titleClass?>"><?php echo $lang->project->teamMember;?></div>
<?php if(!empty($project->teamMembers)):?>
<div class='project-members table-col'>
<?php foreach($project->teamMembers as $member):?>
<?php
if($count > 2) continue;
if(!isset($users[$member]))
{
$project->teamCount --;
continue;
}
$count ++;
?>
<a href='<?php echo helper::createLink('project', 'team', "projectID=$projectID");?>' title="<?php echo $users[$member];?>">
<div class="avatar bg-secondary avatar-circle avatar-<?php echo $member;?>">
<?php echo !empty($usersAvatar[$member]) ? html::image(zget($usersAvatar, $member)) : strtoupper($member[0]);?>
</div>
</a>
<?php endforeach;?>
<?php if($project->teamCount > 3):?>
<?php echo '...';?>
<a href='<?php echo helper::createLink('project', 'team', "projectID=$projectID");?>' title="<?php echo $users[$member];?>">
<div class="avatar bg-secondary avatar-circle avatar-<?php echo $member;?>">
<?php echo !empty($usersAvatar[end($project->teamMembers)]) ? html::image(zget($usersAvatar, end($project->teamMembers))) : strtoupper($member[0]);?>
</div>
</a>
<div class="clearfix">
<?php if(!empty($project->teamMembers)):?>
<div class='project-members pull-left'>
<?php foreach($project->teamMembers as $member):?>
<?php
if($count > 2) continue;
if(!isset($users[$member]))
{
$project->teamCount --;
continue;
}
$count ++;
?>
<a href='<?php echo helper::createLink('project', 'team', "projectID=$projectID");?>' title="<?php echo $users[$member];?>">
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$member], 'account' => $member)); ?>
</a>
<?php endforeach;?>
<?php if($project->teamCount > 3):?>
<?php echo '<span>…</span>';?>
<a href='<?php echo helper::createLink('project', 'team', "projectID=$projectID");?>' title="<?php echo $users[$member];?>">
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[end($project->teamMembers)], 'account' => $member)); ?>
</a>
<?php endif;?>
</div>
<?php endif;?>
<div class='project-members-total pull-left'><?php echo html::a(helper::createLink('project', 'team', "projectID=$projectID"), sprintf($lang->project->teamSumCount, $project->teamCount));?></div>
</div>
<?php endif;?>
<span class='totalMembers'><?php echo html::a(helper::createLink('project', 'team', "projectID=$projectID"), sprintf($lang->project->teamSumCount, $project->teamCount));?></span>
<div class='project-actions table-col'>
<div class='menu-actions'>
<div class='project-actions'>
<div class='dropdown'>
<?php if($canActions):?>
<?php echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");?>
<ul class='dropdown-menu pull-right'>
+1 -2
View File
@@ -1234,8 +1234,7 @@ class userModel extends model
if(!$uploadResult) return array('result' => 'fail', 'message' => $this->lang->fail);
$fileIdList = array_keys($uploadResult);
$file = $this->file->getByID($fileIdList[0]);
$this->dao->update(TABLE_USER)->set('avatar')->eq($file->webPath)->where('account')->eq($this->app->user->account)->exec();
$file = $this->file->getByID($fileIdList[0]);
return array('result' => 'success', 'message' => '', 'locate' => helper::createLink('user', 'cropavatar', "image={$file->id}"));
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.
Binary file not shown.