Merge branch release/21.7.6 of zentao/zentaopms (#11480)

This commit is contained in:
刘刚
2025-09-15 14:50:57 +08:00
committed by Gitfox
91 changed files with 1472 additions and 158 deletions
+10 -9
View File
@@ -787,12 +787,13 @@ $config->featureGroup->waterfallplus = array();
$config->featureGroup->assetlib = array();
$config->featureGroup->other = array('devops', 'kanban', 'setCode');
$config->db->sqliteBlacklist = array('sqlite_queue', 'cron');
$config->hasDropmenuApps = array('program', 'project', 'product', 'execution', 'qa', 'admin', 'bi', 'feedback', 'demandpool');
$config->hasBranchMenuModules = array('product', 'story', 'release', 'bug', 'testcase', 'testtask', 'branch', 'tree');
$config->excludeBranchMenu = array('product-dashboard', 'product-view', 'product-whitelist', 'product-addwhitelist', 'branch-manage', 'branch-batchedit');
$config->excludeDropmenuList = array('program-browse', 'program-productview', 'program-kanban', 'product-all', 'product-index', 'product-kanban', 'project-kanban', 'execution-all', 'execution-executionkanban', 'project-browse', 'project-template', 'project-createtemplate', 'project-batchedit', 'product-batchedit', 'admin-index', 'product-create', 'project-create', 'execution-create', 'program-create', 'execution-batchedit', 'metric-preview', 'metric-browse', 'metric-view', 'metriclib-browse', 'qa-index', 'caselib-create', 'feedback-batchedit', 'feedback-batchclose', 'feedback-showimport', 'dimension-browse', 'dataview-browse', 'dataview-create', 'dataview-query', 'ticket-batchedit', 'ticket-batchfinish', 'ticket-batchactivate', 'file-download');
$config->hasSwitcherModules = array('design');
$config->hasSwitcherMethods = array('project-bug', 'project-testcase', 'execution-bug', 'execution-testcase', 'testtask-cases', 'testtask-view', 'testtask-report', 'testtask-groupcase', 'testtask-linkcase');
$config->excludeSwitcherList = array();
$config->hasMainNavBar = array();
$config->db->sqliteBlacklist = array('sqlite_queue', 'cron');
$config->hasDropmenuApps = array('program', 'project', 'product', 'execution', 'qa', 'admin', 'bi', 'feedback', 'demandpool');
$config->hasBranchMenuModules = array('product', 'story', 'release', 'bug', 'testcase', 'testtask', 'branch', 'tree');
$config->excludeBranchMenu = array('product-dashboard', 'product-view', 'product-whitelist', 'product-addwhitelist', 'branch-manage', 'branch-batchedit');
$config->excludeDropmenuList = array('program-browse', 'program-productview', 'program-kanban', 'product-all', 'product-index', 'product-kanban', 'project-kanban', 'execution-all', 'execution-executionkanban', 'project-browse', 'project-template', 'project-createtemplate', 'project-batchedit', 'product-batchedit', 'admin-index', 'product-create', 'project-create', 'execution-create', 'program-create', 'execution-batchedit', 'metric-preview', 'metric-browse', 'metric-view', 'metriclib-browse', 'qa-index', 'caselib-create', 'feedback-batchedit', 'feedback-batchclose', 'feedback-showimport', 'dimension-browse', 'dataview-browse', 'dataview-create', 'dataview-query', 'ticket-batchedit', 'ticket-batchfinish', 'ticket-batchactivate', 'file-download');
$config->excludeDropmenuModules = array('reporttemplate');
$config->hasSwitcherModules = array('design');
$config->hasSwitcherMethods = array('project-bug', 'project-testcase', 'execution-bug', 'execution-testcase', 'testtask-cases', 'testtask-view', 'testtask-report', 'testtask-groupcase', 'testtask-linkcase');
$config->excludeSwitcherList = array();
$config->hasMainNavBar = array();
+10
View File
@@ -0,0 +1,10 @@
ALTER TABLE `zt_doc` ADD `cycle` char(10) COLLATE 'utf8mb4_general_ci' NOT NULL DEFAULT '' AFTER `chapterType`;
ALTER TABLE `zt_doc` ADD `objects` text COLLATE 'utf8mb4_general_ci' NULL AFTER `templateDesc`;
ALTER TABLE `zt_doc` ADD `cycleConfig` text COLLATE 'utf8mb4_general_ci' NULL AFTER `cycle`;
ALTER TABLE `zt_doc` ADD `weeklyDate` char(8) COLLATE 'utf8mb4_general_ci' NOT NULL DEFAULT '' AFTER `collects`;
CREATE INDEX `templateType` ON `zt_doc`(`templateType`);
DELETE FROM `zt_cron` WHERE `command`='moduleName=weekly&methodName=computeWeekly' AND `type`='zentao';
DELETE FROM `zt_cron` WHERE `command`='moduleName=weekly&methodName=createCycleReport' AND `type`='zentao';
INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`) VALUES('1','0','*','*','*','moduleName=weekly&methodName=createCycleReport','定时生成报告','zentao',1,'normal');
+9 -4
View File
@@ -810,7 +810,10 @@ CREATE TABLE IF NOT EXISTS `zt_doc` (
`template` varchar(30) NOT NULL DEFAULT '',
`templateType` varchar(30) NOT NULL DEFAULT '',
`templateDesc` text NULL,
`objects` text NULL,
`chapterType` varchar(30) NOT NULL DEFAULT '',
`cycle` char(10) NOT NULL DEFAULT '',
`cycleConfig` text NULL,
`module` varchar(30) NOT NULL DEFAULT '',
`title` varchar(255) NOT NULL DEFAULT '',
`keywords` varchar(255) NOT NULL DEFAULT '',
@@ -827,6 +830,7 @@ CREATE TABLE IF NOT EXISTS `zt_doc` (
`fromVersion` smallint(6) NOT NULL DEFAULT '1',
`draft` longtext NULL,
`collects` smallint(6) unsigned NOT NULL DEFAULT '0',
`weeklyDate` char(8) NOT NULL DEFAULT '',
`addedBy` varchar(30) NOT NULL DEFAULT '',
`addedDate` datetime NULL,
`assignedTo` varchar(30) NOT NULL DEFAULT '',
@@ -847,9 +851,10 @@ CREATE TABLE IF NOT EXISTS `zt_doc` (
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE INDEX `product` ON `zt_doc`(`product`);
CREATE INDEX `execution` ON `zt_doc`(`execution`);
CREATE INDEX `lib` ON `zt_doc`(`lib`);
CREATE INDEX `product` ON `zt_doc`(`product`);
CREATE INDEX `execution` ON `zt_doc`(`execution`);
CREATE INDEX `lib` ON `zt_doc`(`lib`);
CREATE INDEX `templateType` ON `zt_doc`(`templateType`);
-- DROP TABLE IF EXISTS `zt_docaction`;
CREATE TABLE IF NOT EXISTS `zt_docaction` (
@@ -15491,7 +15496,7 @@ REPLACE INTO `zt_zoutput` (`id`, `activity`, `name`, `content`, `optional`, `tai
(494, 329, '《量化项目计划及跟踪表》', '', 'no', '', '', 'admin', '2020-01-09 14:59:04', '', NULL, 630, '0');
REPLACE INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`) VALUES
('1','0','*','*','*','moduleName=weekly&methodName=computeWeekly','更新项目周报','zentao',0,'normal');
('1','0','*','*','*','moduleName=weekly&methodName=createCycleReport','定时生成报告','zentao',1,'normal');
-- DROP TABLE IF EXISTS `zt_pivot`;
CREATE TABLE IF NOT EXISTS `zt_pivot` (
+1 -1
View File
@@ -509,7 +509,7 @@ function initPageEntity(object $object): array
* @access public
* @return array
*/
function initTableData(array $items, array &$fieldList, ?object $model = null, string $moduleName = ''): array
function initTableData(array $items, array &$fieldList, ?object $model = null): array
{
if(!empty($_GET['orderBy']) && strpos($_GET['orderBy'], '-') !== false) list($orderField, $orderValue) = explode('_', $_GET['orderBy']);
if(!empty($orderField) && !empty($orderValue) && !empty($fieldList[$orderField]))
+35
View File
@@ -125,6 +125,24 @@ class date
return substr($time, 0, 2) . ':' . substr($time, 2, 2);
}
/**
* Get the begin and end date of next week.
*
* @access public
* @return array
*/
public static function getNextWeek()
{
$weekDay = date('N');
$baseTime = time() + 86400 * 7;
if($weekDay == 1) $baseTime = time() + 86400;
if($weekDay == 7) $baseTime = time() - 86400;
$begin = date(DT_DATE1, strtotime('last monday', $baseTime)) . ' 00:00:00';
$end = date(DT_DATE1, strtotime('next sunday', $baseTime)) . ' 23:59:59';
return array('begin' => $begin, 'end' => $end);
}
/**
* Get the begin and end date of this week.
*
@@ -186,6 +204,23 @@ class date
return $baseTime;
}
/**
* Get begin and end time of next month.
*
* @access public
* @return array
*/
public static function getNextMonth()
{
$thisYear = date('Y');
$thisMonth = date('m');
$year = $thisMonth == 12 ? $thisYear + 1 : $thisYear;
$month = $thisMonth == 12 ? 1 : $thisMonth + 1;
$begin = "{$year}-{$month}-01 00:00:00";
$end = date("{$year}-{$month}-t 23:59:59", strtotime($begin));
return array('begin' => $begin, 'end' => $end);
}
/**
* Get begin and end time of this month.
*
+1
View File
@@ -107,6 +107,7 @@ function productMenu(): productMenu {return createWg('productMenu', func_get_arg
function moduleMenu(): moduleMenu {return createWg('moduleMenu', func_get_args());}
function docMenu(): docMenu {return createWg('docMenu', func_get_args());}
function docApp(): docApp {return createWg('docApp', func_get_args());}
function docViewer(): docViewer {return createWg('docViewer', func_get_args());}
function tree(): Tree {return createWg('tree', func_get_args());}
function treeEditor(): TreeEditor {return createWg('treeEditor', func_get_args());}
function fileList(): fileList {return createWg('fileList', func_get_args());}
+7 -4
View File
@@ -12,9 +12,12 @@ renderContactList = function()
const link = $.createLink('user', 'ajaxGetContactList');
$.getJSON(link, function(contacts)
{
$('#contactBox').addClass('p-0 w-24 input-group-addon').removeClass('input-group-btn');
$('#contactBox #manageContact').addClass('hidden');
$('#contactBox .picker-box').removeClass('hidden').zui('picker').render({items: contacts});
$('.contactBox').addClass('p-0 w-24 input-group-addon').removeClass('input-group-btn');
$('.contactBox #manageContact').addClass('hidden');
$('.contactBox .picker-box').each(function()
{
$(this).removeClass('hidden').zui('picker').render({items: contacts});
});
});
}
@@ -36,7 +39,7 @@ window.loadContactUsers = function(target)
return;
}
const $target = target ? $("[name^='" + target + "']") : $(picker).closest('#contactBox').prev();
const $target = target ? $("[name^='" + target + "']") : $(picker).closest('.contactBox').prev();
const $targetPicker = $target.zui('picker');
if($targetPicker === undefined)
{
+2 -2
View File
@@ -55,8 +55,8 @@ class contactList extends wg
return span
(
setID('contactBox'),
setClass('w-auto input-group-' . ($items ? 'addon p-0 w-24' : 'btn')),
setID('contactList'),
setClass('contactBox w-auto input-group-' . ($items ? 'addon p-0 w-24' : 'btn')),
picker
(
$items ? null : setClass('hidden'),
+2
View File
@@ -29,3 +29,5 @@
.dropdown-menu .divider + .divider {display: none;}
.dropmenu-item .tree-item-inner[data-type="lib"] {padding-left: 8px;}
.doc-app .doc-editor-title {overflow: hidden; text-overflow: clip; white-space: nowrap;}
+9 -7
View File
@@ -155,7 +155,8 @@ window.getDocApp = function()
{
if(!currentDocApp)
{
const docApp = $('#docApp').data('zui.DocApp');
const $docApp = $('#docApp');
const docApp = $docApp.data('zui.DocApp') || $docApp.data('zui.DocViewer');
currentDocApp = docApp ? docApp.$ : null;
}
return currentDocApp;
@@ -951,11 +952,12 @@ const actionsMap =
}
const isToolbar = info.ui === 'toolbar';
const isInModal = $(this.element).closest('.modal').length;
const actions = isInModal ? [] : [
isToolbar ? {hint: docApp.fullscreen ? lang.exitFullscreen : lang.enterFullscreen, icon: docApp.fullscreen ? 'fullscreen-exit' : 'fullscreen', command: 'toggleFullscreen'} : null,
canEditDoc ? {icon: 'edit', class: doc.editable ? null : 'disabled', type: doc.editable ? 'ghost text-primary' : 'ghost text-gray', hint: doc.editable ? lang.edit : lang.needEditable, rounded: 'lg', command: doc.editable ? 'startEditDoc' : null} : null,
(isToolbar && docApp.props.showDocOutline !== false) ? {hint: lang.docOutline, icon: 'list-box', command: 'toggleViewSideTab/outline'} : null,
(isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'history', command: 'toggleViewSideTab/history'} : null,
(isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'file-log', command: 'toggleViewSideTab/history'} : null,
moreItems.length ? {icon: 'icon-ellipsis-v', type: 'dropdown', rounded: 'lg', placement: 'bottom-end', caret: false, items: moreItems} : null,
];
@@ -1161,7 +1163,7 @@ const actionsMap =
return [
isToolbar ? {hint: docApp.fullscreen ? lang.exitFullscreen : lang.enterFullscreen, icon: docApp.fullscreen ? 'fullscreen-exit' : 'fullscreen', command: 'toggleFullscreen'} : null,
(isToolbar && docApp.props.showDocOutline !== false) ? {hint: lang.docOutline, icon: 'list-box', command: 'toggleViewSideTab/outline'} : null,
(isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'history', command: 'toggleViewSideTab/history'} : null,
(isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'file-log', command: 'toggleViewSideTab/history'} : null,
doc.status === 'draft' ? {text: lang.saveDraft, size: 'md', className: 'btn-wide', type: 'secondary', command: 'saveDoc/draft'} : null,
{text: lang.release, size: 'md', className: 'btn-wide', type: 'primary', command: 'saveDoc'},
{text: lang.cancel, size: 'md', className: 'btn-wide', type: 'primary-outline', command: 'cancelEditDoc'},
@@ -2226,7 +2228,7 @@ window.getDocViewSidebarTabs = function(doc, info)
return [
{key: 'info', icon: 'info', title: lang.docInfo},
info.mode === 'edit' ? null : {key: 'outline', icon: 'list-box', title: lang.docOutline},
{key: 'history', icon: 'history', title: lang.history},
{key: 'history', icon: 'file-log', title: lang.history},
].filter(Boolean);
}
@@ -2240,7 +2242,7 @@ window.getDocViewSidebarTabs = function(doc, info)
{
tabList.push(
{key: 'outline', icon: 'list-box', title: getLang('docOutline')},
{key: 'history', icon: 'history', title: getLang('history')}
{key: 'history', icon: 'file-log', title: getLang('history')}
);
}
@@ -2322,7 +2324,7 @@ window.setDocAppOptions = function(_, options)
canMoveDoc : canMoveDoc,
onSwitchView : handleSwitchView,
getActions : getActions,
getTableOptions : getTableOptions,
getTableOptions : options.docViewer ? null : getTableOptions,
getFilterTypes : getFilterTypes,
isMatchFilter : isMatchFilter,
getSortableOptions : getSortableOptions,
@@ -2369,7 +2371,7 @@ window.getFileActions = function(file)
window.useHocuspocus = function(app)
{
if(vision !== 'rnd') return false;
if(config.vision !== 'rnd') return false;
return enableHocuspocus && app.spaceType !== 'mine';
};
+6 -3
View File
@@ -44,6 +44,7 @@ class docApp extends wg
'userMap' => '?array', // 用户映射定义。
'currentUser' => '?string', // 当前用户。
'historyFetcher' => '?string|array|object', // 历史记录数据获取 URL 或回调函数。
'historyPanel' => '?string|array|object', // 历史记录面板。
'uploadUrl' => '?string', // 上传文件 URL。
'downloadUrl' => '?string', // 下载文件 URL。
'privs' => '?array', // 权限定义。
@@ -111,8 +112,8 @@ class docApp extends wg
{
$priv = isset($subMenu['priv']) ? $subMenu['priv'] : null;
if($priv && isset($privs[$priv]) && !$privs[$priv]) continue;
if($subMenu['key'] == 'ER' && !$config->enableER) continue;
if($subMenu['key'] == 'UR' && !$config->URAndSR) continue;
if($subMenu['key'] == 'ER' && !$config->enableER) continue;
if($subMenu['key'] == 'UR' && !$config->URAndSR) continue;
$subMenus[] = $subMenu;
}
@@ -317,8 +318,10 @@ class docApp extends wg
$fileUrl = '';
}
$historyPanelProps = array('fileListProps' => $fileListProps);
$canPreviewOffice = $canDownload && isset($config->file->libreOfficeTurnon) and $config->file->libreOfficeTurnon == 1;
$historyPanelProps = $this->prop('historyPanel');
if(empty($historyPanelProps)) $historyPanelProps = array();
if(is_array($historyPanelProps)) $historyPanelProps['fileListProps'] = $fileListProps;
/* 对比不可用场景:文档模板、API 文档、开源版 */
$diffEnabled = ($config->edition != 'open')
+44
View File
@@ -0,0 +1,44 @@
/**
* 处理保存文档的操作请求,向服务器发送请求并返回保存的文档对象。
* Handle the save doc operation request, send a request to the server and return the saved doc object.
*/
function handleSaveDoc(doc)
{
const docApp = getDocApp();
if(docApp.isSavingDoc) return;
docApp.isSavingDoc = true;
const url = $.createLink('weekly', 'edit', `reportID=${doc.id}`);
const docData = {
rawContent : doc.content,
status : doc.status || 'normal',
contentType: doc.contentType,
type : 'text',
title : doc.title,
keywords : doc.keywords,
content : doc.html,
uid : (doc.uid || `doc${doc.id}`),
};
if(doc.fromVersion) docData.fromVersion = doc.fromVersion;
return new Promise((resolve, reject) => {
$.ajaxSubmit({'url': url, 'data': docData, 'load': false, 'onComplete': function(result)
{
docApp.isSavingDoc = false;
resolve(result.newDoc);
docApp.cancelEditDoc();
}});
});
}
window._setDocViwerOptions = window.setDocAppOptions;
window.setDocAppOptions = function(_, options)
{
options = window._setDocViwerOptions(_, options);
return $.extend(options,
{
onSaveDoc: handleSaveDoc
});
};
+169
View File
@@ -0,0 +1,169 @@
<?php
declare(strict_types=1);
/**
* The docApp widget class file of zin module of ZenTaoPMS.
*
* @copyright Copyright 2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Hao Sun <sunhao@easycorp.ltd>
* @package zin
* @link http://www.zentao.net
*/
namespace zin;
class docViewer extends wg
{
protected static array $defineProps = array
(
'doc' => 'array|string|int'
);
public static function getPageJS(): ?string
{
$docAppJS = file_get_contents(dirname(__DIR__) . DS . 'docapp' . DS . 'js' . DS . 'v1.js');
$appendJS = file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
return $docAppJS . js::scope($appendJS);
}
public static function getPageCSS(): ?string
{
return file_get_contents(dirname(__DIR__) . DS . 'docapp' . DS . 'css' . DS . 'v1.css');
}
protected function build()
{
global $app, $lang, $config;
/**
* 定义文档应用接口链接。
* Define the fetcher links for doc app.
*/
$docFetcher = createLink('doc', 'ajaxGetDoc', 'docID={docID}&version={version}');
$uploadUrl = createLink('file', 'ajaxUpload', 'uid={uid}&objectType={objectType}&objectID={objectID}&extra={extra}&field={field}&api={api}&gid={gid}');
$downloadUrl = createLink('file', 'ajaxQuery', 'fileID={gid}&objectType={objectType}&objectID={objectID}&title={title}&extra={extra}');
$fileInfoUrl = createLink('file', 'ajaxQuery', 'fileID={gid}&objectType={objectType}&objectID={objectID}&title={title}&extra={extra}', 'json');
/**
* 定义文档界面上的文件下载链接。
* Define the file download link for doc app.
*/
$sessionStr = session_name() . '=' . session_id();
$fileUrl = $this->prop('fileUrl');
if(empty($fileUrl))
{
$fileUrl = createLink('file', 'download', 'fileID={id}');
$fileUrl .= strpos($fileUrl, '?') === false ? '?' : '&';
$fileUrl .= $sessionStr;
}
/**
* Setting language data for frontend. Use getLang('xxx') in js/app.ui.js.
* 设置前端语言数据。 在 js/app.ui.js 中使用 getLang('xxx') 来访问语言数据。
*/
$app->loadLang('file');
$app->loadLang('api');
$langData = $lang->doc->docLang;
$langData->filePreview = $lang->file->preview;
$langData->fileDownload = $lang->file->download;
$langData->fileDelete = $lang->file->delete;
$langData->fileRename = $lang->file->edit;
$langData->fileConfirmDelete = $lang->file->confirmDelete;
$langData->deleted = $lang->file->deleted;
$langData->createApi = $lang->api->createApi;
$langData->apifilterTypes = $lang->api->filterTypes;
$langData->module = $lang->api->module;
$langData->struct = $lang->api->struct;
$langData->releases = $lang->api->releases;
$langData->noApi = $lang->api->noApi;
$langData->version = $lang->api->version;
$langData->defaultVersion = $lang->api->defaultVersion;
$langData->createStruct = $lang->api->createStruct;
$langData->createRelease = $lang->api->createRelease;
$langData->libTypeList = $lang->api->libTypeList;
$langData->latestVersion = $lang->api->latestVersion;
$langData->template = $lang->doc->template;
/**
* 合并语言数据。
* Merge the language data.
*/
if($this->hasProp('langData')) $langData = array_merge((array)$langData, (array)$this->prop('langData'));
/**
* 界面模式 URL 格式化模版。
* URL format for view mode change.
*/
$viewModeUrl = $this->prop('viewModeUrl');
if(!$this->hasProp('viewModeUrl'))
{
$viewModeUrl = createLink($app->rawModule, '{mode}', 'docID={docID}');
}
$hasZentaoSlashMenu = $this->prop('hasZentaoSlashMenu');
if($hasZentaoSlashMenu === null ) $hasZentaoSlashMenu = true;
$app->control->loadModel('file');
$canDownload = common::hasPriv('file', 'download');
$fileListProps = array();
if($canDownload)
{
$previewLink = helper::createLink('file', 'download', "fileID={id}&mouse=left");
jsVar('previewLang', $lang->file->preview);
jsVar('downloadLang', $lang->file->download);
jsVar('previewLink', $previewLink);
jsVar('downloadLink', $fileUrl);
jsVar('libreOfficeTurnon', isset($config->file->libreOfficeTurnon) && $config->file->libreOfficeTurnon == 1);
$fileListProps['fileUrl'] = $fileUrl;
$fileListProps['target'] = '_blank';
$fileListProps['hoverItemActions'] = true;
$fileListProps['itemProps'] = array('target' => '_blank');
$fileListProps['fileActions'] = jsCallback('file')->do('return getFileActions(file)');
}
else
{
$fileUrl = '';
}
$canPreviewOffice = $canDownload && isset($config->file->libreOfficeTurnon) and $config->file->libreOfficeTurnon == 1;
$historyPanelProps = $this->prop('historyPanel');
if(empty($historyPanelProps)) $historyPanelProps = array();
if(is_array($historyPanelProps)) $historyPanelProps['fileListProps'] = $fileListProps;
return zui::docViewer
(
set::_class('shadow rounded ring canvas'),
set::_style(array('height' => 'calc(100vh - 72px)')),
set::_id('docApp'),
set::docViewer(true),
set::token(session_id()),
set::awarenessUser(array('id' => $app->user->id, 'account' => $app->user->account, 'name' => $app->user->realname, 'avatar' => $app->user->avatar)),
set::onModeChange(jsRaw('window.onDocAppModeChange')),
set::width('100%'),
set::height('100%'),
set::userMap(data('users')),
set::currentUser($app->user->account),
set::privs(array()),
set::uploadUrl($uploadUrl),
set::downloadUrl($downloadUrl),
set::sessionStr($sessionStr),
set::fileUrl($fileUrl),
set::viewModeUrl($viewModeUrl),
set::langData($langData),
set::historyPanel($historyPanelProps),
set::showToolbar(true),
set::canPreviewOffice($canPreviewOffice),
set::fileInfoUrl($fileInfoUrl),
set::getTableOptions(null),
set::mode('view'),
set::noSidebar(true),
set::noSpace('hidden'),
set::homeName(false),
set::noDocSwitcher(true),
set('$options', jsRaw('window.setDocAppOptions')),
set($this->props)
);
}
}
+6 -3
View File
@@ -94,8 +94,9 @@ class featureBar extends wg
$subItem['text'] = $text;
$subItem['active'] = $rawItem->name == 'QUERY' ? $key == $param : $key == $current;
$subItem['attrs'] = ['data-id' => $key, 'data-load' => $load, 'data-target' => $loadID, 'data-app' => $tab, 'data-success' => "() => zui.updateSearchForm('$searchModule')"];
$subItem['url'] = $isModal ? '#featureBar' : $url;
$isModal ? ($subItem['onClick'] = jsRaw("() => loadModal('{$url}')")) : ($subItem['url'] = $url);
if($isModal) $subItem['onClick'] = jsRaw("() => loadModal('{$url}')");
if($rawItem->name == 'QUERY')
{
@@ -138,9 +139,11 @@ class featureBar extends wg
'active' => $isActive,
'badge' => $isActive && $recTotal != '' ? array('text' => $recTotal, 'class' => 'size-sm canvas ring-0 rounded-md') : null,
'props' => array('data-id' => $rawItem->name, 'data-load' => $load, 'data-target' => $loadID, 'data-app' => $tab, 'title' => $rawItem->text),
'textClass' => 'text-ellipsis max-w-32'
'textClass' => 'text-ellipsis max-w-32',
'url' => $isModal ? '#featureBar' : $url
);
$isModal ? ($item['onClick'] = "loadModal('{$url}')") : ($item['url'] = $url);
if($isModal) $item['onClick'] = "loadModal('{$url}')";
$items[] = $item;
}
+1 -1
View File
@@ -70,7 +70,7 @@ class heading extends wg
$moduleName = $app->rawModule;
$methodName = $app->rawMethod;
if(in_array("$moduleName-$methodName", $config->excludeDropmenuList)) return null;
if(in_array("$moduleName-$methodName", $config->excludeDropmenuList) || in_array($moduleName, $config->excludeDropmenuModules)) return null;
if(in_array($app->tab, $config->hasDropmenuApps))
{
+1
View File
@@ -92,6 +92,7 @@ $config->action->needGetRelateField = ',branch,story,epic,requirement,prod
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,instance,gitea,gogs,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,repo,pivot,scene,boardspace,auditplan,auditresult,productline,chapter,doc,caselib,';
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn';
$config->action->ignoreActions4Dynamic = 'disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan,editmr,removemr,syncdoingbyticket,syncdoingbystory,syncdoingbyuserstory,syncdoingbyepic,syncdoingbytask,syncdoingbybug,syncdoingbytodo,syncdoingbydemand';
if(in_array($config->edition, array('open', 'biz'))) $config->action->ignoreObjectType4Dynamic .= ',reporttemplate';
$config->action->latestDateList = array('today', 'yesterday', 'thisWeek', 'lastWeek', 'thisMonth');
+1 -1
View File
@@ -127,7 +127,7 @@ class actionModel extends model
$this->file->updateObjectID($uid, $objectID, $objectType);
$this->loadModel('message')->send(strtolower($objectType), $objectID, $actionType, $actionID, $actor, $extra);
if(empty($this->app->installing) && empty($this->app->upgrading)) $this->loadModel('message')->send(strtolower($objectType), $objectID, $actionType, $actionID, $actor, $extra);
$this->saveIndex($objectType, $objectID, $actionType);
+1 -1
View File
@@ -207,7 +207,7 @@ function getDocViewSidebarTabs(doc, info)
return [
{key: 'info', icon: 'info', title: lang.docInfo},
info.mode === 'edit' ? null : {key: 'outline', icon: 'list-box', title: lang.docOutline},
{key: 'history', icon: 'history', title: lang.history},
{key: 'history', icon: 'file-log', title: lang.history},
].filter(Boolean);
}
+1
View File
@@ -652,6 +652,7 @@ $lang->datepicker->dpText->TEXT_THIS_WEEK = 'Diese Woche';
$lang->datepicker->dpText->TEXT_TODAY = 'Heute';
$lang->datepicker->dpText->TEXT_NEXT_YEAR = 'Nächstes Jahr';
$lang->datepicker->dpText->TEXT_NEXT_MONTH = 'Nächsten Monat';
$lang->datepicker->dpText->TEXT_NEXT_WEEK = 'Next Week';
$lang->datepicker->dpText->TEXT_CLOSE = 'Schließen';
$lang->datepicker->dpText->TEXT_DATE = 'Zeit wählen';
$lang->datepicker->dpText->TEXT_CHOOSE_DATE = 'Datum wählen';
+1
View File
@@ -652,6 +652,7 @@ $lang->datepicker->dpText->TEXT_THIS_WEEK = 'This Week';
$lang->datepicker->dpText->TEXT_TODAY = 'Today';
$lang->datepicker->dpText->TEXT_NEXT_YEAR = 'Next Year';
$lang->datepicker->dpText->TEXT_NEXT_MONTH = 'Next Month';
$lang->datepicker->dpText->TEXT_NEXT_WEEK = 'Next Week';
$lang->datepicker->dpText->TEXT_CLOSE = 'Close';
$lang->datepicker->dpText->TEXT_DATE = '';
$lang->datepicker->dpText->TEXT_CHOOSE_DATE = 'Choose Date';
+1
View File
@@ -652,6 +652,7 @@ $lang->datepicker->dpText->TEXT_THIS_WEEK = 'Cette Semaine';
$lang->datepicker->dpText->TEXT_TODAY = "Aujourd'hui";
$lang->datepicker->dpText->TEXT_NEXT_YEAR = 'Année Prochaine';
$lang->datepicker->dpText->TEXT_NEXT_MONTH = 'Mois Prochain';
$lang->datepicker->dpText->TEXT_NEXT_WEEK = 'Next Week';
$lang->datepicker->dpText->TEXT_CLOSE = 'Fermer';
$lang->datepicker->dpText->TEXT_DATE = '';
$lang->datepicker->dpText->TEXT_CHOOSE_DATE = 'Choisir une Date';
+6 -6
View File
@@ -254,8 +254,8 @@ $lang->scrum->menuOrder[25] = 'devops';
$lang->scrum->menuOrder[30] = 'doc';
$lang->scrum->menuOrder[35] = 'build';
$lang->scrum->menuOrder[40] = 'release';
$lang->scrum->menuOrder[45] = 'dynamic';
$lang->scrum->menuOrder[55] = 'settings';
$lang->scrum->menuOrder[50] = 'dynamic';
$lang->scrum->menuOrder[60] = 'settings';
$lang->scrum->menu->qa['subMenu'] = new stdclass();
//$lang->scrum->menu->qa['subMenu']->index = array('link' => "$lang->dashboard|project|qa|projectID=%s");
@@ -357,7 +357,7 @@ $lang->kanbanProject->dividerMenu = '';
$lang->kanbanProject->menuOrder = array();
$lang->kanbanProject->menuOrder[5] = 'index';
$lang->kanbanProject->menuOrder[10] = 'build';
$lang->kanbanProject->menuOrder[15] = 'settings';
$lang->kanbanProject->menuOrder[20] = 'settings';
$lang->kanbanProject->menu->settings['subMenu'] = new stdclass();
$lang->kanbanProject->menu->settings['subMenu']->view = array('link' => "$lang->overview|project|view|project=%s", 'alias' => 'edit');
@@ -481,13 +481,13 @@ $lang->project->noMultiple->scrum->menuOrder[35] = 'devops';
$lang->project->noMultiple->scrum->menuOrder[40] = 'doc';
$lang->project->noMultiple->scrum->menuOrder[45] = 'build';
$lang->project->noMultiple->scrum->menuOrder[48] = 'release';
$lang->project->noMultiple->scrum->menuOrder[50] = 'dynamic';
$lang->project->noMultiple->scrum->menuOrder[60] = 'settings';
$lang->project->noMultiple->scrum->menuOrder[55] = 'dynamic';
$lang->project->noMultiple->scrum->menuOrder[65] = 'settings';
$lang->project->noMultiple->kanban->menuOrder[5] = 'kanban';
$lang->project->noMultiple->kanban->menuOrder[10] = 'CFD';
$lang->project->noMultiple->kanban->menuOrder[15] = 'build';
$lang->project->noMultiple->kanban->menuOrder[20] = 'settings';
$lang->project->noMultiple->kanban->menuOrder[25] = 'settings';
/* QA menu.*/
$lang->qa->menu = new stdclass();
+1
View File
@@ -653,6 +653,7 @@ $lang->datepicker->dpText->TEXT_THIS_WEEK = '本周';
$lang->datepicker->dpText->TEXT_TODAY = '今天';
$lang->datepicker->dpText->TEXT_NEXT_YEAR = '明年';
$lang->datepicker->dpText->TEXT_NEXT_MONTH = '下月';
$lang->datepicker->dpText->TEXT_NEXT_WEEK = '下周';
$lang->datepicker->dpText->TEXT_CLOSE = '关闭';
$lang->datepicker->dpText->TEXT_DATE = '选择时间段';
$lang->datepicker->dpText->TEXT_CHOOSE_DATE = '选择日期';
+3 -1
View File
@@ -494,7 +494,9 @@ class commonModel extends model
if(helper::isAjaxRequest())
{
echo json_encode(array('load' => $denyLink));
$isModal = helper::isAjaxRequest('modal');
if($isModal) header("Location: $denyLink");
if(!$isModal) echo json_encode(array('load' => $denyLink));
}
else
{
+1 -1
View File
@@ -57,7 +57,7 @@ $config->compile->dtable->fieldList['createdDate']['hint'] = true;
$config->compile->dtable->fieldList['createdDate']['formatDate'] = 'YYYY-MM-dd hh:mm';
$config->compile->actionList = array();
$config->compile->actionList['logs']['icon'] = 'history';
$config->compile->actionList['logs']['icon'] = 'file-log';
$config->compile->actionList['logs']['text'] = $lang->compile->logs;
$config->compile->actionList['logs']['hint'] = $lang->compile->logs;
$config->compile->actionList['logs']['url'] = 'javascript:openPipelineLog({id})';
+1 -1
View File
@@ -489,7 +489,7 @@ class design extends control
$this->design->unlinkCommit($designID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'load' => inlink('browse', "projectID={$design->project}")));
return $this->send(array('result' => 'success', 'load' => isInModal() ? true : inlink('browse', "projectID={$design->project}")));
}
/**
+11 -2
View File
@@ -166,7 +166,16 @@ class doc extends control
}
$doc = $this->doc->getByID($blockData->doc);
$this->view->isTemplate = !empty($doc->templateType) && $blockData->extra != 'fromReview';
$this->view->isTemplate = !empty($doc->templateType) && !in_array($blockData->extra, array('fromReview', 'fromReport'));
$this->view->fromReport = $blockData->extra == 'fromReport';
$noSupport = false;
if($this->view->fromReport)
{
$project = $this->loadModel('project')->fetchByID((int)$doc->project);
$noSupport = in_array($type, array('HLDS', 'DDS', 'DBDS', 'ADS')) && in_array($project->model, array('scrum', 'agileplus', 'kanban'));
}
$this->view->noSupport = $noSupport;
if($this->view->isTemplate)
{
@@ -181,7 +190,7 @@ class doc extends control
return $this->display();
}
$fromTemplate = $blockData->extra == 'fromTemplate' || $blockData->extra == 'fromReview';
$fromTemplate = in_array($blockData->extra, array('fromTemplate', 'fromReview', 'fromReport'));
if($fromTemplate)
{
$this->view->title = sprintf($this->lang->doc->insertTitle, $this->lang->docTemplate->zentaoList[$type]);
+1 -1
View File
@@ -506,7 +506,7 @@ $.extend(window.docAppActions,
const docApp = this;
return [
isToolbar ? {hint: docApp.fullscreen ? lang.exitFullscreen : lang.enterFullscreen, icon: docApp.fullscreen ? 'fullscreen-exit' : 'fullscreen', command: 'toggleFullscreen'} : null,
(isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'history', command: 'toggleViewSideTab/history'} : null,
(isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'file-log', command: 'toggleViewSideTab/history'} : null,
doc.status === 'draft' ? {text: lang.saveDraft, size: 'md', className: 'btn-wide', type: 'secondary', command: 'saveDoc/draft'} : null,
{text: lang.release, size: 'md', className: 'btn-wide', type: 'primary', command: 'saveDoc'},
{text: lang.cancel, size: 'md', className: 'btn-wide', type: 'primary-outline', command: 'cancelEditDoc'},
+8
View File
@@ -109,6 +109,7 @@ $lang->docTemplate->content = 'Template Text';
$lang->docTemplate->templateDesc = 'Template Desc';
$lang->docTemplate->status = 'Template Status';
$lang->docTemplate->emptyTip = 'There is no system data that conform to this parameter and filtering conditions.';
$lang->docTemplate->emptyDataTip = 'There is no system data that conform to this filtering conditions.';
$lang->docTemplate->previewTip = 'After configuring the parameters, this block will display the corresponding list data according to the filter configuration.';
$lang->docTemplate->confirmDeleteChapterWithSub = "After deleting a chapter, the lower level content of the chapter will be hidden. Are you sure you want to delete the chapter?";
$lang->docTemplate->confirmDeleteTemplateWithSub = "After deleting the template, the lower level content of the template will be hidden. Are you sure you want to delete this template?";
@@ -368,6 +369,7 @@ $lang->doc->zentaoList['caselib'] = 'Case Library' . $lang->testcase->common
$lang->doc->zentaoList['task'] = $lang->task->common;
$lang->doc->zentaoList['bug'] = $lang->bug->common;
$lang->doc->zentaoList['projectBug'] = $lang->projectCommon . $lang->bug->common;
$lang->doc->zentaoList['productBug'] = 'Product Bug';
$lang->doc->zentaoList['planBug'] = 'Plan Bug';
@@ -382,6 +384,11 @@ $lang->doc->zentaoList['feedback'] = 'Feedback';
$lang->doc->zentaoList['ticket'] = 'Ticket';
$lang->doc->zentaoList['gantt'] = 'Gantt Chart';
$lang->doc->zentaoList['HLDS'] = 'Outline Design';
$lang->doc->zentaoList['DDS'] = 'Detailed Design';
$lang->doc->zentaoList['DBDS'] = 'Database Design';
$lang->doc->zentaoList['ADS'] = 'Application Design';
$lang->doc->zentaoAction = array();
$lang->doc->zentaoAction['set'] = 'Setting';
$lang->doc->zentaoAction['delete'] = 'Delete';
@@ -532,6 +539,7 @@ $lang->doc->previewNotAvailable = 'Preview function is not available. Pl
$lang->doc->hocuspocusConnect = 'The collaborative editing service is connected.';
$lang->doc->hocuspocusDisconnect = 'The collaborative editing service is disconnected. Edits will be synchronized after reconnection.';
$lang->doc->docTemplateConvertComment = 'The template has been converted to the new editor format. Switch to version %s to view the template before conversion.';
$lang->doc->noSupportList = "This {$lang->projectCommon} does not support %s.";
$lang->doc->noticeAcl['lib']['product']['default'] = "Users who can access the selected {$lang->productCommon} can access it.";
$lang->doc->noticeAcl['lib']['product']['custom'] = "Users who can access the selected {$lang->productCommon} or users in the whiltelist can access it.";
+8
View File
@@ -109,6 +109,7 @@ $lang->docTemplate->content = 'Template Text';
$lang->docTemplate->templateDesc = 'Template Desc';
$lang->docTemplate->status = 'Template Status';
$lang->docTemplate->emptyTip = 'There is no system data that conform to this parameter and filtering conditions.';
$lang->docTemplate->emptyDataTip = 'There is no system data that conform to this filtering conditions.';
$lang->docTemplate->previewTip = 'After configuring the parameters, this block will display the corresponding list data according to the filter configuration.';
$lang->docTemplate->confirmDeleteChapterWithSub = "After deleting a chapter, the lower level content of the chapter will be hidden. Are you sure you want to delete the chapter?";
$lang->docTemplate->confirmDeleteTemplateWithSub = "After deleting the template, the lower level content of the template will be hidden. Are you sure you want to delete this template?";
@@ -368,6 +369,7 @@ $lang->doc->zentaoList['caselib'] = 'Case Library' . $lang->testcase->common
$lang->doc->zentaoList['task'] = $lang->task->common;
$lang->doc->zentaoList['bug'] = $lang->bug->common;
$lang->doc->zentaoList['projectBug'] = $lang->projectCommon . $lang->bug->common;
$lang->doc->zentaoList['productBug'] = 'Product Bug';
$lang->doc->zentaoList['planBug'] = 'Plan Bug';
@@ -382,6 +384,11 @@ $lang->doc->zentaoList['feedback'] = 'Feedback';
$lang->doc->zentaoList['ticket'] = 'Ticket';
$lang->doc->zentaoList['gantt'] = 'Gantt Chart';
$lang->doc->zentaoList['HLDS'] = 'Outline Design';
$lang->doc->zentaoList['DDS'] = 'Detailed Design';
$lang->doc->zentaoList['DBDS'] = 'Database Design';
$lang->doc->zentaoList['ADS'] = 'Application Design';
$lang->doc->zentaoAction = array();
$lang->doc->zentaoAction['set'] = 'Setting';
$lang->doc->zentaoAction['delete'] = 'Delete';
@@ -532,6 +539,7 @@ $lang->doc->previewNotAvailable = 'Preview function is not available. Pl
$lang->doc->hocuspocusConnect = 'The collaborative editing service is connected.';
$lang->doc->hocuspocusDisconnect = 'The collaborative editing service is disconnected. Edits will be synchronized after reconnection.';
$lang->doc->docTemplateConvertComment = 'The template has been converted to the new editor format. Switch to version %s to view the template before conversion.';
$lang->doc->noSupportList = "This {$lang->projectCommon} does not support %s.";
$lang->doc->noticeAcl['lib']['product']['default'] = "Users who can access the selected {$lang->productCommon} can access it.";
$lang->doc->noticeAcl['lib']['product']['custom'] = "Users who can access the selected {$lang->productCommon} or users in the whiltelist can access it.";
+8
View File
@@ -109,6 +109,7 @@ $lang->docTemplate->content = 'Template Text';
$lang->docTemplate->templateDesc = 'Template Desc';
$lang->docTemplate->status = 'Template Status';
$lang->docTemplate->emptyTip = 'There is no system data that conform to this parameter and filtering conditions.';
$lang->docTemplate->emptyDataTip = 'There is no system data that conform to this filtering conditions.';
$lang->docTemplate->previewTip = 'After configuring the parameters, this block will display the corresponding list data according to the filter configuration.';
$lang->docTemplate->confirmDeleteChapterWithSub = "After deleting a chapter, the lower level content of the chapter will be hidden. Are you sure you want to delete the chapter?";
$lang->docTemplate->confirmDeleteTemplateWithSub = "After deleting the template, the lower level content of the template will be hidden. Are you sure you want to delete this template?";
@@ -368,6 +369,7 @@ $lang->doc->zentaoList['caselib'] = 'Case Library' . $lang->testcase->common
$lang->doc->zentaoList['task'] = $lang->task->common;
$lang->doc->zentaoList['bug'] = $lang->bug->common;
$lang->doc->zentaoList['projectBug'] = $lang->projectCommon . 'Bug';
$lang->doc->zentaoList['productBug'] = 'Product Bug';
$lang->doc->zentaoList['planBug'] = 'Plan Bug';
@@ -382,6 +384,11 @@ $lang->doc->zentaoList['feedback'] = 'Feedback';
$lang->doc->zentaoList['ticket'] = 'Ticket';
$lang->doc->zentaoList['gantt'] = 'Gantt Chart';
$lang->doc->zentaoList['HLDS'] = 'Outline Design';
$lang->doc->zentaoList['DDS'] = 'Detailed Design';
$lang->doc->zentaoList['DBDS'] = 'Database Design';
$lang->doc->zentaoList['ADS'] = 'Application Design';
$lang->doc->zentaoAction = array();
$lang->doc->zentaoAction['set'] = 'Setting';
$lang->doc->zentaoAction['delete'] = 'Delete';
@@ -532,6 +539,7 @@ $lang->doc->previewNotAvailable = 'Preview function is not available. Pl
$lang->doc->hocuspocusConnect = 'The collaborative editing service is connected.';
$lang->doc->hocuspocusDisconnect = 'The collaborative editing service is disconnected. Edits will be synchronized after reconnection.';
$lang->doc->docTemplateConvertComment = 'The template has been converted to the new editor format. Switch to version %s to view the template before conversion.';
$lang->doc->noSupportList = "This {$lang->projectCommon} does not support %s.";
$lang->doc->noticeAcl['lib']['product']['default'] = "Users who can access the selected {$lang->productCommon} can access it.";
$lang->doc->noticeAcl['lib']['product']['custom'] = "Users who can access the selected {$lang->productCommon} or users in the whiltelist can access it.";
+8
View File
@@ -109,6 +109,7 @@ $lang->docTemplate->content = '模板内容';
$lang->docTemplate->templateDesc = '模板描述';
$lang->docTemplate->status = '模板状态';
$lang->docTemplate->emptyTip = '此参数与筛选条件下,暂无符合条件系统数据。';
$lang->docTemplate->emptyDataTip = '此筛选条件下,暂无符合条件系统数据。';
$lang->docTemplate->previewTip = '配置参数后,此区块会根据筛选器的配置展示相应的列表数据。';
$lang->docTemplate->confirmDeleteChapterWithSub = "删除章节后,章节下层级内容将一并隐藏,确定要删除该章节吗?";
$lang->docTemplate->confirmDeleteTemplateWithSub = "删除文档模板后,文档模板下层级内容将一并隐藏,确定要删除该文档模板吗?";
@@ -368,6 +369,7 @@ $lang->doc->zentaoList['caselib'] = '用例库' . $lang->testcase->common;
$lang->doc->zentaoList['task'] = $lang->task->common;
$lang->doc->zentaoList['bug'] = $lang->bug->common;
$lang->doc->zentaoList['projectBug'] = $lang->projectCommon . $lang->bug->common;
$lang->doc->zentaoList['productBug'] = '产品Bug';
$lang->doc->zentaoList['planBug'] = '计划Bug';
@@ -382,6 +384,11 @@ $lang->doc->zentaoList['feedback'] = '反馈';
$lang->doc->zentaoList['ticket'] = '工单';
$lang->doc->zentaoList['gantt'] = '甘特图';
$lang->doc->zentaoList['HLDS'] = '概要设计';
$lang->doc->zentaoList['DDS'] = '详细设计';
$lang->doc->zentaoList['DBDS'] = '数据库设计';
$lang->doc->zentaoList['ADS'] = '接口设计';
$lang->doc->zentaoAction = array();
$lang->doc->zentaoAction['set'] = '设置';
$lang->doc->zentaoAction['delete'] = '删除';
@@ -532,6 +539,7 @@ $lang->doc->previewNotAvailable = '预览功能暂不可用,请访问
$lang->doc->hocuspocusConnect = '协作编辑服务已连接。';
$lang->doc->hocuspocusDisconnect = '协作编辑服务已断开,编辑内容将在重新连接后同步。';
$lang->doc->docTemplateConvertComment = "文档模板已经转换为新编辑器格式,切换版本 %s 来查看转换前的文档模板。";
$lang->doc->noSupportList = "当前{$lang->projectCommon}暂不支持“ %s”";
$lang->doc->noticeAcl['lib']['product']['default'] = "有所选{$lang->productCommon}访问权限的用户可以访问。";
$lang->doc->noticeAcl['lib']['product']['custom'] = "有所选{$lang->productCommon}访问权限或白名单里的用户可以访问。";
+35 -30
View File
@@ -666,16 +666,17 @@ class docModel extends model
*/
public function getDocTemplateList(int $libID = 0, string $type = 'all', string $orderBy = 'id_desc', ?object $pager = null, string $searchName = ''): array
{
return $this->dao->select('*')->from(TABLE_DOC)
->where('templateType')->ne('')
->andWhere('builtIn')->eq('0')
->andWhere('vision')->eq($this->config->vision)
->beginIF(!$this->app->user->admin)->andWhere("(`status` = 'normal' or (`status` = 'draft' and `addedBy`='{$this->app->user->account}'))")->fi()
->beginIF($libID)->andWhere('lib')->eq($libID)->fi()
->beginIF($type == 'draft')->andWhere('status')->eq('draft')->fi()
->beginIF($type == 'released')->andWhere('status')->eq('normal')->fi()
->beginIF($type == 'createdByMe')->andWhere('addedBy')->eq($this->app->user->account)->fi()
->beginIF($searchName)->andWhere('title')->like("%{$searchName}%")->fi()
return $this->dao->select('t1.*')->from(TABLE_DOC)->alias('t1')
->leftJoin(TABLE_MODULE)->alias('t2')->on('t1.module=t2.id')
->where('t2.type')->eq('docTemplate')
->andWhere('t1.builtIn')->eq('0')
->andWhere('t1.vision')->eq($this->config->vision)
->beginIF(!$this->app->user->admin)->andWhere("(t1.`status` = 'normal' or (t1.`status` = 'draft' and t1.`addedBy`='{$this->app->user->account}'))")->fi()
->beginIF($libID)->andWhere('t1.lib')->eq($libID)->fi()
->beginIF($type == 'draft')->andWhere('t1.status')->eq('draft')->fi()
->beginIF($type == 'released')->andWhere('t1.status')->eq('normal')->fi()
->beginIF($type == 'createdByMe')->andWhere('t1.addedBy')->eq($this->app->user->account)->fi()
->beginIF($searchName)->andWhere('t1.title')->like("%{$searchName}%")->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('', false);
@@ -1634,11 +1635,11 @@ class docModel extends model
$docID = $this->dao->lastInsertID();
$path = ",{$docID}";
$path = ",{$docID},";
if($doc->parent)
{
$parentDoc = $this->getByID($doc->parent);
$path = $parentDoc->path . $path;
$path = ',' . trim($parentDoc->path, ',') . ',' . $path;
}
$this->dao->update(TABLE_DOC)->set('`order`')->eq($docID)->set('path')->eq($path)->where('id')->eq($docID)->exec();
@@ -3663,14 +3664,15 @@ class docModel extends model
* Get editors of a document.
*
* @param int $docID
* @param string $objectType
* @access public
* @return array
*/
public function getEditors(int $docID = 0): array
public function getEditors(int $docID = 0, string $objectType = 'doc'): array
{
if(!$docID) return array();
$actions = $this->dao->select('*')->from(TABLE_ACTION)
->where('objectType')->eq('doc')
->where('objectType')->eq($objectType)
->andWhere('objectID')->eq($docID)
->andWhere('action')->in('edited')
->orderBy('date_desc')
@@ -4054,13 +4056,14 @@ class docModel extends model
$usedTemplateTypes = $this->dao->select('`key`, `value`')->from(TABLE_LANG)->alias('t1')
->leftJoin(TABLE_DOC)->alias('t2')->on('t1.key = t2.templateType')
->leftJoin(TABLE_MODULE)->alias('t3')->on('t1.module = t3.id')
->where('t1.module')->eq('baseline')
->andWhere('t1.section')->eq('objectList')
->andWhere('t1.lang', true)->ne($currentLang)
->orWhere('t1.vision')->ne($this->config->vision)
->markRight(1)
->andWhere('t1.key')->notin(array_keys($templateTypes))
->andWhere('t2.templateType')->ne('')
->andWhere('t3.type')->eq('docTemplate')
->andWhere('t2.lib')->eq('')
->andWhere('t2.module')->eq('')
->andWhere('t2.deleted')->eq(0)
@@ -4299,14 +4302,15 @@ class docModel extends model
*/
public function getHotTemplates($scopeID = 0, $limit = 0)
{
return $this->dao->select('*, CASE WHEN addedDate > editedDate THEN addedDate ELSE editedDate END as hotDate')->from(TABLE_DOC)
->where('templateType')->ne('')
->andWhere('builtIn')->eq('0')
->andWhere('deleted')->eq('0')
->andWhere('status')->eq('normal')
->andWhere('parent')->eq(0)
->andWhere('vision')->eq($this->config->vision)
->beginIF($scopeID)->andWhere('lib')->eq($scopeID)->fi()
return $this->dao->select('t1.*, CASE WHEN t1.addedDate > t1.editedDate THEN t1.addedDate ELSE t1.editedDate END as hotDate')->from(TABLE_DOC)->alias('t1')
->leftJoin(TABLE_MODULE)->alias('t2')->on('t1.module = t2.id')
->where('t2.type')->eq('docTemplate')
->andWhere('t1.builtIn')->eq('0')
->andWhere('t1.deleted')->eq('0')
->andWhere('t1.status')->eq('normal')
->andWhere('t1.parent')->eq(0)
->andWhere('t1.vision')->eq($this->config->vision)
->beginIF($scopeID)->andWhere('t1.lib')->eq($scopeID)->fi()
->orderBy('hotDate_desc')
->beginIF($limit)->limit($limit)->fi()
->fetchAll('', false);
@@ -4374,13 +4378,14 @@ class docModel extends model
$types[] = $type;
}
return $this->dao->select('*')->from(TABLE_DOC)
->where('deleted')->eq('0')
->andWhere('templateType')->ne('')
->andWhere('builtIn')->eq('0')
->andWhere('vision')->eq($this->config->vision)
->beginIF(!is_null($type))->andWhere('module')->in($types)->fi()
->beginIF($status != 'all')->andWhere('status')->eq($status)->fi()
return $this->dao->select('t1.*')->from(TABLE_DOC)->alias('t1')
->leftJoin(TABLE_MODULE)->alias('t2')->on('t1.module=t2.id')
->where('t1.deleted')->eq('0')
->andWhere('t2.type')->eq('docTemplate')
->andWhere('t1.builtIn')->eq('0')
->andWhere('t1.vision')->eq($this->config->vision)
->beginIF(!is_null($type))->andWhere('t1.module')->in($types)->fi()
->beginIF($status != 'all')->andWhere('t1.status')->eq($status)->fi()
->fetchAll('id', false);
}
@@ -78,6 +78,7 @@ include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/doc.unittest.class.php';
zenData('doc')->loadYaml('template')->gen(20);
zenData('module')->loadYaml('templatemodule')->gen(20);
zenData('user')->gen(5);
su('admin');
@@ -32,6 +32,7 @@ include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/doc.unittest.class.php';
zenData('doc')->loadYaml('template')->gen(20);
zenData('module')->loadYaml('templatemodule')->gen(20);
zenData('user')->gen(5);
su('admin');
+40 -19
View File
@@ -10,6 +10,8 @@ declare(strict_types=1);
*/
namespace zin;
$noticeTip = $noSupport ? sprintf($lang->doc->noSupportList, $lang->doc->zentaoList[$type] . $lang->doc->list) : '';
if($type == 'gantt' && !empty($ganttData))
{
$userList = array();
@@ -35,8 +37,8 @@ if($type == 'productCase')
}
$actions = array();
$setText = (!$isTemplate && $fromTemplate) ? $lang->doc->zentaoAction['setParams'] : $lang->doc->zentaoAction['set'];
if($type != 'gantt' || !$isTemplate) $actions[] = array('icon' => 'menu-backend', 'text' => $setText, 'data-toggle' => 'modal', 'url' => str_replace('{blockID}', "$blockID", $settings), 'data-size' => $isTemplate ? 'sm' : 'lg');
$setText = (!$isTemplate && $fromTemplate && !$fromReport) ? $lang->doc->zentaoAction['setParams'] : $lang->doc->zentaoAction['set'];
if(!$noSupport && ($type != 'gantt' || !$isTemplate)) $actions[] = array('icon' => 'menu-backend', 'text' => $setText, 'data-toggle' => 'modal', 'url' => str_replace('{blockID}', "$blockID", $settings), 'data-size' => $isTemplate || $fromReport ? 'sm' : 'lg');
$actions[] = array('icon' => 'trash', 'text' => $lang->doc->zentaoAction['delete'], 'zui-on-click' => "deleteZentaoList($blockID)");
if($isTemplate || $fromTemplate)
@@ -49,10 +51,36 @@ if($isTemplate || $fromTemplate)
$emptyTip = $lang->doc->previewTip;
if(!$isTemplate && $fromTemplate) $emptyTip = $isSetted ? $lang->docTemplate->emptyTip : $lang->docTemplate->previewTip;
if($fromReport) $emptyTip = $lang->docTemplate->emptyDataTip;
$listText = $type == 'gantt' ? $lang->docTemplate->zentaoList['gantt'] : $lang->doc->list;
$emptyText = $isTemplate ? sprintf($lang->docTemplate->configTip, $listText) : $emptyTip;
$pagerSetting = usePager();
unset($pagerSetting['linkCreator']);
$dataTable = null;
if(!$isTemplate && $type != 'gantt' && !$noSupport)
{
$dataTable = dtable
(
set::cols(array_values($cols)),
set::data(array_values($data)),
set::userMap($users),
set::emptyTip($emptyTip),
set::checkable(false),
set::colResize(true),
set::customCols(false),
set::onRenderCell(jsRaw('window.renderCell')),
set::localPager(),
set::footPager($pagerSetting),
set::footer(array('flex', 'pager')),
$type == 'productRelease' ? set::rowKey('rowID') : null,
$type == 'productRelease' ? set::plugins(array('cellspan')) : null,
$type == 'productRelease' ? set::getCellSpan(jsRaw('window.getCellSpan')) : null
);
}
div
(
set('data-id', $blockID),
@@ -66,7 +94,7 @@ div
h2
(
setClass('font-bold text-xl'),
($isTemplate || $fromTemplate ? $blockTitle . $lang->docTemplate->zentaoList[$type] : $lang->doc->zentaoList[$type]) . ($type == 'gantt' ? '' : $lang->doc->list)
(($isTemplate || $fromTemplate || $fromReport) ? $blockTitle . $lang->docTemplate->zentaoList[$type] : $lang->doc->zentaoList[$type]) . ($type == 'gantt' ? '' : $lang->doc->list)
),
div
(
@@ -86,25 +114,18 @@ div
div
(
setClass('config-tip text-center px-3 py-2'),
$isTemplate ? sprintf($lang->docTemplate->configTip, $type == 'gantt' ? $lang->docTemplate->zentaoList['gantt'] : $lang->doc->list) : $emptyTip
$emptyText
)
):null,
!$isTemplate && $type != 'gantt' ? dtable
$dataTable,
$noSupport ? div
(
set::cols(array_values($cols)),
set::data(array_values($data)),
set::userMap($users),
set::emptyTip($emptyTip),
set::checkable(false),
set::colResize(true),
set::customCols(false),
set::onRenderCell(jsRaw('window.renderCell')),
set::localPager(),
set::footPager($pagerSetting),
set::footer(array('flex', 'pager')),
$type == 'productRelease' ? set::rowKey('rowID') : null,
$type == 'productRelease' ? set::plugins(array('cellspan')) : null,
$type == 'productRelease' ? set::getCellSpan(jsRaw('window.getCellSpan')) : null
setClass('canvas border rounded py-3 px-3'),
div
(
setClass('config-tip text-center px-3 py-2 text-gray-400'),
div($noticeTip)
)
) : null,
$type == 'gantt' && !empty($ganttData) ? zui::gantt
(
+1
View File
@@ -4173,6 +4173,7 @@ class executionModel extends model
* Build task search form.
*
* @param int $executionID
* @param int $productID
* @param array $executions
* @param int $queryID
* @param string $actionURL
@@ -32,6 +32,10 @@ $module = zenData('module');
$module->name->range('1,2,3,4,5')->prefix('模块');
$module->gen(5);
$module = zenData('module');
$module->name->range('1,2,3,4,5')->prefix('模块');
$module->gen(5);
su('admin');
/**
@@ -179,4 +183,4 @@ r($searchConfig) && p('module') && e('task')
r($searchConfig) && p('queryID') && e('1'); // module 为 task,不缓存查询参数,打印 queryID 的值。
r($searchConfig) && p('actionURL') && e('/execution-task-3-bySearch-myQueryID.html'); // module 为 task,不缓存查询参数,打印 actionURL 的值。
r($searchConfig['params']['project']['values']) && p('1,2,all') && e('项目1,项目2,所有项目'); // module 为 task,不缓存查询参数,打印所属项目列表。
r($searchConfig['params']['execution']['values']) && p(',3,all') && e('~~,迭代1,所有执行'); // module 为 task,不缓存查询参数,打印所属执行列表。
r($searchConfig['params']['execution']['values']) && p(',3,all') && e('~~,迭代1,所有执行'); // module 为 task,不缓存查询参数,打印所属执行列表。
+2
View File
@@ -848,3 +848,5 @@ $lang->changelog['21.4'][] = 'testtask-assignCase';
$lang->changelog['21.7.1'][] = 'project-template';
$lang->changelog['21.7.1'][] = 'project-createTemplate';
$lang->changelog['21.7.3'][] = 'reporttemplate-index';
+7 -2
View File
@@ -404,8 +404,10 @@ $lang->group->package->manageReview = 'Manage Review';
$lang->group->package->manageIssue = 'Manage Issue';
$lang->group->package->projectSetting = 'Project Setting';
$lang->group->package->browseProjectRelease = 'Browse Project Release';
$lang->group->package->projectWeekly = 'Project Weekly';
$lang->group->package->projectMilestone = 'Project Milestone';
$lang->group->package->browseProjectReport = 'Browse Report';
$lang->group->package->manageProjectReport = 'Create and Manage Report';
$lang->group->package->deleteProjectReport = 'Delete Report';
$lang->group->package->projectMilestone = 'Milestone Report';
$lang->group->package->researchPlan = 'Research Plan';
$lang->group->package->researchReport = 'Research Report';
$lang->group->package->budget = 'Budget';
@@ -627,5 +629,8 @@ $lang->group->package->manageRule = 'Manage Rule';
$lang->group->package->executionDeliverable = 'Execution Deliverable';
$lang->group->package->projectDeliverable = 'Project Deliverable';
$lang->group->package->projectTemplate = 'Project Template';
$lang->group->package->browseReportTemplate = 'Browse Report Template';
$lang->group->package->manageReportTemplate = 'Manage Report Template';
$lang->group->package->deleteReportTemplate = 'Delete Report Template';
include (dirname(__FILE__) . '/resource.php');
+7 -2
View File
@@ -404,8 +404,10 @@ $lang->group->package->manageReview = 'Manage Review';
$lang->group->package->manageIssue = 'Manage Issue';
$lang->group->package->projectSetting = 'Project Setting';
$lang->group->package->browseProjectRelease = 'Browse Project Release';
$lang->group->package->projectWeekly = 'Project Weekly';
$lang->group->package->projectMilestone = 'Project Milestone';
$lang->group->package->browseProjectReport = 'Browse Report';
$lang->group->package->manageProjectReport = 'Create and Manage Report';
$lang->group->package->deleteProjectReport = 'Delete Report';
$lang->group->package->projectMilestone = 'Milestone Report';
$lang->group->package->researchPlan = 'Research Plan';
$lang->group->package->researchReport = 'Research Report';
$lang->group->package->budget = 'Budget';
@@ -627,5 +629,8 @@ $lang->group->package->manageRule = 'Manage Rule';
$lang->group->package->executionDeliverable = 'Execution Deliverable';
$lang->group->package->projectDeliverable = 'Project Deliverable';
$lang->group->package->projectTemplate = 'Project Template';
$lang->group->package->browseReportTemplate = 'Browse Report Template';
$lang->group->package->manageReportTemplate = 'Manage Report Template';
$lang->group->package->deleteReportTemplate = 'Delete Report Template';
include (dirname(__FILE__) . '/resource.php');
+7 -2
View File
@@ -404,8 +404,10 @@ $lang->group->package->manageReview = 'Manage Review';
$lang->group->package->manageIssue = 'Manage Issue';
$lang->group->package->projectSetting = 'Project Setting';
$lang->group->package->browseProjectRelease = 'Browse Project Release';
$lang->group->package->projectWeekly = 'Project Weekly';
$lang->group->package->projectMilestone = 'Project Milestone';
$lang->group->package->browseProjectReport = 'Browse Report';
$lang->group->package->manageProjectReport = 'Create and Manage Report';
$lang->group->package->deleteProjectReport = 'Delete Report';
$lang->group->package->projectMilestone = 'Milestone Report';
$lang->group->package->researchPlan = 'Research Plan';
$lang->group->package->researchReport = 'Research Report';
$lang->group->package->budget = 'Budget';
@@ -627,5 +629,8 @@ $lang->group->package->manageRule = 'Manage Rule';
$lang->group->package->executionDeliverable = 'Execution Deliverable';
$lang->group->package->projectDeliverable = 'Project Deliverable';
$lang->group->package->projectTemplate = 'Project Template';
$lang->group->package->browseReportTemplate = 'Browse Report Template';
$lang->group->package->manageReportTemplate = 'Manage Report Template';
$lang->group->package->deleteReportTemplate = 'Delete Report Template';
include (dirname(__FILE__) . '/resource.php');
+7 -2
View File
@@ -404,8 +404,10 @@ $lang->group->package->manageReview = '维护基线评审';
$lang->group->package->manageIssue = '维护问题';
$lang->group->package->projectSetting = '项目配置';
$lang->group->package->browseProjectRelease = '浏览项目发布';
$lang->group->package->projectWeekly = '项目周报';
$lang->group->package->projectMilestone = '项目里程碑报告';
$lang->group->package->browseProjectReport = '浏览报告';
$lang->group->package->manageProjectReport = '创建与维护报告';
$lang->group->package->deleteProjectReport = '删除报告';
$lang->group->package->projectMilestone = '里程碑报告';
$lang->group->package->researchPlan = '调研计划';
$lang->group->package->researchReport = '调研报告';
$lang->group->package->budget = '费用估算';
@@ -627,5 +629,8 @@ $lang->group->package->manageRule = '创建维护规则';
$lang->group->package->executionDeliverable = '交付物';
$lang->group->package->projectDeliverable = '交付物';
$lang->group->package->projectTemplate = '项目模板';
$lang->group->package->browseReportTemplate = '浏览报告模板';
$lang->group->package->manageReportTemplate = '创建与维护报告模板';
$lang->group->package->deleteReportTemplate = '删除报告模板';
include (dirname(__FILE__) . '/resource.php');
+49 -7
View File
@@ -301,6 +301,10 @@ $config->group->subset->metric = new stdclass();
$config->group->subset->metric->order = 890;
$config->group->subset->metric->nav = 'bi';
$config->group->subset->reporttemplate = new stdclass();
$config->group->subset->reporttemplate->order = 900;
$config->group->subset->reporttemplate->nav = 'bi';
$config->group->subset->systemteam = new stdclass();
$config->group->subset->systemteam->order = 920;
$config->group->subset->systemteam->nav = 'system';
@@ -2235,15 +2239,28 @@ $config->group->package->browseProjectRelease->privs = array();
$config->group->package->browseProjectRelease->privs['projectrelease-browse'] = array('edition' => 'open,biz,max,ipd', 'vision' => 'rnd', 'order' => 0, 'depend' => array('project-index'), 'recommend' => array('projectrelease-create', 'projectrelease-edit', 'projectrelease-view'));
$config->group->package->browseProjectRelease->privs['projectrelease-view'] = array('edition' => 'open,biz,max,ipd', 'vision' => 'rnd', 'order' => 1, 'depend' => array('projectrelease-browse'), 'recommend' => array('projectrelease-create', 'projectrelease-edit'));
$config->group->package->projectWeekly = new stdclass();
$config->group->package->projectWeekly->order = 5;
$config->group->package->projectWeekly->subset = 'projectreport';
$config->group->package->projectWeekly->privs = array();
$config->group->package->projectWeekly->privs['weekly-index'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array('project-index'), 'recommend' => array());
$config->group->package->projectWeekly->privs['weekly-exportweeklyreport'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 10, 'depend' => array('weekly-index'), 'recommend' => array('weekly-index'));
$config->group->package->browseProjectReport = new stdclass();
$config->group->package->browseProjectReport->order = 5;
$config->group->package->browseProjectReport->subset = 'projectreport';
$config->group->package->browseProjectReport->privs = array();
$config->group->package->browseProjectReport->privs['weekly-browse'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array(), 'recommend' => array('weekly-view'));
$config->group->package->browseProjectReport->privs['weekly-view'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 10, 'depend' => array('weekly-browse'), 'recommend' => array());
$config->group->package->manageProjectReport = new stdclass();
$config->group->package->manageProjectReport->order = 10;
$config->group->package->manageProjectReport->subset = 'projectreport';
$config->group->package->manageProjectReport->privs = array();
$config->group->package->manageProjectReport->privs['weekly-create'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array('weekly-browse', 'weekly-edit'), 'recommend' => array());
$config->group->package->manageProjectReport->privs['weekly-edit'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 10, 'depend' => array('weekly-browse', 'weekly-view'), 'recommend' => array('weekly-create'));
$config->group->package->deleteProjectReport = new stdclass();
$config->group->package->deleteProjectReport->order = 15;
$config->group->package->deleteProjectReport->subset = 'projectreport';
$config->group->package->deleteProjectReport->privs = array();
$config->group->package->deleteProjectReport->privs['weekly-delete'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array('weekly-browse'), 'recommend' => array());
$config->group->package->projectMilestone = new stdclass();
$config->group->package->projectMilestone->order = 10;
$config->group->package->projectMilestone->order = 20;
$config->group->package->projectMilestone->subset = 'projectreport';
$config->group->package->projectMilestone->privs = array();
$config->group->package->projectMilestone->privs['milestone-index'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array('project-index', 'weekly-index'), 'recommend' => array('milestone-saveOtherProblem'));
@@ -3636,6 +3653,31 @@ $config->group->package->manageMetric->privs['metric-delist'] = array('edit
$config->group->package->manageMetric->privs['metric-delete'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd', 'order' => 45, 'depend' => array('metric-browse'), 'recommend' => array());
$config->group->package->manageMetric->privs['metric-recalculate'] = array('edition' => 'open,biz,max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array(), 'recommend' => array());
$config->group->package->browseReportTemplate = new stdclass();
$config->group->package->browseReportTemplate->order = 10;
$config->group->package->browseReportTemplate->subset = 'reporttemplate';
$config->group->package->browseReportTemplate->privs = array();
$config->group->package->browseReportTemplate->privs['reporttemplate-browse'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 5, 'depend' => array(), 'recommend' => array('reporttemplate-view'));
$config->group->package->browseReportTemplate->privs['reporttemplate-view'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 10, 'depend' => array('reporttemplate-browse'), 'recommend' => array());
$config->group->package->manageReportTemplate = new stdclass();
$config->group->package->manageReportTemplate->order = 15;
$config->group->package->manageReportTemplate->subset = 'reporttemplate';
$config->group->package->manageReportTemplate->privs = array();
$config->group->package->manageReportTemplate->privs['reporttemplate-addcategory'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 15, 'depend' => array('reporttemplate-browse'), 'recommend' => array('reporttemplate-editcategory'));
$config->group->package->manageReportTemplate->privs['reporttemplate-editcategory'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 20, 'depend' => array('reporttemplate-browse'), 'recommend' => array('reporttemplate-addcategory'));
$config->group->package->manageReportTemplate->privs['reporttemplate-create'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 25, 'depend' => array('reporttemplate-browse', 'reporttemplate-edit'), 'recommend' => array('reporttemplate-pause'));
$config->group->package->manageReportTemplate->privs['reporttemplate-edit'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 30, 'depend' => array('reporttemplate-browse', 'reporttemplate-view'), 'recommend' => array('reporttemplate-create', 'reporttemplate-pause'));
$config->group->package->manageReportTemplate->privs['reporttemplate-pause'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 35, 'depend' => array('reporttemplate-browse'), 'recommend' => array('reporttemplate-create', 'reporttemplate-edit'));
$config->group->package->manageReportTemplate->privs['reporttemplate-cron'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 40, 'depend' => array('reporttemplate-browse', 'reporttemplate-edit'), 'recommend' => array('reporttemplate-create', 'reporttemplate-edit'));
$config->group->package->deleteReportTemplate = new stdclass();
$config->group->package->deleteReportTemplate->order = 20;
$config->group->package->deleteReportTemplate->subset = 'reporttemplate';
$config->group->package->deleteReportTemplate->privs = array();
$config->group->package->deleteReportTemplate->privs['reporttemplate-deletecategory'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 10, 'depend' => array('reporttemplate-browse'), 'recommend' => array());
$config->group->package->deleteReportTemplate->privs['reporttemplate-delete'] = array('edition' => 'max,ipd', 'vision' => 'rnd', 'order' => 15, 'depend' => array('reporttemplate-browse', 'reporttemplate-view'), 'recommend' => array());
$config->group->package->browseDoc = new stdclass();
$config->group->package->browseDoc->order = 10;
$config->group->package->browseDoc->subset = 'doc';
+1
View File
@@ -309,6 +309,7 @@ class install extends control
$mode = form::data()->get()->mode;
$this->loadModel('setting')->setItem('system.common.global.mode', $mode);
$this->loadModel('custom')->disableFeaturesByMode($mode);
$this->loadModel('weekly')->addBuiltinWeeklyTemplate();
return $this->send(array('result' => 'success', 'load' => inlink('step5')));
}
+1 -1
View File
@@ -84,7 +84,7 @@ $config->job->dtable->fieldList['lastExec']['show'] = true;
$config->job->dtable->fieldList['lastExec']['formatDate'] = 'YYYY-MM-dd hh:mm';
$config->job->actionList = array();
$config->job->actionList['compile']['icon'] = 'history';
$config->job->actionList['compile']['icon'] = 'file-log';
$config->job->actionList['compile']['text'] = $lang->compile->browse;
$config->job->actionList['compile']['hint'] = $lang->compile->browse;
$config->job->actionList['compile']['url'] = array('module' => 'compile', 'method' => 'browse', 'params' => "repoID={repo}&jobID={id}");
@@ -28,7 +28,7 @@ class count_of_finished_story extends baseCalc
public function calculate($row)
{
if($row->stage == 'closed' and $row->closedReason == 'done') $this->result ++;
if($row->status == 'closed' and $row->closedReason == 'done') $this->result ++;
}
public function getResult($options = array())
@@ -31,7 +31,7 @@ class scale_of_finished_story extends baseCalc
if($row->isParent == '1') return false;
if(empty($row->estimate)) return null;
if($row->closedReason == 'done') $this->result += $row->estimate;
if($row->status == 'closed' && $row->closedReason == 'done') $this->result += $row->estimate;
}
public function getResult($options = array())
+1
View File
@@ -2,6 +2,7 @@
#contactTab .listitem.selected {color: var(--color-primary-500); font-weight: bold;}
#contactPanel .form-row .form-group {padding-left: 70px;}
[lang^=en] #contactPanel .form-row .form-group, [lang^=de] #contactPanel .form-row .form-group, [lang^=fr] #contactPanel .form-row .form-group {padding-left: 80px;}
#contactPanel .form-row .form-group .form-label {padding-left: 0; justify-content: start; width: 80px;}
#contactPanel .form-actions {margin-top: 0;}
+3
View File
@@ -408,6 +408,9 @@ if($config->systemMode == 'light')
$lang->project->authList['extend'] = "Inherit (system privilege and {$lang->projectCommon} privilege)";
$lang->project->authList['reset'] = "Reset ({$lang->projectCommon} privilege only)";
$lang->project->sortAuthList['extend'] = 'Inherit';
$lang->project->sortAuthList['reset'] = 'Reset';
$lang->project->statusList[''] = '';
$lang->project->statusList['wait'] = 'Waiting';
$lang->project->statusList['doing'] = 'Doing';
+3
View File
@@ -408,6 +408,9 @@ if($config->systemMode == 'light')
$lang->project->authList['extend'] = "Inherit (system privilege and {$lang->projectCommon} privilege)";
$lang->project->authList['reset'] = "Reset ({$lang->projectCommon} privilege only)";
$lang->project->sortAuthList['extend'] = 'Inherit';
$lang->project->sortAuthList['reset'] = 'Reset';
$lang->project->statusList[''] = '';
$lang->project->statusList['wait'] = 'Waiting';
$lang->project->statusList['doing'] = 'Doing';
+3
View File
@@ -408,6 +408,9 @@ if($config->systemMode == 'light')
$lang->project->authList['extend'] = "Inherit (system privilege and {$lang->projectCommon} privilege)";
$lang->project->authList['reset'] = "Reset ({$lang->projectCommon} privilege only)";
$lang->project->sortAuthList['extend'] = 'Inherit';
$lang->project->sortAuthList['reset'] = 'Reset';
$lang->project->statusList[''] = '';
$lang->project->statusList['wait'] = 'Waiting';
$lang->project->statusList['doing'] = 'Doing';
+3
View File
@@ -408,6 +408,9 @@ if($config->systemMode == 'light')
$lang->project->authList['extend'] = "继承 (取系统权限与{$lang->projectCommon}权限的合集)";
$lang->project->authList['reset'] = "重新定义 (只取{$lang->projectCommon}权限)";
$lang->project->sortAuthList['extend'] = '继承';
$lang->project->sortAuthList['reset'] = '重新定义';
$lang->project->statusList[''] = '';
$lang->project->statusList['wait'] = '未开始';
$lang->project->statusList['doing'] = '进行中';
+6 -5
View File
@@ -157,11 +157,12 @@ $config->story->actionList['copy']['url'] = array('module' => 'story', 'me
$config->story->actionList['copy']['data-app'] = $app->tab;
$config->story->actionList['copy']['notInModal'] = true;
$config->story->actionList['delete']['icon'] = 'trash';
$config->story->actionList['delete']['text'] = $lang->task->delete;
$config->story->actionList['delete']['hint'] = $lang->task->delete;
$config->story->actionList['delete']['url'] = array('module' => 'story', 'method' => 'delete', 'params' => 'storyID={id}');
$config->story->actionList['delete']['className'] = 'ajax-submit';
$config->story->actionList['delete']['icon'] = 'trash';
$config->story->actionList['delete']['text'] = $lang->task->delete;
$config->story->actionList['delete']['hint'] = $lang->task->delete;
$config->story->actionList['delete']['url'] = array('module' => 'story', 'method' => 'delete', 'params' => 'storyID={id}&confirm=yes');
$config->story->actionList['delete']['data-confirm'] = array('message' => $lang->story->confirmDelete, 'icon' => 'icon-exclamation-sign', 'iconClass' => 'warning-pale rounded-full icon-2x');
$config->story->actionList['delete']['className'] = 'ajax-submit';
$config->story->actionList['createBranch']['icon'] = 'treemap';
$config->story->actionList['createBranch']['hint'] = $lang->story->codeBranch;
+1
View File
@@ -681,6 +681,7 @@ class story extends control
if($this->app->tab == 'execution' and $from == 'taskkanban') return $this->send(array('result' => 'success', 'closeModal' => true, 'callback' => "refreshKanban()"));
$locateLink = $this->session->storyList ? $this->session->storyList : $this->createLink('product', 'browse', "productID={$story->product}");
$locateLink = isInModal() ? true : $locateLink;
return $this->send(array('result' => 'success', 'load' => $locateLink, 'closeModal' => true));
}
}
+1
View File
@@ -1019,6 +1019,7 @@ class task extends control
if($from == 'view') return $this->send(array('result' => 'success', 'closeModal' => true, 'load' => true));
$link = $this->session->taskList ? $this->session->taskList : $this->createLink('execution', 'task', "executionID={$task->execution}");
$link = isInModal() ? true : $link;
return $this->send(array('result' => 'success', 'load' => $link, 'closeModal' => true));
}
+1 -1
View File
@@ -341,4 +341,4 @@ r($result['cases']) && p('1:project,product,case,version,order') && e('101,1,2,1
$result = $testtask->linkCaseTest(16, 'bybug', $cases1);
r($result['cases']) && p('0:project,product,case,version,order') && e('101,1,1,1,9'); // 在执行 2 中按缺陷关联标签下关联用例 1,2 到测试单 16,查看关联后的执行 2 中的用例 1。
r($result['cases']) && p('1:project,product,case,version,order') && e('101,1,2,1,10'); // 在执行 2 中按缺陷关联标签下关联用例 1,2 到测试单 16,查看关联后的执行 2 中的用例 2。
r($result['cases']) && p('1:project,product,case,version,order') && e('101,1,2,1,10'); // 在执行 2 中按缺陷关联标签下关联用例 1,2 到测试单 16,查看关联后的执行 2 中的用例 2。
+1
View File
@@ -112,6 +112,7 @@ $config->upgrade->execFlow['21_6_beta'] = array('functions' => 'processCharter
$config->upgrade->execFlow['21_6_1'] = array('xxsqls' => "$appRoot/db/upgradexuanxuan9.1.2.sql");
$config->upgrade->execFlow['21_7'] = array('functions' => 'fixWorkflowNameForExecution');
$config->upgrade->execFlow['21_7_1'] = array('functions' => 'convertCharset,processActionProduct');
$config->upgrade->execFlow['21_7_5'] = array('functions' => 'weekly-addBuiltinWeeklyTemplate');
if(!empty($config->isINT))
{
+54 -1
View File
@@ -545,10 +545,11 @@ class upgrade extends control
* @param string $skipMoveFile
* @param string $skipUpdateDocs
* @param string $skipUpdateDocTemplates
* @param string $skipUpdateWeeklyReports
* @access public
* @return void
*/
public function afterExec($fromVersion, $processed = 'no', $skipMoveFile = 'no', $skipUpdateDocs = 'no', $skipUpdateDocTemplates = 'no')
public function afterExec($fromVersion, $processed = 'no', $skipMoveFile = 'no', $skipUpdateDocs = 'no', $skipUpdateDocTemplates = 'no', $skipUpdateWeeklyReports = 'no')
{
/* 如果数据库有冲突,显示更改的 sql。*/
/* If there is a conflict with the standard database, display the changed sql. */
@@ -596,6 +597,17 @@ class upgrade extends control
}
}
/* 如果有需要升级的周报,显示升级周报界面。*/
if($skipUpdateWeeklyReports == 'no')
{
$upgradeWeeklyReports = $this->upgrade->getUpgradeWeeklyReports();
if(!empty($upgradeWeeklyReports))
{
$this->session->set('upgradeWeeklyReports', $upgradeWeeklyReports);
$this->locate(inlink('upgradeWeeklyReports', "fromVersion={$fromVersion}"));
}
}
unset($_SESSION['user']);
/* 检查是否还有需要处理的。*/
@@ -1036,4 +1048,45 @@ class upgrade extends control
$this->send(array('result' => 'success'));
}
}
/**
* 升级周报数据。
* Upgrade weekly reports.
*
* @param string $fromVersion
* @param string $processed
* @access public
* @return void
*/
public function upgradeWeeklyReports(string $fromVersion = '', string $processed = 'no')
{
$upgradeReports = $this->session->upgradeWeeklyReports;
if($processed === 'yes' || empty($upgradeReports))
{
if(!empty($upgradeReports)) $this->session->set('upgradeWeeklyReports', true);
$this->locate(inlink('afterExec', "fromVersion={$fromVersion}&processed=no&skipMoveFile=yes&skipUpdateDocs=yes&skipUpdateDocTemplates=yes&skipUpdateWeeklyReports=yes"));
}
$this->view->title = $this->lang->upgrade->upgradeWeeklyReports;
$this->view->upgradeReports = $upgradeReports;
$this->view->fromVersion = $fromVersion;
$this->display();
}
/**
* 升级周报数据。
* Upgrade weekly reports.
*
* @access public
* @return void
*/
public function ajaxUpgradeWeeklyReport()
{
if($_POST)
{
$data = isset($_POST['data']) ? $_POST['data'] : array();
if($data) $this->upgrade->upgradeWeeklyReport($data);
$this->send(array('result' => 'success'));
}
}
}
@@ -0,0 +1,50 @@
/* 开始升级周报。*/
window.startUpgradeReports = function(event, reportList, upgradingReportsText, nextText)
{
const $btn = $('#upgradeReportsBtn');
if($btn.hasClass('is-finished')) return;
event.preventDefault();
const $progressBar = $('#upgradeReportsProgress').addClass('active').find('.progress-bar');
$btn.attr('disabled', 'disabled').addClass('disabled').removeClass('primary').find('.text').text(upgradingReportsText);
upgradeReports(reportList,
{
onProgress: (current, total) =>
{
$progressBar.css('width', (100 * current / total) + '%');
$btn.find('.text').text(`${upgradingReportsText} (${current}/${total})`);
}
}).then(() =>
{
$btn.removeAttr('disabled').removeClass('disabled').addClass('primary is-finished').find('.text').text(nextText);
$('#upgradeReportsProgress').removeClass('active')
});
};
/* 更新升级周报进度。*/
async function upgradeReports(reportList, options)
{
let current = 0;
const total = reportList.length;
const onProgress = options.onProgress;
for(const report of reportList)
{
onProgress(current, total);
await upgradeReport(report);
await zui.delay(50);
current ++;
}
onProgress(current, total);
return reportList;
}
/* 升级周报。*/
async function upgradeReport(report)
{
let result;
await $.post($.createLink('upgrade', 'ajaxUpgradeWeeklyReport'), {data: report}, (res) =>
{
result = res.result === 'success' ? true : res.message;
}, 'json');
return result;
}
+5
View File
@@ -114,6 +114,11 @@ $lang->upgrade->upgradeDocTemplates = 'Upgrade templates data';
$lang->upgrade->upgradingDocTemplates = 'Upgrading templates data, please wait...';
$lang->upgrade->upgradeDocTemplatesTip = 'We are upgrading the historical data of the template. After the upgrade, it can be viewed and maintained in the template square under the document.';
$lang->upgrade->weeklyReportTitle = 'Week % s (% s ~% s)';
$lang->upgrade->upgradeWeeklyReports = "Upgrading {$lang->projectCommon} weekly report data";
$lang->upgrade->upgradingWeeklyReports = "Upgrading {$lang->projectCommon} weekly report data, please wait...";
$lang->upgrade->upgradeWeeklyReportsTip = "Detected %s {$lang->projectCommon} weekly report-related data requiring an upgrade";
$lang->upgrade->newProgram = 'Create';
$lang->upgrade->editedName = 'New Name';
$lang->upgrade->projectEmpty = 'Project must be not empty.';
+5
View File
@@ -114,6 +114,11 @@ $lang->upgrade->upgradeDocTemplates = 'Upgrade templates data';
$lang->upgrade->upgradingDocTemplates = 'Upgrading templates data, please wait...';
$lang->upgrade->upgradeDocTemplatesTip = 'We are upgrading the historical data of the template. After the upgrade, it can be viewed and maintained in the template square under the document.';
$lang->upgrade->weeklyReportTitle = 'Week % s (% s ~% s)';
$lang->upgrade->upgradeWeeklyReports = "Upgrading {$lang->projectCommon} weekly report data";
$lang->upgrade->upgradingWeeklyReports = "Upgrading {$lang->projectCommon} weekly report data, please wait...";
$lang->upgrade->upgradeWeeklyReportsTip = "Detected %s {$lang->projectCommon} weekly report-related data requiring an upgrade";
$lang->upgrade->newProgram = 'Create';
$lang->upgrade->editedName = 'New Name';
$lang->upgrade->projectEmpty = 'Project must be not empty.';
+5
View File
@@ -114,6 +114,11 @@ $lang->upgrade->upgradeDocTemplates = 'Upgrade templates data';
$lang->upgrade->upgradingDocTemplates = 'Upgrading templates data, please wait...';
$lang->upgrade->upgradeDocTemplatesTip = 'We are upgrading the historical data of the template. After the upgrade, it can be viewed and maintained in the template square under the document.';
$lang->upgrade->weeklyReportTitle = 'Week % s (% s ~% s)';
$lang->upgrade->upgradeWeeklyReports = "Upgrading {$lang->projectCommon} weekly report data";
$lang->upgrade->upgradingWeeklyReports = "Upgrading {$lang->projectCommon} weekly report data, please wait...";
$lang->upgrade->upgradeWeeklyReportsTip = "Detected %s {$lang->projectCommon} weekly report-related data requiring an upgrade";
$lang->upgrade->newProgram = 'Create';
$lang->upgrade->editedName = 'New Name';
$lang->upgrade->projectEmpty = 'Project must be not empty.';
+1 -2
View File
@@ -217,8 +217,7 @@ $lang->upgrade->fromVersions['21_7_1'] = '21.7.1';
$lang->upgrade->fromVersions['21_7_2'] = '21.7.2';
$lang->upgrade->fromVersions['21_7_3'] = '21.7.3';
$lang->upgrade->fromVersions['21_7_4'] = '21.7.4';
$lang->upgrade->fromVersions['21_7_5'] = '21.7.5';
$lang->upgrade->fromVersions['21_7_5'] = '21.7.5'; // pms insert position.
$lang->upgrade->fromVersions['21_7_5'] = '21.7.5'; // pms insert position.
global $config;
/* Lite. */
+5
View File
@@ -114,6 +114,11 @@ $lang->upgrade->upgradeDocTemplates = '升级文档模板数据';
$lang->upgrade->upgradingDocTemplates = '正在升级文档模板,请稍候...';
$lang->upgrade->upgradeDocTemplatesTip = '正在升级后台文档模板的历史数据,升级后可在文档下模板广场中查看与维护。';
$lang->upgrade->weeklyReportTitle = '第 %s 周( %s ~ %s)';
$lang->upgrade->upgradeWeeklyReports = "升级{$lang->projectCommon}周报数据";
$lang->upgrade->upgradingWeeklyReports = "正在升级{$lang->projectCommon}周报数据,请稍候...";
$lang->upgrade->upgradeWeeklyReportsTip = "检测到 %s 个{$lang->projectCommon}周报相关数据需要升级";
$lang->upgrade->newProgram = '新建';
$lang->upgrade->editedName = '调整后名称';
$lang->upgrade->projectEmpty = '所属项目不能为空!';
+63
View File
@@ -11201,4 +11201,67 @@ class upgradeModel extends model
return array('blockTitle' => $blockTitle, 'exportUrl' => $exportUrl, 'fetcherUrl' => $fetcherUrl);
}
/**
* 获取需要更新的周报数据。
* Get weekly reports that need to be updated.
*
* @access public
* @return array
*/
public function getUpgradeWeeklyReports(): array
{
$reports = $this->dao->select('t1.id,t1.project,t1.weekStart,t2.status as projectStatus,t2.realBegan,t2.realEnd,t2.suspendedDate')->from(TABLE_WEEKLYREPORT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t2.status')->ne('wait')
->orderBy('t1.project asc, t1.weekStart asc')
->fetchAll();
if(empty($reports)) return array();
$thisSunday = date('Y-m-d', strtotime('this Sunday'));
foreach($reports as $key => $report)
{
if($report->projectStatus == 'doing') $report->realBegan = !helper::isZeroDate($report->realBegan) ? $report->realBegan : $report->weekStart;
if(helper::isZeroDate($report->realBegan)) unset($reports[$key]);
/* Filter date < project begin date report. */
$report->projectBegin = date('Y-m-d', strtotime($report->realBegan));
if($report->weekStart < $report->projectBegin) unset($reports[$key]);
if($report->projectStatus == 'doing') $report->projectEnd = $thisSunday;
if($report->projectStatus == 'suspended') $report->projectEnd = $report->suspendedDate;
if($report->projectStatus == 'closed') $report->projectEnd = $report->realEnd;
/* Filter date > project end date report. */
$report->projectEnd = date('Y-m-d', strtotime($report->projectEnd));
if($report->weekStart > $report->projectEnd) unset($reports[$key]);
}
return array_values($reports);
}
/**
* 升级周报数据。
* Upgrade Weekly Report.
*
* @param array $data
* @access public
* @return bool
*/
public function upgradeWeeklyReport(array $data): bool
{
$weekNumber = ceil(helper::diffDate($data['weekStart'], $data['projectBegin']) / 7);
$weekNumber = empty($weekNumber) ? 1 : $weekNumber;
$weekEnd = date('Y-m-d', strtotime('+6 day', strtotime($data['weekStart'])));
$report = new stdclass();
$report->title = sprintf($this->lang->upgrade->weeklyReportTitle, $weekNumber, $data['weekStart'], $weekEnd);
$report->project = $data['project'];
$report->templateType = 'weekly';
$report->weeklyDate = str_replace('-', '', $data['weekStart']);
$report->addedBy = 'system';
$report->addedDate = $data['weekStart'] . ' 00:00:00';
$this->dao->insert(TABLE_DOC)->data($report)->exec();
return !dao::isError();
}
}
@@ -902,4 +902,18 @@ class upgradeTest
$this->objectModel->upgradeWikiTemplates(array($wikiTemplateID));
return $this->objectModel->dao->select('*')->from(TABLE_DOCCONTENT)->where('doc')->eq($wikiTemplateID)->orderBy('id_desc')->fetch();
}
/**
* 升级周报数据。
* Upgrade Weekly Report.
*
* @param array $data
* @access public
* @return object
*/
public function upgradeWeeklyReportTest(array $data): object
{
$this->objectModel->upgradeWeeklyReport($data);
return $this->objectModel->dao->select('*')->from(TABLE_DOC)->orderBy('id_desc')->limit(1)->fetch();
}
}
@@ -0,0 +1,34 @@
#!/usr/bin/env php
<?php
/**
title=测试 projectModel->getUpgradeWeeklyReports();
timeout=0
cid=1
- 检查周报数量 @8
- 检查周报信息
- 属性project @2
- 属性weekStart @2025-01-08
- 属性projectStatus @doing
- 属性projectBegin @2025-01-01
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
$projectTable = zenData('project')->loadYaml('project');
$projectTable->realBegan->range('`0000-00-00`,`2025-01-01`,`0000-00-00`,`2025-06-01`');
$projectTable->realEnd->range('`0000-00-00`{3},`2025-10-01`');
$projectTable->suspendedDate->range('`0000-00-00`{2},`2025-06-01`,`0000-00-00`');
$projectTable->gen(5);
zenData('weeklyreport')->loadYaml('weeklyreport')->gen(30);
zenData('user')->gen(5);
su('admin');
global $tester;
$upgradeModel = $tester->loadModel('upgrade');
$result = $upgradeModel->getUpgradeWeeklyReports();
r(count($result)) && p() && e('8'); // 检查周报数量
r($result[0]) && p('project,weekStart,projectStatus,projectBegin') && e('2,2025-01-08,doing,2025-01-01'); // 检查周报信息
@@ -0,0 +1,35 @@
#!/usr/bin/env php
<?php
/**
title=测试 projectModel->upgradeWeeklyReport();
timeout=0
cid=1
- 测试升级开始日期跟项目开始日期相同的周报
- 属性title @第 1 周( 2025-01-01 ~ 2025-01-07)
- 属性project @1
- 属性templateType @weekly
- 属性weeklyDate @20250101
- 属性addedBy @system
- 测试升级开始日期跟项目开始日期不同的周报
- 属性title @第 4 周( 2025-09-08 ~ 2025-09-14)
- 属性project @1
- 属性templateType @weekly
- 属性weeklyDate @20250908
- 属性addedBy @system
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/upgrade.unittest.class.php';
zenData('doc')->gen(0);
zenData('user')->gen(5);
su('admin');
$data[] = array('weekStart' => '2025-01-01', 'projectBegin' => '2025-01-01', 'project' => 1);
$data[] = array('weekStart' => '2025-09-08', 'projectBegin' => '2025-08-11', 'project' => 1);
$upgradeTester = new upgradeTest();
r($upgradeTester->upgradeWeeklyReportTest($data[0])) && p('title,project,templateType,weeklyDate,addedBy') && e('第 1 周( 2025-01-01 ~ 2025-01-07),1,weekly,20250101,system'); // 测试升级开始日期跟项目开始日期相同的周报
r($upgradeTester->upgradeWeeklyReportTest($data[1])) && p('title,project,templateType,weeklyDate,addedBy') && e('第 4 周( 2025-09-08 ~ 2025-09-14),1,weekly,20250908,system'); // 测试升级开始日期跟项目开始日期不同的周报
@@ -0,0 +1,19 @@
title: project.
desc: project data.
author: Shujie Tian
version: "1.0"
fields:
- field: id
range: 1-100
- field: name
perfix: '项目'
range: 1-100
- field: project
range: 0
range: 1-1000
- field: model
range: waterfall
- field: type
range: project
- field: status
range: wait,doing,suspended,closed
@@ -0,0 +1,15 @@
title: weeklyreport.
desc: weeklyreport data.
author: Shujie Tian
version: "1.0"
fields:
- field: id
range: 1-100
- field: project
range: 1-5
- field: weekStart
range: "20250101 000000:7D"
type: timestamp
format: "YYYY-MM-DD"
- field: staff
range: 1-10
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/**
* The upgradeWeeklyReports view file of upgrade module of ZenTaoPMS.
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Shujie Tian <tianshujie@chandao.com>
* @package upgrade
* @link https://www.zentao.net
*/
namespace zin;
set::zui(true);
div
(
setID('main'),
setClass('flex'),
div
(
setID('mainContent'),
setClass('mx-auto'),
panel
(
setStyle('width', '600px'),
set::title(sprintf($lang->upgrade->upgradeWeeklyReportsTip, count($upgradeReports))),
set::size('lg'),
progressBar
(
setID('upgradeReportsProgress'),
set::striped(),
set::percent(0)
),
div
(
setClass('mt-3 py-3 row items-center gap-4 justify-center'),
btn
(
setID('upgradeReportsBtn'),
set::type('primary'),
set::url('upgrade', 'upgradeWeeklyReports', "fromVersion={$fromVersion}&processed=yes"),
on::click()->call('startUpgradeReports', jsRaw('event'), $upgradeReports, $lang->upgrade->upgradingWeeklyReports, $lang->upgrade->next),
span(setClass('hidden as-upgrading-text'), $lang->upgrade->upgradingWeeklyReports),
span(setClass('hidden as-finish-text'), $lang->upgrade->next),
$lang->upgrade->upgradeWeeklyReports
)
)
)
)
);
render('pagebase');
+3 -1
View File
@@ -39,6 +39,8 @@ if($denyType == 'noview')
}
h::css("#header{display:none;}");
$gobackBtn = null;
if(!isInModal()) $gobackBtn = $referer ? array('url' => helper::safe64Decode($referer), 'text' => $lang->user->goback) : array('back' => 'APP', 'text' => $lang->user->goback, 'class' => 'go-back-btn');
panel
(
setID('denyBox'),
@@ -46,7 +48,7 @@ panel
set::footerActions
(array(
array('text' => $lang->close, 'class' => 'close-app-btn hidden'),
$referer ? array('url' => helper::safe64Decode($referer), 'text' => $lang->user->goback) : array('back' => 'APP', 'text' => $lang->user->goback, 'class' => 'go-back-btn'),
$gobackBtn,
array('data-url' => createLink('user', 'logout', "referer=" . helper::safe64Encode($denyPage)), 'class' => 'primary re-login-btn', 'text' => $lang->user->relogin, 'onclick' => 'locateLogin(this)')
)),
set::footerClass('justify-center'),
+8
View File
@@ -0,0 +1,8 @@
<?php
$config->weekly->charts['weekly_term'] = array('date' => '$thisWeek');
$config->weekly->charts['weekly_staff'] = array('date' => '$thisWeek');
$config->weekly->charts['project_progress_summary'] = array();
$config->weekly->charts['task_basicStatistic_finished'] = array('date' => '$thisWeek');
$config->weekly->charts['task_basicStatistic_unfinished'] = array('date' => '$thisWeek');
$config->weekly->charts['task_basicStatistic_workplan'] = array('date' => '$nextWeek');
$config->weekly->charts['project_basicStatistic_workload'] = array();
+18 -7
View File
@@ -33,11 +33,6 @@ class weekly extends control
*/
public function commonAction($projectID = 0)
{
if(common::hasPriv('weekly', 'exportweeklyreport'))
{
$this->lang->TRActions = "<div class='btn-toolbar pull-right'>" . html::a($this->createLink('weekly', 'exportweeklyreport', 'module=' . $this->app->getModuleName() . '&projectID=' . $projectID), $this->lang->export, '', "class='btn btn-primary' data-width='30%' id='exportreport' data-group='project'") . '</div';
}
$this->loadModel('project')->setMenu($projectID);
}
@@ -51,6 +46,8 @@ class weekly extends control
*/
public function index($projectID = 0, $date = '')
{
if(!common::hasPriv('weekly', 'view')) return $this->locate($this->createLink('user', 'deny', 'module=weekly&method=view'));
$this->commonAction($projectID);
if(!$date) $date = helper::today();
$date = date('Y-m-d', strtotime($date));
@@ -63,8 +60,6 @@ class weekly extends control
$this->view->title = $this->lang->weekly->common;
$this->view->date = $date;
$this->lang->modulePageNav = $this->weekly->getPageNav($this->view->project, $date);
$this->display();
}
@@ -91,4 +86,20 @@ class weekly extends control
$this->weekly->save($projectID, $date);
}
}
/**
* 定时创建报告。
* Generate weekly report.
*
* @access public
* @return void
*/
public function createCycleReport()
{
if(in_array($this->config->edition, array('open', 'biz'))) return print('Support min edition is max');
$errors = $this->loadModel('reporttemplate')->createCycleReport();
if($errors) return print(json_encode($errors));
return print('success');
}
}
+1
View File
@@ -6,3 +6,4 @@
#helpDropdown .dropdown-menu{width:600px; text-align:left; height:300px; overflow:auto; background: #fff; padding-left:8px;}
#helpDropdown h2{font-size:14px; padding:0px; margin:0px; margin-top:10px;}
#helpDropdown p{padding:0px; margin:0px; margin-top:10px;}
#mainMenu .btn-toolbar {margin-bottom: 5px;}
+14 -6
View File
@@ -9,7 +9,7 @@
* @version $Id
* @link https://www.zentao.net
*/
$lang->weekly->common = $lang->projectCommon . ' Weekly';
$lang->weekly->common = 'Report';
$lang->weekly->index = 'Weekly Overview';
$lang->weekly->progress = 'Progress';
$lang->weekly->workload = 'Workload';
@@ -22,10 +22,11 @@ $lang->weekly->postponed = 'Work unfinished this week';
$lang->weekly->nextWeek = 'Work planned for next week';
$lang->weekly->workloadByType = 'Workload Summary';
$lang->weekly->term = 'Reporting Cycle';
$lang->weekly->project = $lang->projectCommon . ' Name';
$lang->weekly->master = 'Project Manager ';
$lang->weekly->staff = 'Weekly Effort';
$lang->weekly->term = 'Reporting Cycle';
$lang->weekly->project = $lang->projectCommon . ' Name';
$lang->weekly->master = 'Project Manager ';
$lang->weekly->staff = 'Weekly Effort';
$lang->weekly->projectTemplate = "{$lang->projectCommon} Weekly Report Template";
$lang->weekly->weekDesc = 'Week % s (% s ~% s)';
$lang->weekly->progress = 'Progress of the ' . $lang->projectCommon;
@@ -38,10 +39,15 @@ $lang->weekly->ac = 'Actual Cost(AC)';
$lang->weekly->sv = 'Schedule Variance(SV%)';
$lang->weekly->cv = 'Cost Variance(CV%)';
$lang->weekly->totalCount = 'Total : %u tasks';
$lang->weekly->totalCount = 'Total : %u tasks';
$lang->weekly->builtinDesc = "The system's built-in {$lang->projectCommon} weekly report template automatically generates this week's report under the {$lang->projectCommon} every Monday.";
$lang->weekly->exportWeeklyReport = 'Export Weekly Report';
$lang->weekly->builtInScopes = array();
$lang->weekly->builtInScopes['rnd'] = array();
$lang->weekly->builtInScopes['rnd']['project'] = 'Project';
$lang->weekly->reportHelpNotice = <<<EOD
<h2>PV Planned Value</h2>
Calculation method:
@@ -143,3 +149,5 @@ Calculation method: SV(%) = -1 * (1 - (EV / PV))%
<h2>CV(%) Schedule Variance</h2>
Calculation method: CV(%) = -1 * (1 - (EV / AC))%
EOD;
$lang->weekly->builtinRawContent = '{"type":"page","meta":{"id":"DzzHUxGuzi","title":"Project Weekly Report Template","createDate":1757395000965,"tags":[]},"blocks":{"type":"block","id":"cJZg7QCPpE","flavour":"affine:page","version":2,"props":{"title":{"$blocksuite:internal:text$":true,"delta":[{"insert":"Project Weekly Report Template"}]}},"children":[{"type":"block","id":"aS-yFwCosD","flavour":"affine:note","version":1,"props":{"xywh":"[0,0,498,92]","background":"--affine-note-background-white","index":"a0","lockedBySelf":false,"hidden":false,"displayMode":"both","edgeless":{"style":{"borderRadius":8,"borderSize":4,"borderStyle":"none","shadowType":"--affine-note-shadow-box"}}},"children":[{"type":"block","id":"YCy8XkfbbP","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[{"insert":" ","attributes":{"holder":{"id":"tsoxyETETF","name":"weekly_term","text":"Report Term","hint":"Filter: “Date Range”BetweenThis Week","data":{"type":"weekly_term","blockID":2746,"hint":"Filter: “Date Range”BetweenThis Week","text":"Report Term"}}}},{"insert":" weekly report: "},{"insert":" ","attributes":{"holder":{"id":"q1YcO2kmC7","name":"property_name","text":"Name","hint":"Name"}}},{"insert":" is managed by the project manager "},{"insert":" ","attributes":{"holder":{"id":"eefTgQguvL","name":"property_PM","text":"Manager","hint":"Manager"}}},{"insert":", the number of people involved is "},{"insert":" ","attributes":{"holder":{"id":"jwupyH0HTa","name":"weekly_staff","text":"Staff Number","hint":"Filter: “Date Range”BetweenThis Week","data":{"type":"weekly_staff","blockID":2747,"hint":"Filter: “Date Range”BetweenThis Week","text":"Staff Number"}}}},{"insert":"."}]},"collapsed":false},"children":[]},{"type":"block","id":"cL0cyfMcnI","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_progress_summary&blockID=__TML_ZENTAOCHART__{project_progress_summary}","clearBeforeLoad":false,"isTemplate":true,"title":"Project Progress Summary"}},"children":[]},{"type":"block","id":"FqBsfENZPf","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_finished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_finished}","clearBeforeLoad":false,"isTemplate":true,"title":"Finished Tasks"}},"children":[]},{"type":"block","id":"egherwGMIV","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_unfinished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_unfinished}","clearBeforeLoad":false,"isTemplate":true,"title":"Unfinished Tasks"}},"children":[]},{"type":"block","id":"xfmvHk6o3o","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_workplan&blockID=__TML_ZENTAOCHART__{task_basicStatistic_workplan}","clearBeforeLoad":false,"isTemplate":true,"title":"Work Plan"}},"children":[]},{"type":"block","id":"ZZ4Jsuq4Bq","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_basicStatistic_workload&blockID=__TML_ZENTAOCHART__{project_basicStatistic_workload}","clearBeforeLoad":false,"isTemplate":true,"title":"Project Plan Workload Statistic"}},"children":[]},{"type":"block","id":"BPy4La92az","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[]},"collapsed":false},"children":[]}]}]}}';
+14 -6
View File
@@ -9,7 +9,7 @@
* @version $Id
* @link https://www.zentao.net
*/
$lang->weekly->common = $lang->projectCommon . ' Weekly';
$lang->weekly->common = 'Report';
$lang->weekly->index = 'Weekly Overview';
$lang->weekly->progress = 'Progress';
$lang->weekly->workload = 'Workload';
@@ -22,10 +22,11 @@ $lang->weekly->postponed = 'Work unfinished this week';
$lang->weekly->nextWeek = 'Work planned for next week';
$lang->weekly->workloadByType = 'Workload Summary';
$lang->weekly->term = 'Reporting Cycle';
$lang->weekly->project = $lang->projectCommon . ' Name';
$lang->weekly->master = 'Project Manager ';
$lang->weekly->staff = 'Weekly Effort';
$lang->weekly->term = 'Reporting Cycle';
$lang->weekly->project = $lang->projectCommon . ' Name';
$lang->weekly->master = 'Project Manager ';
$lang->weekly->staff = 'Weekly Effort';
$lang->weekly->projectTemplate = "{$lang->projectCommon} Weekly Report Template";
$lang->weekly->weekDesc = 'Week % s (% s ~% s)';
$lang->weekly->progress = 'Progress of the ' . $lang->projectCommon;
@@ -38,10 +39,15 @@ $lang->weekly->ac = 'Actual Cost(AC)';
$lang->weekly->sv = 'Schedule Variance(SV%)';
$lang->weekly->cv = 'Cost Variance(CV%)';
$lang->weekly->totalCount = 'Total : %u tasks';
$lang->weekly->totalCount = 'Total : %u tasks';
$lang->weekly->builtinDesc = "The system's built-in {$lang->projectCommon} weekly report template automatically generates this week's report under the {$lang->projectCommon} every Monday.";
$lang->weekly->exportWeeklyReport = 'Export Weekly Report';
$lang->weekly->builtInScopes = array();
$lang->weekly->builtInScopes['rnd'] = array();
$lang->weekly->builtInScopes['rnd']['project'] = 'Project';
$lang->weekly->reportHelpNotice = <<<EOD
<h2>PV Planned Value</h2>
Calculation method:
@@ -143,3 +149,5 @@ Calculation method: SV(%) = -1 * (1 - (EV / PV))%
<h2>CV(%) Schedule Variance</h2>
Calculation method: CV(%) = -1 * (1 - (EV / AC))%
EOD;
$lang->weekly->builtinRawContent = '{"type":"page","meta":{"id":"DzzHUxGuzi","title":"Project Weekly Report Template","createDate":1757395000965,"tags":[]},"blocks":{"type":"block","id":"cJZg7QCPpE","flavour":"affine:page","version":2,"props":{"title":{"$blocksuite:internal:text$":true,"delta":[{"insert":"Project Weekly Report Template"}]}},"children":[{"type":"block","id":"aS-yFwCosD","flavour":"affine:note","version":1,"props":{"xywh":"[0,0,498,92]","background":"--affine-note-background-white","index":"a0","lockedBySelf":false,"hidden":false,"displayMode":"both","edgeless":{"style":{"borderRadius":8,"borderSize":4,"borderStyle":"none","shadowType":"--affine-note-shadow-box"}}},"children":[{"type":"block","id":"YCy8XkfbbP","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[{"insert":" ","attributes":{"holder":{"id":"tsoxyETETF","name":"weekly_term","text":"Report Term","hint":"Filter: “Date Range”BetweenThis Week","data":{"type":"weekly_term","blockID":2746,"hint":"Filter: “Date Range”BetweenThis Week","text":"Report Term"}}}},{"insert":" weekly report: "},{"insert":" ","attributes":{"holder":{"id":"q1YcO2kmC7","name":"property_name","text":"Name","hint":"Name"}}},{"insert":" is managed by the project manager "},{"insert":" ","attributes":{"holder":{"id":"eefTgQguvL","name":"property_PM","text":"Manager","hint":"Manager"}}},{"insert":", the number of people involved is "},{"insert":" ","attributes":{"holder":{"id":"jwupyH0HTa","name":"weekly_staff","text":"Staff Number","hint":"Filter: “Date Range”BetweenThis Week","data":{"type":"weekly_staff","blockID":2747,"hint":"Filter: “Date Range”BetweenThis Week","text":"Staff Number"}}}},{"insert":"."}]},"collapsed":false},"children":[]},{"type":"block","id":"cL0cyfMcnI","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_progress_summary&blockID=__TML_ZENTAOCHART__{project_progress_summary}","clearBeforeLoad":false,"isTemplate":true,"title":"Project Progress Summary"}},"children":[]},{"type":"block","id":"FqBsfENZPf","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_finished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_finished}","clearBeforeLoad":false,"isTemplate":true,"title":"Finished Tasks"}},"children":[]},{"type":"block","id":"egherwGMIV","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_unfinished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_unfinished}","clearBeforeLoad":false,"isTemplate":true,"title":"Unfinished Tasks"}},"children":[]},{"type":"block","id":"xfmvHk6o3o","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_workplan&blockID=__TML_ZENTAOCHART__{task_basicStatistic_workplan}","clearBeforeLoad":false,"isTemplate":true,"title":"Work Plan"}},"children":[]},{"type":"block","id":"ZZ4Jsuq4Bq","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_basicStatistic_workload&blockID=__TML_ZENTAOCHART__{project_basicStatistic_workload}","clearBeforeLoad":false,"isTemplate":true,"title":"Project Plan Workload Statistic"}},"children":[]},{"type":"block","id":"BPy4La92az","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[]},"collapsed":false},"children":[]}]}]}}';
+14 -6
View File
@@ -9,7 +9,7 @@
* @version $Id
* @link https://www.zentao.net
*/
$lang->weekly->common = $lang->projectCommon . ' Weekly';
$lang->weekly->common = 'Report';
$lang->weekly->index = 'Weekly Overview';
$lang->weekly->progress = 'Progress';
$lang->weekly->workload = 'Workload';
@@ -22,10 +22,11 @@ $lang->weekly->postponed = 'Work unfinished this week';
$lang->weekly->nextWeek = 'Work planned for next week';
$lang->weekly->workloadByType = 'Workload Summary';
$lang->weekly->term = 'Reporting Cycle';
$lang->weekly->project = $lang->projectCommon . ' Name';
$lang->weekly->master = 'Project Manager ';
$lang->weekly->staff = 'Weekly Effort';
$lang->weekly->term = 'Reporting Cycle';
$lang->weekly->project = $lang->projectCommon . ' Name';
$lang->weekly->master = 'Project Manager ';
$lang->weekly->staff = 'Weekly Effort';
$lang->weekly->projectTemplate = "{$lang->projectCommon} Weekly Report Template";
$lang->weekly->weekDesc = 'Week % s (% s ~% s)';
$lang->weekly->progress = 'Progress of the ' . $lang->projectCommon;
@@ -38,10 +39,15 @@ $lang->weekly->ac = 'Actual Cost(AC)';
$lang->weekly->sv = 'Schedule Variance(SV%)';
$lang->weekly->cv = 'Cost Variance(CV%)';
$lang->weekly->totalCount = 'Total : %u tasks';
$lang->weekly->totalCount = 'Total : %u tasks';
$lang->weekly->builtinDesc = "The system's built-in {$lang->projectCommon} weekly report template automatically generates this week's report under the {$lang->projectCommon} every Monday.";
$lang->weekly->exportWeeklyReport = 'Export Weekly Report';
$lang->weekly->builtInScopes = array();
$lang->weekly->builtInScopes['rnd'] = array();
$lang->weekly->builtInScopes['rnd']['project'] = 'Project';
$lang->weekly->reportHelpNotice = <<<EOD
<h2>PV Planned Value</h2>
Calculation method:
@@ -143,3 +149,5 @@ Calculation method: SV(%) = -1 * (1 - (EV / PV))%
<h2>CV(%) Schedule Variance</h2>
Calculation method: CV(%) = -1 * (1 - (EV / AC))%
EOD;
$lang->weekly->builtinRawContent = '{"type":"page","meta":{"id":"DzzHUxGuzi","title":"Project Weekly Report Template","createDate":1757395000965,"tags":[]},"blocks":{"type":"block","id":"cJZg7QCPpE","flavour":"affine:page","version":2,"props":{"title":{"$blocksuite:internal:text$":true,"delta":[{"insert":"Project Weekly Report Template"}]}},"children":[{"type":"block","id":"aS-yFwCosD","flavour":"affine:note","version":1,"props":{"xywh":"[0,0,498,92]","background":"--affine-note-background-white","index":"a0","lockedBySelf":false,"hidden":false,"displayMode":"both","edgeless":{"style":{"borderRadius":8,"borderSize":4,"borderStyle":"none","shadowType":"--affine-note-shadow-box"}}},"children":[{"type":"block","id":"YCy8XkfbbP","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[{"insert":" ","attributes":{"holder":{"id":"tsoxyETETF","name":"weekly_term","text":"Report Term","hint":"Filter: “Date Range”BetweenThis Week","data":{"type":"weekly_term","blockID":2746,"hint":"Filter: “Date Range”BetweenThis Week","text":"Report Term"}}}},{"insert":" weekly report: "},{"insert":" ","attributes":{"holder":{"id":"q1YcO2kmC7","name":"property_name","text":"Name","hint":"Name"}}},{"insert":" is managed by the project manager "},{"insert":" ","attributes":{"holder":{"id":"eefTgQguvL","name":"property_PM","text":"Manager","hint":"Manager"}}},{"insert":", the number of people involved is "},{"insert":" ","attributes":{"holder":{"id":"jwupyH0HTa","name":"weekly_staff","text":"Staff Number","hint":"Filter: “Date Range”BetweenThis Week","data":{"type":"weekly_staff","blockID":2747,"hint":"Filter: “Date Range”BetweenThis Week","text":"Staff Number"}}}},{"insert":"."}]},"collapsed":false},"children":[]},{"type":"block","id":"cL0cyfMcnI","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_progress_summary&blockID=__TML_ZENTAOCHART__{project_progress_summary}","clearBeforeLoad":false,"isTemplate":true,"title":"Project Progress Summary"}},"children":[]},{"type":"block","id":"FqBsfENZPf","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_finished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_finished}","clearBeforeLoad":false,"isTemplate":true,"title":"Finished Tasks"}},"children":[]},{"type":"block","id":"egherwGMIV","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_unfinished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_unfinished}","clearBeforeLoad":false,"isTemplate":true,"title":"Unfinished Tasks"}},"children":[]},{"type":"block","id":"xfmvHk6o3o","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_workplan&blockID=__TML_ZENTAOCHART__{task_basicStatistic_workplan}","clearBeforeLoad":false,"isTemplate":true,"title":"Work Plan"}},"children":[]},{"type":"block","id":"ZZ4Jsuq4Bq","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_basicStatistic_workload&blockID=__TML_ZENTAOCHART__{project_basicStatistic_workload}","clearBeforeLoad":false,"isTemplate":true,"title":"Project Plan Workload Statistic"}},"children":[]},{"type":"block","id":"BPy4La92az","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[]},"collapsed":false},"children":[]}]}]}}';
+14 -6
View File
@@ -9,7 +9,7 @@
* @version $Id
* @link https://www.zentao.net
*/
$lang->weekly->common = $lang->projectCommon . '周报';
$lang->weekly->common = '报告';
$lang->weekly->index = '周报总览';
$lang->weekly->progress = '完成百分比';
$lang->weekly->workload = '工作量';
@@ -22,10 +22,11 @@ $lang->weekly->postponed = '本周未完成工作';
$lang->weekly->nextWeek = '下周工作计划';
$lang->weekly->workloadByType = '工作量统计';
$lang->weekly->term = '报告周期';
$lang->weekly->project = $lang->projectCommon . '名称';
$lang->weekly->master = '项目经理 ';
$lang->weekly->staff = '本周投入人数';
$lang->weekly->term = '报告周期';
$lang->weekly->project = $lang->projectCommon . '名称';
$lang->weekly->master = '项目经理 ';
$lang->weekly->staff = '本周投入人数';
$lang->weekly->projectTemplate = "{$lang->projectCommon}周报模板";
$lang->weekly->weekDesc = '第 %s 周( %s ~ %s)';
$lang->weekly->progress = $lang->projectCommon . '当前进展状况';
@@ -38,10 +39,15 @@ $lang->weekly->ac = '实际花费的成本(AC)';
$lang->weekly->sv = '进度偏差率(SV%)';
$lang->weekly->cv = '成本偏差率(CV%)';
$lang->weekly->totalCount = '总计 : %u 个任务';
$lang->weekly->totalCount = '总计 : %u 个任务';
$lang->weekly->builtinDesc = "系统内置的{$lang->projectCommon}周报模板,每周一在{$lang->projectCommon}下自动生成本周周报。";
$lang->weekly->exportWeeklyReport = '导出周报';
$lang->weekly->builtInScopes = array();
$lang->weekly->builtInScopes['rnd'] = array();
$lang->weekly->builtInScopes['rnd']['project'] = '项目';
$lang->weekly->reportHelpNotice = <<<EOD
<h2>PV 计划完成的工作</h2>
计算方式:
@@ -144,3 +150,5 @@ $lang->weekly->blockHelpNotice = <<<EOD
<h2>CV(%) 成本偏差率</h2>
计算方式:CV(%) = -1 * (1 - (EV / AC))%
EOD;
$lang->weekly->builtinRawContent = '{"type":"page","meta":{"id":"pGFGrn8mbr","title":"项目周报模板","createDate":1757379096204,"tags":[]},"blocks":{"type":"block","id":"Z3C1batqB7","flavour":"affine:page","version":2,"props":{"title":{"$blocksuite:internal:text$":true,"delta":[{"insert":"项目周报模板"}]}},"children":[{"type":"block","id":"kDFfXsGBPr","flavour":"affine:note","version":1,"props":{"xywh":"[0,0,498,92]","background":"--affine-note-background-white","index":"a0","lockedBySelf":false,"hidden":false,"displayMode":"both","edgeless":{"style":{"borderRadius":8,"borderSize":4,"borderStyle":"none","shadowType":"--affine-note-shadow-box"}}},"children":[{"type":"block","id":"A8QUW_uBSE","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[{"insert":" ","attributes":{"holder":{"id":"yqEBqqGHil","name":"weekly_term","text":"报告周期","hint":"筛选条件:“日期范围”介于本周","data":{"type":"weekly_term","blockID":2737,"hint":"筛选条件:“日期范围”介于本周","text":"报告周期"}}}},{"insert":"周报:"},{"insert":" ","attributes":{"holder":{"id":"PcqpwqBES3","name":"property_name","text":"项目名称","hint":"项目名称"}}},{"insert":"项目由项目经理"},{"insert":" ","attributes":{"holder":{"id":"p7Gw9A-ktu","name":"property_PM","text":"负责人","hint":"负责人"}}},{"insert":"负责,投入人数为"},{"insert":" ","attributes":{"holder":{"id":"uZ3j7QvSxb","name":"weekly_staff","text":"投入人数","hint":"筛选条件:“日期范围”介于本周","data":{"type":"weekly_staff","blockID":2738,"hint":"筛选条件:“日期范围”介于本周","text":"投入人数"}}}},{"insert":"。"}]},"collapsed":false},"children":[]},{"type":"block","id":"V5pHY6-x0A","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_progress_summary&blockID=__TML_ZENTAOCHART__{project_progress_summary}","clearBeforeLoad":false,"isTemplate":true,"title":"项目进展状况"}},"children":[]},{"type":"block","id":"cbuO57uG59","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_finished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_finished}","clearBeforeLoad":false,"isTemplate":true,"title":"已完成任务情况"}},"children":[]},{"type":"block","id":"r3Mi7MQ4Jq","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_unfinished&blockID=__TML_ZENTAOCHART__{task_basicStatistic_unfinished}","clearBeforeLoad":false,"isTemplate":true,"title":"未完成任务情况"}},"children":[]},{"type":"block","id":"jrqVmVb0Ze","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=task_basicStatistic_workplan&blockID=__TML_ZENTAOCHART__{task_basicStatistic_workplan}","clearBeforeLoad":false,"isTemplate":true,"title":"工作计划"}},"children":[]},{"type":"block","id":"RhBxuJ6tj-","flavour":"affine:embed-zui-custom","version":1,"props":{"index":"a0","xywh":"[0,0,0,0]","lockedBySelf":false,"rotate":0,"content":{"fetcher":"/index.php?m=reporttemplate&f=ajaxZentaoChart&type=project_basicStatistic_workload&blockID=__TML_ZENTAOCHART__{project_basicStatistic_workload}","clearBeforeLoad":false,"isTemplate":true,"title":"项目计划工作量统计"}},"children":[]},{"type":"block","id":"mpqkXURxFF","flavour":"affine:paragraph","version":1,"props":{"align":"left","type":"text","text":{"$blocksuite:internal:text$":true,"delta":[]},"collapsed":false},"children":[]}]}]}}';
+193
View File
@@ -591,4 +591,197 @@ class weeklyModel extends model
return $data;
}
/**
* 添加内置项目周报模板。
* Add builtin project weekly report template.
*
* @access public
* @return bool
*/
public function addBuiltinWeeklyTemplate()
{
/* Set scope data. */
$scopeID = $this->addBuiltinScope();
if(!$scopeID) return false;
/* Set category data. */
$categoryID = $this->addBuiltinCategory($scopeID);
/* Set docblock data. */
$blockIdList = array();
$docBlock = new stdclass();
foreach($this->config->weekly->charts as $chartKey => $chartContent)
{
$docBlock->type = $chartKey;
$docBlock->content = json_encode($chartContent);
$this->dao->insert(TABLE_DOCBLOCK)->data($docBlock)->exec();
$blockIdList[$chartKey] = $this->dao->lastInsertId();
}
/* Set template data. */
$this->addBuiltinTemplate($scopeID, $categoryID, $blockIdList);
return !dao::isError();
}
/**
* 添加内置报告模板范围。
* Add builtin report template scope.
*
* @access public
* @return int|bool
*/
public function addBuiltinScope(): int|bool
{
$scope = $this->dao->select('id')->from(TABLE_DOCLIB)->where('type')->eq('reportTemplate')->andWhere('main')->eq(1)->andWhere('vision')->eq($this->config->vision)->fetch();
if($scope) return false;
$this->loadModel('setting');
/* Set scope data. */
$scope = new stdClass();
$scope->type = 'reportTemplate';
$scope->main = '1';
$scope->vision = $this->config->vision;
$scope->addedBy = 'system';
$scope->addedDate = helper::now();
foreach($this->lang->weekly->builtInScopes as $vision => $scopeList)
{
$scopeMaps = array();
$scope->vision = $vision;
foreach($scopeList as $scopeKey => $scopeName)
{
if(empty($scopeName)) continue;
$scope->name = $scopeName;
$this->dao->insert(TABLE_DOCLIB)->data($scope)->exec();
$scopeMaps[$scopeKey] = $this->dao->lastInsertID();
}
if(!empty($scopeMaps)) $this->setting->setItem("system.reporttemplate.builtInScopeMaps@{$vision}", json_encode($scopeMaps));
}
return array_push($scopeMaps);
}
/**
* 添加内置报告模板分类。
* Add builtin report template category.
*
* @param int $scopeID
* @access public
* @return int
*/
public function addBuiltinCategory(int $scopeID): int
{
/* Set category data. */
$category = new stdClass();
$category->root = $scopeID;
$category->name = $this->lang->projectCommon;
$category->grade = 1;
$category->type = 'reportTemplate';
$this->dao->insert(TABLE_MODULE)->data($category)->exec();
$categoryID = $this->dao->lastInsertID();
$this->dao->update(TABLE_MODULE)->set('`path`')->eq(",{$categoryID},")->where('id')->eq($categoryID)->exec();
return $categoryID;
}
/**
* 添加内置报告模板。
* Add builtin report template.
*
* @param int $libID
* @param int $moduleID
* @param array $blockIdList
* @access public
* @return bool
*/
public function addBuiltinTemplate(int $libID, int $moduleID, array $blockIdList): bool
{
$now = helper::now();
$cycleConfig = array('turnon' => 'on', 'frequency' => 'week', 'acl' => 'open', 'readGroups' => array(), 'readUsers' => array(), 'groups' => array(), 'users' => array());
$objects = $this->dao->select('id')->from(TABLE_WORKFLOWGROUP)->where('type')->eq('project')->andWhere('projectModel')->eq('waterfall')->andWhere('status')->eq('normal')->andWhere('vision')->eq($this->config->vision)->andWhere('objectID')->eq(0)->andWhere('deleted')->eq(0)->fetchPairs('id');
$template = new stdclass();
$template->lib = $libID;
$template->module = $moduleID;
$template->title = $this->lang->weekly->projectTemplate;
$template->type = 'text';
$template->status = 'normal';
$template->acl = 'open';
$template->builtIn = 1;
$template->templateType = 'reportTemplate';
$template->templateDesc = $this->lang->weekly->builtinDesc;
$template->cycle = 'week';
$template->cycleConfig = json_encode($cycleConfig);
$template->objects = ',' . implode(',', $objects) . ',';
$template->addedBy = 'system';
$template->addedDate = $now;
$this->dao->insert(TABLE_DOC)->data($template)->exec();
$templateID = $this->dao->lastInsertID();
$this->dao->update(TABLE_DOC)->set('`path`')->eq(",{$templateID},")->set('`order`')->eq($templateID)->where('id')->eq($templateID)->exec();
$this->dao->update(TABLE_DOCBLOCK)->set('doc')->eq($templateID)->where('id')->in(array_values($blockIdList))->exec();
$templateContent = new stdclass();
$templateContent->doc = $templateID;
$templateContent->title = $template->title;
$templateContent->type = 'doc';
$templateContent->version = 1;
$templateContent->rawContent = $this->getBuildinRawContent($blockIdList);
$templateContent->addedBy = 'system';
$templateContent->addedDate = $now;
$this->dao->insert(TABLE_DOCCONTENT)->data($templateContent)->exec();
$this->loadModel('action')->create('reportTemplate', $templateID, 'Created', '', '', 'system');
return !dao::isError();
}
/**
* 获取内置项目周报模板内容。
* Get builtin project weekly report template content.
*
* @param array $blockIdList
* @access public
* @return string
*/
public function getBuildinRawContent(array $blockIdList): string
{
$blockCodes = array();
foreach($blockIdList as $blockKey => $blockID) $blockCodes[] = '{' . $blockKey . '}';
$rawContent = json_decode($this->lang->weekly->builtinRawContent);
foreach($rawContent as $content)
{
if(isset($content->id)) $content->id = uniqid();
if(isset($content->createDate)) $content->createDate = time();
if(empty($content->children)) continue;
foreach($content->children as $childList)
{
if(isset($childList->id)) $childList->id = uniqid();
if(empty($childList->children)) continue;
foreach($childList->children as $child)
{
if(isset($child->id)) $child->id = uniqid();
if(!empty($child->props->text->delta))
{
foreach($child->props->text->delta as $delta)
{
if(isset($delta->attributes->holder->id)) $delta->attributes->holder->id = uniqid();
if(isset($delta->attributes->holder->name) && isset($blockIdList[$delta->attributes->holder->name])) $delta->attributes->holder->name = "{$delta->attributes->holder->name}_{$blockIdList[$delta->attributes->holder->name]}";
if(isset($delta->attributes->holder->data->blockID) && isset($blockIdList[$delta->attributes->holder->data->type])) $delta->attributes->holder->data->blockID = $blockIdList[$delta->attributes->holder->data->type];
}
}
if(!empty($child->props->content)) $child->props->content->fetcher = str_replace($blockCodes, array_values($blockIdList), $child->props->content->fetcher);
}
}
}
return json_encode($rawContent);
}
}
@@ -373,4 +373,78 @@ class weeklyTest
return $objects;
}
/**
* 添加内置报告模板范围。
* Add built-in report template scope.
*
* @access public
* @return bool|object
*/
public function addBuiltinScopeTest(): bool|object
{
$scopeID = $this->objectModel->addBuiltinScope();
if(!$scopeID) return false;
return $this->objectModel->dao->select('*')->from(TABLE_DOCLIB)->where('id')->eq($scopeID)->fetch();
}
/**
* 添加内置分类。
* Add built-in category.
*
* @access public
* @return object
*/
public function addBuiltinCategoryTest(): object
{
$scopeID = $this->objectModel->addBuiltinScope();
$categroyID = $this->objectModel->addBuiltinCategory($scopeID);
return $this->objectModel->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($categroyID)->fetch();
}
/**
* 添加内置报告模板。
* Add builtin report template.
*
* @access public
* @return array|object
*/
public function addBuiltinTemplateTest(): array|object
{
$scopeID = $this->objectModel->addBuiltinScope();
$categroyID = $this->objectModel->addBuiltinCategory($scopeID);
$this->objectModel->addBuiltinTemplate($scopeID, $categroyID, array());
if(dao::isError()) return dao::getError();
return $this->objectModel->dao->select('*')->from(TABLE_DOC)->fetch();
}
/**
* 获取内置项目周报模板内容。
* Get builtin project weekly report template content.
*
* @access public
* @return array
*/
public function getBuildinRawContentTest(): array
{
$content = $this->objectModel->getBuildinRawContent(array());
return json_decode($content, true);
}
/**
* 添加内置项目周报模板。
* Add builtin project weekly report template.
*
* @access public
* @return bool|object
*/
public function addBuiltinWeeklyTemplateTest():bool|object
{
$result = $this->objectModel->addBuiltinWeeklyTemplate();
if(!$result) return false;
return $this->objectModel->dao->select('*')->from(TABLE_DOC)->fetch();
}
}
@@ -0,0 +1,26 @@
#!/usr/bin/env php
<?php
/**
title=测试 weeklyModel->addBuiltinCategory();
timeout=0
cid=1
- 测试添加内置分类
- 属性id @1
- 属性root @1
- 属性name @项目
- 属性grade @1
- 属性type @reportTemplate
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/weekly.unittest.class.php';
zenData('doclib')->gen(0);
zenData('module')->gen(0);
zenData('user')->gen(5);
su('admin');
$weeklyTester = new weeklyTest();
r($weeklyTester->addBuiltinCategoryTest()) && p('id,root,name,grade,type') && e('1,1,项目,1,reportTemplate'); // 测试添加内置分类
@@ -0,0 +1,26 @@
#!/usr/bin/env php
<?php
/**
title=测试 weeklyModel->addBuiltinScope();
timeout=0
cid=1
- 测试添加内置范围
- 属性name @项目
- 属性type @reportTemplate
- 属性main @1
- 属性addedBy @system
- 测试重复添加内置范围 @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/weekly.unittest.class.php';
zenData('doclib')->gen(0);
zenData('user')->gen(5);
su('admin');
$weeklyTester = new weeklyTest();
r($weeklyTester->addBuiltinScopeTest()) && p('name,type,main,addedBy') && e('项目,reportTemplate,1,system'); // 测试添加内置范围
r($weeklyTester->addBuiltinScopeTest()) && p() && e('0'); // 测试重复添加内置范围
@@ -0,0 +1,33 @@
#!/usr/bin/env php
<?php
/**
title=测试 weeklyModel->addBuiltinTemplate();
timeout=0
cid=1
- 测试添加内置模板
- 属性title @项目周报模板
- 属性type @text
- 属性status @normal
- 属性acl @open
- 属性builtIn @1
- 属性templateType @reportTemplate
- 属性cycle @week
- 属性addedBy @system
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/weekly.unittest.class.php';
zenData('action')->gen(0);
zenData('doclib')->gen(0);
zenData('module')->gen(0);
zenData('workflowgroup')->gen(0);
zenData('doc')->gen(0);
zenData('doccontent')->gen(0);
zenData('user')->gen(5);
su('admin');
$weeklyTester = new weeklyTest();
r($weeklyTester->addBuiltinTemplateTest()) && p('title,type,status,acl,builtIn,templateType,cycle,addedBy') && e('项目周报模板,text,normal,open,1,reportTemplate,week,system'); // 测试添加内置模板
@@ -0,0 +1,35 @@
#!/usr/bin/env php
<?php
/**
title=测试 weeklyModel->addBuiltinWeeklyTemplate();
timeout=0
cid=1
- 测试添加内置周报模板
- 属性title @项目周报模板
- 属性type @text
- 属性status @normal
- 属性acl @open
- 属性builtIn @1
- 属性templateType @reportTemplate
- 属性cycle @week
- 属性addedBy @system
- 测试重复添加内置周报模板 @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/weekly.unittest.class.php';
zenData('docblock')->gen(0);
zenData('doclib')->gen(0);
zenData('module')->gen(0);
zenData('workflowgroup')->gen(0);
zenData('doc')->gen(0);
zenData('doccontent')->gen(0);
zenData('user')->gen(5);
su('admin');
$weeklyTester = new weeklyTest();
r($weeklyTester->addBuiltinWeeklyTemplateTest()) && p('title,type,status,acl,builtIn,templateType,cycle,addedBy') && e('项目周报模板,text,normal,open,1,reportTemplate,week,system'); // 测试添加内置周报模板
r($weeklyTester->addBuiltinWeeklyTemplateTest()) && p() && e('0'); // 测试重复添加内置周报模板
@@ -0,0 +1,29 @@
#!/usr/bin/env php
<?php
/**
title=测试 weeklyModel->getBuildinRawContent();
timeout=0
cid=1
- 检查模板标题属性title @项目周报模板
- 获取holder数据
- 属性name @weekly_term
- 属性text @报告周期
- 属性hint @筛选条件:“date”介于本周
- 检查区块数量 @6
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/weekly.unittest.class.php';
zenData('user')->gen(5);
su('admin');
$weeklyTester = new weeklyTest();
$content = $weeklyTester->getBuildinRawContentTest();
r($content['meta']) && p('title') && e('项目周报模板'); // 检查模板标题
r($content['blocks']['children'][0]['children'][0]['props']['text']['delta'][0]['attributes']['holder']) && p('name,text,hint') && e('weekly_term,报告周期,筛选条件:“date”介于本周'); // 获取holder数据
r(count($content['blocks'])) && p() && e('6'); // 检查区块数量
@@ -0,0 +1,30 @@
#!/usr/bin/env php
<?php
/**
title=测试 weeklyModel->getReportData();
timeout=0
cid=1
- 检查是否存在pv属性 @1
- 检查是否存在ev属性 @1
- 检查是否存在project属性 @1
- 检查是否存在staff属性 @1
- 检查是否存在progress属性 @1
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
zenData('project')->loadYaml('project')->gen(5);
zenData('task')->loadYaml('task')->gen(30);
zenData('user')->gen(5);
su('admin');
global $tester;
$weeklyModel = $tester->loadModel('weekly');
$result = $weeklyModel->getReportData(1);
r(isset($result->pv)) && p() && e('1'); // 检查是否存在pv属性
r(isset($result->ev)) && p() && e('1'); // 检查是否存在ev属性
r(isset($result->project)) && p() && e('1'); // 检查是否存在project属性
r(isset($result->staff)) && p() && e('1'); // 检查是否存在staff属性
r(isset($result->progress)) && p() && e('1'); // 检查是否存在progress属性
+18
View File
@@ -0,0 +1,18 @@
title: project.
desc: project data.
author: Sun Guangming
version: "1.0"
fields:
- field: id
range: 1-100
- field: name
note: "名称"
fields:
- field: name1
range: 敏捷项目,瀑布项目,看板项目
- field: name2
range: 1-100
- field: model
range: scrum,waterfall,kanban
- field: type
range: project
+3
View File
@@ -17,6 +17,9 @@ $(function(){$('#exportreport').modalTrigger();});
</script>
<?php endif;?>
<div id="mainMenu" class="clearfix text-center">
<div class="btn-toolbar pull-right">
<?php echo html::a($this->createLink('weekly', 'exportweeklyreport', "module=weekly&projectID={$project->id}"), $this->lang->export, '', "class='btn btn-primary' data-width='30%' id='exportreport' data-group='project'");?>
</div>
<div id='mainContent' >
<div class='main-table'>
<table class='table table-bordered'>
File diff suppressed because one or more lines are too long