Merge branch 'feature/workflow' into main
This commit is contained in:
@@ -583,6 +583,7 @@ define('TABLE_TRAINRECORDS', '`' . $config->db->prefix . 'trainrecords
|
||||
define('TABLE_TRIP', '`' . $config->db->prefix . 'trip`');
|
||||
define('TABLE_WORKESTIMATION', '`' . $config->db->prefix . 'workestimation`');
|
||||
define('TABLE_WORKFLOW', '`' . $config->db->prefix . 'workflow`');
|
||||
define('TABLE_WORKFLOWGROUP', '`' . $config->db->prefix . 'workflowgroup`');
|
||||
define('TABLE_WORKFLOWACTION', '`' . $config->db->prefix . 'workflowaction`');
|
||||
define('TABLE_WORKFLOWDATASOURCE', '`' . $config->db->prefix . 'workflowdatasource`');
|
||||
define('TABLE_WORKFLOWFIELD', '`' . $config->db->prefix . 'workflowfield`');
|
||||
@@ -717,6 +718,7 @@ $config->objectTables['market'] = TABLE_MARKET;
|
||||
$config->objectTables['marketreport'] = TABLE_MARKETREPORT;
|
||||
$config->objectTables['marketresearch'] = TABLE_PROJECT;
|
||||
$config->objectTables['researchstage'] = TABLE_PROJECT;
|
||||
$config->objectTables['workflowgroup'] = TABLE_WORKFLOWGROUP;
|
||||
$config->objectTables['productline'] = TABLE_MODULE;
|
||||
|
||||
$config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme', 'visions', 'aiPrompts', 'promptDesign', 'promptExec');
|
||||
|
||||
@@ -1,2 +1,53 @@
|
||||
ALTER TABLE zt_opportunity ADD `desc` mediumtext NULL AFTER `from`;
|
||||
ALTER TABLE zt_taskteam MODIFY `status` enum('wait','doing','done','cancel','closed') NOT NULL DEFAULT 'wait';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflowgroup` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`type` varchar(10) NOT NULL DEFAULT '',
|
||||
`projectModel` varchar(10) NOT NULL DEFAULT '',
|
||||
`projectType` varchar(10) NOT NULL DEFAULT '',
|
||||
`name` varchar(30) NOT NULL DEFAULT '',
|
||||
`desc` text NULL,
|
||||
`disabledModules` text NULL,
|
||||
`status` varchar(10) NOT NULL DEFAULT 'wait',
|
||||
`vision` varchar(10) NOT NULL DEFAULT 'rnd',
|
||||
`createdBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`createdDate` datetime NULL,
|
||||
`editedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`editedDate` datetime NULL,
|
||||
`deleted` enum('0', '1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
CREATE INDEX `type` ON `zt_workflowgroup` (`type`);
|
||||
|
||||
ALTER TABLE `zt_workflow` ADD `group` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `id`;
|
||||
ALTER TABLE `zt_workflow` ADD `role` varchar(10) NOT NULL DEFAULT 'custom' AFTER `buildin`;
|
||||
ALTER TABLE `zt_workflowfield` ADD `group` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `id`;
|
||||
ALTER TABLE `zt_workflowaction` ADD `group` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `id`;
|
||||
ALTER TABLE `zt_workflowlabel` ADD `group` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `id`;
|
||||
ALTER TABLE `zt_workflowlayout` ADD `group` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `id`;
|
||||
ALTER TABLE `zt_workflowui` ADD `group` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `id`;
|
||||
|
||||
UPDATE `zt_workflow` SET `role` = 'buildin' WHERE `buildin` = '1';
|
||||
|
||||
ALTER TABLE `zt_workflow` DROP INDEX `unique`;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflow`(`group`,`app`,`module`,`vision`);
|
||||
ALTER TABLE `zt_workflowfield` DROP INDEX `unique`;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowfield`(`group`,`module`,`field`);
|
||||
ALTER TABLE `zt_workflowaction` DROP INDEX `unique`;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowaction`(`group`,`module`,`action`,`vision`);
|
||||
ALTER TABLE `zt_workflowlayout` DROP INDEX `unique`;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowlayout`(`group`,`module`,`action`,`ui`,`field`,`vision`);
|
||||
|
||||
ALTER TABLE `zt_product` ADD `workflowGroup` int(8) NOT NULL DEFAULT '0' AFTER `ticket`;
|
||||
ALTER TABLE `zt_project` ADD `workflowGroup` int(8) NOT NULL DEFAULT '0' AFTER `hasProduct`;
|
||||
ALTER TABLE `zt_workflowgroup` ADD `main` enum('0','1') NOT NULL DEFAULT '0' AFTER `vision`;
|
||||
ALTER TABLE `zt_workflowgroup` ADD `code` varchar(30) NOT NULL DEFAULT '' AFTER `name`;
|
||||
|
||||
DELETE FROM `zt_workflowgroup` WHERE `main` = '1';
|
||||
INSERT INTO `zt_workflowgroup` (`type`, `projectModel`, `projectType`, `name`, `code`, `status`, `vision`, `main`) VALUES
|
||||
('product', '', 'project', '默认流程', 'productproject', 'normal', 'rnd', '1'),
|
||||
('project', 'scrum', 'product', '敏捷-产品型默认流程', 'scrumproduct', 'normal', 'rnd', '1'),
|
||||
('project', 'scrum', 'project', '敏捷-项目型默认流程', 'scrumproject', 'normal', 'rnd', '1'),
|
||||
('project', 'waterfall', 'product', '瀑布-产品型默认流程', 'waterfallproduct', 'normal', 'rnd', '1'),
|
||||
('project', 'waterfall', 'project', '瀑布-项目型默认流程', 'waterfallproject', 'normal', 'rnd', '1');
|
||||
|
||||
+42
-4
@@ -1379,6 +1379,7 @@ CREATE TABLE IF NOT EXISTS `zt_product` (
|
||||
`RD` varchar(30) NOT NULL DEFAULT '',
|
||||
`feedback` varchar(30) NOT NULL DEFAULT '',
|
||||
`ticket` varchar(30) NOT NULL DEFAULT '',
|
||||
`workflowGroup` int(8) NOT NULL DEFAULT '0',
|
||||
`acl` enum('open','private','custom') NOT NULL DEFAULT 'open',
|
||||
`groups` text NULL,
|
||||
`whitelist` text NULL,
|
||||
@@ -1469,6 +1470,7 @@ CREATE TABLE IF NOT EXISTS `zt_project` (
|
||||
`name` varchar(90) NOT NULL DEFAULT '',
|
||||
`code` varchar(45) NOT NULL DEFAULT '',
|
||||
`hasProduct` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||
`workflowGroup` int(8) NOT NULL DEFAULT '0',
|
||||
`begin` date NULL,
|
||||
`end` date NULL,
|
||||
`firstEnd` date DEFAULT NULL,
|
||||
@@ -13213,6 +13215,7 @@ SELECT `module`, `method`, 16 from `zt_grouppriv` where `group` = 9;
|
||||
-- DROP TABLE IF EXISTS `zt_workflow`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflow` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`group` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`parent` varchar(30) NOT NULL DEFAULT '',
|
||||
`child` varchar(30) NOT NULL DEFAULT '',
|
||||
`type` varchar(10) NOT NULL DEFAULT 'flow',
|
||||
@@ -13230,6 +13233,7 @@ CREATE TABLE IF NOT EXISTS `zt_workflow` (
|
||||
`css` text NULL,
|
||||
`order` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`buildin` tinyint(1) unsigned NOT NULL DEFAULT '0',
|
||||
`role` varchar(10) NOT NULL DEFAULT 'custom',
|
||||
`belong` varchar(50) NOT NULL DEFAULT '',
|
||||
`administrator` text NULL,
|
||||
`desc` text NULL,
|
||||
@@ -13243,15 +13247,38 @@ CREATE TABLE IF NOT EXISTS `zt_workflow` (
|
||||
`editedDate` datetime NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflow`(`app`,`module`,`vision`);
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflow`(`group`,`app`,`module`,`vision`);
|
||||
CREATE INDEX `type` ON `zt_workflow` (`type`);
|
||||
CREATE INDEX `app` ON `zt_workflow` (`app`);
|
||||
CREATE INDEX `module` ON `zt_workflow` (`module`);
|
||||
CREATE INDEX `order` ON `zt_workflow` (`order`);
|
||||
|
||||
-- DROP TABLE IF EXISTS `zt_workflowgroup`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflowgroup` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`type` varchar(10) NOT NULL DEFAULT '',
|
||||
`projectModel` varchar(10) NOT NULL DEFAULT '',
|
||||
`projectType` varchar(10) NOT NULL DEFAULT '',
|
||||
`name` varchar(30) NOT NULL DEFAULT '',
|
||||
`code` varchar(30) NOT NULL DEFAULT '',
|
||||
`desc` text NULL,
|
||||
`disabledModules` text NULL,
|
||||
`status` varchar(10) NOT NULL DEFAULT 'wait',
|
||||
`vision` varchar(10) NOT NULL DEFAULT 'rnd',
|
||||
`main` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`createdBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`createdDate` datetime NULL,
|
||||
`editedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`editedDate` datetime NULL,
|
||||
`deleted` enum('0', '1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
CREATE INDEX `type` ON `zt_workflowgroup` (`type`);
|
||||
|
||||
-- DROP TABLE IF EXISTS `zt_workflowaction`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflowaction` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`group` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`module` varchar(30) NOT NULL DEFAULT '',
|
||||
`action` varchar(50) NOT NULL DEFAULT '',
|
||||
`method` varchar(50) NOT NULL DEFAULT '',
|
||||
@@ -13284,7 +13311,7 @@ CREATE TABLE IF NOT EXISTS `zt_workflowaction` (
|
||||
`editedDate` datetime NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowaction`(`module`,`action`,`vision`);
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowaction`(`group`,`module`,`action`,`vision`);
|
||||
CREATE INDEX `module` ON `zt_workflowaction` (`module`);
|
||||
CREATE INDEX `action` ON `zt_workflowaction` (`action`);
|
||||
CREATE INDEX `order` ON `zt_workflowaction` (`order`);
|
||||
@@ -13312,6 +13339,7 @@ CREATE INDEX `type` ON `zt_workflowdatasource` (`type`);
|
||||
-- DROP TABLE IF EXISTS `zt_workflowfield`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflowfield` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`group` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`module` varchar(30) NOT NULL DEFAULT '',
|
||||
`field` varchar(50) NOT NULL DEFAULT '',
|
||||
`type` varchar(20) NOT NULL DEFAULT 'varchar',
|
||||
@@ -13339,7 +13367,7 @@ CREATE TABLE IF NOT EXISTS `zt_workflowfield` (
|
||||
`editedDate` datetime NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowfield`(`module`, `field`);
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowfield`(`group`, `module`, `field`);
|
||||
CREATE INDEX `module` ON `zt_workflowfield` (`module`);
|
||||
CREATE INDEX `field` ON `zt_workflowfield` (`field`);
|
||||
CREATE INDEX `order` ON `zt_workflowfield` (`order`);
|
||||
@@ -13347,6 +13375,7 @@ CREATE INDEX `order` ON `zt_workflowfield` (`order`);
|
||||
-- DROP TABLE IF EXISTS `zt_workflowlayout`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflowlayout` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`group` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`module` varchar(30) NOT NULL DEFAULT '',
|
||||
`action` varchar(50) NOT NULL DEFAULT '',
|
||||
`ui` mediumint(8) NOT NULL DEFAULT 0,
|
||||
@@ -13362,7 +13391,7 @@ CREATE TABLE IF NOT EXISTS `zt_workflowlayout` (
|
||||
`vision` varchar(10) NOT NULL DEFAULT 'rnd',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowlayout`(`module`,`action`,`ui`,`field`,`vision`);
|
||||
CREATE UNIQUE INDEX `unique` ON `zt_workflowlayout`(`group`,`module`,`action`,`ui`,`field`,`vision`);
|
||||
CREATE INDEX `module` ON `zt_workflowlayout` (`module`);
|
||||
CREATE INDEX `action` ON `zt_workflowlayout` (`action`);
|
||||
CREATE INDEX `order` ON `zt_workflowlayout` (`order`);
|
||||
@@ -13370,6 +13399,7 @@ CREATE INDEX `order` ON `zt_workflowlayout` (`order`);
|
||||
-- DROP TABLE IF EXISTS `zt_workflowlabel`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflowlabel` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`group` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`module` varchar(30) NOT NULL DEFAULT '',
|
||||
`action` varchar(30) NOT NULL DEFAULT 'browse',
|
||||
`code` varchar(30) NOT NULL DEFAULT '',
|
||||
@@ -13482,6 +13512,7 @@ CREATE INDEX `version` ON `zt_workflowversion` (`version`);
|
||||
-- DROP TABLE IF EXISTS `zt_workflowui`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_workflowui` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`group` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`module` varchar(30) NOT NULL,
|
||||
`action` varchar(50) NOT NULL,
|
||||
`name` varchar(30) NOT NULL,
|
||||
@@ -13516,6 +13547,13 @@ REPLACE INTO `zt_workflowrule`(`type`, `name`, `rule`, `createdBy`, `createdDate
|
||||
('system','电话','phone','admin','2020-10-14 14:06:14'),
|
||||
('system','IP','ip','admin','2020-10-14 14:06:14');
|
||||
|
||||
INSERT INTO `zt_workflowgroup` (`type`, `projectModel`, `projectType`, `name`, `code`, `status`, `vision`, `main`) VALUES
|
||||
('product', '', 'project', '默认流程', 'productproject', 'normal', 'rnd', '1'),
|
||||
('project', 'scrum', 'product', '敏捷-产品型默认流程', 'scrumproduct', 'normal', 'rnd', '1'),
|
||||
('project', 'scrum', 'project', '敏捷-项目型默认流程', 'scrumproject', 'normal', 'rnd', '1'),
|
||||
('project', 'waterfall', 'product', '瀑布-产品型默认流程', 'waterfallproduct', 'normal', 'rnd', '1'),
|
||||
('project', 'waterfall', 'project', '瀑布-项目型默认流程', 'waterfallproject', 'normal', 'rnd', '1');
|
||||
|
||||
INSERT INTO `zt_workflowdatasource` (`type`, `name`, `code`, `buildin`, `vision`, `createdBy`, `createdDate`, `datasource`, `view`, `keyField`, `valueField`) VALUES
|
||||
('system', '产品', 'products', '1', 'rnd', 'admin', '1970-01-01 00:00:01', '{\"app\":\"system\",\"module\":\"product\",\"method\":\"getPairs\",\"methodDesc\":\"Get product pairs.\",\"params\":[{\"name\":\"mode\",\"type\":\"string\",\"desc\":\"\",\"value\":\"all\"}]}', '', '', ''),
|
||||
('system', '项目', 'projects', '1', 'rnd', 'admin', '1970-01-01 00:00:01', '{\"app\":\"system\",\"module\":\"project\",\"method\":\"getPairsByModel\",\"methodDesc\":\"Get project pairs by model and project.\",\"params\":[{\"name\":\"model\",\"type\":\"string\",\"desc\":\"all|scrum|waterfall\",\"value\":\"all\"},{\"name\":\"programID\",\"type\":\"int\",\"desc\":\"\",\"value\":\"0\"},{\"name\":\"param\",\"type\":\"\",\"desc\":\"\",\"value\":\"\"}]}', '', '', ''),
|
||||
|
||||
+20
-15
@@ -525,16 +525,17 @@ class control extends baseControl
|
||||
if(!empty($this->app->installing) || !empty($this->app->upgrading)) return $fields;
|
||||
|
||||
$moduleName = $moduleName ? $moduleName : $this->app->rawModule;
|
||||
$methodName = $methodName ? $moduleName : $this->app->rawMethod;
|
||||
$methodName = $methodName ? $methodName : $this->app->rawMethod;
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
$groupID = $this->loadModel('workflowgroup')->getGroupIDByData($moduleName, $object);
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName, false, $groupID);
|
||||
if(!$flow) return $fields;
|
||||
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName, $groupID);
|
||||
if(!$action || $action->extensionType != 'extend') return $fields;
|
||||
|
||||
$uiID = $this->loadModel('workflowlayout')->getUIByData($flow->module, $action->action, $object);
|
||||
$fieldList = $this->workflowaction->getFields($flow->module, $action->action, true, null, $uiID);
|
||||
$fieldList = $this->workflowaction->getPageFields($flow->module, $action->action, true, null, $uiID, $groupID);
|
||||
return $this->loadModel('flow')->buildFormFields($fields, $fieldList, array(), $object);
|
||||
}
|
||||
|
||||
@@ -556,14 +557,15 @@ class control extends baseControl
|
||||
$moduleName = $moduleName ? $moduleName : $this->app->rawModule;
|
||||
$methodName = $methodName ? $methodName : $this->app->rawMethod;
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
$groupID = $this->loadModel('workflowgroup')->getGroupIDByData($moduleName, $object);
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName, false, $groupID);
|
||||
if(!$flow) return '';
|
||||
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName, $groupID);
|
||||
if(!$action || $action->extensionType == 'none') return '';
|
||||
|
||||
$uiID = $this->loadModel('workflowlayout')->getUIByData($flow->module, !empty($action->action) ? $action->action: '', $object);
|
||||
$fieldList = $this->loadModel('workflowaction')->getFields($flow->module, !empty($action->action) ? $action->action: '', true, null, $uiID);
|
||||
$fieldList = $this->loadModel('workflowaction')->getPageFields($flow->module, !empty($action->action) ? $action->action: '', true, null, $uiID, $groupID);
|
||||
|
||||
$html = '';
|
||||
if(!empty($flow->css)) $html .= "<style>$flow->css</style>";
|
||||
@@ -599,17 +601,17 @@ class control extends baseControl
|
||||
$this->loadModel('flow');
|
||||
$this->loadModel('workflowfield');
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
$groupID = $this->loadModel('workflowgroup')->getGroupIDByData($moduleName, $object);
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName, false, $groupID);
|
||||
if(!$flow) return array();
|
||||
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName, $groupID);
|
||||
if(!$action || $action->extensionType != 'extend') return array();
|
||||
|
||||
$uiID = is_object($object) ? $this->loadModel('workflowlayout')->getUIByData($flow->module, $action->action, $object) : 0;
|
||||
|
||||
$wrapControl = array('textarea', 'richtext', 'file');
|
||||
$fieldList = $this->workflowaction->getFields($flow->module, $action->action, true, $object, $uiID);
|
||||
$layouts = $this->loadModel('workflowlayout')->getFields($moduleName, $methodName, $uiID);
|
||||
$fieldList = $this->workflowaction->getPageFields($flow->module, $action->action, true, $object, $uiID, $groupID);
|
||||
$layouts = $this->loadModel('workflowlayout')->getFields($moduleName, $methodName, $uiID, $groupID);
|
||||
$notEmptyRule = $this->loadModel('workflowrule')->getByTypeAndRule('system', 'notempty');
|
||||
|
||||
if($layouts)
|
||||
@@ -631,8 +633,10 @@ class control extends baseControl
|
||||
$field->required = $field->readonly || ($notEmptyRule && strpos(",$field->rules,", ",{$notEmptyRule->id},") !== false);
|
||||
$field->control = $this->flow->buildFormControl($field);
|
||||
$field->items = $field->options ? array_filter($field->options) : null;
|
||||
$field->value = !empty($object) ? zget($object, $field->field, '') : '';
|
||||
$field->value = !empty($object->{$field->field}) ? zget($object, $field->field, '') : '';
|
||||
$field->width = $field->width != 'auto' ? $field->width : 'full';
|
||||
|
||||
if(!$field->value && $field->defaultValue) $field->value = $field->defaultValue;
|
||||
}
|
||||
|
||||
return $fieldList;
|
||||
@@ -695,9 +699,10 @@ class control extends baseControl
|
||||
{
|
||||
if($this->config->edition == 'open') return;
|
||||
|
||||
$groupID = $this->loadModel('workflowgroup')->getGroupIDByDataID($this->moduleName, $objectID);
|
||||
$uiID = $this->loadModel('workflowlayout')->getUIByDataID($this->moduleName, $this->methodName, $objectID);
|
||||
$fields = $this->loadModel('workflowaction')->getFields($this->moduleName, $this->methodName, true, null, $uiID);
|
||||
$layouts = $this->loadModel('workflowlayout')->getFields($this->moduleName, $this->methodName, $uiID);
|
||||
$fields = $this->loadModel('workflowaction')->getPageFields($this->moduleName, $this->methodName, true, null, $uiID, $groupID);
|
||||
$layouts = $this->loadModel('workflowlayout')->getFields($this->moduleName, $this->methodName, $uiID, $groupID);
|
||||
$notEmptyRule = $this->loadModel('workflowrule')->getByTypeAndRule('system', 'notempty');
|
||||
foreach($fields as $field)
|
||||
{
|
||||
|
||||
@@ -394,13 +394,14 @@ class model extends baseModel
|
||||
$moduleName = $this->app->getModuleName();
|
||||
$methodName = $this->app->getMethodName();
|
||||
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($moduleName, $methodName);
|
||||
$groupID = $this->loadModel('workflowgroup')->getGroupIDByDataID($moduleName, $objectID);
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($moduleName, $methodName, $groupID);
|
||||
if(empty($action) or $action->extensionType == 'none') return '';
|
||||
|
||||
$this->loadModel('file');
|
||||
if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $moduleName);
|
||||
$uiID = $this->loadModel('workflowlayout')->getUIByDataID($moduleName, $methodName, $objectID);
|
||||
$fields = $this->workflowaction->getFields($moduleName, $action->action, '', null, $uiID);
|
||||
$fields = $this->workflowaction->getPageFields($moduleName, $action->action, '', null, $uiID, $groupID);
|
||||
foreach($fields as $field)
|
||||
{
|
||||
if($field->control == 'file' && $field->show && !$field->readonly)
|
||||
@@ -409,7 +410,7 @@ class model extends baseModel
|
||||
}
|
||||
}
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName, false, $groupID);
|
||||
if($flow && $action) return $this->loadModel('workflowhook')->execute($flow, $action, $objectID);
|
||||
}
|
||||
|
||||
|
||||
@@ -223,8 +223,12 @@ class router extends baseRouter
|
||||
/* When upgrading from version 12 to the paid version, the workflow table does not exist. */
|
||||
try
|
||||
{
|
||||
$flows = $this->dbQuery('SELECT * FROM ' . TABLE_WORKFLOW . " WHERE `buildin` = 0 AND `vision` = '{$this->config->vision}' AND status = 'normal' AND type = 'flow' AND `navigator` = 'primary'")->fetchAll();
|
||||
foreach($flows as $flow) $this->lang->mainNav->{$flow->module} = "{$this->lang->navIcons['workflow']} {$flow->name}|{$flow->module}|browse|";
|
||||
$flows = $this->dbQuery('SELECT * FROM ' . TABLE_WORKFLOW . " WHERE `buildin` = 0 AND `vision` = '{$this->config->vision}' AND status = 'normal' AND type = 'flow'")->fetchAll();
|
||||
foreach($flows as $flow)
|
||||
{
|
||||
if($flow->navigator == 'primary') $this->lang->mainNav->{$flow->module} = "{$this->lang->navIcons['workflow']} {$flow->name}|{$flow->module}|browse|";
|
||||
if($flow->belong) $this->config->hasDropmenuApps[] = $flow->app; // 带有1.5级导航的应用
|
||||
}
|
||||
}
|
||||
catch(PDOException){}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class fixer extends baseFixer
|
||||
$action = $app->control->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
if(!$action || $action->extensionType != 'extend') return parent::get($fields);
|
||||
|
||||
$fieldList = $app->control->workflowaction->getFields($flow->module, $action->action);
|
||||
$fieldList = $app->control->workflowaction->getPageFields($flow->module, $action->action);
|
||||
$layouts = $app->control->loadModel('workflowlayout')->getFields($moduleName, $methodName);
|
||||
if($layouts)
|
||||
{
|
||||
|
||||
@@ -122,12 +122,13 @@ class form extends fixer
|
||||
$flow = $app->control->loadModel('workflow')->getByModule($moduleName);
|
||||
if(!$flow) return $configObject;
|
||||
|
||||
$action = $app->control->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName);
|
||||
$groupID = $app->control->loadModel('workflowgroup')->getGroupIDByDataID($flow->module, $objectID);
|
||||
$action = $app->control->loadModel('workflowaction')->getByModuleAndAction($flow->module, $methodName, $groupID);
|
||||
if(!$action || $action->extensionType != 'extend') return $configObject;
|
||||
|
||||
$uiID = $app->control->loadModel('workflowlayout')->getUIByDataID($flow->module, $action->action, $objectID);
|
||||
$fieldList = $app->control->workflowaction->getFields($flow->module, $action->action, true, null, $uiID);
|
||||
$layouts = $app->control->workflowlayout->getFields($moduleName, $methodName, $uiID);
|
||||
$fieldList = $app->control->workflowaction->getPageFields($flow->module, $action->action, true, null, $uiID, $groupID);
|
||||
$layouts = $app->control->workflowlayout->getFields($moduleName, $methodName, $uiID, $groupID);
|
||||
$notEmptyRule = $app->control->loadModel('workflowrule')->getByTypeAndRule('system', 'notempty');
|
||||
if($layouts)
|
||||
{
|
||||
|
||||
@@ -238,6 +238,7 @@ function queryBase(): queryBase {return createWg('queryBase', func_get_args());}
|
||||
function queryFilterModal(): queryFilterModal {return createWg('queryFilterModal', func_get_args());}
|
||||
function pivotTable(): pivotTable {return createWg('pivotTable', func_get_args());}
|
||||
function pivotConfig(): pivotConfig {return createWg('pivotConfig', func_get_args());}
|
||||
function iconPicker(): iconPicker {return createWg('iconPicker', func_get_args());}
|
||||
|
||||
if(is_dir(__DIR__ . DS . 'wg' . DS . 'schedule'))
|
||||
{
|
||||
|
||||
@@ -76,13 +76,22 @@ class dropmenu extends wg
|
||||
{
|
||||
list($url, $text, $objectID, $cache, $tab, $module, $method, $extra, $id, $data, $menuID) = $this->prop(array('url', 'text', 'objectID', 'cache', 'tab', 'module', 'method', 'extra', 'id', 'data', 'menuID'));
|
||||
|
||||
$app = data('app');
|
||||
$lang = data('lang');
|
||||
$app = data('app');
|
||||
$lang = data('lang');
|
||||
$config = data('config');
|
||||
|
||||
if(empty($menuID)) $menuID = $id . '-menu';
|
||||
if(empty($tab)) $tab = $app->tab;
|
||||
if(empty($module)) $module = $app->rawModule;
|
||||
if(empty($method)) $method = $app->rawMethod;
|
||||
|
||||
/* 打印工作流1.5级导航. */
|
||||
if($config->edition != 'open')
|
||||
{
|
||||
$flow = $app->control->loadModel('workflow')->getByModule($module);
|
||||
if($flow && $flow->buildin == '0' && $flow->belong) $tab = $flow->belong;
|
||||
}
|
||||
|
||||
if(empty($menuID)) $menuID = $id . '-menu';
|
||||
if(empty($extra)) $extra = '';
|
||||
if(empty($objectID)) $objectID = data($tab . 'ID');
|
||||
if(empty($objectID))
|
||||
|
||||
+59
-24
@@ -77,19 +77,69 @@ class formPanel extends panel
|
||||
{
|
||||
global $app;
|
||||
$moduleName = $app->getModuleName();
|
||||
if($moduleName == 'caselib') $moduleName = 'lib';
|
||||
if($moduleName == 'productplan') $moduleName = 'plan';
|
||||
if($moduleName == 'flow') return data('data');
|
||||
if($moduleName == 'caselib') return data('lib');
|
||||
if($moduleName == 'flow') return data('data');
|
||||
if($moduleName == 'productplan') return data('plan');
|
||||
if($moduleName == 'projectrelease') return data('release');
|
||||
if($moduleName == 'projectbuild') return data('build');
|
||||
return data($moduleName);
|
||||
}
|
||||
|
||||
protected function getModuleAndMethodForExtend()
|
||||
{
|
||||
global $app;
|
||||
$moduleName = $app->rawModule;
|
||||
$methodName = $app->rawMethod;
|
||||
|
||||
/* 项目发布和项目版本用自己的工作流。 */
|
||||
if($moduleName == 'projectrelease') $moduleName = 'release';
|
||||
if($moduleName == 'projectplan') $moduleName = 'productplan';
|
||||
if($moduleName == 'projectbuild')
|
||||
{
|
||||
$moduleName = 'build';
|
||||
if($methodName == 'browse')
|
||||
{
|
||||
$moduleName = 'execution';
|
||||
$methodName = 'build';
|
||||
}
|
||||
}
|
||||
|
||||
/* 反馈转化。 */
|
||||
if($moduleName == 'feedback')
|
||||
{
|
||||
if($methodName == 'tostory')
|
||||
{
|
||||
$moduleName = 'story';
|
||||
$methodName = 'create';
|
||||
}
|
||||
elseif($methodName == 'touserstory')
|
||||
{
|
||||
$moduleName = 'requirement';
|
||||
$methodName = 'create';
|
||||
}
|
||||
elseif($methodName == 'toepic')
|
||||
{
|
||||
$moduleName = 'epic';
|
||||
$methodName = 'create';
|
||||
}
|
||||
elseif($methodName == 'toticket')
|
||||
{
|
||||
$moduleName = 'ticket';
|
||||
$methodName = 'create';
|
||||
}
|
||||
}
|
||||
|
||||
return array($moduleName, $methodName);
|
||||
}
|
||||
|
||||
protected function created()
|
||||
{
|
||||
$fields = $this->prop('fields');
|
||||
if(is_object($fields))
|
||||
{
|
||||
global $app;
|
||||
$fields = $app->control->appendExtendFields($fields, '', '', $this->getData());
|
||||
list($moduleName, $methodName) = $this->getModuleAndMethodForExtend();
|
||||
$fields = $app->control->appendExtendFields($fields, $moduleName, $methodName, $this->getData());
|
||||
$this->setProp('fields', $fields);
|
||||
}
|
||||
|
||||
@@ -181,24 +231,7 @@ class formPanel extends panel
|
||||
$layout = $this->prop('layout');
|
||||
if($layout == 'grid') return null;
|
||||
|
||||
$moduleName = $app->rawModule;
|
||||
$methodName = $app->rawMethod;
|
||||
|
||||
/* 项目发布和项目版本用自己的工作流。 */
|
||||
if($moduleName == 'projectrelease') $moduleName = 'release';
|
||||
if($moduleName == 'projectplan') $moduleName = 'productplan';
|
||||
if($moduleName == 'projectbuild')
|
||||
{
|
||||
if($methodName == 'browse')
|
||||
{
|
||||
$moduleName = 'execution';
|
||||
$methodName = 'build';
|
||||
}
|
||||
else
|
||||
{
|
||||
$moduleName = 'build';
|
||||
}
|
||||
}
|
||||
list($moduleName, $methodName) = $this->getModuleAndMethodForExtend();
|
||||
|
||||
$data = $this->getData();
|
||||
$fields = $app->control->appendExtendForm('info', $data, $moduleName, $methodName);
|
||||
@@ -233,8 +266,9 @@ class formPanel extends panel
|
||||
{
|
||||
global $app;
|
||||
|
||||
list($moduleName, $methodName) = $this->getModuleAndMethodForExtend();
|
||||
$data = $this->getData();
|
||||
$fields = $app->control->appendExtendForm('info', $data);
|
||||
$fields = $app->control->appendExtendForm('info', $data, $moduleName, $methodName);
|
||||
|
||||
$formBatchItem = array();
|
||||
foreach($fields as $field)
|
||||
@@ -331,12 +365,13 @@ class formPanel extends panel
|
||||
{
|
||||
global $app;
|
||||
|
||||
list($moduleName, $methodName) = $this->getModuleAndMethodForExtend();
|
||||
return div
|
||||
(
|
||||
setClass('panel-body ' . $this->prop('bodyClass')),
|
||||
set($this->prop('bodyProps')),
|
||||
$this->buildContainer($this->buildForm()),
|
||||
html($app->control->appendExtendCssAndJS('', '', $this->getData()))
|
||||
html($app->control->appendExtendCssAndJS($moduleName, $methodName, $this->getData()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
window.selectIcon = function()
|
||||
{
|
||||
const icon = $(this).data('icon');
|
||||
$(this).closest('#iconPicker').find('#iconPreview').html("<i class='icon icon-" + icon + "'></i>");
|
||||
$(this).closest('#iconPicker').find('#icon').val(icon);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The iconPicker widget class file of zin module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-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 Gang Liu <liugang@easycorp.ltd>
|
||||
* @package zin
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
class iconPicker extends wg
|
||||
{
|
||||
protected static array $defineProps = array(
|
||||
'name?: string="icon"', // 控件名称。
|
||||
'value?: string="flow"', // 控件默认值。
|
||||
'items?: array' // 图标列表项。
|
||||
);
|
||||
|
||||
public static function getPageJS(): ?string
|
||||
{
|
||||
return file_get_contents(__DIR__ . DS . 'js' . DS . 'v1.js');
|
||||
}
|
||||
|
||||
protected function buildIcons(): array
|
||||
{
|
||||
$icons = [];
|
||||
$items = $this->prop('items', []);
|
||||
foreach($items as $icon)
|
||||
{
|
||||
$icons[] = button
|
||||
(
|
||||
setClass('btn square ghost'),
|
||||
setData(['icon' => $icon]),
|
||||
on::click('selectIcon'),
|
||||
icon($icon)
|
||||
);
|
||||
}
|
||||
return $icons;
|
||||
}
|
||||
|
||||
protected function build()
|
||||
{
|
||||
$name = $this->prop('name');
|
||||
$icon = $this->prop('value');
|
||||
|
||||
return div
|
||||
(
|
||||
setID('iconPicker'),
|
||||
button
|
||||
(
|
||||
setClass('btn'),
|
||||
setData(['toggle' => 'dropdown']),
|
||||
span
|
||||
(
|
||||
setID('iconPreview'),
|
||||
setClass('mr-2'),
|
||||
icon($icon)
|
||||
),
|
||||
icon('angle-down')
|
||||
),
|
||||
div
|
||||
(
|
||||
setClass('dropdown-menu menu w-64'),
|
||||
$this->buildIcons()
|
||||
),
|
||||
formHidden($name, $icon, setID('icon'))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ class inputGroupAddon extends wg
|
||||
{
|
||||
protected function build()
|
||||
{
|
||||
return h::span(setClass('input-group-addon'), set($this->props), $this->children());
|
||||
$class = $this->prop('class');
|
||||
return h::span(setClass("input-group-addon {$class}"), set($this->props), $this->children());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,13 @@ function getCurrentMainNavbarItems()
|
||||
{
|
||||
const $elm = $(element);
|
||||
$a = $elm.find('a');
|
||||
items.push(
|
||||
{
|
||||
name: $a.attr('data-id'),
|
||||
order: index * 5
|
||||
}
|
||||
);
|
||||
|
||||
const menuItem = {};
|
||||
menuItem.name = $a.attr('data-id'),
|
||||
menuItem.order = index * 5;
|
||||
if(typeof $elm.data('hidden') != 'undefined') menuItem.hidden = true;
|
||||
|
||||
items.push(menuItem);
|
||||
}
|
||||
);
|
||||
return items;
|
||||
@@ -157,7 +158,7 @@ $(document).on(
|
||||
onClick: hideDisabled
|
||||
? null
|
||||
: () => {
|
||||
$li.remove();
|
||||
$li.hide().attr('data-hidden', '1');
|
||||
saveMainNavbarToServer($item);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -42,16 +42,17 @@ function getCurrentNavbarItems()
|
||||
$nav.children().each(
|
||||
function(index, element)
|
||||
{
|
||||
const $elm = $(element)
|
||||
const $a = $elm.find('a');
|
||||
items.push(
|
||||
{
|
||||
name: $elm.is('.nav-divider') ? 'divider' : ($a.attr('data-id') || $a.attr('id')),
|
||||
order: index * 5
|
||||
}
|
||||
);
|
||||
const $elm = $(element)
|
||||
const $a = $elm.find('a');
|
||||
const menuItem = {};
|
||||
menuItem.name = $elm.is('.nav-divider') ? 'divider' : ($a.attr('data-id') || $a.attr('id'));
|
||||
menuItem.order = index * 5;
|
||||
if(typeof $elm.data('hidden') != 'undefined') menuItem.hidden = true;
|
||||
|
||||
items.push(menuItem);
|
||||
}
|
||||
);
|
||||
console.log(items);
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -198,7 +199,7 @@ $(document).on(
|
||||
onClick: hideDisabled
|
||||
? null
|
||||
: () => {
|
||||
$li.remove();
|
||||
$li.hasClass('nav-divider') ? $li.remove() : $li.hide().attr('data-hidden', '1');
|
||||
saveNavbarToServer();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -62,10 +62,14 @@ class actionModel extends model
|
||||
if(empty($comment)) $comment = '';
|
||||
$action->comment = fixer::stripDataTags($comment);
|
||||
|
||||
if($this->post->uid)
|
||||
$uid = $this->post->uid;
|
||||
if(is_string($uid)) $uid = array($uid);
|
||||
if(!is_array($uid)) $uid = array();
|
||||
$this->loadModel('file');
|
||||
foreach($uid as $value)
|
||||
{
|
||||
$action = $this->loadModel('file')->processImgURL($action, 'comment', $this->post->uid);
|
||||
if($autoDelete) $this->file->autoDelete($this->post->uid);
|
||||
$action = $this->file->processImgURL($action, 'comment', $value);
|
||||
if($autoDelete) $this->file->autoDelete($value);
|
||||
}
|
||||
|
||||
/* 获取对象的产品项目以及执行。 */
|
||||
@@ -89,7 +93,7 @@ class actionModel extends model
|
||||
}
|
||||
if($hasRecentTable) $this->dao->insert(TABLE_ACTIONRECENT)->data($action)->autoCheck()->exec();
|
||||
|
||||
if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $objectType);
|
||||
$this->file->updateObjectID($uid, $objectID, $objectType);
|
||||
|
||||
$this->loadModel('message')->send(strtolower($objectType), $objectID, $actionType, $actionID, $actor, $extra);
|
||||
|
||||
|
||||
@@ -126,7 +126,6 @@ class actionZen extends action
|
||||
$tab = '';
|
||||
$canView = common::hasPriv($module, $methodName);
|
||||
if($trash->objectType == 'meeting') $tab = $trash->project ? "data-app='project'" : "data-app='my'";
|
||||
if($module == 'requirement') $module = 'story';
|
||||
$trash->objectName = $canView ? html::a($this->createLink($module, $methodName, $params), $trash->objectName, '_self', "title='{$trash->objectName}' $tab") : "<span title='$trash->objectName'>$trash->objectName</span>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
window.reloadByProduct = function(e)
|
||||
{
|
||||
loadPage($.createLink('bug', 'create', 'productID=' + $(e.target).val() + '&branch=0&extra=projectID=' + projectID + ',executionID=' + executionID));
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ include($this->app->getModuleRoot() . 'ai/ui/inputinject.html.php');
|
||||
$fields = useFields('bug.create');
|
||||
if(!empty($executionType) && $executionType == 'kanban') $fields->merge('bug.kanban');
|
||||
|
||||
$fields->autoLoad('product', array('items' => 'product,module,execution,project,story,task,assignedTo', 'updateOrders' => true))
|
||||
->autoLoad('branch', 'module,execution,project,story,task,assignedTo')
|
||||
$fields->autoLoad('branch', 'module,execution,project,story,task,assignedTo')
|
||||
->autoLoad('module', 'assignedTo,story')
|
||||
->autoLoad('project', 'project,execution,story,task,assignedTo,injection,identify')
|
||||
->autoLoad('execution', 'execution,story,task,assignedTo')
|
||||
@@ -30,6 +29,8 @@ if(!$product->shadow) $fields->fullModeOrders('module,project,execution');
|
||||
jsVar('bug', $bug);
|
||||
jsVar('moduleID', $bug->moduleID);
|
||||
jsVar('methodName', $app->methodName);
|
||||
jsVar('projectID', isset($projectID) ? $projectID : 0);
|
||||
jsVar('executionID', isset($executionID) ? $executionID : 0);
|
||||
jsVar('tab', $this->app->tab);
|
||||
jsVar('createRelease', $lang->release->create);
|
||||
jsVar('refresh', $lang->refreshIcon);
|
||||
@@ -37,7 +38,8 @@ jsVar('projectExecutionPairs', $projectExecutionPairs);
|
||||
|
||||
formGridPanel
|
||||
(
|
||||
on::change('[name="product"], [name="branch"], [name="project"], [name="execution"]', 'loadBuilds'),
|
||||
on::change('[name="product"]', 'reloadByProduct'),
|
||||
on::change('[name="branch"], [name="project"], [name="execution"]', 'loadBuilds'),
|
||||
set::title($lang->bug->create),
|
||||
set::fields($fields),
|
||||
set::loadUrl($loadUrl)
|
||||
|
||||
+26
-7
@@ -621,18 +621,37 @@ class commonModel extends model
|
||||
/* Ensure user has latest rights set. */
|
||||
$app->user->rights = $app->control->loadModel('user')->authorize($app->user->account);
|
||||
|
||||
$menuOrder = array();
|
||||
$menuOrder = $lang->mainNav->menuOrder;
|
||||
$hasCustomMenu = false;
|
||||
if(isset($config->customMenu->nav) && !$useDefault && !commonModel::isTutorialMode())
|
||||
{
|
||||
$items = json_decode($config->customMenu->nav);
|
||||
foreach($items as $item) $menuOrder[$item->order] = $item->name;
|
||||
$customMenuOrder = array();
|
||||
$items = json_decode($config->customMenu->nav);
|
||||
$hiddenItems = array();
|
||||
foreach($items as $item)
|
||||
{
|
||||
if(!empty($item->hidden))
|
||||
{
|
||||
$hiddenItems[] = $item->name;
|
||||
continue;
|
||||
}
|
||||
|
||||
$customMenuOrder[$item->order] = $item->name;
|
||||
}
|
||||
|
||||
$customMenuItems = array_values($customMenuOrder);
|
||||
foreach($menuOrder as $order => $name)
|
||||
{
|
||||
if(in_array($name, $customMenuItems) || in_array($name, $hiddenItems)) continue;
|
||||
|
||||
while(isset($customMenuOrder[$order])) $order ++;
|
||||
$customMenuOrder[$order] = $name;
|
||||
}
|
||||
|
||||
$menuOrder = $customMenuOrder;
|
||||
$hasCustomMenu = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$menuOrder = $lang->mainNav->menuOrder;
|
||||
}
|
||||
|
||||
ksort($menuOrder);
|
||||
|
||||
$items = array();
|
||||
|
||||
@@ -586,6 +586,24 @@ class custom extends control
|
||||
$menu = $this->post->menu; // 导航类型,nav(左侧主导航)|$app(顶部一级导航)|$app-home(项目集、项目的首页导航)|$app-$subMenu(顶部二级导航)|admin-$menuKey(后台导航)
|
||||
$items = $this->post->items; // 导航项
|
||||
$account = $this->app->user->account;
|
||||
$oldMenu = isset($this->config->customMenu->{$menu}) ? $this->config->customMenu->{$menu} : '';
|
||||
|
||||
/* 之前隐藏的导航若没开启继续保持隐藏。 */
|
||||
if($oldMenu)
|
||||
{
|
||||
$oldMenus = json_decode($oldMenu);
|
||||
$menus = json_decode($items);
|
||||
|
||||
$menuNames = array();
|
||||
foreach($menus as $key => $item) $menuNames[] = $item->name;
|
||||
|
||||
foreach($oldMenus as $key => $item)
|
||||
{
|
||||
if(!empty($item->hidden) && !in_array($item->name, $menuNames)) $menus[] = $item;
|
||||
}
|
||||
|
||||
$items = json_encode($menus);
|
||||
}
|
||||
|
||||
if($menu && $items) $this->loadModel('setting')->setItem("$account.common.customMenu.$menu@{$this->config->vision}", $items);
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ class customModel extends model
|
||||
*/
|
||||
public static function setMenuByConfig(object|array $allMenu, string|array $customMenu, string $module = ''): array
|
||||
{
|
||||
global $app, $lang, $config;
|
||||
global $app, $lang;
|
||||
|
||||
$tab = $app->tab;
|
||||
list($customMenuMap, $order) = static::buildCustomMenuMap($allMenu, $customMenu, $module);
|
||||
@@ -194,6 +194,7 @@ class customModel extends model
|
||||
}
|
||||
|
||||
$menu = static::buildMenuItems($allMenu, $customMenuMap, $module, $order);
|
||||
|
||||
ksort($menu, SORT_NUMERIC);
|
||||
|
||||
if(!isset($lang->{$tab})) return array();
|
||||
@@ -365,7 +366,7 @@ class customModel extends model
|
||||
/* Process menu item's order and hidden attirbute. */
|
||||
$menuItem = static::buildMenuItem($item, $customMenuMap, $name, $label, $itemLink, $isTutorialMode, $subMenu);
|
||||
$menuItem->order = (isset($customMenuMap[$name]) && isset($customMenuMap[$name]->order) ? $customMenuMap[$name]->order : $order ++);
|
||||
if(!empty($customMenuMap) && !isset($customMenuMap[$name])) $menuItem->hidden = true; // 自定义过滤掉的菜单不显示。
|
||||
if(!empty($customMenuMap) && !empty($customMenuMap[$name]->hidden)) $menuItem->hidden = true; // 自定义过滤掉的菜单不显示。
|
||||
if(isset($customMenuMap[$name]) && isset($customMenuMap[$name]->divider)) $menuItem->divider = true;
|
||||
if($app->viewType == 'mhtml' && isset($config->custom->moblieHidden[$menuModuleName]) && in_array($name, $config->custom->moblieHidden[$menuModuleName])) $menuItem->hidden = 1; // Hidden menu by config in mobile.
|
||||
while(isset($menu[$menuItem->order])) $menuItem->order ++;
|
||||
|
||||
+39
-31
@@ -58,7 +58,7 @@ class datatableModel extends model
|
||||
}
|
||||
|
||||
/* 加载工作流字段配置。 */
|
||||
if($this->config->edition != 'open') $fieldList = $this->appendWorkflowFields($module, $method, $fieldList);
|
||||
if($this->config->edition != 'open') $fieldList += $this->appendWorkflowFields($module, $method);
|
||||
|
||||
return $fieldList;
|
||||
}
|
||||
@@ -441,11 +441,10 @@ class datatableModel extends model
|
||||
*
|
||||
* @param string $module
|
||||
* @param string $method
|
||||
* @param array $fieldList
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function appendWorkflowFields(string $module, string $method, array $fieldList): array
|
||||
public function appendWorkflowFields(string $module, string $method): array
|
||||
{
|
||||
if(in_array($module, array('epic', 'story', 'requirement')))
|
||||
{
|
||||
@@ -475,39 +474,48 @@ class datatableModel extends model
|
||||
$module = 'release'; // 项目发布加载release-browse的layout配置。
|
||||
}
|
||||
|
||||
$flow = $this->loadModel('workflow')->getByModule($module);
|
||||
if(empty($flow)) return $fieldList;
|
||||
|
||||
if($flow->buildin == 1)
|
||||
$this->loadModel('workflow');
|
||||
$this->loadModel('workflowgroup');
|
||||
$this->loadModel('workflowaction');
|
||||
if(($this->app->tab == 'project' || $this->app->tab == 'execution') && in_array($module, $this->config->workflowgroup->modules['product']))
|
||||
{
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($module, $method);
|
||||
if(!$action || (isset($action->extensionType) && $action->extensionType != 'extend')) return $fieldList; // 不扩展不追加字段。
|
||||
}
|
||||
$groupIdList = array();
|
||||
$fields = array();
|
||||
$projectID = $this->app->tab == 'execution' ? $this->session->execution : $this->session->project;
|
||||
$products = $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
||||
->where('t1.project')->eq((int)$projectID)
|
||||
->fetchAll('id');
|
||||
|
||||
$fields = $this->loadModel('workflowaction')->getFields($module, $method);
|
||||
if($flow->buildin == 1) return array_merge($fieldList, $this->loadModel('flow')->buildDtableCols($fields));
|
||||
|
||||
foreach($fields as $field)
|
||||
{
|
||||
if(!$field->show) continue;
|
||||
|
||||
$fieldList[$field->field]['name'] = $field->field;
|
||||
$fieldList[$field->field]['title'] = $field->name;
|
||||
$fieldList[$field->field]['show'] = true;
|
||||
$fieldList[$field->field]['width'] = (empty($field->width) || $field->width == 'auto') ? '120' : $field->width;
|
||||
|
||||
if($field->field == 'id')
|
||||
foreach($products as $product) $groupIdList[] = $product->workflowGroup;
|
||||
foreach(array_unique($groupIdList) as $groupID)
|
||||
{
|
||||
$fieldList[$field->field]['fixed'] = 'left';
|
||||
$fieldList[$field->field]['required'] = true;
|
||||
}
|
||||
elseif($field->field == 'actions')
|
||||
{
|
||||
$fieldList[$field->field]['fixed'] = 'right';
|
||||
$fieldList[$field->field]['required'] = true;
|
||||
$flow = $this->workflow->getByModule($module, false, $groupID);
|
||||
if(empty($flow)) countinue;
|
||||
|
||||
if($flow->buildin)
|
||||
{
|
||||
$action = $this->workflowaction->getByModuleAndAction($module, $method, $groupID);
|
||||
if(!$action || (isset($action->extensionType) && $action->extensionType != 'extend')) continue; // 不扩展不追加字段。
|
||||
}
|
||||
$fields += $this->workflowaction->getPageFields($module, $method, true, array(), 0, $groupID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$groupID = $this->workflowgroup->getGroupIDBySession($module);
|
||||
$flow = $this->workflow->getByModule($module, false, $groupID);
|
||||
if(empty($flow)) return [];
|
||||
|
||||
return $fieldList;
|
||||
if($flow->buildin)
|
||||
{
|
||||
$action = $this->workflowaction->getByModuleAndAction($module, $method, $groupID);
|
||||
if(!$action || (isset($action->extensionType) && $action->extensionType != 'extend')) return []; // 不扩展不追加字段。
|
||||
}
|
||||
|
||||
$fields = $this->workflowaction->getPageFields($module, $method, true, array(), 0, $groupID);
|
||||
}
|
||||
|
||||
return $this->loadModel('flow')->buildDtableCols($fields, [], [], !$flow->buildin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1006,6 +1006,7 @@ class execution extends control
|
||||
if($executionID) return $this->executionZen->displayAfterCreated($projectID, $executionID, $planID, $confirm);
|
||||
|
||||
$allProjects = $this->project->getPairsByModel('all', 'noclosed,multiple');
|
||||
$this->loadModel('project')->checkAccess($projectID, $allProjects);
|
||||
if(empty($projectID)) $projectID = key($allProjects) ? key($allProjects) : 0;
|
||||
|
||||
$project = empty($projectID) ? null : $this->loadModel('project')->fetchByID($projectID);
|
||||
@@ -1253,6 +1254,7 @@ class execution extends control
|
||||
$allChanges = $this->execution->batchUpdate($postData);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->executeHooks(key($this->post->id));
|
||||
if(!empty($allChanges))
|
||||
{
|
||||
foreach($allChanges as $executionID => $changes)
|
||||
|
||||
@@ -56,15 +56,12 @@ $cols = $this->loadModel('datatable')->getSetting('execution');
|
||||
if($execution->type != 'stage') unset($cols['design']);
|
||||
|
||||
$tableData = initTableData($tasks, $cols, $this->task);
|
||||
$tableData = array_map(
|
||||
function($task)
|
||||
{
|
||||
if(helper::isZeroDate($task->deadline)) $task->deadline = '';
|
||||
if(helper::isZeroDate($task->estStarted)) $task->estStarted = '';
|
||||
return $task;
|
||||
},
|
||||
$tableData
|
||||
);
|
||||
foreach($tableData as $task)
|
||||
{
|
||||
$task->status = $this->processStatus('task', $task);
|
||||
if(helper::isZeroDate($task->deadline)) $task->deadline = '';
|
||||
if(helper::isZeroDate($task->estStarted)) $task->estStarted = '';
|
||||
}
|
||||
|
||||
if($config->edition == 'ipd')
|
||||
{
|
||||
|
||||
@@ -1576,7 +1576,7 @@ class executionZen extends execution
|
||||
if($this->config->edition != 'open')
|
||||
{
|
||||
$flow = $this->loadModel('workflow')->getByModule($module);
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . '#app=execution';
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . "#app=$flow->app";
|
||||
}
|
||||
|
||||
$link = helper::createLink($module, $method, "executionID=%s");
|
||||
|
||||
+17
-10
@@ -875,23 +875,30 @@ class fileModel extends model
|
||||
/**
|
||||
* Update objectID.
|
||||
*
|
||||
* @param string $uid
|
||||
* @param int $objectID
|
||||
* @param string $objectType
|
||||
* @param array|string|bool $uid
|
||||
* @param int $objectID
|
||||
* @param string $objectType
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function updateObjectID(string|bool $uid, int $objectID, string $objectType): bool
|
||||
public function updateObjectID(array|string|bool $uid, int $objectID, string $objectType): bool
|
||||
{
|
||||
if(empty($uid)) return true;
|
||||
if(empty($_SESSION['album']['used'][$uid])) return true;
|
||||
|
||||
$data = new stdclass();
|
||||
$data->objectID = $objectID;
|
||||
$data->objectType = $objectType;
|
||||
if(!defined('RUN_MODE') || RUN_MODE != 'api') $data->extra = 'editor';
|
||||
if(is_string($uid)) $uid = array($uid);
|
||||
if(!is_array($uid)) return true;
|
||||
|
||||
$this->dao->update(TABLE_FILE)->data($data)->where('id')->in($_SESSION['album']['used'][$uid])->exec();
|
||||
foreach($uid as $value)
|
||||
{
|
||||
if(empty($_SESSION['album']['used'][$value])) continue;
|
||||
|
||||
$data = new stdclass();
|
||||
$data->objectID = $objectID;
|
||||
$data->objectType = $objectType;
|
||||
if(!defined('RUN_MODE') || RUN_MODE != 'api') $data->extra = 'editor';
|
||||
|
||||
$this->dao->update(TABLE_FILE)->data($data)->where('id')->in($_SESSION['album']['used'][$value])->exec();
|
||||
}
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
|
||||
@@ -426,6 +426,7 @@ $lang->group->package->workflowLabel = 'Workflow Label';
|
||||
$lang->group->package->workflowReport = 'Workflow Report';
|
||||
$lang->group->package->workflowDatasource = 'Workflow Datasource';
|
||||
$lang->group->package->workflowRule = 'Workflow Rule';
|
||||
$lang->group->package->workflowGroup = 'Workflow Group';
|
||||
$lang->group->package->workflow = 'Workflow';
|
||||
$lang->group->package->downloadCode = 'Download Code';
|
||||
$lang->group->package->dev = 'Dev';
|
||||
|
||||
@@ -426,6 +426,7 @@ $lang->group->package->workflowLabel = 'Workflow Label';
|
||||
$lang->group->package->workflowReport = 'Workflow Report';
|
||||
$lang->group->package->workflowDatasource = 'Workflow Datasource';
|
||||
$lang->group->package->workflowRule = 'Workflow Rule';
|
||||
$lang->group->package->workflowGroup = 'Workflow Group';
|
||||
$lang->group->package->workflow = 'Workflow';
|
||||
$lang->group->package->downloadCode = 'Download Code';
|
||||
$lang->group->package->dev = 'Dev';
|
||||
|
||||
@@ -426,6 +426,7 @@ $lang->group->package->workflowLabel = 'Workflow Label';
|
||||
$lang->group->package->workflowReport = 'Workflow Report';
|
||||
$lang->group->package->workflowDatasource = 'Workflow Datasource';
|
||||
$lang->group->package->workflowRule = 'Workflow Rule';
|
||||
$lang->group->package->workflowGroup = 'Workflow Group';
|
||||
$lang->group->package->workflow = 'Workflow';
|
||||
$lang->group->package->downloadCode = 'Download Code';
|
||||
$lang->group->package->dev = 'Dev';
|
||||
|
||||
@@ -426,6 +426,7 @@ $lang->group->package->workflowLabel = '工作流标签';
|
||||
$lang->group->package->workflowReport = '工作流报表';
|
||||
$lang->group->package->workflowDatasource = '工作流数据源';
|
||||
$lang->group->package->workflowRule = '工作流验证规则';
|
||||
$lang->group->package->workflowGroup = '工作流流程模板';
|
||||
$lang->group->package->workflow = '工作流';
|
||||
$lang->group->package->downloadCode = '下载代码';
|
||||
$lang->group->package->dev = '二次开发';
|
||||
|
||||
@@ -2607,6 +2607,23 @@ $config->group->package->workflowRule->privs['workflowrule-edit'] = array('edi
|
||||
$config->group->package->workflowRule->privs['workflowrule-view'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 20, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowRule->privs['workflowrule-delete'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 25, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
|
||||
$config->group->package->workflowGroup = new stdclass();
|
||||
$config->group->package->workflowGroup->order = 65;
|
||||
$config->group->package->workflowGroup->subset = 'workflow';
|
||||
$config->group->package->workflowGroup->privs = array();
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-product'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 5, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-project'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 10, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-create'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 15, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-edit'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 20, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-view'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 25, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-delete'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 30, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-design'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 35, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-release'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 40, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-deactivate'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 45, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-setExclusive'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 50, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-activateFlow'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 55, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
$config->group->package->workflowGroup->privs['workflowgroup-deactivateFlow'] = array('edition' => 'biz,max,ipd', 'vision' => 'rnd,lite,or', 'order' => 60, 'depend' => array('workflow-browseFlow'), 'recommend' => array());
|
||||
|
||||
$config->group->package->workflow = new stdclass();
|
||||
$config->group->package->workflow->order = 5;
|
||||
$config->group->package->workflow->subset = 'workflow';
|
||||
|
||||
+10
-12
@@ -836,14 +836,15 @@ function getMenuNavData()
|
||||
const data = [];
|
||||
const $nav = $('#menuMainNav');
|
||||
$nav.children().each(function(index, element) {
|
||||
const $elm = $(element);
|
||||
data.push(
|
||||
{
|
||||
name: $elm.is('.divider') ? 'divider' : $elm.data('app'),
|
||||
order: index * 5
|
||||
}
|
||||
);
|
||||
const $elm = $(element);
|
||||
const menuItem = {};
|
||||
menuItem.name = $elm.is('.divider') ? 'divider' : $elm.data('app');
|
||||
menuItem.order = index * 5;
|
||||
if(typeof $elm.data('hidden') != 'undefined') menuItem.hidden = true;
|
||||
|
||||
data.push(menuItem);
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -864,6 +865,7 @@ function restoreMenuNavToServer()
|
||||
{
|
||||
const url = $.createLink('custom', 'ajaxRestoreMenu');
|
||||
$.ajaxSubmit({url, data: {menu: 'nav'}});
|
||||
top.location.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -979,8 +981,6 @@ $(document).on('contextmenu', '#menuMainNav .divider', function(event)
|
||||
{
|
||||
text: langData.restore,
|
||||
onClick: () => {
|
||||
initAppsMenu(allAppsItems);
|
||||
refreshMenu();
|
||||
restoreMenuNavToServer();
|
||||
}
|
||||
}
|
||||
@@ -1070,7 +1070,7 @@ $(document).on('click', '.open-in-app,.show-in-app', function(e)
|
||||
: () => {
|
||||
closeApp(code);
|
||||
const $li = $btn.closest('li');
|
||||
$li.remove();
|
||||
$li.hide().attr('data-hidden', '1');
|
||||
refreshMenu();
|
||||
saveMenuNavToServer();
|
||||
},
|
||||
@@ -1096,8 +1096,6 @@ $(document).on('click', '.open-in-app,.show-in-app', function(e)
|
||||
{
|
||||
text: langData.restore,
|
||||
onClick: () => {
|
||||
initAppsMenu(allAppsItems);
|
||||
refreshMenu();
|
||||
restoreMenuNavToServer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,6 +389,8 @@ class product extends control
|
||||
/* Execute hooks. */
|
||||
$this->executeHooks($productID);
|
||||
|
||||
if($this->config->edition != 'open') $this->view->workflowGroups = $this->loadModel('workflowgroup')->getPairs('product');
|
||||
|
||||
$this->view->title = $product->name . $this->lang->hyphen . $this->lang->product->view;
|
||||
$this->view->product = $product;
|
||||
$this->view->actions = $this->loadModel('action')->getList('product', $productID);
|
||||
|
||||
@@ -2030,7 +2030,7 @@ class productModel extends model
|
||||
if($this->config->edition != 'open')
|
||||
{
|
||||
$flow = $this->loadModel('workflow')->getByModule($module);
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . '#app=product';
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . "app=$flow->app";
|
||||
}
|
||||
|
||||
if($module == 'execution' && in_array($method, array('bug', 'testcase'))) return helper::createLink($module, $method, "executionID={$params[0]}&productID=%s{$branchParam}");
|
||||
|
||||
@@ -25,6 +25,6 @@ if($config->systemMode != 'light')
|
||||
|
||||
if(!empty($config->setCode))
|
||||
{
|
||||
$fields->field('code')->width('1/4');
|
||||
$fields->field('code')->width('1/2');
|
||||
$fields->field('type')->width('1/4');
|
||||
}
|
||||
|
||||
@@ -180,17 +180,24 @@ div
|
||||
setClass('flex mt-4'),
|
||||
in_array($this->config->systemMode, array('ALM', 'PLM')) && $product->program ? div
|
||||
(
|
||||
setClass('clip w-1/2'),
|
||||
setClass('clip w-1/3'),
|
||||
set::title($lang->product->program),
|
||||
icon('program', setClass('pr-1')),
|
||||
$product->programName
|
||||
) : null,
|
||||
$product->line ? div
|
||||
(
|
||||
setClass('clip w-1/2'),
|
||||
setClass('clip w-1/3'),
|
||||
set::title($lang->product->line),
|
||||
icon('lane', setClass('pr-1')),
|
||||
$product->lineName
|
||||
) : null,
|
||||
$config->edition != 'open' && $product->workflowGroup ? div
|
||||
(
|
||||
setClass('clip w-1/3'),
|
||||
set::title($lang->product->workflowGroup),
|
||||
icon('flow', setClass('pr-1')),
|
||||
zget($workflowGroups, $product->workflowGroup)
|
||||
) : null
|
||||
),
|
||||
div
|
||||
|
||||
@@ -253,6 +253,11 @@ class productZen extends product
|
||||
if(isset($fields['program'])) $fields['program']['options'] = $this->loadModel('program')->getTopPairs('noclosed');
|
||||
if(isset($fields['line'])) $fields['line']['options'] = $this->product->getLinePairs($programID, true);
|
||||
|
||||
if($this->config->edition != 'open' && isset($fields['workflowGroup']))
|
||||
{
|
||||
$fields['workflowGroup']['options'] = $this->loadModel('workflowGroup')->getPairs();
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,12 @@ class productplan extends control
|
||||
*/
|
||||
public function commonAction(int $productID, int $branch = 0)
|
||||
{
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
$products = $this->product->getPairs('all', 0, '', 'all');
|
||||
if(empty($product)) $this->locate($this->createLink('product', 'create'));
|
||||
|
||||
$this->product->checkAccess($productID, $products);
|
||||
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
|
||||
$this->app->loadConfig('execution');
|
||||
|
||||
@@ -360,7 +360,7 @@ class programZen extends program
|
||||
if($this->config->edition != 'open')
|
||||
{
|
||||
$flow = $this->loadModel('workflow')->getByModule($moduleName);
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=$programID&moduleName=$moduleName") . '#app=program';
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=$programID&moduleName=$moduleName") . "#app=$flow->app";
|
||||
}
|
||||
if($moduleName == 'project')
|
||||
{
|
||||
|
||||
@@ -645,6 +645,8 @@ class project extends control
|
||||
$this->executeHooks($projectID);
|
||||
list($userPairs, $userList) = $this->projectZen->buildUsers();
|
||||
|
||||
if($this->config->edition != 'open') $this->view->workflowGroups = $this->loadModel('workflowgroup')->getPairs('project', $project->model, $project->hasProduct);
|
||||
|
||||
$this->view->title = $this->lang->project->view;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->project = $project;
|
||||
@@ -1714,4 +1716,24 @@ class project extends control
|
||||
$this->view->currentMethod = $currentMethod;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get workflow group items.
|
||||
*
|
||||
* @param string $model
|
||||
* @param int $hasProduct
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetWorkflowGroups(string $model, int $hasProduct)
|
||||
{
|
||||
if($this->config->edition == 'open') return false;
|
||||
|
||||
$workflowGroups = $this->loadModel('workflowgroup')->getPairs('project', $model, $hasProduct);
|
||||
|
||||
$items = array();
|
||||
foreach($workflowGroups as $id => $name) $items[] = array('text' => $name, 'value' => $id);
|
||||
|
||||
return $this->send(array('items' => array_values($items), 'defaultValue' => key($workflowGroups)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ const ignoreTips = {
|
||||
*/
|
||||
function changeType()
|
||||
{
|
||||
if($(this).val() == 0)
|
||||
const hasProduct = $(this).val();
|
||||
if(hasProduct == 0)
|
||||
{
|
||||
if(!$('[name=charter]').length || ($('[name=charter]').length && !parseInt($('[name=charter]').val()))) $('.productsBox').addClass('hidden');
|
||||
$('.stageByBox').addClass('hidden');
|
||||
@@ -24,6 +25,17 @@ function changeType()
|
||||
{
|
||||
$('.productsBox').removeClass('hidden');
|
||||
}
|
||||
|
||||
const link = $.createLink('project', 'ajaxGetWorkflowGroups', `model=${model}&hasProduct=${hasProduct}`);
|
||||
$.getJSON(link, function(data)
|
||||
{
|
||||
if(data.items)
|
||||
{
|
||||
const $workflowGroup = $('[name=workflowGroup]').zui('picker');
|
||||
$workflowGroup.render({items: data.items});
|
||||
$workflowGroup.$.setValue(data.defaultValue);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -571,7 +571,7 @@ class projectModel extends model
|
||||
if($this->config->edition != 'open')
|
||||
{
|
||||
$flow = $this->loadModel('workflow')->getByModule($module);
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . '#app=project';
|
||||
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . "#app=$flow->app";
|
||||
}
|
||||
|
||||
if(in_array($module, $this->config->waterfallModules)) return helper::createLink($module, 'browse', "projectID=%s");
|
||||
|
||||
@@ -397,6 +397,8 @@ class projectTao extends projectModel
|
||||
$product->createdVersion = $this->config->version;
|
||||
$product->vision = zget($project, 'vision', 'rnd');
|
||||
|
||||
if($this->config->edition != 'open') $product->workflowGroup = $this->dao->select('id')->from(TABLE_WORKFLOWGROUP)->where('code')->eq('productproject')->fetch('id');
|
||||
|
||||
$this->app->loadLang('product');
|
||||
$this->dao->insert(TABLE_PRODUCT)->data($product)
|
||||
->check('name', 'notempty')
|
||||
|
||||
@@ -67,7 +67,7 @@ foreach($projects as $programID => $programProjects)
|
||||
$item['keys'] = zget(common::convert2Pinyin(array($project->name)), $project->name, '');
|
||||
$item['url'] = sprintf($link, $project->id);
|
||||
|
||||
if(empty($project->multiple) || $project->type == 'kanban' || $project->model == 'kanban') $item['url'] = helper::createLink('project', 'index', "projectID={$project->id}");
|
||||
if((empty($project->multiple) || $project->type == 'kanban' || $project->model == 'kanban') && strpos($link, 'ajaxSwitchBelong') === false) $item['url'] = helper::createLink('project', 'index', "projectID={$project->id}");
|
||||
|
||||
if(empty($activeGroup) && $projectID == $project->id) $activeGroup = $group;
|
||||
|
||||
|
||||
@@ -21,4 +21,4 @@ if(strpos($config->project->edit->requiredFields, 'budget') === false) $fields->
|
||||
$fields->field('budget')->value(data('project.budget') !== null && data('project.budget') == 0 ? '' : data('project.budget'));
|
||||
|
||||
$fields->field('acl')->control(array('control' => 'aclBox', 'aclItems' => data('project.parent') ? $lang->project->subAclList : $lang->project->aclList, 'aclValue' => data('project.acl'), 'whitelistLabel' => $lang->project->whitelist, 'userValue' => data('project.whitelist')));
|
||||
$fields->field('storyType')->foldable()->value(data('project.storyType'));
|
||||
$fields->field('storyType')->width('full')->value(data('project.storyType'));
|
||||
|
||||
@@ -273,7 +273,18 @@ row
|
||||
)
|
||||
)
|
||||
),
|
||||
div(setClass('flex mt-4 program'), div(setClass('clip programBox'), $programDom)),
|
||||
div
|
||||
(
|
||||
setClass('flex mt-4 program'),
|
||||
$programDom ? div(setClass('clip programBox w-1/2'), $programDom) : null,
|
||||
$config->edition != 'open' ? div
|
||||
(
|
||||
setClass('clip w-1/2'),
|
||||
set::title($lang->project->workflowGroup),
|
||||
icon('flow', setClass('pr-1')),
|
||||
zget($workflowGroups, $project->workflowGroup)
|
||||
) : null
|
||||
),
|
||||
div
|
||||
(
|
||||
set::className('detail-content mt-4 overflow-hidden desc-box'),
|
||||
|
||||
@@ -327,6 +327,9 @@ class projectZen extends project
|
||||
}
|
||||
}
|
||||
|
||||
$hasProduct = isset($copyProject->hasProduct) ? $copyProject->hasProduct : 1;
|
||||
if($this->config->edition != 'open') $this->view->workflowGroups = $this->loadModel('workflowgroup')->getPairs('project', $model, $hasProduct);
|
||||
|
||||
/* Get copy projects. */
|
||||
$copyProjects = $this->project->getPairsByModel($model, '', 0, false);
|
||||
$copyProjectPairs = !commonModel::isTutorialMode() ? array_combine(array_keys($copyProjects), array_column($copyProjects, 'name')) : $copyProjects;
|
||||
|
||||
@@ -96,10 +96,11 @@ class projectrelease extends control
|
||||
* Create a release.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create(int $projectID)
|
||||
public function create(int $projectID, int $productID = 0)
|
||||
{
|
||||
/* Set create config. */
|
||||
$this->config->projectrelease->create = $this->config->release->create;
|
||||
@@ -136,7 +137,7 @@ class projectrelease extends control
|
||||
|
||||
/* Set menu. */
|
||||
$this->project->setMenu($projectID);
|
||||
$this->projectreleaseZen->commonAction($projectID);
|
||||
$this->projectreleaseZen->commonAction($projectID, $productID);
|
||||
|
||||
unset($this->lang->release->statusList['fail']);
|
||||
unset($this->lang->release->statusList['terminate']);
|
||||
|
||||
@@ -22,6 +22,7 @@ class projectreleaseZen extends projectrelease
|
||||
/* 获取当前的产品。*/
|
||||
/* Get current product. */
|
||||
if(!$productID) $productID = key($this->products);
|
||||
$this->loadModel('product')->checkAccess($productID, $this->products);
|
||||
$product = $this->product->getByID($productID);
|
||||
|
||||
$this->view->products = $this->products;
|
||||
|
||||
@@ -25,9 +25,12 @@ class release extends control
|
||||
{
|
||||
$this->loadModel('product')->setMenu($productID, $branch);
|
||||
|
||||
$product = $this->product->getById($productID);
|
||||
$product = $this->product->getById($productID);
|
||||
$products = $this->product->getPairs('all', 0, '', 'all');
|
||||
if(empty($product)) $this->locate($this->createLink('product', 'create'));
|
||||
|
||||
$this->product->checkAccess($productID, $products);
|
||||
|
||||
$this->view->product = $product;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id);
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
function loadBuilds(event)
|
||||
function changeProduct(event)
|
||||
{
|
||||
let productID = $(event.target).val();
|
||||
$.get($.createLink('projectrelease', 'ajaxLoadBuilds', "projectID=" + projectID + "&productID=" + productID), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
data = JSON.parse(data);
|
||||
$('[name*="build"]').zui('picker').render({items: data});
|
||||
}
|
||||
});
|
||||
loadPage($.createLink('projectrelease', 'create', 'projectID=' + projectID + '&' + 'productID=' + productID));
|
||||
}
|
||||
|
||||
window.changeStatus = function(e)
|
||||
|
||||
@@ -15,7 +15,7 @@ jsVar('projectID', isset($projectID) ? $projectID : 0);
|
||||
$productRow = array();
|
||||
if(!empty($projectID))
|
||||
{
|
||||
$productRow[] = on::change('#product', 'loadBuilds');
|
||||
$productRow[] = on::change('#product', 'changeProduct');
|
||||
$productRow[] = formRow
|
||||
(
|
||||
setClass($product->shadow ? 'hidden' : ''),
|
||||
|
||||
@@ -368,7 +368,7 @@ class story extends control
|
||||
}
|
||||
|
||||
$stories = $this->storyZen->getStoriesByChecked();
|
||||
if(!$stories) return $this->send(array('result' => 'success', 'load' => $this->session->storyList));
|
||||
if(!$stories) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->story->batchEditError, 'locate' => $this->session->storyList)));
|
||||
|
||||
/* Set Custom*/
|
||||
foreach(explode(',', $this->config->story->list->customBatchEditFields) as $field) $customFields[$field] = $this->lang->story->$field;
|
||||
|
||||
@@ -38,8 +38,8 @@ window.loadProduct = function(e)
|
||||
const productID = $this.val();
|
||||
const $modal = $this.closest('.modal');
|
||||
const inModal = $modal.length > 0;
|
||||
if(inModal) loadModal($.createLink('story', 'create', 'productID=' + productID + '&' + createParams), $modal.attr('id'));
|
||||
if(!inModal) loadPage($.createLink('story', 'create', 'productID=' + productID + '&' + createParams));
|
||||
if(inModal) loadModal($.createLink(storyType, 'create', 'productID=' + productID + '&' + createParams), $modal.attr('id'));
|
||||
if(!inModal) loadPage($.createLink(storyType, 'create', 'productID=' + productID + '&' + createParams));
|
||||
};
|
||||
|
||||
window.setLane = function(e)
|
||||
|
||||
@@ -125,6 +125,7 @@ $lang->story->activateSyncTip = "Twin stories are activated synchronously";
|
||||
$lang->story->relievedTwinsTip = "After {$lang->productCommon} adjustment, the twin relationship of this story will be automatically removed, and the story will no longer be synchronized. Do you want to save?";
|
||||
$lang->story->batchEditTip = "{$lang->SRCommon} %sis twin stories, and this operation has been filtered.";
|
||||
$lang->story->planTip = "{$lang->SRCommon} only supports single selection plan, other requirements can select multiple plans.";
|
||||
$lang->story->batchEditError = "All selected {$lang->SRCommon} can not be edited.";
|
||||
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Parent';
|
||||
|
||||
@@ -125,6 +125,7 @@ $lang->story->activateSyncTip = "Twin stories are activated synchronously";
|
||||
$lang->story->relievedTwinsTip = "After {$lang->productCommon} adjustment, the twin relationship of this story will be automatically removed, and the story will no longer be synchronized. Do you want to save?";
|
||||
$lang->story->batchEditTip = "{$lang->SRCommon} %sis twin stories, and this operation has been filtered.";
|
||||
$lang->story->planTip = "{$lang->SRCommon} only supports single selection plan, other requirements can select multiple plans.";
|
||||
$lang->story->batchEditError = "All selected {$lang->SRCommon} can not be edited.";
|
||||
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Parent';
|
||||
|
||||
@@ -125,6 +125,7 @@ $lang->story->activateSyncTip = "Twin stories are activated synchronously";
|
||||
$lang->story->relievedTwinsTip = "After {$lang->productCommon} adjustment, the twin relationship of this story will be automatically removed, and the story will no longer be synchronized. Do you want to save?";
|
||||
$lang->story->batchEditTip = "{$lang->SRCommon} %sis twin stories, and this operation has been filtered.";
|
||||
$lang->story->planTip = "{$lang->SRCommon} only supports single selection plan, other requirements can select multiple plans.";
|
||||
$lang->story->batchEditError = "All selected {$lang->SRCommon} can not be edited.";
|
||||
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Parent';
|
||||
|
||||
@@ -125,6 +125,7 @@ $lang->story->activateSyncTip = "孪生需求均同步激活";
|
||||
$lang->story->relievedTwinsTip = "{$lang->productCommon}调整后,本需求自动解除孪生关系,需求不再同步,是否保存?";
|
||||
$lang->story->batchEditTip = "{$lang->SRCommon} %s为孪生需求,本次操作已被过滤。";
|
||||
$lang->story->planTip = "{$lang->SRCommon}只能单选计划,其他需求可多选计划。";
|
||||
$lang->story->batchEditError = "所选需求皆不可编辑,本次操作已被过滤。";
|
||||
|
||||
$lang->story->id = '编号';
|
||||
$lang->story->parent = '父需求';
|
||||
|
||||
@@ -186,7 +186,7 @@ if($isInModal) $config->story->actionList['recall']['url'] = str_replace('&from=
|
||||
if($story->status == 'changing') $config->story->actionList['recall']['text'] = $lang->story->recallChange;
|
||||
$this->loadModel('repo');
|
||||
$hasRepo = $this->repo->getListByProduct($story->product, implode(',', $config->repo->gitServiceTypeList), 1);
|
||||
$actions = $story->deleted ? array() : $this->loadModel('common')->buildOperateMenu($story);
|
||||
$actions = $story->deleted ? array() : $this->loadModel('common')->buildOperateMenu($story, $story->type);
|
||||
$hasDivider = !empty($actions['mainActions']) && !empty($actions['suffixActions']);
|
||||
if(!empty($actions)) $actions = array_merge($actions['mainActions'], $hasDivider ? array(array('type' => 'divider')) : array(), $actions['suffixActions']);
|
||||
|
||||
|
||||
@@ -467,6 +467,7 @@ class storyZen extends story
|
||||
if($product->type != 'normal') $branches = $this->loadModel('branch')->getPairs($productID, 'active');
|
||||
}
|
||||
|
||||
$this->product->checkAccess($productID, $products);
|
||||
return array($products, $branches);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,3 +64,13 @@ window.readScriptContent = function(object)
|
||||
reader.readAsText(object.file, 'UTF-8');
|
||||
reader.onload = function(evt){$('[name=script]').val(evt.target.result);}
|
||||
}
|
||||
|
||||
window.loadProduct = function(e)
|
||||
{
|
||||
const $this = $(e.target);
|
||||
const productID = $this.val();
|
||||
const $modal = $this.closest('.modal');
|
||||
const inModal = $modal.length > 0;
|
||||
if(inModal) loadModal($.createLink('testcase', 'create', 'productID=' + productID + '&' + createParams), $modal.attr('id'));
|
||||
if(!inModal) loadPage($.createLink('testcase', 'create', 'productID=' + productID + '&' + createParams));
|
||||
};
|
||||
|
||||
@@ -13,6 +13,9 @@ namespace zin;
|
||||
|
||||
include($this->app->getModuleRoot() . 'ai/ui/inputinject.html.php');
|
||||
|
||||
$params = $app->getParams();
|
||||
array_shift($params);
|
||||
jsVar('createParams', http_build_query($params));
|
||||
jsVar('tab', $this->app->tab);
|
||||
if($app->tab == 'execution') jsVar('objectID', $executionID);
|
||||
if($app->tab == 'project') jsVar('objectID', $projectID);
|
||||
@@ -34,5 +37,6 @@ formGridPanel
|
||||
set::loadUrl(helper::createLink('testcase', 'create', "productID={product}&branch={branch}&moduleID={module}")),
|
||||
!empty($gobackLink) ? set::backUrl($gobackLink) : null,
|
||||
on::change('#story', 'changeStory'),
|
||||
on::change('[name=product]', 'loadProduct'),
|
||||
on::click('#auto', 'checkScript'),
|
||||
);
|
||||
|
||||
@@ -7,64 +7,75 @@ $config->testtask->dtable = new stdclass();
|
||||
$config->testtask->dtable->fieldList['id']['name'] = 'id';
|
||||
$config->testtask->dtable->fieldList['id']['title'] = $lang->idAB;
|
||||
$config->testtask->dtable->fieldList['id']['type'] = 'id';
|
||||
$config->testtask->dtable->fieldList['id']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['title']['name'] = 'name';
|
||||
$config->testtask->dtable->fieldList['title']['title'] = $lang->testtask->name;
|
||||
$config->testtask->dtable->fieldList['title']['type'] = 'title';
|
||||
$config->testtask->dtable->fieldList['title']['link'] = array('module' => 'testtask', 'method' => 'cases', 'params' => 'taskID={id}');
|
||||
$config->testtask->dtable->fieldList['title']['fixed'] = 'left';
|
||||
$config->testtask->dtable->fieldList['name']['name'] = 'name';
|
||||
$config->testtask->dtable->fieldList['name']['title'] = $lang->testtask->name;
|
||||
$config->testtask->dtable->fieldList['name']['type'] = 'title';
|
||||
$config->testtask->dtable->fieldList['name']['link'] = array('module' => 'testtask', 'method' => 'cases', 'params' => 'taskID={id}');
|
||||
$config->testtask->dtable->fieldList['name']['fixed'] = 'left';
|
||||
$config->testtask->dtable->fieldList['name']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['pri']['name'] = 'pri';
|
||||
$config->testtask->dtable->fieldList['pri']['title'] = $lang->priAB;
|
||||
$config->testtask->dtable->fieldList['pri']['type'] = 'pri';
|
||||
$config->testtask->dtable->fieldList['pri']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['build']['name'] = 'buildName';
|
||||
$config->testtask->dtable->fieldList['build']['title'] = $lang->testtask->build;
|
||||
$config->testtask->dtable->fieldList['build']['type'] = 'text';
|
||||
$config->testtask->dtable->fieldList['build']['link'] = array('module' => 'build', 'method' => 'view', 'params' => 'buildID={build}');
|
||||
$config->testtask->dtable->fieldList['build']['data-app'] = 'execution';
|
||||
$config->testtask->dtable->fieldList['build']['group'] = 'text';
|
||||
$config->testtask->dtable->fieldList['buildName']['name'] = 'buildName';
|
||||
$config->testtask->dtable->fieldList['buildName']['title'] = $lang->testtask->build;
|
||||
$config->testtask->dtable->fieldList['buildName']['type'] = 'text';
|
||||
$config->testtask->dtable->fieldList['buildName']['link'] = array('module' => 'build', 'method' => 'view', 'params' => 'buildID={build}');
|
||||
$config->testtask->dtable->fieldList['buildName']['data-app'] = 'execution';
|
||||
$config->testtask->dtable->fieldList['buildName']['group'] = 'text';
|
||||
$config->testtask->dtable->fieldList['buildName']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['product']['name'] = 'productName';
|
||||
$config->testtask->dtable->fieldList['product']['title'] = $lang->testtask->product;
|
||||
$config->testtask->dtable->fieldList['product']['type'] = 'text';
|
||||
$config->testtask->dtable->fieldList['product']['group'] = 'text';
|
||||
$config->testtask->dtable->fieldList['productName']['name'] = 'productName';
|
||||
$config->testtask->dtable->fieldList['productName']['title'] = $lang->testtask->product;
|
||||
$config->testtask->dtable->fieldList['productName']['type'] = 'text';
|
||||
$config->testtask->dtable->fieldList['productName']['group'] = 'text';
|
||||
$config->testtask->dtable->fieldList['productName']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['execution']['name'] = 'executionName';
|
||||
$config->testtask->dtable->fieldList['execution']['title'] = $lang->testtask->execution;
|
||||
$config->testtask->dtable->fieldList['execution']['type'] = 'text';
|
||||
$config->testtask->dtable->fieldList['execution']['group'] = 'text';
|
||||
$config->testtask->dtable->fieldList['executionName']['name'] = 'executionName';
|
||||
$config->testtask->dtable->fieldList['executionName']['title'] = $lang->testtask->execution;
|
||||
$config->testtask->dtable->fieldList['executionName']['type'] = 'text';
|
||||
$config->testtask->dtable->fieldList['executionName']['group'] = 'text';
|
||||
$config->testtask->dtable->fieldList['executionName']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['owner']['name'] = 'owner';
|
||||
$config->testtask->dtable->fieldList['owner']['title'] = $lang->testtask->owner;
|
||||
$config->testtask->dtable->fieldList['owner']['type'] = 'user';
|
||||
$config->testtask->dtable->fieldList['owner']['group'] = 'user';
|
||||
$config->testtask->dtable->fieldList['owner']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['members']['name'] = 'members';
|
||||
$config->testtask->dtable->fieldList['members']['title'] = $lang->testtask->members;
|
||||
$config->testtask->dtable->fieldList['members']['type'] = 'text';
|
||||
$config->testtask->dtable->fieldList['members']['group'] = 'user';
|
||||
$config->testtask->dtable->fieldList['members']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['begin']['name'] = 'begin';
|
||||
$config->testtask->dtable->fieldList['begin']['title'] = $lang->testtask->begin;
|
||||
$config->testtask->dtable->fieldList['begin']['type'] = 'date';
|
||||
$config->testtask->dtable->fieldList['begin']['group'] = 'user';
|
||||
$config->testtask->dtable->fieldList['begin']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['end']['name'] = 'end';
|
||||
$config->testtask->dtable->fieldList['end']['title'] = $lang->testtask->end;
|
||||
$config->testtask->dtable->fieldList['end']['type'] = 'date';
|
||||
$config->testtask->dtable->fieldList['end']['group'] = 'user';
|
||||
$config->testtask->dtable->fieldList['end']['show'] = true;
|
||||
|
||||
$config->testtask->dtable->fieldList['status']['name'] = 'status';
|
||||
$config->testtask->dtable->fieldList['status']['title'] = $lang->testtask->status;
|
||||
$config->testtask->dtable->fieldList['status']['type'] = 'status';
|
||||
$config->testtask->dtable->fieldList['status']['statusMap'] = $lang->testtask->statusList;
|
||||
$config->testtask->dtable->fieldList['status']['group'] = 'status';
|
||||
|
||||
$config->testtask->dtable->fieldList['actions']['name'] = 'actions';
|
||||
$config->testtask->dtable->fieldList['actions']['title'] = $lang->actions;
|
||||
$config->testtask->dtable->fieldList['actions']['type'] = 'actions';
|
||||
$config->testtask->dtable->fieldList['actions']['sortType'] = false;
|
||||
$config->testtask->dtable->fieldList['actions']['width'] = '120px';
|
||||
$config->testtask->dtable->fieldList['actions']['list'] = $config->testtask->actionList;
|
||||
$config->testtask->dtable->fieldList['actions']['menu'] = array('cases', 'linkCase', 'report', 'view', 'edit', 'delete');
|
||||
|
||||
@@ -123,12 +134,12 @@ $config->testtask->browseUnits = new stdclass();
|
||||
$config->testtask->browseUnits->dtable = new stdclass();
|
||||
$config->testtask->browseUnits->dtable->fieldList['id'] = $config->testtask->dtable->fieldList['id'];
|
||||
|
||||
$config->testtask->browseUnits->dtable->fieldList['title'] = $config->testtask->dtable->fieldList['title'];
|
||||
$config->testtask->browseUnits->dtable->fieldList['title']['title'] = $lang->testtask->unitName;
|
||||
$config->testtask->browseUnits->dtable->fieldList['title']['link'] = array('module' => 'testtask', 'method' => 'unitCases', 'params' => 'taskID={id}');
|
||||
$config->testtask->browseUnits->dtable->fieldList['name'] = $config->testtask->dtable->fieldList['name'];
|
||||
$config->testtask->browseUnits->dtable->fieldList['name']['title'] = $lang->testtask->unitName;
|
||||
$config->testtask->browseUnits->dtable->fieldList['name']['link'] = array('module' => 'testtask', 'method' => 'unitCases', 'params' => 'taskID={id}');
|
||||
|
||||
$config->testtask->browseUnits->dtable->fieldList['execution'] = $config->testtask->dtable->fieldList['execution'];
|
||||
$config->testtask->browseUnits->dtable->fieldList['build'] = $config->testtask->dtable->fieldList['build'];
|
||||
$config->testtask->browseUnits->dtable->fieldList['executionName'] = $config->testtask->dtable->fieldList['executionName'];
|
||||
$config->testtask->browseUnits->dtable->fieldList['buildName'] = $config->testtask->dtable->fieldList['buildName'];
|
||||
|
||||
$config->testtask->browseUnits->dtable->fieldList['owner'] = $config->testtask->dtable->fieldList['owner'];
|
||||
$config->testtask->browseUnits->dtable->fieldList['begin']['name'] = 'begin';
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace zin;
|
||||
|
||||
modalHeader();
|
||||
|
||||
form
|
||||
formPanel
|
||||
(
|
||||
setClass('testtask-block-form'),
|
||||
formGroup
|
||||
|
||||
@@ -55,8 +55,6 @@ featureBar
|
||||
)
|
||||
);
|
||||
|
||||
if($product->shadow) unset($config->testtask->dtable->fieldList['product']);
|
||||
|
||||
$canCreate = common::canModify('product', $product) && common::hasPriv('testtask', 'create');
|
||||
|
||||
toolbar
|
||||
@@ -70,18 +68,20 @@ toolbar
|
||||
) : null
|
||||
);
|
||||
|
||||
$tasks = initTableData($tasks, $config->testtask->dtable->fieldList, $this->testtask);
|
||||
$cols = array_values($config->testtask->dtable->fieldList);
|
||||
$cols = $this->loadModel('datatable')->getSetting('testtask');
|
||||
$tasks = initTableData($tasks, $cols, $this->testtask);
|
||||
$data = array_values($tasks);
|
||||
$footerHTML = strtolower($status) == 'totalstatus' ? $allSummary : $pageSummary;
|
||||
$beginTime = str_replace('-', '', $beginTime);
|
||||
$endTime = str_replace('-', '', $endTime);
|
||||
|
||||
if($product->shadow) unset($cols['product']);
|
||||
dtable
|
||||
(
|
||||
set::cols($cols),
|
||||
set::data($data),
|
||||
set::userMap($users),
|
||||
set::fixedLeftWidth('20%'),
|
||||
set::customCols(true),
|
||||
set::orderBy($orderBy),
|
||||
set::sortLink(createLink('testtask', 'browse', "productID={$product->id}&branch={$branch}&type={$type}&orderBy={name}_{sortType}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&beginTime={$beginTime}&endTime={$endTime}")),
|
||||
set::onRenderCell(jsRaw('window.onRenderCell')),
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace zin;
|
||||
|
||||
modalHeader();
|
||||
|
||||
form
|
||||
formPanel
|
||||
(
|
||||
setClass('testtask-start-form'),
|
||||
formGroup
|
||||
|
||||
@@ -47,11 +47,17 @@ class transfer extends control
|
||||
/* Get workflow fields by module. */
|
||||
if($this->config->edition != 'open')
|
||||
{
|
||||
$appendFields = $this->transferZen->getWorkflowFieldsByModule($module);
|
||||
foreach($appendFields as $appendField)
|
||||
$groupID = $this->loadModel('workflowgroup')->getGroupIDByData($module, null);
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($module, 'exportTemplate', $groupID);
|
||||
|
||||
if(!empty($action->extensionType) && $action->extensionType == 'extend')
|
||||
{
|
||||
$this->lang->$module->{$appendField->field} = $appendField->name;
|
||||
$this->config->$module->templateFields .= ',' . $appendField->field;
|
||||
$appendFields = $this->loadModel('workflowaction')->getPageFields($module, 'exportTemplate', true, null, 0, $groupID);
|
||||
foreach($appendFields as $appendField)
|
||||
{
|
||||
$this->lang->$module->{$appendField->field} = $appendField->name;
|
||||
$this->config->$module->templateFields .= ',' . $appendField->field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,21 +215,19 @@ class transferModel extends model
|
||||
|
||||
$moduleName = $this->app->rawModule;
|
||||
$methodName = $this->app->rawMethod;
|
||||
$action = $this->dao->select('*')->from(TABLE_WORKFLOWACTION)->where('module')->eq($moduleName)->andWhere('action')->eq($methodName)->fetch();
|
||||
$groupID = $this->loadModel('workflowgroup')->getGroupIDByData($moduleName, null);
|
||||
$action = $this->loadModel('workflowaction')->getByModuleAndAction($moduleName, $methodName, $groupID);
|
||||
|
||||
if(empty($action)) return $fieldList;
|
||||
if($action->extensionType == 'none' and $action->buildin == 1) return $fieldList;
|
||||
|
||||
$layouts = $this->loadModel('workflowlayout')->getFields($moduleName, $methodName);
|
||||
$notEmptyRule = $this->loadModel('workflowrule')->getByTypeAndRule('system', 'notempty');
|
||||
|
||||
$workflowFields = $this->loadModel('workflowaction')->getFields($moduleName, $methodName);
|
||||
$notEmptyRule = $this->loadModel('workflowrule')->getByTypeAndRule('system', 'notempty');
|
||||
$workflowFields = $this->workflowaction->getPageFields($moduleName, $methodName, true, null, 0, $groupID);
|
||||
foreach($workflowFields as $field)
|
||||
{
|
||||
if(empty($fieldList[$field->field])) continue;
|
||||
if(!empty($field->buildin)) continue;
|
||||
if(empty($field->show)) continue;
|
||||
if(!isset($layouts[$field->field])) continue;
|
||||
if($field->control == 'file')
|
||||
{
|
||||
unset($fieldList[$field->field]);
|
||||
|
||||
@@ -12,28 +12,6 @@ declare(strict_types=1);
|
||||
|
||||
class transferZen extends transfer
|
||||
{
|
||||
/**
|
||||
* 获取工作流字段.
|
||||
* Get workflow fields by module.
|
||||
*
|
||||
* @param string $module
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function getWorkflowFieldsByModule(string $module): array
|
||||
{
|
||||
$this->app->loadConfig('workflowaction');
|
||||
$relatedModule = isset($this->config->workflowaction->buildin->relatedModules[$module]['exporttemplate']) ? $this->config->workflowaction->buildin->relatedModules[$module]['exporttemplate'] : '';
|
||||
return $this->dao->select('t2.*')->from(TABLE_WORKFLOWLAYOUT)->alias('t1')
|
||||
->beginIF(!$relatedModule)->leftJoin(TABLE_WORKFLOWFIELD)->alias('t2')->on('t1.module=t2.module AND t1.field=t2.field')->fi()
|
||||
->beginIF($relatedModule)->leftJoin(TABLE_WORKFLOWFIELD)->alias('t2')->on("t2.module='$relatedModule' AND t1.field=t2.field")->fi()
|
||||
->where('t1.module')->eq($module)
|
||||
->andWhere('t1.action')->eq('exporttemplate')
|
||||
->andWhere('t2.buildin')->eq(0)
|
||||
->orderBy('t1.order')
|
||||
->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将参数转成变量存到SESSION中。
|
||||
* Set SESSION by params.
|
||||
|
||||
@@ -182,7 +182,7 @@ class tree extends control
|
||||
|
||||
if($type == 'doc')
|
||||
{
|
||||
$docLib = $this->loadModel('doc')->getLibById($module->root);
|
||||
$docLib = $this->loadModel('doc')->getLibById((int)$module->root);
|
||||
$objectID = isset($docLib->{$docLib->type}) ? $docLib->{$docLib->type} : 0;
|
||||
$this->view->libs = $this->doc->getLibs($docLib->type, '', '', $objectID, 'book');
|
||||
}
|
||||
|
||||
@@ -1975,7 +1975,8 @@ class treeModel extends model
|
||||
if($repeatName)
|
||||
{
|
||||
$tips = in_array($self->type, array('doc', 'api')) ? $this->lang->tree->repeatDirName : $this->lang->tree->repeatName;
|
||||
helper::end(js::alert(sprintf($tips, $repeatName)));
|
||||
dao::$errors['name'] = sprintf($tips, $repeatName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((empty($module->root) || empty($module->name)) && in_array($self->type, array('doc', 'api')))
|
||||
|
||||
@@ -104,6 +104,7 @@ $config->upgrade->execFlow['20_4'] = array('functions' => 'createDefaultD
|
||||
$config->upgrade->execFlow['20_5'] = array('functions' => 'fixWorkflowFieldOptions');
|
||||
$config->upgrade->execFlow['20_6'] = array('functions' => 'processDemandFiles,processSqlbuilderTables');
|
||||
$config->upgrade->execFlow['20_7'] = array('functions' => 'upgradeMyDocSpace');
|
||||
$config->upgrade->execFlow['20_8'] = array('functions' => 'processWorkflowGroups');
|
||||
|
||||
if(!empty($config->isINT))
|
||||
{
|
||||
|
||||
@@ -10030,4 +10030,34 @@ class upgradeModel extends model
|
||||
$this->dao->update(TABLE_DOCLIB)->set('main')->eq(0)->where('id')->in(array_keys($spaces))->exec();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史产品、项目绑定默认工作流模板。
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function processWorkflowGroups()
|
||||
{
|
||||
$workflowGroups = $this->dao->select('code, id')->from(TABLE_WORKFLOWGROUP)->where('main')->eq('1')->fetchPairs();
|
||||
|
||||
foreach($workflowGroups as $code => $groupID)
|
||||
{
|
||||
if($code == 'productproject')
|
||||
{
|
||||
$this->dao->update(TABLE_PRODUCT)->set('workflowGroup')->eq($groupID)->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->dao->update(TABLE_PROJECT)
|
||||
->set('workflowGroup')->eq($groupID)
|
||||
->where('type')->eq('project')
|
||||
->beginIF($code == 'scrumproduct')->andWhere('model')->eq('scrum')->andWhere('hasProduct')->eq('1')->fi()
|
||||
->beginIF($code == 'scrumproject')->andWhere('model')->eq('scrum')->andWhere('hasProduct')->eq('0')->fi()
|
||||
->beginIF($code == 'waterfallproduct')->andWhere('model')->eq('waterfall')->andWhere('hasProduct')->eq('1')->fi()
|
||||
->beginIF($code == 'waterfallproject')->andWhere('model')->eq('waterfall')->andWhere('hasProduct')->eq('0')->fi()
|
||||
->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-33
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user