From f2e7e6091d2929be7d8c7f39a535157695348429 Mon Sep 17 00:00:00 2001 From: zhouxin Date: Mon, 22 Apr 2024 10:26:42 +0800 Subject: [PATCH 001/141] * Fix bug #48073. --- module/metric/js/preview.ui.js | 8 ++++---- module/metric/ui/component/filterpanel.html.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/module/metric/js/preview.ui.js b/module/metric/js/preview.ui.js index 3bf9e03dfc..3793df3cd4 100644 --- a/module/metric/js/preview.ui.js +++ b/module/metric/js/preview.ui.js @@ -83,7 +83,7 @@ window.handleFilterCheck = function() window.handleFilterToggle = function($el) { - $el.toggleClass('primary-600'); + $el.toggleClass('ring-primary'); $('.filter-panel').toggleClass('hidden'); } @@ -274,10 +274,10 @@ window.initFilterPanel = function() $('#mainMenu').after($('.filter-panel')); - $('.filter-btn').removeClass('primary-600'); + $('.filter-btn').removeClass('ring-primary'); if(scope == 'filter') { - $('.filter-btn').addClass('primary-600'); + $('.filter-btn').addClass('ring-primary'); $('.filter-panel').removeClass('hidden'); window.updateFilterCheck(); } @@ -697,7 +697,7 @@ window.genDataZoom = function(dataLength, initZoom = 10, axis = 'x') window.hideFilterPanel = function() { - $('.filter-btn').removeClass('primary-600'); + $('.filter-btn').removeClass('ring-primary'); $('.filter-panel').addClass('hidden'); } diff --git a/module/metric/ui/component/filterpanel.html.php b/module/metric/ui/component/filterpanel.html.php index 08f435844f..872ede2348 100644 --- a/module/metric/ui/component/filterpanel.html.php +++ b/module/metric/ui/component/filterpanel.html.php @@ -44,7 +44,7 @@ $fnGenerateFilterContent = function($filterItems) use($lang, $fnGenerateFilterBl ( btn ( - setClass('btn ghost filter-btn'), + setClass('search-form-toggle rounded-full gray-300-outline size-sm btn filter-btn'), set::icon('search'), bind::click('window.handleFilterToggle($element)'), span From b54e02d27ed8b93fb8686880622ce7fe238d0525 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 10:40:11 +0800 Subject: [PATCH 002/141] * Fix bug #48142. --- module/user/config/form.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/user/config/form.php b/module/user/config/form.php index 142bbfeaa8..749e110be2 100644 --- a/module/user/config/form.php +++ b/module/user/config/form.php @@ -81,12 +81,12 @@ $config->user->form->edit['passwordLength'] = array('required' => false, 'type $config->user->form->edit['passwordStrength'] = array('required' => false, 'type' => 'int', 'default' => 0); $config->user->form->batchEdit = array(); -$config->user->form->batchEdit['dept'] = array('required' => false, 'type' => 'int', 'width' => '200px', 'name' => 'dept', 'label' => $lang->user->dept, 'control' => array('control' => 'picker', 'required' => true), 'default' => 0, 'ditto' => true); +$config->user->form->batchEdit['dept'] = array('required' => false, 'type' => 'int', 'width' => '200px', 'name' => 'dept', 'label' => $lang->user->dept, 'control' => array('control' => 'picker', 'required' => true), 'default' => 0, 'ditto' => true, 'defaultDitto' => 'off'); $config->user->form->batchEdit['company'] = array('required' => false, 'type' => 'int', 'width' => '200px', 'name' => 'company', 'label' => $lang->user->company, 'control' => 'picker', 'default' => 0); $config->user->form->batchEdit['account'] = array('required' => true, 'type' => 'string', 'width' => '140px', 'name' => 'account', 'label' => $lang->user->account, 'control' => 'text', 'default' => '', 'readonly' => true, 'base' => true); $config->user->form->batchEdit['realname'] = array('required' => true, 'type' => 'string', 'width' => '96px', 'name' => 'realname', 'label' => $lang->user->realname, 'control' => 'text', 'default' => ''); $config->user->form->batchEdit['visions'] = array('required' => true, 'type' => 'array', 'width' => '240px', 'name' => 'visions', 'label' => $lang->user->visions, 'control' => 'picker', 'default' => [], 'multiple' => true, 'filter' => 'join'); -$config->user->form->batchEdit['role'] = array('required' => false, 'type' => 'string', 'width' => '160px', 'name' => 'role', 'label' => $lang->user->role, 'control' => 'picker', 'default' => '', 'ditto' => true, 'items' => $lang->user->roleList); +$config->user->form->batchEdit['role'] = array('required' => false, 'type' => 'string', 'width' => '160px', 'name' => 'role', 'label' => $lang->user->role, 'control' => 'picker', 'default' => '', 'ditto' => true, 'defaultDitto' => 'off', 'items' => $lang->user->roleList); $config->user->form->batchEdit['email'] = array('required' => false, 'type' => 'string', 'width' => '160px', 'name' => 'email', 'label' => $lang->user->email, 'control' => 'text', 'default' => ''); $config->user->form->batchEdit['gender'] = array('required' => false, 'type' => 'string', 'width' => '100px', 'name' => 'gender', 'label' => $lang->user->gender, 'control' => array('control' => 'radioList', 'inline' => true), 'default' => 'm', 'items' => $lang->user->genderList); $config->user->form->batchEdit['commiter'] = array('required' => false, 'type' => 'string', 'width' => '120px', 'name' => 'commiter', 'label' => $lang->user->commiter, 'control' => 'text', 'default' => ''); From 8821618ebaf46b2fe7a1286bf93b7a9055af93bd Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 10:43:27 +0800 Subject: [PATCH 003/141] * Fix bug #48150. --- extension/lite/project/ext/ui/create.html.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/extension/lite/project/ext/ui/create.html.php b/extension/lite/project/ext/ui/create.html.php index 2826e05592..0716f7a869 100644 --- a/extension/lite/project/ext/ui/create.html.php +++ b/extension/lite/project/ext/ui/create.html.php @@ -217,20 +217,6 @@ modalTrigger ) ), - to::footer - ( - div - ( - setClass('flex mt-4 w-full justify-center'), - btn - ( - setClass('px-6'), - set::type('primary'), - on::click($copySelectedProject), - $lang->confirm - ) - ) - ), div ( set::id('copyProjects'), From f86bc4d08d1634608e917be60e8cb1f1cace38c6 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 22 Apr 2024 11:18:30 +0800 Subject: [PATCH 004/141] * Add release label for builds in bug::resolve. --- module/bug/control.php | 6 ++-- module/bug/ui/resolve.html.php | 15 +++++++- module/build/model.php | 63 +++++++++++++++++++++------------- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index c76f8f5ebf..86ebf9653e 100755 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -457,7 +457,8 @@ class bug extends control /* Set menu. */ $this->qa->setMenu($oldBug->product, $oldBug->branch); - $users = $this->loadModel('user')->getPairs('noclosed'); + $users = $this->loadModel('user')->getPairs('noclosed'); + $builds = $this->loadModel('build')->getBuildPairs(array($oldBug->product), $oldBug->branch, 'withbranch,noreleased'); /* 展示相关变量。 */ /* Show the variables associated. */ @@ -467,7 +468,8 @@ class bug extends control $this->view->users = $users; $this->view->assignedTo = isset($users[$oldBug->openedBy]) ? $oldBug->openedBy : $this->bug->getModuleOwner($oldBug->module, $oldBug->product); $this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($oldBug->product, $oldBug->branch ? "0,{$oldBug->branch}" : '0', (int)$oldBug->project, 'stagefilter'); - $this->view->builds = $this->loadModel('build')->getBuildPairs(array($oldBug->product), $oldBug->branch, 'withbranch,noreleased'); + $this->view->builds = $builds; + $this->view->releases = $this->build->getRelatedReleases(array($oldBug->product)); $this->view->actions = $this->loadModel('action')->getList('bug', $bugID); $this->display(); } diff --git a/module/bug/ui/resolve.html.php b/module/bug/ui/resolve.html.php index bf45658f27..ceaba0bfab 100644 --- a/module/bug/ui/resolve.html.php +++ b/module/bug/ui/resolve.html.php @@ -16,6 +16,19 @@ jsVar('page', 'resolve'); jsVar('released', $lang->build->released); jsVar('requiredFields', $config->bug->resolve->requiredFields); +$buildItems = array(); +foreach($builds as $buildID => $buildName) +{ + $buildItem = array('value' => $buildID, 'text' => $buildName); + if(isset($releases[$buildID])) $buildItem['content'] = array('html' => "{$buildName}"); + $buildItems[$buildID] = $buildItem; +} +foreach($releases as $releaseID => $release) +{ + if(isset($buildItems[$release->shadow])) $buildItems[$release->shadow]['content'] = array('html' => "
{$buildItems[$release->shadow]['text']}
", "class='flex'"); +} +var_dump($buildItems); + $createBuild = ''; if(common::hasPriv('build', 'create')) { @@ -94,7 +107,7 @@ formPanel ( set::name('resolvedBuild'), set::value(''), - set::items($builds) + set::items(array_values($buildItems)) ) ), formGroup diff --git a/module/build/model.php b/module/build/model.php index da457dc062..de23bae5a1 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -263,30 +263,8 @@ class buildModel extends model /* if the build has been released and replace is true, replace build name with release name. */ if($replace) { - $releases = $this->dao->select('t1.id,t1.shadow,t1.product,t1.branch,t1.build,t1.name,t1.date,t3.name as branchName,t4.type as productType')->from(TABLE_RELEASE)->alias('t1') - ->leftJoin(TABLE_BUILD)->alias('t2')->on('FIND_IN_SET(t2.id, t1.build)') - ->leftJoin(TABLE_BRANCH)->alias('t3')->on('FIND_IN_SET(t3.id, t1.branch)') - ->leftJoin(TABLE_PRODUCT)->alias('t4')->on('t1.product=t4.id') - ->where('t1.product')->in($productIdList) - ->beginIF(!empty($buildIdList))->andWhere('t2.id')->in($buildIdList)->fi() - ->andWhere('t1.deleted')->eq(0) - ->andWhere('t1.shadow')->ne(0) - ->fetchAll('id'); - - /* Get the buildID under the shadow product. */ - $shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where('product')->in($productIdList)->fetchPairs('shadow', 'shadow'); - if($shadows) - { - /* Append releases of only shadow and not link build. */ - $releases += $this->dao->select('t1.id,t1.shadow,t1.product,t1.branch,t1.build,t1.name,t1.date,t2.name as branchName,t3.type as productType')->from(TABLE_RELEASE)->alias('t1') - ->leftJoin(TABLE_BRANCH)->alias('t2')->on('FIND_IN_SET(t2.id, t1.branch)') - ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product=t3.id') - ->where('t1.shadow')->in($shadows) - ->andWhere('t1.build')->eq(0) - ->andWhere('t1.deleted')->eq(0) - ->fetchAll('id'); - } - $builds = $this->replaceNameWithRelease($allBuilds, $builds, $releases, $branch, $params, $excludedReleaseIdList); + $releases = $this->getRelatedReleases($productIdList, $buildIdList, $shadows); + $builds = $this->replaceNameWithRelease($allBuilds, $builds, $releases, $branch, $params, $excludedReleaseIdList); } krsort($builds); @@ -409,6 +387,43 @@ class buildModel extends model return $builds; } + /** + * 获取关联的发布。 + * Get releated release. + * + * @param array $productIdList + * @param string $buildIdList + * @param array $shadows + * @access public + * @return void + */ + public function getRelatedReleases(array $productIdList, string $buildIdList = '', array|bool $shadows = false): array + { + $releases = $this->dao->select('t1.id,t1.shadow,t1.product,t1.branch,t1.build,t1.name,t1.date,t3.name as branchName,t4.type as productType')->from(TABLE_RELEASE)->alias('t1') + ->leftJoin(TABLE_BUILD)->alias('t2')->on('FIND_IN_SET(t2.id, t1.build)') + ->leftJoin(TABLE_BRANCH)->alias('t3')->on('FIND_IN_SET(t3.id, t1.branch)') + ->leftJoin(TABLE_PRODUCT)->alias('t4')->on('t1.product=t4.id') + ->where('t1.product')->in($productIdList) + ->beginIF(!empty($buildIdList))->andWhere('t2.id')->in($buildIdList)->fi() + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t1.shadow')->ne(0) + ->fetchAll('id'); + + if($shadows === false) $shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where('product')->in($productIdList)->fetchPairs('shadow', 'shadow'); // Get the buildID under the shadow product. + if($shadows) + { + /* Append releases of only shadow and not link build. */ + $releases += $this->dao->select('t1.id,t1.shadow,t1.product,t1.branch,t1.build,t1.name,t1.date,t2.name as branchName,t3.type as productType')->from(TABLE_RELEASE)->alias('t1') + ->leftJoin(TABLE_BRANCH)->alias('t2')->on('FIND_IN_SET(t2.id, t1.branch)') + ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product=t3.id') + ->where('t1.shadow')->in($shadows) + ->andWhere('t1.build')->eq(0) + ->andWhere('t1.deleted')->eq(0) + ->fetchAll('id'); + } + return $releases; + } + /** * 获取最后一次创建的版本信息。 * Get the last build. From d0b9b1367fcf03de1edf761f57f21e979779d849 Mon Sep 17 00:00:00 2001 From: sunguangming Date: Mon, 22 Apr 2024 11:21:44 +0800 Subject: [PATCH 005/141] * Move table defined from ipd to open. --- config/zentaopms.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config/zentaopms.php b/config/zentaopms.php index d1d7953112..1864b7eaf1 100644 --- a/config/zentaopms.php +++ b/config/zentaopms.php @@ -395,6 +395,10 @@ define('TABLE_DESIGN', '`' . $config->db->prefix . 'design`'); define('TABLE_DESIGNSPEC', '`' . $config->db->prefix . 'designspec`'); define('TABLE_DOCLIB', '`' . $config->db->prefix . 'doclib`'); define('TABLE_DOC', '`' . $config->db->prefix . 'doc`'); +define('TABLE_DEMANDPOOL', '`' . $config->db->prefix . 'demandpool`'); +define('TABLE_DEMAND', '`' . $config->db->prefix . 'demand`'); +define('TABLE_DEMANDSPEC', '`' . $config->db->prefix . 'demandspec`'); +define('TABLE_DEMANDREVIEW', '`' . $config->db->prefix . 'demandreview`'); define('TABLE_API', '`' . $config->db->prefix . 'api`'); define('TABLE_API_SPEC', '`' . $config->db->prefix . 'apispec`'); define('TABLE_APISTRUCT', '`' . $config->db->prefix . 'apistruct`'); @@ -614,6 +618,10 @@ $config->objectTables['user'] = TABLE_USER; $config->objectTables['api'] = TABLE_API; $config->objectTables['doc'] = TABLE_DOC; $config->objectTables['doclib'] = TABLE_DOCLIB; +$config->objectTables['demand'] = TABLE_DEMAND; +$config->objectTables['demandpool'] = TABLE_DEMANDPOOL; +$config->objectTables['demandspec'] = TABLE_DEMANDSPEC; +$config->objectTables['demandreview'] = TABLE_DEMANDREVIEW; $config->objectTables['todo'] = TABLE_TODO; $config->objectTables['custom'] = TABLE_LANG; $config->objectTables['branch'] = TABLE_BRANCH; From 28b58c8e780ec66a1debb09aec241bd7b784ce55 Mon Sep 17 00:00:00 2001 From: sunguangming Date: Mon, 22 Apr 2024 11:25:36 +0800 Subject: [PATCH 006/141] * Modify group priv method name. --- db/update20.0.beta2.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/update20.0.beta2.sql b/db/update20.0.beta2.sql index 1cbda37170..8ab811ff39 100644 --- a/db/update20.0.beta2.sql +++ b/db/update20.0.beta2.sql @@ -17,3 +17,5 @@ ALTER TABLE zt_metriclib MODIFY id bigint AUTO_INCREMENT; UPDATE `zt_chart` SET `sql` = 'select tt.topProgram,tt.programID as id,tt.`year`,sum(tt.product) as product,sum(tt.plan) as plan,sum(tt.`release`) as `release`,sum(tt.story) as story,sum(tt.bug) as bug,sum(tt.doc) as doc\r\nfrom (\r\nselect t2.name as topProgram,t2.id as programID,t0.`year`,count(1) as product,0 as plan,0 as story,0 as bug,0 as `release`, 0 as doc\r\nfrom zt_product t1\r\nleft join (SELECT DISTINCT YEAR(`date`) as \'year\' FROM zt_action) t0 on YEAR(t1.createdDate) = t0.`year`\r\nleft join zt_project t2 on t1.program = t2.id\r\nwhere t1.deleted = \'0\' and t1.shadow = \'0\'\r\nand t2.type = \'program\' and t2.grade = 1 and t2.deleted = \'0\'\r\ngroup by t2.id, t0.`year`\r\nunion all\r\nselect t3.name as topProgram,t3.id as programID,t0.`year`,0 as product,count(1) as plan,0 as story,0 as bug,0 as `release`, 0 as doc\r\nfrom zt_productplan t1\r\nleft join (SELECT DISTINCT YEAR(`date`) as \'year\' FROM zt_action) t0 on YEAR(t1.createdDate) = t0.`year`\r\nleft join zt_product t2 on t2.id = t1.product\r\nleft join zt_project t3 on t2.program = t3.id\r\nwhere t1.deleted = \'0\'\r\nand t2.deleted = \'0\'\r\nand t3.type = \'program\' and t3.grade = 1 and t3.deleted = \'0\'\r\ngroup by t3.id, t0.`year`\r\nunion all\r\nselect t3.name as topProgram,t3.id as programID,t0.`year`,0 as product,0 as plan,0 as story,0 as bug,0 as `release`, count(1) as doc\r\nfrom zt_doc t1\r\nleft join (SELECT DISTINCT YEAR(`date`) as \'year\' FROM zt_action) t0 on YEAR(t1.addedDate) = t0.`year`\r\nleft join zt_product t2 on t2.id = t1.product\r\nleft join zt_project t3 on t2.program = t3.id\r\nwhere t1.deleted = \'0\'\r\nand t2.deleted = \'0\'\r\nand t3.type = \'program\' and t3.grade = 1 and t3.deleted = \'0\'\r\ngroup by t3.id, t0.`year`\r\nunion all\r\nselect t3.name as topProgram,t3.id as programID,t0.`year`,0 as product,0 as plan,0 as story,0 as bug,0 as `release`, count(distinct t1.id) as doc\r\nfrom zt_doc t1\r\nleft join (SELECT DISTINCT YEAR(`date`) as \'year\' FROM zt_action) t0 on YEAR(t1.addedDate) = t0.`year`\r\nleft join zt_projectproduct t4 on t1.project = t4.project\r\nleft join zt_product t2 on t2.id = t4.product\r\nleft join zt_project t3 on t2.program = t3.id\r\nwhere t1.deleted = \'0\'\r\nand t2.deleted = \'0\'\r\nand t3.type = \'program\' and t3.grade = 1 and t3.deleted = \'0\'\r\ngroup by t3.id, t0.`year`\r\nunion all\r\nselect t3.name as topProgram,t3.id as programID,t0.`year`,0 as product,0 as plan,0 as story,0 as bug,count(1) as `release`, 0 as doc\r\nfrom zt_release t1\r\nleft join (SELECT DISTINCT YEAR(`date`) as \'year\' FROM zt_action) t0 on YEAR(t1.date) = t0.`year`\r\nleft join zt_product t2 on t2.id = t1.product\r\nleft join zt_project t3 on t2.program = t3.id\r\nwhere t1.deleted = \'0\'\r\nand t2.deleted = \'0\'\r\nand t3.type = \'program\' and t3.grade = 1 and t3.deleted = \'0\'\r\ngroup by t3.id, t0.`year`\r\nunion all\r\nselect t3.name as topProgram,t3.id as programID,t0.`year`,0 as product,0 as plan,count(1) as story,0 as bug,0 as `release`, 0 as doc\r\nfrom zt_story t1\r\nleft join (SELECT DISTINCT YEAR(`date`) as \'year\' FROM zt_action) t0 on YEAR(t1.openedDate) = t0.`year`\r\nleft join zt_product t2 on t2.id = t1.product\r\nleft join zt_project t3 on t2.program = t3.id\r\nwhere t1.deleted = \'0\'\r\nand t2.deleted = \'0\'\r\nand t3.type = \'program\' and t3.grade = 1 and t3.deleted = \'0\'\r\ngroup by t3.id, t0.`year`\r\nunion all\r\nselect t3.name as topProgram,t3.id as programID,t0.`year`,0 as product,0 as plan,0 as story,count(1) as bug,0 as `release`, 0 as doc\r\nfrom zt_bug t1\r\nleft join (SELECT DISTINCT YEAR(`date`) as \'year\' FROM zt_action) t0 on YEAR(t1.openedDate) = t0.`year`\r\nleft join zt_product t2 on t2.id = t1.product\r\nleft join zt_project t3 on t2.program = t3.id\r\nwhere t1.deleted = \'0\'\r\nand t2.deleted = \'0\'\r\nand t3.type = \'program\' and t3.grade = 1 and t3.deleted = \'0\'\r\ngroup by t3.id, t0.`year`\r\n) tt\r\ngroup by tt.programID, tt.`year`' WHERE `name` = '年度新增-项目集年度新增数据汇总表'; UPDATE `zt_chart` SET `sql` = 'SELECT YEAR(t1.date) AS `year`,IFNULL(t2.realname,t1.actor) AS realname,count(1) AS count FROM zt_action t1 LEFT JOIN zt_user AS t2 ON t1.actor=t2.account where t1.actor is not null and t1.actor not in(\'\', \'system\') GROUP BY `year`,t1.actor ORDER BY `year`, `count` DESC' WHERE `name` = '年度排行-个人-禅道操作次数榜'; UPDATE `zt_chart` SET `sql` = 'SELECT t1.id, t1.NAME AS project, IFNULL( t2.NAME, \'/\') AS program, IFNULL( t3.story, 0 ) AS story, IFNULL( t3.estimate, 0 ) AS estimate, IFNULL( t4.execution, 0 ) AS execution, IFNULL( t5.workhour, 0 ) AS workhour FROM zt_project AS t1 LEFT JOIN zt_project AS t2 ON FIND_IN_SET( t2.id, t1.path ) AND t2.deleted = \'0\' AND t2.type = \'program\' AND t2.grade = 1 LEFT JOIN( SELECT t1.parent AS project, COUNT( 1 ) AS story, ROUND( SUM( t1.estimate ), 1 ) AS estimate FROM ( SELECT DISTINCT t1.parent, t3.id, t3.estimate FROM zt_project AS t1 LEFT JOIN zt_projectstory AS t2 ON t1.id = t2.project LEFT JOIN zt_story AS t3 ON t2.story = t3.id AND t3.deleted = \'0\' AND t3.stage NOT IN ( \'verified\', \'released\', \'closed\' ) WHERE t1.deleted = \'0\' AND t1.type IN ( \'sprint\', \'stage\', \'kanban\' ) AND t3.id IS NOT NULL ) AS t1 GROUP BY project ) AS t3 ON t1.id = t3.project LEFT JOIN ( SELECT parent AS project, COUNT( 1 ) AS execution FROM zt_project WHERE deleted = \'0\' AND type IN ( \'sprint\', \'stage\', \'kanban\' ) AND multiple = \'1\' AND STATUS NOT IN ( \'done\', \'closed\' ) GROUP BY project ) AS t4 ON t1.id = t4.project LEFT JOIN ( SELECT t1.parent AS project, ROUND( SUM( t2.LEFT ), 1 ) AS workhour FROM zt_project AS t1 LEFT JOIN zt_task AS t2 ON t1.id = t2.execution AND t2.deleted = \'0\' AND t2.parent < 1 WHERE t1.deleted = \'0\' AND t1.type IN ( \'sprint\', \'stage\', \'kanban\' ) AND t1.STATUS NOT IN ( \'done\', \'closed\' ) AND t2.id IS NOT NULL GROUP BY project ) AS t5 ON t1.id = t5.project WHERE t1.deleted = \'0\' AND t1.type = \'project\' AND t1.STATUS = \'doing\'' WHERE `name` = '年度进行中项目-项目剩余工作量透视表'; + +UPDATE `zt_grouppriv` SET `method` = 'recordWorkhour' WHERE `module` = 'task' AND `method` = 'recordEstimate'; From fa93427bc08a0c0b004dae18f379d345c42e891b Mon Sep 17 00:00:00 2001 From: xieqiyu Date: Mon, 22 Apr 2024 11:25:32 +0800 Subject: [PATCH 007/141] * Fix bug#47841. --- module/my/control.php | 1 - 1 file changed, 1 deletion(-) diff --git a/module/my/control.php b/module/my/control.php index 620c73a30f..406f831e90 100755 --- a/module/my/control.php +++ b/module/my/control.php @@ -140,7 +140,6 @@ class my extends control $this->session->set('todoList', $uri, 'my'); $this->session->set('bugList', $uri, 'my'); $this->session->set('taskList', $uri, 'my'); - $this->session->set('storyList', $uri, 'my'); $this->session->set('testtaskList', $uri, 'my'); /* Load pager. */ From 92d6e76b948329a5b64cb26b0f3914302ae3bbbf Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 22 Apr 2024 13:05:43 +0800 Subject: [PATCH 008/141] * Modify style of build picker items. --- module/bug/ui/resolve.html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/bug/ui/resolve.html.php b/module/bug/ui/resolve.html.php index ceaba0bfab..ecea8d891d 100644 --- a/module/bug/ui/resolve.html.php +++ b/module/bug/ui/resolve.html.php @@ -20,12 +20,12 @@ $buildItems = array(); foreach($builds as $buildID => $buildName) { $buildItem = array('value' => $buildID, 'text' => $buildName); - if(isset($releases[$buildID])) $buildItem['content'] = array('html' => "{$buildName}"); + if(isset($releases[$buildID])) $buildItem['content'] = array('html' => "
{$buildName}
", 'class' => 'w-full flex nowrap'); $buildItems[$buildID] = $buildItem; } foreach($releases as $releaseID => $release) { - if(isset($buildItems[$release->shadow])) $buildItems[$release->shadow]['content'] = array('html' => "
{$buildItems[$release->shadow]['text']}
", "class='flex'"); + if(isset($buildItems[$release->shadow])) $buildItems[$release->shadow]['content'] = array('html' => "
{$buildItems[$release->shadow]['text']}
", 'class' => 'w-full flex nowrap'); } var_dump($buildItems); From 06adae1d175a11f2c8cba86743cf50448cf9aa0d Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 22 Apr 2024 13:17:13 +0800 Subject: [PATCH 009/141] * Fix bug of undefined property. --- module/block/ui/executionstatisticblock.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/block/ui/executionstatisticblock.html.php b/module/block/ui/executionstatisticblock.html.php index d219e23ed2..6dbd1d7361 100644 --- a/module/block/ui/executionstatisticblock.html.php +++ b/module/block/ui/executionstatisticblock.html.php @@ -254,7 +254,7 @@ statisticBlock ), set::block($block), set::active($active), - set::moreLink(createLink('execution', 'all', 'status=' . $block->params->type)), + set::moreLink(createLink('execution', 'all', 'status=' . zget($block->params, 'type', ''))), set::items($items), $blockView, ); From de3ed896266a82f57f7b1ef545271e9f7dd790b0 Mon Sep 17 00:00:00 2001 From: liugang Date: Mon, 22 Apr 2024 13:19:48 +0800 Subject: [PATCH 010/141] * productplanConfig: remove configuration items from form.php and add them in control file. --- module/productplan/config/form.php | 37 ++++++++++++++---------------- module/productplan/control.php | 5 +++- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/module/productplan/config/form.php b/module/productplan/config/form.php index 5a702f7bf9..081af7a5fd 100644 --- a/module/productplan/config/form.php +++ b/module/productplan/config/form.php @@ -1,5 +1,5 @@ productplan->form = new stdclass(); $config->productplan->form->batchEdit = array(); $config->productplan->form->batchEdit['id'] = array('type' => 'int', 'control' => 'text', 'width' => '60px', 'name' => 'id', 'label' => $lang->idAB, 'required' => false, 'default' => 0, 'base' => true); @@ -9,23 +9,20 @@ $config->productplan->form->batchEdit['status'] = array('type' => 'string', 'con $config->productplan->form->batchEdit['begin'] = array('type' => 'date', 'control' => 'date', 'width' => '128px', 'name' => 'begin', 'label' => $lang->productplan->begin, 'required' => false, 'default' => ''); $config->productplan->form->batchEdit['end'] = array('type' => 'date', 'control' => 'date', 'width' => '128px', 'name' => 'end', 'label' => $lang->productplan->end, 'required' => false, 'default' => ''); -$now = helper::now(); -$config->productplan->form->create['parent'] = array('type' => 'int', 'required' => false, 'default' => 0); -$config->productplan->form->create['branch'] = array('type' => 'array', 'required' => false, 'default' => '0', 'filter' => 'join'); -$config->productplan->form->create['title'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->productplan->form->create['begin'] = array('type' => 'date', 'required' => false, 'default' => null); -$config->productplan->form->create['end'] = array('type' => 'date', 'required' => false, 'default' => null); -$config->productplan->form->create['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); -$config->productplan->form->create['product'] = array('type' => 'int', 'required' => false, 'default' => 0); -$config->productplan->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); -$config->productplan->form->create['createdDate'] = array('type' => 'datetime ', 'required' => false, 'default' => $now); -$config->productplan->form->create['order'] = array('type' => 'string', 'required' => false, 'default' => 0); +$config->productplan->form->create['parent'] = array('type' => 'int', 'required' => false, 'default' => 0); +$config->productplan->form->create['branch'] = array('type' => 'array', 'required' => false, 'default' => '0', 'filter' => 'join'); +$config->productplan->form->create['title'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); +$config->productplan->form->create['begin'] = array('type' => 'date', 'required' => false, 'default' => null); +$config->productplan->form->create['end'] = array('type' => 'date', 'required' => false, 'default' => null); +$config->productplan->form->create['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); +$config->productplan->form->create['product'] = array('type' => 'int', 'required' => false, 'default' => 0); +$config->productplan->form->create['order'] = array('type' => 'string', 'required' => false, 'default' => 0); -$config->productplan->form->edit['parent'] = array('type' => 'int', 'required' => false, 'default' => 0); -$config->productplan->form->edit['branch'] = array('type' => 'array', 'required' => false, 'default' => '0', 'filter' => 'join'); -$config->productplan->form->edit['title'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->productplan->form->edit['begin'] = array('type' => 'date', 'required' => false, 'default' => null); -$config->productplan->form->edit['end'] = array('type' => 'date', 'required' => false, 'default' => null); -$config->productplan->form->edit['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); -$config->productplan->form->edit['product'] = array('type' => 'int', 'required' => false, 'default' => 0); -$config->productplan->form->edit['status'] = array('type' => 'string', 'required' => false, 'default' => ''); +$config->productplan->form->edit['parent'] = array('type' => 'int', 'required' => false, 'default' => 0); +$config->productplan->form->edit['branch'] = array('type' => 'array', 'required' => false, 'default' => '0', 'filter' => 'join'); +$config->productplan->form->edit['title'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); +$config->productplan->form->edit['begin'] = array('type' => 'date', 'required' => false, 'default' => null); +$config->productplan->form->edit['end'] = array('type' => 'date', 'required' => false, 'default' => null); +$config->productplan->form->edit['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); +$config->productplan->form->edit['product'] = array('type' => 'int', 'required' => false, 'default' => 0); +$config->productplan->form->edit['status'] = array('type' => 'string', 'required' => false, 'default' => ''); diff --git a/module/productplan/control.php b/module/productplan/control.php index d22ffcfe05..c87d8b756e 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -69,7 +69,10 @@ class productplan extends control { if(!empty($_POST)) { - $planData = form::data()->get(); + $planData = form::data() + ->add('createdBy', $this->app->user->account) + ->add('createdDate', helper::now()) + ->get(); $planID = $this->productplan->create($planData, (int)$this->post->future); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('action')->create('productplan', $planID, 'opened'); From 1ea10db6e8489eb262344ac0f63ed86aa6ff99f1 Mon Sep 17 00:00:00 2001 From: hufangzhou Date: Mon, 22 Apr 2024 13:25:23 +0800 Subject: [PATCH 011/141] * Fix bug #48039. --- config/zentaopms.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/zentaopms.php b/config/zentaopms.php index 1864b7eaf1..911196b51c 100644 --- a/config/zentaopms.php +++ b/config/zentaopms.php @@ -595,6 +595,13 @@ define('TABLE_AI_MODEL', '`' . $config->db->prefix . 'ai_model`'); define('TABLE_SQLITE_QUEUE', '`' . $config->db->prefix . 'sqlite_queue`'); +if(!defined('TABLE_ROADMAP')) define('TABLE_ROADMAP', '`' . $config->db->prefix . 'roadmap`'); +if(!defined('TABLE_ROADMAPSTORY')) define('TABLE_ROADMAPSTORY', '`' . $config->db->prefix . 'roadmapstory`'); +if(!defined('TABLE_CHARTER')) define('TABLE_CHARTER', '`' . $config->db->prefix . 'charter`'); +if(!defined('TABLE_MARKET')) define('TABLE_MARKET', '`' . $config->db->prefix . 'market`'); +if(!defined('TABLE_MARKETREPORT')) define('TABLE_MARKETREPORT', '`' . $config->db->prefix . 'marketreport`'); +if(!defined('TABLE_MARKETRESEARCH')) define('TABLE_MARKETRESEARCH', '`' . $config->db->prefix . 'project`'); + $config->objectTables['dept'] = TABLE_DEPT; $config->objectTables['product'] = TABLE_PRODUCT; $config->objectTables['productplan'] = TABLE_PRODUCTPLAN; From 1889f7da827f20e991f99744eef5074ec550044f Mon Sep 17 00:00:00 2001 From: liugang Date: Mon, 22 Apr 2024 13:32:32 +0800 Subject: [PATCH 012/141] * testcaseModel: fix error of calling undefined property. --- module/testcase/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testcase/model.php b/module/testcase/model.php index 74dfe7671f..8a451c96dd 100755 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -1446,7 +1446,7 @@ class testcaseModel extends model $projects = array($this->session->execution); } if(!empty($case->project)) $projects[] = $case->project; - if(!empty($case->execution)) $projects[] = $case->project; + if(!empty($case->execution)) $projects[] = $case->execution; if(empty($projects)) return false; $this->loadModel('action'); From c33e2161604dcf7727679add9d83b3c9d98717c1 Mon Sep 17 00:00:00 2001 From: hufangzhou Date: Mon, 22 Apr 2024 13:37:36 +0800 Subject: [PATCH 013/141] * Move the table configurations to zentaopms. --- config/zentaopms.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/zentaopms.php b/config/zentaopms.php index 911196b51c..823209c6f1 100644 --- a/config/zentaopms.php +++ b/config/zentaopms.php @@ -686,6 +686,12 @@ $config->objectTables['design'] = TABLE_DESIGN; $config->objectTables['prompt'] = TABLE_AI_PROMPT; $config->objectTables['aiapp'] = TABLE_AI_MINIPROGRAM; $config->objectTables['miniprogram'] = TABLE_AI_MINIPROGRAM; +$config->objectTables['roadmap'] = TABLE_ROADMAP; +$config->objectTables['charter'] = TABLE_CHARTER; +$config->objectTables['market'] = TABLE_MARKET; +$config->objectTables['marketreport'] = TABLE_MARKETREPORT; +$config->objectTables['marketresearch'] = TABLE_PROJECT; +$config->objectTables['researchstage'] = TABLE_PROJECT; $config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme', 'visions', 'aiPrompts', 'promptDesign', 'promptExec'); $config->disabledFeatures = ''; From 12d5c2cb356c6bfd063234a95285a6f70715365d Mon Sep 17 00:00:00 2001 From: wangyuting Date: Mon, 22 Apr 2024 13:45:58 +0800 Subject: [PATCH 014/141] * Fix taskkanban story view link bug. --- module/execution/js/taskkanban.ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/execution/js/taskkanban.ui.js b/module/execution/js/taskkanban.ui.js index 9e53ba453e..3f64df38e1 100644 --- a/module/execution/js/taskkanban.ui.js +++ b/module/execution/js/taskkanban.ui.js @@ -233,7 +233,7 @@ window.getItem = function(info) info.item.title = info.item.title.replaceAll(searchValue, "" + searchValue + ""); info.item.title = {html: info.item.title}; } - info.item.titleUrl = $.createLink(info.laneInfo.type, 'view', `id=${info.item.id}`); + info.item.titleUrl = info.laneInfo.type == 'story' ? $.createLink('execution', 'storyView', `id=${info.item.id}&executionID=${executionID}`) : $.createLink(info.laneInfo.type, 'view', `id=${info.item.id}`); info.item.titleAttrs = {'data-toggle': 'modal', 'data-size' : 'lg', 'title' : info.item.title}; info.item.content = {html: content}; From 56bc51123873dbee60569c76f3bdcca7f6207f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 22 Apr 2024 13:45:59 +0800 Subject: [PATCH 015/141] * Fix bug #48107. --- module/backup/model.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/module/backup/model.php b/module/backup/model.php index bcfa92ccd3..cdc50b700c 100644 --- a/module/backup/model.php +++ b/module/backup/model.php @@ -326,7 +326,11 @@ class backupModel extends model public function getBackupDirProgress(string $backup): array { $tmpLogFile = $this->getTmpLogFile($backup); - if(file_exists($tmpLogFile)) return json_decode(file_get_contents($tmpLogFile), true); + if(file_exists($tmpLogFile)) + { + $log = json_decode(file_get_contents($tmpLogFile), true); + return empty($log) ? array() : $log; + } return array(); } @@ -433,6 +437,7 @@ class backupModel extends model public function getDirSize(string $dir): int { if(!file_exists($dir)) return 0; + if(!is_readable($dir)) return 0; $totalSize = 0; $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)); From 88328f86b2420f6a77d8944e47508372e18ef9e5 Mon Sep 17 00:00:00 2001 From: zhouxin Date: Mon, 22 Apr 2024 13:56:36 +0800 Subject: [PATCH 016/141] * Fix php version error of sqlparser. --- lib/sqlparser/vendor/composer/platform_check.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sqlparser/vendor/composer/platform_check.php b/lib/sqlparser/vendor/composer/platform_check.php index 589e9e770b..7f2efc1a1a 100644 --- a/lib/sqlparser/vendor/composer/platform_check.php +++ b/lib/sqlparser/vendor/composer/platform_check.php @@ -4,7 +4,7 @@ $issues = array(); -if (!(PHP_VERSION_ID >= 70200)) { +if (!(PHP_VERSION_ID >= 50400)) { $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.'; } From 0531e5a7fffe170896e2542d0d68bf41aa4a77b1 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 13:57:19 +0800 Subject: [PATCH 017/141] * Fix bug #48159. --- extension/lite/task/ext/config/lite.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extension/lite/task/ext/config/lite.php b/extension/lite/task/ext/config/lite.php index 076a194eab..76394495d1 100644 --- a/extension/lite/task/ext/config/lite.php +++ b/extension/lite/task/ext/config/lite.php @@ -12,5 +12,5 @@ $config->task->dtable->fieldList['lane']['sortType'] = false; $config->task->dtable->fieldList['name']['data-toggle'] = 'modal'; $config->task->dtable->fieldList['name']['data-size'] = 'lg'; -$config->task->view->operateList['main'] = array('assignTo', 'start', 'restart', 'recordWorkhour', 'pause', 'finish', 'activate', 'close', 'cancel'); -$config->task->view->operateList['common'] = array('edit', 'delete', 'view'); +$config->task->actions->view['mainActions'] = array('assignTo', 'start', 'restart', 'recordWorkhour', 'pause', 'finish', 'activate', 'close', 'cancel'); +$config->task->actions->view['suffixActions'] = array('edit', 'delete', 'view'); From 424bd094d28a93c1f02bf69f130cb01fe1c0aaa7 Mon Sep 17 00:00:00 2001 From: qishiyao Date: Mon, 22 Apr 2024 14:00:43 +0800 Subject: [PATCH 018/141] * Fix pipeline encrypt xuan --- misc/ci/Jenkinsfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/misc/ci/Jenkinsfile b/misc/ci/Jenkinsfile index a7119e5de5..319bcfc3d8 100644 --- a/misc/ci/Jenkinsfile +++ b/misc/ci/Jenkinsfile @@ -185,6 +185,15 @@ pipeline { } } + stage("xuan") { + steps { + container('package') { + sh 'cd $SRC_ZENTAOEXT_PATH && make xuan' + sh 'cd $SRC_ZENTAOEXT_PATH && make encrypt-xuan UUID=`uuidgen`' + } + } + } + stage("中转") { steps { container('package') { From 9dbb3ac4d3a353e0ce06e9e44f485823641086f7 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 22 Apr 2024 14:06:02 +0800 Subject: [PATCH 019/141] - Fix bug #48126. --- module/testcase/zen.php | 1 - 1 file changed, 1 deletion(-) diff --git a/module/testcase/zen.php b/module/testcase/zen.php index 41436de99d..b6210d447e 100755 --- a/module/testcase/zen.php +++ b/module/testcase/zen.php @@ -393,7 +393,6 @@ class testcaseZen extends testcase $storyModuleID = array_key_exists($currentModuleID, $productModules) ? $currentModuleID : 0; $modules = $this->tree->getStoryModule($storyModuleID); $modules = $this->tree->getAllChildID($modules); - $currentModuleID = $storyModuleID; } /* 获取未关闭的需求。 */ From 07a2830ebfcffd3d502dbf6674ea2ce476851925 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 14:07:13 +0800 Subject: [PATCH 020/141] * Fix bug #48162. --- module/execution/model.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/module/execution/model.php b/module/execution/model.php index 81da973b67..7f68ea9ded 100755 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -1283,8 +1283,7 @@ class executionModel extends model /* Order by status's content whether or not done. */ $executions = $this->dao->select("*, IF(INSTR('done,closed', status) < 2, 0, 1) AS isDone, INSTR('doing,wait,suspended,closed', status) AS sortStatus")->from(TABLE_EXECUTION) - ->where('type')->ne('') - ->beginIF(strpos(',lite,or,', ",{$this->config->vision},") !== false)->andWhere('vision')->eq($this->config->vision)->fi() + ->where('vision')->eq($this->config->vision) ->beginIF((!$this->session->multiple && $this->app->tab == 'execution') || strpos($mode, 'multiple') !== false)->andWhere('multiple')->eq('1')->fi() ->beginIF($type != 'all')->andWhere('type')->in($type)->fi() ->beginIF($type == 'all')->andWhere('type')->in('stage,sprint,kanban')->fi() From d5efe9c870aa24a725778f2cd01512bda04900aa Mon Sep 17 00:00:00 2001 From: liugang Date: Mon, 22 Apr 2024 14:08:32 +0800 Subject: [PATCH 021/141] * xuanxuan: fix error of calling undefined index from an array. --- extension/xuanxuan/extension/xuan/user/ext/lang/en/xuanxuan.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/xuanxuan/extension/xuan/user/ext/lang/en/xuanxuan.php b/extension/xuanxuan/extension/xuan/user/ext/lang/en/xuanxuan.php index d2a3bc7ac6..3fb99baddd 100644 --- a/extension/xuanxuan/extension/xuan/user/ext/lang/en/xuanxuan.php +++ b/extension/xuanxuan/extension/xuan/user/ext/lang/en/xuanxuan.php @@ -1,7 +1,7 @@ user->tokenInvalid = "Token denied, please login with password."; -if(strpos($_SERVER['HTTP_USER_AGENT'], 'xuanxuan') != false) +if(isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'xuanxuan') != false) { $lang->user->errorDeny = "Sorry, your access to %2\$s of %1\$s is denied. Please contact your Admin to get privileges."; } From 356d63e7a1a83eed4116af9b2cd3766200d7311a Mon Sep 17 00:00:00 2001 From: liugang Date: Mon, 22 Apr 2024 14:08:53 +0800 Subject: [PATCH 022/141] * taskConfig: fix error of trying to get property of non-object. --- module/task/config/form.php | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/module/task/config/form.php b/module/task/config/form.php index 79fde6f843..d3d589f6ca 100644 --- a/module/task/config/form.php +++ b/module/task/config/form.php @@ -6,6 +6,8 @@ $config->task->form->team = new stdclass(); $config->task->form->testTask = new stdclass(); global $app; +$account = isset($app->user->account) ? $app->user->account : ''; + $config->task->form->create = array(); $config->task->form->create['execution'] = array('type' => 'int', 'required' => true, 'default' => 0); $config->task->form->create['type'] = array('type' => 'string', 'required' => true, 'default' => ''); @@ -22,7 +24,7 @@ $config->task->form->create['estStarted'] = array('type' => 'date', 'requi $config->task->form->create['deadline'] = array('type' => 'date', 'required' => false, 'default' => null); $config->task->form->create['vision'] = array('type' => 'string', 'required' => false, 'default' => $config->vision); $config->task->form->create['status'] = array('type' => 'string', 'required' => false, 'default' => 'wait'); -$config->task->form->create['openedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->create['openedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->create['openedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->create['version'] = array('type' => 'int', 'required' => false, 'default' => 1); $config->task->form->create['storyVersion'] = array('type' => 'int', 'required' => false, 'default' => 1); @@ -34,7 +36,7 @@ $config->task->form->assign = array(); $config->task->form->assign['assignedTo'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->task->form->assign['assignedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->assign['left'] = array('type' => 'float', 'required' => true); -$config->task->form->assign['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->assign['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->assign['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->cancel = array(); @@ -76,7 +78,7 @@ $config->task->form->edit['canceledDate'] = array('type' => 'datetime', 'requi $config->task->form->edit['closedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->task->form->edit['closedReason'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->task->form->edit['closedDate'] = array('type' => 'datetime', 'required' => false, 'default' => null); -$config->task->form->edit['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->edit['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->edit['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->edit['deleteFiles'] = array('type' => 'array', 'required' => false, 'default' => array()); @@ -103,7 +105,7 @@ $config->task->form->batchedit['consumed'] = array('type' => 'float', ' $config->task->form->batchedit['left'] = array('type' => 'float', 'required' => false, 'default' => 0); $config->task->form->batchedit['estStarted'] = array('type' => 'date', 'required' => false, 'default' => null); $config->task->form->batchedit['deadline'] = array('type' => 'date', 'required' => false, 'default' => null); -$config->task->form->batchedit['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->batchedit['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->batchedit['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->batchcreate = array(); @@ -122,12 +124,12 @@ $config->task->form->batchcreate['deadline'] = array('type' => 'date', $config->task->form->batchcreate['desc'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->task->form->batchcreate['pri'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->task->form->batchcreate['lane'] = array('type' => 'int', 'required' => false, 'default' => 0); -$config->task->form->batchcreate['openedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->batchcreate['openedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->batchcreate['openedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->batchcreate['vision'] = array('type' => 'string', 'required' => false, 'default' => $config->vision); $config->task->form->pause = array(); -$config->task->form->pause['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->pause['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->pause['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->pause['status'] = array('type' => 'string', 'required' => false, 'default' => 'pause'); @@ -139,7 +141,7 @@ $config->task->form->activate['comment'] = array('type' => 'string', 'r $config->task->form->activate['status'] = array('type' => 'string', 'required' => false, 'default' => 'doing'); $config->task->form->activate['activatedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->activate['assignedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); -$config->task->form->activate['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->activate['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->activate['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->activate['finishedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->task->form->activate['canceledBy'] = array('type' => 'string', 'required' => false, 'default' => ''); @@ -155,7 +157,7 @@ $config->task->form->start['consumed'] = array('type' => 'float', 'requ $config->task->form->start['left'] = array('type' => 'float', 'required' => false, 'default' => 0); $config->task->form->start['assignedTo'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->task->form->start['realStarted'] = array('type' => 'datetime', 'required' => false, 'default' => null); -$config->task->form->start['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->start['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->start['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->finish = array(); @@ -167,17 +169,17 @@ $config->task->form->finish['status'] = array('type' => 'string', 're $config->task->form->finish['finishedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->finish['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->finish['assignedDate'] = array('type' => 'string', 'required' => false, 'default' => $now); -$config->task->form->finish['finishedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); -$config->task->form->finish['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->finish['finishedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); +$config->task->form->finish['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->finish['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->close = array(); $config->task->form->close['status'] = array('type' => 'string', 'required' => false, 'default' => 'closed'); $config->task->form->close['assignedTo'] = array('type' => 'string', 'required' => false, 'default' => 'closed'); $config->task->form->close['assignedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); -$config->task->form->close['closedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->close['closedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->close['closedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); -$config->task->form->close['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->task->form->close['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $account); $config->task->form->close['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->task->form->testTask->create = array(); From b5ccb2dfddb078ad19bd1e0616f85566dc95d3cd Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 14:09:41 +0800 Subject: [PATCH 023/141] * Show no data tips. --- module/task/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/task/control.php b/module/task/control.php index 28f7e5d406..9b1888cf3f 100755 --- a/module/task/control.php +++ b/module/task/control.php @@ -333,7 +333,7 @@ class task extends control if(!$task) { if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'fail', 'code' => 404, 'message' => '404 Not found')); - return $this->send(array('result' => 'success', 'load' => array('alert' => $this->lang->notFound, 'locate' => $this->config->vision == 'lite' ? $this->createLink('project', 'index') : $this->createLink('execution', 'all')))); + return $this->sendError($this->lang->notFound, $this->config->vision == 'lite' ? $this->createLink('project', 'index') : $this->createLink('execution', 'all')); } if(!$this->loadModel('common')->checkPrivByObject('execution', $task->execution)) return print(js::error($this->lang->execution->accessDenied) . js::locate($this->createLink('execution', 'all'))); From 57c47cfc9b1b3955aff188380ed86a4cec6c1523 Mon Sep 17 00:00:00 2001 From: daitingting Date: Mon, 22 Apr 2024 06:20:42 +0000 Subject: [PATCH 024/141] * Fix bug #48055. --- module/kanban/tao.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module/kanban/tao.php b/module/kanban/tao.php index acadced9b5..66eaefa2fd 100644 --- a/module/kanban/tao.php +++ b/module/kanban/tao.php @@ -910,6 +910,8 @@ class kanbanTao extends kanbanModel */ protected function getStoryCardMenu(int $executionID, array $objects): array { + $execution = $this->loadModel('execution')->getByID($executionID); + $menus = array(); $objects = $this->loadModel('story')->mergeReviewer($objects); foreach($objects as $story) @@ -923,7 +925,7 @@ class kanbanTao extends kanbanModel if(common::hasPriv('task', 'create') and $toTaskPriv) $menu[] = array('label' => $this->lang->execution->wbs, 'icon' => 'plus', 'url' => helper::createLink('task', 'create', "executionID=$executionID&storyID=$story->id&moduleID=$story->module"), 'modal' => true, 'size' => 'lg'); if(common::hasPriv('task', 'batchCreate') and $toTaskPriv) $menu[] = array('label' => $this->lang->execution->batchWBS, 'icon' => 'pluses', 'url' => helper::createLink('task', 'batchCreate', "executionID=$executionID&storyID=$story->id&moduleID=0&taskID=0&iframe=true"), 'modal' => true, 'size' => 'lg'); if(common::hasPriv('story', 'activate') and $this->story->isClickable($story, 'activate')) $menu[] = array('label' => $this->lang->story->activate, 'icon' => 'magic', 'url' => helper::createLink('story', 'activate', "storyID=$story->id"), 'modal' => true, 'size' => 'lg'); - if(common::hasPriv('execution', 'unlinkStory')) $menu[] = array('label' => $this->lang->execution->unlinkStory, 'icon' => 'unlink', 'url' => helper::createLink('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->story&confirm=no&from=taskkanban")); + if(common::hasPriv('execution', 'unlinkStory') && $execution->hasProduct) $menu[] = array('label' => $this->lang->execution->unlinkStory, 'icon' => 'unlink', 'url' => helper::createLink('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->story&confirm=no&from=taskkanban")); if(common::hasPriv('story', 'delete')) $menu[] = array('label' => $this->lang->story->delete, 'icon' => 'trash', 'url' => helper::createLink('story', 'delete', "storyID=$story->id&confirm=no&from=taskkanban")); $menus[$story->id] = $menu; From 1f2b61d872578852661cf481a0f2eecf4b79c8e2 Mon Sep 17 00:00:00 2001 From: tanghucheng Date: Mon, 22 Apr 2024 14:26:28 +0800 Subject: [PATCH 025/141] * Fix bug #47758, remove percent when disabled percent. --- module/programplan/zen.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/programplan/zen.php b/module/programplan/zen.php index 0c44f09e6e..d6faad3713 100644 --- a/module/programplan/zen.php +++ b/module/programplan/zen.php @@ -89,6 +89,8 @@ class programplanZen extends programplan if(!empty($this->config->setCode) && empty($plan->code) && strpos(",{$this->config->execution->create->requiredFields},", ',code,') !== false) dao::$errors["code[{$rowID}]"] = sprintf($this->lang->error->notempty, $plan->type == 'stage' ? $this->lang->execution->code : $this->lang->code); } + if(strpos(",{$this->config->programplan->list->customCreateFields},", ',percent,') === false) $plan->percent = 0; + $totalPercent += $plan->percent; $names[] = $plan->name; if(!empty($plan->code)) $codes[] = $plan->code; From cf772f7d389b55f4a53cbefbe5ba87f76a752fd7 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 14:26:03 +0800 Subject: [PATCH 026/141] * Modify params type of the getRelatedReleases method. --- module/build/model.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/build/model.php b/module/build/model.php index de23bae5a1..519caa421e 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -391,13 +391,13 @@ class buildModel extends model * 获取关联的发布。 * Get releated release. * - * @param array $productIdList - * @param string $buildIdList - * @param array $shadows + * @param array|int $productIdList + * @param string $buildIdList + * @param array $shadows * @access public * @return void */ - public function getRelatedReleases(array $productIdList, string $buildIdList = '', array|bool $shadows = false): array + public function getRelatedReleases(array|int $productIdList, string $buildIdList = '', array|bool $shadows = false): array { $releases = $this->dao->select('t1.id,t1.shadow,t1.product,t1.branch,t1.build,t1.name,t1.date,t3.name as branchName,t4.type as productType')->from(TABLE_RELEASE)->alias('t1') ->leftJoin(TABLE_BUILD)->alias('t2')->on('FIND_IN_SET(t2.id, t1.build)') From 724de0fc856695d5de750d356487dacb6ee699ff Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 14:26:23 +0800 Subject: [PATCH 027/141] * Change the set user default of build module. --- module/build/config/form.php | 2 +- module/build/control.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/build/config/form.php b/module/build/config/form.php index 0798b3274c..7b20f78dd6 100644 --- a/module/build/config/form.php +++ b/module/build/config/form.php @@ -17,7 +17,7 @@ $config->build->form->create['builds'] = array('type' => 'array', 'r $config->build->form->create['bugs'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->build->form->create['stories'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->build->form->create['date'] = array('type' => 'date', 'required' => true, 'default' => helper::today()); -$config->build->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->build->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->build->form->create['createdDate'] = array('type' => 'datetime ', 'required' => false, 'default' => $now); $config->build->form->edit['execution'] = array('type' => 'int', 'required' => $app->tab == 'execution', 'default' => 0); diff --git a/module/build/control.php b/module/build/control.php index 7d32f284d3..35514661d3 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -49,7 +49,7 @@ class build extends control { if(!empty($_POST)) { - $build = form::data()->get(); + $build = form::data()->setDefault('createdBy', $this->app->user->account)->get(); if(!empty($_FILES['buildFiles'])) $_FILES['files'] = $_FILES['buildFiles']; unset($_FILES['buildFiles']); if(dao::isError()) return $this->sendError(dao::getError()); From 0530830ad61076c11b4c78ac7425c36661e9e54a Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 14:52:48 +0800 Subject: [PATCH 028/141] * Change the set user default of design module. --- module/design/config/dtable.php | 1 - module/design/config/form.php | 8 ++++---- module/design/control.php | 5 +++-- module/design/model.php | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/module/design/config/dtable.php b/module/design/config/dtable.php index f9e6ef7f8b..cc6e3b32bf 100644 --- a/module/design/config/dtable.php +++ b/module/design/config/dtable.php @@ -26,7 +26,6 @@ $config->design->dtable->fieldList['type']['statusMap'] = $lang->design->typeLis $config->design->dtable->fieldList['type']['sortType'] = true; $config->design->dtable->fieldList['assignedTo']['type'] = 'assign'; -$config->design->dtable->fieldList['assignedTo']['currentUser'] = $app->user->account; $config->design->dtable->fieldList['assignedTo']['assignLink'] = array('module' => 'design', 'method' => 'assignTo', 'params' => 'designID={id}'); $config->design->dtable->fieldList['assignedTo']['data-toggle'] = 'modal'; $config->design->dtable->fieldList['assignedTo']['sortType'] = false; diff --git a/module/design/config/form.php b/module/design/config/form.php index b1acd11e7e..1ba880c4c4 100644 --- a/module/design/config/form.php +++ b/module/design/config/form.php @@ -12,7 +12,7 @@ $config->design->form->create['project'] = array('type' => 'int', 'requ $config->design->form->create['story'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->design->form->create['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); $config->design->form->create['version'] = array('type' => 'int', 'required' => false, 'default' => 1); -$config->design->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->design->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->design->form->create['createdDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->design->form->batchcreate['name'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim', 'base' => true); @@ -22,7 +22,7 @@ $config->design->form->batchcreate['project'] = array('type' => 'int', $config->design->form->batchcreate['story'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->design->form->batchcreate['desc'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->design->form->batchcreate['version'] = array('type' => 'int', 'required' => false, 'default' => 1); -$config->design->form->batchcreate['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->design->form->batchcreate['createdBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->design->form->batchcreate['createdDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->design->form->edit['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); @@ -30,10 +30,10 @@ $config->design->form->edit['type'] = array('type' => 'string', 'require $config->design->form->edit['product'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->design->form->edit['story'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->design->form->edit['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); -$config->design->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->design->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->design->form->edit['editedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->design->form->assignto['assignedTo'] = array('type' => 'string', 'required' => false, 'default' => ''); -$config->design->form->assignto['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->design->form->assignto['editedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->design->form->assignto['editedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->design->form->assignto['assignedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); diff --git a/module/design/control.php b/module/design/control.php index 23b7223940..f5e1dd04d8 100755 --- a/module/design/control.php +++ b/module/design/control.php @@ -138,6 +138,7 @@ class design extends control { $designData = form::data() ->add('project', $projectID) + ->setDefault('createdBy', $this->app->user->account) ->get(); $designID = $this->design->create($designData); @@ -247,7 +248,7 @@ class design extends control if($_POST) { - $designData = form::data()->get(); + $designData = form::data()->setDefault('editedBy', $this->app->user->account)->get(); $changes = $this->design->update($designID, $designData); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -482,7 +483,7 @@ class design extends control { if($_POST) { - $designData = form::data()->get(); + $designData = form::data()->setDefault('editedBy', $this->app->user->account)->get(); $changes = $this->design->assign($designID, $designData); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); diff --git a/module/design/model.php b/module/design/model.php index 0cb1ae1a04..1b189c5289 100755 --- a/module/design/model.php +++ b/module/design/model.php @@ -60,8 +60,9 @@ class designModel extends model $this->loadModel('action'); foreach($designs as $rowID => $design) { - $design->product = $productID; - $design->project = $projectID; + $design->product = $productID; + $design->project = $projectID; + $design->createdBy = $this->app->user->account; $this->dao->insert(TABLE_DESIGN)->data($design)->autoCheck()->batchCheck($this->config->design->batchcreate->requiredFields, 'notempty')->exec(); if(dao::isError()) From 1ca4b1de46b01c56f1ab673debb55dfe8d48a0d4 Mon Sep 17 00:00:00 2001 From: xieqiyu Date: Mon, 22 Apr 2024 14:56:36 +0800 Subject: [PATCH 029/141] * Fix bug#48044. --- module/product/js/browse.ui.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/module/product/js/browse.ui.js b/module/product/js/browse.ui.js index 748ef8138b..b21a019315 100644 --- a/module/product/js/browse.ui.js +++ b/module/product/js/browse.ui.js @@ -37,6 +37,14 @@ $(document).off('click', '.batchUnlinkStory').on('click', '.batchUnlinkStory', f const checkedList = dtable.$.getChecks(); if(!checkedList.length) return; + /* 处理选中的子需求的ID,截取-后的子需求ID。*/ + /* Process selected child story ID. */ + for(i in checkedList) + { + const storyID = checkedList[i]; + if(storyID.includes('-')) checkedList[i] = storyID.slice(storyID.indexOf('-') + 1); + } + let batchUnlinkStoryURL = $.createLink('projectstory', 'batchUnlinkStory', 'projectID=' + projectID + '&stories=' + encodeURIComponent(checkedList.join(','))); $.get(batchUnlinkStoryURL, function(data) { From c51d43adcf21b9ba2941c4c2701f563f00e0bafd Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 14:58:52 +0800 Subject: [PATCH 030/141] * Change the set user default of doc module. --- module/doc/config/form.php | 8 ++++---- module/doc/control.php | 11 +++++++++-- module/doc/zen.php | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/module/doc/config/form.php b/module/doc/config/form.php index 414a49dc4b..6cb7229289 100644 --- a/module/doc/config/form.php +++ b/module/doc/config/form.php @@ -15,7 +15,7 @@ $config->doc->form->createlib['execution'] = array('type' => 'int', 'requir $config->doc->form->createlib['groups'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); $config->doc->form->createlib['users'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); $config->doc->form->createlib['vision'] = array('type' => 'string', 'required' => false, 'default' => $config->vision); -$config->doc->form->createlib['addedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->doc->form->createlib['addedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->doc->form->createlib['addedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->doc->form->editlib['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); @@ -35,9 +35,9 @@ $config->doc->form->create['type'] = array('type' => 'string', 'requir $config->doc->form->create['keywords'] = array('type' => 'string', 'required' => false, 'default' => '', 'skipRequired' => true); $config->doc->form->create['acl'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->doc->form->create['vision'] = array('type' => 'string', 'required' => false, 'default' => $config->vision); -$config->doc->form->create['addedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->doc->form->create['addedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->doc->form->create['addedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); -$config->doc->form->create['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->doc->form->create['editedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->doc->form->create['editedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->doc->form->create['groups'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); $config->doc->form->create['users'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); @@ -62,5 +62,5 @@ $config->doc->form->edit['content'] = array('type' => 'string', 'required' $config->doc->form->edit['groups'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); $config->doc->form->edit['users'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); $config->doc->form->edit['mailto'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); -$config->doc->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); +$config->doc->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->doc->form->edit['editedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); diff --git a/module/doc/control.php b/module/doc/control.php index 61b1afdd73..d2ec54b1f3 100755 --- a/module/doc/control.php +++ b/module/doc/control.php @@ -332,7 +332,11 @@ class doc extends control helper::setcookie('lastDocModule', $moduleID); if(!isset($_POST['lib']) && strpos($_POST['module'], '_') !== false) list($_POST['lib'], $_POST['module']) = explode('_', $_POST['module']); - $docData = form::data()->get(); + $docData = form::data() + ->setDefault('addedBy', $this->app->user->account) + ->setDefault('editedBy', $this->app->user->account) + ->get(); + $docResult = $this->doc->create($docData, $this->post->labels); if(!$docResult || dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); return $this->docZen->responseAfterCreate($docData->lib, $docResult); @@ -383,7 +387,10 @@ class doc extends control if($comment == false) { if(!isset($_POST['lib']) && strpos($_POST['module'], '_') !== false) list($_POST['lib'], $_POST['module']) = explode('_', $_POST['module']); - $docData = form::data()->setIF(strpos(",$doc->editedList,", ",{$this->app->user->account},") === false, 'editedList', $doc->editedList . ",{$this->app->user->account}")->get(); + $docData = form::data() + ->setDefault('editedBy', $this->app->user->account) + ->setIF(strpos(",$doc->editedList,", ",{$this->app->user->account},") === false, 'editedList', $doc->editedList . ",{$this->app->user->account}") + ->get(); $result = $this->doc->update($docID, $docData); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); diff --git a/module/doc/zen.php b/module/doc/zen.php index 012613ccf9..8ae5ae5bb9 100644 --- a/module/doc/zen.php +++ b/module/doc/zen.php @@ -271,6 +271,7 @@ class docZen extends doc { $this->lang->doc->name = $this->lang->doclib->name; $lib = form::data() + ->setDefault('addedBy', $this->app->user->account) ->setIF($this->post->type == 'product' && !empty($_POST['product']), 'product', $this->post->product) ->setIF($this->post->type == 'project' && !empty($_POST['project']), 'project', $this->post->project) ->setIF($this->post->libType != 'api' && !empty($_POST['execution']), 'execution', $this->post->execution) From 5ec5f63d7769d1596610dea29e681eceec98f4cf Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 15:17:42 +0800 Subject: [PATCH 031/141] * Fix bug #48111. --- module/execution/ui/build.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/execution/ui/build.html.php b/module/execution/ui/build.html.php index 1de6fa2943..a1f4a0599e 100644 --- a/module/execution/ui/build.html.php +++ b/module/execution/ui/build.html.php @@ -44,7 +44,7 @@ jsVar('filePathTip', $lang->build->filePath); jsVar('confirmDelete', $lang->build->confirmDelete); $fieldList = $config->build->dtable->fieldList; -if($execution->type == 'kanban') unset($fieldList['actions']['actionsMap']['createTest']['data-app']); +if($execution->type == 'kanban') unset($fieldList['actions']['list']['createTest']['data-app']); $builds = initTableData($builds, $fieldList, $this->build); dtable From 15305455a991682f7a57126b20b262f3fcff69e4 Mon Sep 17 00:00:00 2001 From: sunguangming Date: Mon, 22 Apr 2024 15:24:32 +0800 Subject: [PATCH 032/141] * Remove app->user from kanban config. --- module/kanban/config/form.php | 24 ++++++++++++------------ module/kanban/control.php | 21 ++++++++++++++++++--- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/module/kanban/config/form.php b/module/kanban/config/form.php index c9e1a9ad8d..833d9ca9ba 100644 --- a/module/kanban/config/form.php +++ b/module/kanban/config/form.php @@ -14,15 +14,15 @@ $config->kanban->form->createSpace['desc'] = array('type' => 'string', 're $config->kanban->form->editSpace = $config->kanban->form->createSpace; $config->kanban->form->activateSpace['status'] = array('type' => 'string', 'required' => true, 'default' => 'active'); -$config->kanban->form->activateSpace['activatedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->activateSpace['activatedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->activateSpace['activatedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); -$config->kanban->form->activateSpace['lastEditedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->activateSpace['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->activateSpace['lastEditedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); $config->kanban->form->closeSpace['status'] = array('type' => 'string', 'required' => true, 'default' => 'closed'); -$config->kanban->form->closeSpace['closedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->closeSpace['closedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->closeSpace['closedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); -$config->kanban->form->closeSpace['lastEditedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->closeSpace['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->closeSpace['lastEditedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); $config->kanban->form->create['name'] = array('type' => 'string', 'required' => true, 'default' => ''); @@ -39,7 +39,7 @@ $config->kanban->form->create['performable'] = array('type' => 'string', 'req $config->kanban->form->create['alignment'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->create['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); $config->kanban->form->create['whitelist'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); -$config->kanban->form->create['createdBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->create['createdDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->kanban->form->create['copyKanbanID'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->kanban->form->create['copyRegion'] = array('type' => 'string', 'required' => false, 'default' => '0'); @@ -49,7 +49,7 @@ $config->kanban->form->edit['space'] = array('type' => 'int', 'req $config->kanban->form->edit['owner'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->edit['team'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join'); $config->kanban->form->edit['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); -$config->kanban->form->edit['lastEditedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->edit['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->edit['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->kanban->form->setting['showWIP'] = array('type' => 'string', 'required' => false, 'default' => ''); @@ -62,15 +62,15 @@ $config->kanban->form->setting['performable'] = array('type' => 'string', 'req $config->kanban->form->setting['alignment'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->activate['status'] = array('type' => 'string', 'required' => true, 'default' => 'active'); -$config->kanban->form->activate['activatedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->activate['activatedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->activate['activatedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); -$config->kanban->form->activate['lastEditedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->activate['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->activate['lastEditedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); $config->kanban->form->close['status'] = array('type' => 'string', 'required' => true, 'default' => 'closed'); -$config->kanban->form->close['closedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->close['closedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->close['closedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); -$config->kanban->form->close['lastEditedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->close['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->close['lastEditedDate'] = array('type' => 'datetime', 'required' => true, 'default' => $now); $config->kanban->form->createLane['name'] = array('type' => 'string', 'required' => true, 'default' => ''); @@ -98,7 +98,7 @@ $config->kanban->form->createCard['assignedTo'] = array('type' => 'array', $config->kanban->form->createCard['begin'] = array('type' => 'date', 'required' => false, 'default' => ''); $config->kanban->form->createCard['end'] = array('type' => 'date', 'required' => false, 'default' => ''); $config->kanban->form->createCard['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); -$config->kanban->form->createCard['createdBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->createCard['createdBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->createCard['createdDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->kanban->form->createCard['assignedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->kanban->form->createCard['color'] = array('type' => 'string', 'required' => false, 'default' => '#fff'); @@ -112,7 +112,7 @@ $config->kanban->form->editCard['assignedTo'] = array('type' => 'array', $config->kanban->form->editCard['begin'] = array('type' => 'date', 'required' => false, 'default' => ''); $config->kanban->form->editCard['end'] = array('type' => 'date', 'required' => false, 'default' => ''); $config->kanban->form->editCard['desc'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor'); -$config->kanban->form->editCard['lastEditedBy'] = array('type' => 'string', 'required' => true, 'default' => $app->user->account); +$config->kanban->form->editCard['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->kanban->form->editCard['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->kanban->form->batchCreateCard['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'base' => 'true'); diff --git a/module/kanban/control.php b/module/kanban/control.php index 67ddff6975..22051bd2a9 100644 --- a/module/kanban/control.php +++ b/module/kanban/control.php @@ -129,6 +129,8 @@ class kanban extends control $space = form::data($this->config->kanban->form->activateSpace) ->add('closedBy', '') ->add('closedDate', null) + ->add('activatedBy', $this->app->user->account) + ->add('lastEditedBy', $this->app->user->account) ->get(); $this->kanban->activateSpace($spaceID, $space); @@ -160,6 +162,8 @@ class kanban extends control $space = form::data($this->config->kanban->form->closeSpace) ->add('activatedBy', '') ->add('activatedDate', null) + ->add('closedBy', $this->app->user->account) + ->add('lastEditedBy', $this->app->user->account) ->get(); $this->kanban->closeSpace($spaceID, $space); @@ -205,7 +209,9 @@ class kanban extends control { if(!empty($_POST)) { - $kanban = form::data($this->config->kanban->form->create)->get(); + $kanban = form::data($this->config->kanban->form->create) + ->setDefault('createdBy', $this->app->user->account) + ->get(); $this->kanban->create($kanban); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -227,7 +233,9 @@ class kanban extends control { if(!empty($_POST)) { - $kanban = form::data($this->config->kanban->form->edit)->get(); + $kanban = form::data($this->config->kanban->form->edit) + ->setDefault('lastEditedBy', $this->app->user->account) + ->get(); $this->kanban->update($kanbanID, $kanban); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -297,6 +305,8 @@ class kanban extends control $kanban = form::data($this->config->kanban->form->activate) ->setDefault('closedBy', '') ->setDefault('closedDate', null) + ->setDefault('activatedBy', $this->app->user->account) + ->setDefault('lastEditedBy', $this->app->user->account) ->get(); $this->kanban->activate($kanbanID, $kanban); @@ -327,6 +337,8 @@ class kanban extends control $kanban = form::data($this->config->kanban->form->close) ->setDefault('activatedBy', '') ->setDefault('activatedDate', null) + ->setDefault('closedBy', $this->app->user->account) + ->setDefault('lastEditedBy', $this->app->user->account) ->get(); $this->kanban->close($kanbanID, $kanban); @@ -745,6 +757,7 @@ class kanban extends control ->add('kanban', $kanbanID) ->add('region', $regionID) ->add('group', $groupID) + ->setDefault('createdBy', $this->app->user->account) ->get(); $this->kanban->createCard($columnID, $card); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -810,7 +823,9 @@ class kanban extends control { if(!empty($_POST)) { - $card = form::data($this->config->kanban->form->editCard)->get(); + $card = form::data($this->config->kanban->form->editCard) + ->setDefault('lastEditedBy', $this->app->user->account) + ->get(); $this->kanban->updateCard($cardID, $card); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); From b7e28d5c8393d9d953f9abcbbe4736d128bf047f Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 22 Apr 2024 15:42:30 +0800 Subject: [PATCH 033/141] * Add label for the release in the builds. --- module/bug/control.php | 3 +-- module/bug/ui/resolve.html.php | 15 +-------------- module/bug/zen.php | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index 86ebf9653e..d79fb6d6ad 100755 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -468,8 +468,7 @@ class bug extends control $this->view->users = $users; $this->view->assignedTo = isset($users[$oldBug->openedBy]) ? $oldBug->openedBy : $this->bug->getModuleOwner($oldBug->module, $oldBug->product); $this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($oldBug->product, $oldBug->branch ? "0,{$oldBug->branch}" : '0', (int)$oldBug->project, 'stagefilter'); - $this->view->builds = $builds; - $this->view->releases = $this->build->getRelatedReleases(array($oldBug->product)); + $this->view->builds = $this->bugZen->addReleaseLabelForBuilds($oldBug->product, $builds); $this->view->actions = $this->loadModel('action')->getList('bug', $bugID); $this->display(); } diff --git a/module/bug/ui/resolve.html.php b/module/bug/ui/resolve.html.php index ecea8d891d..bf45658f27 100644 --- a/module/bug/ui/resolve.html.php +++ b/module/bug/ui/resolve.html.php @@ -16,19 +16,6 @@ jsVar('page', 'resolve'); jsVar('released', $lang->build->released); jsVar('requiredFields', $config->bug->resolve->requiredFields); -$buildItems = array(); -foreach($builds as $buildID => $buildName) -{ - $buildItem = array('value' => $buildID, 'text' => $buildName); - if(isset($releases[$buildID])) $buildItem['content'] = array('html' => "
{$buildName}
", 'class' => 'w-full flex nowrap'); - $buildItems[$buildID] = $buildItem; -} -foreach($releases as $releaseID => $release) -{ - if(isset($buildItems[$release->shadow])) $buildItems[$release->shadow]['content'] = array('html' => "
{$buildItems[$release->shadow]['text']}
", 'class' => 'w-full flex nowrap'); -} -var_dump($buildItems); - $createBuild = ''; if(common::hasPriv('build', 'create')) { @@ -107,7 +94,7 @@ formPanel ( set::name('resolvedBuild'), set::value(''), - set::items(array_values($buildItems)) + set::items($builds) ) ), formGroup diff --git a/module/bug/zen.php b/module/bug/zen.php index 886995483e..f31506e125 100644 --- a/module/bug/zen.php +++ b/module/bug/zen.php @@ -988,6 +988,7 @@ class bugZen extends bug { $builds = $this->build->getBuildPairs(array($productID), $branch, 'noempty,noterminate,nodone,withbranch,noreleased'); } + $builds = $this->addReleaseLabelForBuilds($productID, $builds); return $this->updateBug($bug, array('builds' => $builds)); } @@ -1205,10 +1206,13 @@ class bugZen extends bug $cases = $this->loadmodel('testcase')->getPairsByProduct($bug->product, array(0, $bug->branch), $case->title, $this->config->maxCount); } + $resolvedBuilds = $this->build->getBuildPairs(array($bug->product), $bug->branch, 'noempty'); + $resolvedBuilds = $this->addReleaseLabelForBuilds($bug->product, $resolvedBuilds); + $this->config->moreLinks['case'] = inlink('ajaxGetProductCases', "bugID={$bug->id}"); $this->view->openedBuilds = $openedBuilds; - $this->view->resolvedBuilds = $this->build->getBuildPairs(array($bug->product), $bug->branch, 'noempty'); + $this->view->resolvedBuilds = $resolvedBuilds; $this->view->plans = $this->loadModel('productplan')->getPairs($bug->product, $bug->branch, '', true); $this->view->stories = $bug->execution ? $this->story->getExecutionStoryPairs($bug->execution) : $this->story->getProductStoryPairs($bug->product, $bug->branch, 0, 'all', 'id_desc', 0, 'full', 'story', false); $this->view->tasks = $this->task->getExecutionTaskPairs($bug->execution); @@ -2390,4 +2394,32 @@ class bugZen extends bug return $chartOption; } + + /** + * 给版本中的发布增加标识。 + * Add label for the release in the builds. + * + * @param int $productID + * @param array $builds + * @access protected + * @return array + */ + protected function addReleaseLabelForBuilds(int $productID, array $builds): array + { + $releases = $this->loadModel('build')->getRelatedReleases(array($productID)); + + $buildItems = array(); + foreach($builds as $buildID => $buildName) + { + $buildItem = array('value' => $buildID, 'text' => $buildName); + if(isset($releases[$buildID])) $buildItem['content'] = array('html' => "
{$buildName}
", 'class' => 'w-full flex nowrap'); + $buildItems[$buildID] = $buildItem; + } + foreach($releases as $release) + { + if(isset($buildItems[$release->shadow])) $buildItems[$release->shadow]['content'] = array('html' => "
{$buildItems[$release->shadow]['text']}
", 'class' => 'w-full flex nowrap'); + } + + return array_values($buildItems); + } } From 8988a4bc639e63f54e7ae991421da9503e2ff571 Mon Sep 17 00:00:00 2001 From: qixinzhi Date: Mon, 22 Apr 2024 07:45:35 +0000 Subject: [PATCH 034/141] * Move control function from pms to ext. --- module/metric/control.php | 164 -------------------------------------- 1 file changed, 164 deletions(-) diff --git a/module/metric/control.php b/module/metric/control.php index 2fe03a5da6..da7a163481 100755 --- a/module/metric/control.php +++ b/module/metric/control.php @@ -158,126 +158,6 @@ class metric extends control $this->display(); } - /** - * 计算一个度量项的历史数据。 - * Update history metric lib of single metric. - * - * @param string $code - * @param string $date - * @param string $calcType - * @access public - * @return void - */ - public function ajaxUpdateSingleMetricLib($code, $date, $calcType) - { - $date = str_replace('_', '-', $date); - $dateType = $this->metric->getDateTypeByCode($code); - - if($calcType == 'inference') $isCalcByCron = $this->metric->isCalcByCron($code, $date, $dateType); - - if($calcType == 'all' || !$isCalcByCron) - { - $calc = $this->metric->calculateMetricByCode($code); - $record = $this->metricZen->getRecordByCodeAndDate($code, $calc, $date); - - $records = array(); - $records[$code] = $record; - $this->metric->insertMetricLib($records, 'inference'); - } - } - - /** - * 计算历史数据。 - * Update metric lib of history. - * - * @param string $date - * @param string $calcType - * @access public - * @return void - */ - public function ajaxUpdateHistoryMetricLib($date, $calcType) - { - $date = str_replace('_', '-', $date); - $calcList = $this->metric->getCalcInstanceList(); - - $classifiedCalcGroup = json_decode(file_get_contents($this->app->getTmpRoot() . 'calc')); - - $records = array(); - foreach($classifiedCalcGroup as $calcGroup) - { - foreach($calcGroup->calcList as $code => $calc) - { - if($calcType == 'inference') - { - $dateType = $this->metric->getDateTypeByCode($code); - if($dateType == 'nodate') continue; - - $isCalcByCron = $this->metric->isCalcByCron($code, $date, $dateType); - if($isCalcByCron) continue; - } - - $calcObj = $calcList[$code]; - $calcObj->result = json_decode(json_encode($calc->result), true); - $inferenceRecord = $this->metricZen->getRecordByCodeAndDate($code, $calcObj, $date); - if(!empty($inferenceRecord)) $records[$code] = $inferenceRecord; - } - } - $this->metric->insertMetricLib($records, 'inference'); - } - - /** - * 保存计算后的度量项对象。 - * Save calculated metric to file. - * - * @access public - * @return void - */ - public function ajaxSaveCalculatedMetrics() - { - $calcList = $this->metric->getCalcInstanceList(); - $classifiedCalcGroup = $this->metric->classifyCalc($calcList); - - foreach($classifiedCalcGroup as $calcGroup) - { - if($this->config->edition == 'open' and in_array($calcGroup->dataset, array('getFeedbacks', 'getIssues', 'getRisks'))) continue; - if($this->config->edition == 'biz' and in_array($calcGroup->dataset, array('getIssues', 'getRisks'))) continue; - - try - { - $statement = $this->metricZen->prepareDataset($calcGroup); - if(empty($statement)) continue; - - $rows = $statement->fetchAll(); - $this->metricZen->calcMetric($rows, $calcGroup->calcList); - - foreach($calcGroup->calcList as $calc) $calc->setDAO(null); - } - catch(Exception $e) - { - a($this->metricZen->formatException($e)); - } - catch(Error $e) - { - a($this->metricZen->formatException($e)); - } - } - - file_put_contents($this->app->getTmpRoot() . 'calc', json_encode($classifiedCalcGroup)); - } - - /** - * 删除重复度量库数据。 - * Delete duplication record in metric data. - * - * @access public - * @return void - */ - public function ajaxDeduplicateRecord() - { - $metrics = $this->metric->getExecutableMetric(); - foreach($metrics as $code) $this->metric->deduplication($code); - } - /** * 计算度量项。 * Execute metric. @@ -483,50 +363,6 @@ class metric extends control $this->display(); } - /** - * 重算度量项历史数据。 - * Recalculate metric history data. - * - * @param string $calcRange all|single - * @param string $code - * @access public - * @return string - */ - public function recalculateSetting($calcRange= 'all', $code = '') - { - $this->view->calcRange = $calcRange; - $this->view->code = $code; - $this->display(); - } - - /** - * 重算度量项进度。 - * Show recalculate progress. - * - * @param string $calcType all|inference - * @param string $calcRange all|single - * @param string $code - * @access public - * @return string - */ - public function recalculate($calcType, $calcRange = 'all', $code = '') - { - $metric = !empty($code) ? $this->metric->getByCode($code) : ''; - $dateType = !empty($code) ? $this->metric->getDateTypeByCode($code) : ''; - - $startDate = $this->metric->getInstallDate(); - $endDate = helper::now(); - - $this->view->code = $code; - $this->view->metric = $metric; - $this->view->dateType = $dateType; - $this->view->calcType = $calcType; - $this->view->calcRange = $calcRange; - $this->view->startDate = substr($startDate, 0, 10); - $this->view->endDate = substr($endDate, 0, 10); - $this->display(); - } - /** * 获取数据表格的数据。 * Get data of datatable. From 9e79e38deb5c0d95e989d0045872c281a7d130c3 Mon Sep 17 00:00:00 2001 From: qixinzhi Date: Mon, 22 Apr 2024 07:46:28 +0000 Subject: [PATCH 035/141] * Skip closed scope when calculate metric. --- module/metric/model.php | 11 +++++++++++ module/metric/zen.php | 11 +++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/module/metric/model.php b/module/metric/model.php index 382e3c3124..fe282b6bf1 100755 --- a/module/metric/model.php +++ b/module/metric/model.php @@ -1230,6 +1230,7 @@ class metricModel extends model ->where('deleted')->eq(0) ->andWhere('shadow')->eq(0) ->andWhere('createdDate')->le($date) + ->andWhere("if(closedDate IS NOT NULL and YEAR(closedDate)!='0000', closedDate>='$date', true)") ->andWhere("vision LIKE '%{$vision}%'", true) ->orWhere("vision IS NULL")->markRight(1) ->fetchPairs(); @@ -1239,6 +1240,7 @@ class metricModel extends model ->where('deleted')->eq(0) ->andWhere('type')->eq('project') ->andWhere('openedDate')->le($date) + ->andWhere("if(closedDate IS NOT NULL and YEAR(closedDate)!='0000', closedDate>='$date', true)") ->andWhere("vision LIKE '%{$vision}%'", true) ->orWhere("vision IS NULL")->markRight(1) ->fetchPairs(); @@ -1248,6 +1250,7 @@ class metricModel extends model ->where('deleted')->eq(0) ->andWhere('type')->in('sprint,stage,kanban') ->andWhere('openedDate')->le($date) + ->andWhere("if(closedDate IS NOT NULL and YEAR(closedDate)!='0000', closedDate>='$date', true)") ->andWhere("vision LIKE '%{$vision}%'", true) ->orWhere("vision IS NULL")->markRight(1) ->fetchPairs(); @@ -2611,6 +2614,14 @@ class metricModel extends model */ public function getInstallDate() { + $installedDate = $this->dao->select('value')->from(TABLE_CONFIG) + ->where('section')->eq('global') + ->andWhere('key')->eq('installedDate') + ->limit(1) + ->fetch('value'); + + if(!empty($installedDate) && substr($installedDate, 0 ,4) == '0000') return $installedDate; + return $this->dao->select('date')->from(TABLE_ACTION) ->orderBy('date_asc') ->limit(1) diff --git a/module/metric/zen.php b/module/metric/zen.php index 718dc6b579..bee105e654 100644 --- a/module/metric/zen.php +++ b/module/metric/zen.php @@ -291,14 +291,9 @@ class metricZen extends metric } else { - if($date == 'now') - { - $scopeList = $this->metric->getPairsByScope($scope); - } - else - { - $scopeList = $this->metric->getPairsByScopeAndDate($scope, $date); - } + if($date == 'now') $date = helper::today(); + + $scopeList = $this->metric->getPairsByScopeAndDate($scope, $date); foreach($scopeList as $key => $value) { From 2584cdcfc80a9eb25506ad516b008e98c265d292 Mon Sep 17 00:00:00 2001 From: sunhao Date: Mon, 22 Apr 2024 15:54:39 +0800 Subject: [PATCH 036/141] * testcase: bug #48181, fix search form not show after switch page from testtask to testcase. --- module/testcase/js/browse.ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testcase/js/browse.ui.js b/module/testcase/js/browse.ui.js index 39ea934b37..eba0a8dc16 100644 --- a/module/testcase/js/browse.ui.js +++ b/module/testcase/js/browse.ui.js @@ -208,7 +208,7 @@ window.setStatistics = function(element, checks) }); } - return element.options.customData.pageSummary; + return element.options.customData ? element.options.customData.pageSummary : ''; } /** From 213fa5be216617e3b08ef48c46f7fe8c605d2135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E8=BE=B0=E8=BD=A9?= Date: Mon, 22 Apr 2024 16:03:44 +0800 Subject: [PATCH 037/141] * Fix bug #48184. --- module/story/zen.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/module/story/zen.php b/module/story/zen.php index 32b912990d..7ed163e463 100644 --- a/module/story/zen.php +++ b/module/story/zen.php @@ -1696,6 +1696,11 @@ class storyZen extends story return $this->session->storyList; } + if($this->app->tab == 'product') + { + return $this->createLink('product', 'browse', "productID=$productID&branch=$branch&browseType=unclosed&queryID=0&storyType=$storyType"); + } + helper::setcookie('storyModule', '0', 0); if($this->session->storyList) return $this->session->storyList; return $this->createLink('product', 'browse', "productID=$productID&branch=$branch&browseType=unclosed&queryID=0&storyType=$storyType"); From 7ba317678512fb9d6ddfed2d4dae933af59ebbc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 22 Apr 2024 16:08:34 +0800 Subject: [PATCH 038/141] * Fix bug #48031. --- module/file/control.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/file/control.php b/module/file/control.php index 383279f131..997b377fb8 100755 --- a/module/file/control.php +++ b/module/file/control.php @@ -184,7 +184,7 @@ class file extends control $output .= '"'; foreach($fields as $fieldName => $fieldLabel) { - $output .= isset($row->$fieldName) ? str_replace(array('"', ' '), array('“', ' '), htmlspecialchars_decode(strip_tags((string)$row->$fieldName, ''))) : ''; + $output .= isset($row->$fieldName) ? str_replace(array('"', ' '), array('“', ' '), htmlSpecialString(strip_tags((string)$row->$fieldName, ''))) : ''; $output .= '","'; } $output .= '"' . "\n"; @@ -218,7 +218,7 @@ class file extends control $output .= " \n"; foreach($fields as $fieldName => $fieldLabel) { - $fieldValue = isset($row->$fieldName) ? htmlSpecialString($row->$fieldName) : ''; + $fieldValue = isset($row->$fieldName) ? htmlSpecialString(strip_tags((string)$row->$fieldName, '')) : ''; $output .= " <$fieldName>$fieldValue\n"; } $output .= " \n"; From f4b8e8e86335e1a14bba1edf61fd5ba1622308d7 Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:12:33 +0800 Subject: [PATCH 039/141] * Move user account setting of serverroom. --- module/serverroom/config/form.php | 3 --- module/serverroom/control.php | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/module/serverroom/config/form.php b/module/serverroom/config/form.php index 856236fc00..468f98599c 100644 --- a/module/serverroom/config/form.php +++ b/module/serverroom/config/form.php @@ -1,5 +1,4 @@ serverroom->form = new stdclass(); $config->serverroom->form->create['name'] = array('type' => 'string', 'required' => true, 'default' => ''); $config->serverroom->form->create['bandwidth'] = array('type' => 'string', 'required' => false, 'default' => ''); @@ -7,7 +6,6 @@ $config->serverroom->form->create['city'] = array('type' => 'string', 're $config->serverroom->form->create['line'] = array('type' => 'string', 'required' => true, 'default' => ''); $config->serverroom->form->create['provider'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->serverroom->form->create['owner'] = array('type' => 'string', 'required' => false, 'default' => ''); -$config->serverroom->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->serverroom->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->serverroom->form->edit['name'] = array('type' => 'string', 'required' => true, 'default' => ''); @@ -16,5 +14,4 @@ $config->serverroom->form->edit['city'] = array('type' => 'string', 'requi $config->serverroom->form->edit['line'] = array('type' => 'string', 'required' => true, 'default' => ''); $config->serverroom->form->edit['provider'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->serverroom->form->edit['owner'] = array('type' => 'string', 'required' => false, 'default' => ''); -$config->serverroom->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->serverroom->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); diff --git a/module/serverroom/control.php b/module/serverroom/control.php index ec989872f0..6e6043d4d3 100644 --- a/module/serverroom/control.php +++ b/module/serverroom/control.php @@ -62,7 +62,9 @@ class serverroom extends control { if($_POST) { - $room = form::data($this->config->serverroom->form->create)->get(); + $room = form::data($this->config->serverroom->form->create) + ->add('createdBy', $this->app->user->account) + ->get(); $createID = $this->serverroom->create($room); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -87,7 +89,9 @@ class serverroom extends control { if($_POST) { - $room = form::data($this->config->serverroom->form->edit)->get(); + $room = form::data($this->config->serverroom->form->edit) + ->add('editedBy', $this->app->user->account) + ->get(); $changes = $this->serverroom->update($roomID, $room); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); From 59bf4d858dd2b076be896512c89a834fb27386c1 Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:14:58 +0800 Subject: [PATCH 040/141] * Move user account setting of gitlab. --- module/gitlab/config/form.php | 3 --- module/gitlab/control.php | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/module/gitlab/config/form.php b/module/gitlab/config/form.php index 5a1069e123..7066b3415c 100644 --- a/module/gitlab/config/form.php +++ b/module/gitlab/config/form.php @@ -1,5 +1,4 @@ gitlab->form = new stdclass(); $config->gitlab->form->create = array(); $config->gitlab->form->create['appType'] = array('type' => 'string', 'required' => true, 'default' => 'gitlab'); @@ -7,7 +6,6 @@ $config->gitlab->form->create['type'] = array('type' => 'string', 'requ $config->gitlab->form->create['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitlab->form->create['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitlab->form->create['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gitlab->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gitlab->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->gitlab->form->create['private'] = array('type' => 'string', 'required' => false, 'default' => uniqid()); @@ -15,7 +13,6 @@ $config->gitlab->form->edit = array(); $config->gitlab->form->edit['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitlab->form->edit['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitlab->form->edit['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gitlab->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gitlab->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->gitlab->form->user = new stdclass(); diff --git a/module/gitlab/control.php b/module/gitlab/control.php index c8fd774cfb..46fd90bf0f 100644 --- a/module/gitlab/control.php +++ b/module/gitlab/control.php @@ -75,7 +75,9 @@ class gitlab extends control { if($_POST) { - $gitlab = form::data($this->config->gitlab->form->create)->get(); + $gitlab = form::data($this->config->gitlab->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); $this->checkToken($gitlab); $gitlabID = $this->loadModel('pipeline')->create($gitlab); @@ -123,7 +125,9 @@ class gitlab extends control if($_POST) { - $gitlab = form::data($this->config->gitlab->form->edit)->get(); + $gitlab = form::data($this->config->gitlab->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); $this->checkToken($gitlab, $gitlabID); $this->loadModel('pipeline')->update($gitlabID, $gitlab); $gitLab = $this->gitlab->getByID($gitlabID); From e709ce1cc7f3da5b4459eb647ea65308ab32791c Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:16:16 +0800 Subject: [PATCH 041/141] * Move user account setting of gitea. --- module/gitea/config/form.php | 3 --- module/gitea/control.php | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/module/gitea/config/form.php b/module/gitea/config/form.php index a483bae20a..b393ba0682 100644 --- a/module/gitea/config/form.php +++ b/module/gitea/config/form.php @@ -1,5 +1,4 @@ gitea->form = new stdclass(); $config->gitea->form->create = array(); $config->gitea->form->create['appType'] = array('type' => 'string', 'required' => true, 'default' => 'gitea'); @@ -7,7 +6,6 @@ $config->gitea->form->create['type'] = array('type' => 'string', 'require $config->gitea->form->create['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitea->form->create['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitea->form->create['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gitea->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gitea->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->gitea->form->create['private'] = array('type' => 'string', 'required' => false, 'default' => uniqid()); @@ -15,5 +13,4 @@ $config->gitea->form->edit = array(); $config->gitea->form->edit['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitea->form->edit['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitea->form->edit['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gitea->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gitea->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); diff --git a/module/gitea/control.php b/module/gitea/control.php index 3f776c306a..e14cfdd51f 100644 --- a/module/gitea/control.php +++ b/module/gitea/control.php @@ -71,7 +71,9 @@ class gitea extends control { if($_POST) { - $gitea = form::data($this->config->gitea->form->create)->get(); + $gitea = form::data($this->config->gitea->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); $result = $this->checkToken($gitea); if(is_array($result)) return $this->send($result); @@ -118,7 +120,9 @@ class gitea extends control if($_POST) { - $gitea = form::data($this->config->gitea->form->edit)->get(); + $gitea = form::data($this->config->gitea->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); $result = $this->checkToken($gitea); if(is_array($result)) return $this->send($result); From 6b0eac97c4ec6eeaa72b61233553690370793a7c Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:17:17 +0800 Subject: [PATCH 042/141] * Move user account setting of job. --- module/job/config/form.php | 3 --- module/job/control.php | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/module/job/config/form.php b/module/job/config/form.php index e0eb0bfc54..b5d85e03b7 100644 --- a/module/job/config/form.php +++ b/module/job/config/form.php @@ -1,7 +1,6 @@ job->form = new stdclass(); $config->job->form->create = array(); @@ -23,7 +22,6 @@ $config->job->form->create['jkServer'] = array('type' => 'int', 'requi $config->job->form->create['jkTask'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->job->form->create['paramName'] = array('type' => 'array', 'required' => false, 'default' => array()); $config->job->form->create['paramValue'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->job->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->job->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => $now); $config->job->form->edit = array(); @@ -45,5 +43,4 @@ $config->job->form->edit['jkServer'] = array('type' => 'int', 'require $config->job->form->edit['jkTask'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->job->form->edit['paramName'] = array('type' => 'array', 'required' => false, 'default' => array()); $config->job->form->edit['paramValue'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->job->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->job->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => $now); diff --git a/module/job/control.php b/module/job/control.php index c3d518f6be..b087fa4229 100644 --- a/module/job/control.php +++ b/module/job/control.php @@ -100,6 +100,7 @@ class job extends control ->setIF($this->post->useZentao != '1' || $this->post->triggerType != 'tag', 'lastTag', '') ->setIF($this->post->frame != 'sonarqube', 'sonarqubeServer', 0) ->setIF($this->post->frame != 'sonarqube', 'projectKey', '') + ->add('createdBy', $this->app->user->acount) ->get(); $jobID = $this->job->create($job); @@ -142,6 +143,7 @@ class job extends control ->setIF($this->post->useZentao != '1' || $this->post->triggerType != 'tag', 'lastTag', '') ->setIF($this->post->frame != 'sonarqube', 'sonarqubeServer', 0) ->setIF($this->post->frame != 'sonarqube', 'projectKey', '') + ->add('editedBy', $this->app->user->acount) ->get(); $this->job->update($jobID, $job); From c26470ac744e9c40bd3db2cfbe02977c99f8c32d Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:18:41 +0800 Subject: [PATCH 043/141] * Move user account setting of jenkins. --- module/jenkins/config/form.php | 3 --- module/jenkins/control.php | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/module/jenkins/config/form.php b/module/jenkins/config/form.php index a14c156a54..f34be8761f 100644 --- a/module/jenkins/config/form.php +++ b/module/jenkins/config/form.php @@ -1,5 +1,4 @@ jenkins->form = new stdclass(); $config->jenkins->form->create = array(); @@ -10,7 +9,6 @@ $config->jenkins->form->create['url'] = array('type' => 'string', 'req $config->jenkins->form->create['account'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->jenkins->form->create['token'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); $config->jenkins->form->create['password'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); -$config->jenkins->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->jenkins->form->create['createdDate'] = array('type' => 'datetime', 'required' => false, 'default' => helper::now()); $config->jenkins->form->create['private'] = array('type' => 'string', 'required' => false, 'default' => uniqid()); @@ -20,5 +18,4 @@ $config->jenkins->form->edit['url'] = array('type' => 'string', 'requir $config->jenkins->form->edit['account'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->jenkins->form->edit['token'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); $config->jenkins->form->edit['password'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); -$config->jenkins->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->jenkins->form->edit['editedDate'] = array('type' => 'datetime', 'required' => false, 'default' => helper::now()); diff --git a/module/jenkins/control.php b/module/jenkins/control.php index 70c7154c37..51d20e77f7 100644 --- a/module/jenkins/control.php +++ b/module/jenkins/control.php @@ -38,7 +38,9 @@ class jenkins extends control { if($_POST) { - $jenkins = form::data($this->config->jenkins->form->create)->get(); + $jenkins = form::data($this->config->jenkins->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); $this->jenkinsZen->checkTokenAccess($jenkins->url, $jenkins->account, $jenkins->password, $jenkins->token); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -63,7 +65,9 @@ class jenkins extends control $jenkins = $this->loadModel('pipeline')->getByID($jenkinsID); if($_POST) { - $jenkins = form::data($this->config->jenkins->form->edit)->get(); + $jenkins = form::data($this->config->jenkins->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); $this->jenkinsZen->checkTokenAccess($jenkins->url, $jenkins->account, $jenkins->password, $jenkins->token); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); From 47f72739f9bfa03b06e8e9aa2a4fedb8c74d5190 Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:19:51 +0800 Subject: [PATCH 044/141] * Move user account setting of gogs. --- module/gogs/config/form.php | 3 --- module/gogs/control.php | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/module/gogs/config/form.php b/module/gogs/config/form.php index 25e8916ee0..d5fad89867 100644 --- a/module/gogs/config/form.php +++ b/module/gogs/config/form.php @@ -1,5 +1,4 @@ gogs->form = new stdclass(); $config->gogs->form->create = array(); $config->gogs->form->create['appType'] = array('type' => 'string', 'required' => true, 'default' => 'gogs'); @@ -7,7 +6,6 @@ $config->gogs->form->create['type'] = array('type' => 'string', 'requir $config->gogs->form->create['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gogs->form->create['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gogs->form->create['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gogs->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gogs->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->gogs->form->create['private'] = array('type' => 'string', 'required' => false, 'default' => uniqid()); @@ -15,5 +13,4 @@ $config->gogs->form->edit = array(); $config->gogs->form->edit['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gogs->form->edit['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gogs->form->edit['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gogs->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gogs->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); diff --git a/module/gogs/control.php b/module/gogs/control.php index e06622011b..96c9846a8a 100644 --- a/module/gogs/control.php +++ b/module/gogs/control.php @@ -70,7 +70,9 @@ class gogs extends control { if($_POST) { - $gogs = form::data($this->config->gogs->form->create)->get(); + $gogs = form::data($this->config->gogs->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); $priv = $this->checkToken($gogs); if(is_array($priv)) return $this->send($priv); @@ -118,7 +120,9 @@ class gogs extends control if($_POST) { - $gogs = form::data($this->config->gogs->form->edit)->get(); + $gogs = form::data($this->config->gogs->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); $this->checkToken($gogs); $this->loadModel('pipeline')->update($gogsID, $gogs); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); From cf70dd5c7d89dd30b0e5406590ab81d0565795b4 Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:21:42 +0800 Subject: [PATCH 045/141] * Move user account setting of instance. --- module/instance/config/form.php | 3 --- module/instance/control.php | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/module/instance/config/form.php b/module/instance/config/form.php index c25da1481f..041a8abda8 100644 --- a/module/instance/config/form.php +++ b/module/instance/config/form.php @@ -1,5 +1,4 @@ instance->form = new stdclass(); $config->instance->form->create = array(); $config->instance->form->create['appType'] = array('type' => 'string', 'required' => true, 'default' => ''); @@ -7,7 +6,6 @@ $config->instance->form->create['name'] = array('type' => 'string', 'requ $config->instance->form->create['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->instance->form->create['account'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->instance->form->create['password'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->instance->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => isset($app->user->account) ? $app->user->account : ''); $config->instance->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->instance->form->create['private'] = array('type' => 'string', 'required' => false, 'default' => uniqid()); @@ -16,7 +14,6 @@ $config->instance->form->edit['name'] = array('type' => 'string', 'require $config->instance->form->edit['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->instance->form->edit['account'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->instance->form->edit['password'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->instance->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => isset($app->user->account) ? $app->user->account : ''); $config->instance->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->instance->form->install = array(); diff --git a/module/instance/control.php b/module/instance/control.php index 1228c49bf1..9b42eb9b8f 100644 --- a/module/instance/control.php +++ b/module/instance/control.php @@ -203,7 +203,9 @@ class instance extends control $this->loadModel('sonarqube'); $this->app->loadLang('pipeline'); - $externalApp = form::data($this->config->instance->form->create)->get(); + $externalApp = form::data($this->config->instance->form->create) + ->add('createdBy', isset($this->app->user->account) ? $this->app->user->account : '') + ->get(); $externalApp->type = $type; $externalApp->url = rtrim($externalApp->url, '/'); if(!$this->instance->checkAppNameUnique($externalApp->name)) return $this->send(array('result' => false, 'message' => array('name' => sprintf($this->lang->error->repeat, $this->lang->pipeline->name, $externalApp->name)))); @@ -231,7 +233,9 @@ class instance extends control if($_POST) { - $instance = form::data($this->config->instance->form->edit)->get(); + $instance = form::data($this->config->instance->form->edit) + ->add('editedBy', isset($this->app->user->account) ? $this->app->user->account : '') + ->get(); $this->pipeline->update($externalID, $instance); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); From 99f41b20d40ef6dedb0a0e347a0d8485986b4bb6 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 22 Apr 2024 16:22:07 +0800 Subject: [PATCH 046/141] * Modify parameter type. --- module/build/model.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/module/build/model.php b/module/build/model.php index 519caa421e..5ae41ea987 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -391,13 +391,13 @@ class buildModel extends model * 获取关联的发布。 * Get releated release. * - * @param array|int $productIdList - * @param string $buildIdList - * @param array $shadows + * @param array $productIdList + * @param string $buildIdList + * @param array $shadows * @access public - * @return void + * @return array */ - public function getRelatedReleases(array|int $productIdList, string $buildIdList = '', array|bool $shadows = false): array + public function getRelatedReleases(array $productIdList, string $buildIdList = '', array|bool $shadows = false): array { $releases = $this->dao->select('t1.id,t1.shadow,t1.product,t1.branch,t1.build,t1.name,t1.date,t3.name as branchName,t4.type as productType')->from(TABLE_RELEASE)->alias('t1') ->leftJoin(TABLE_BUILD)->alias('t2')->on('FIND_IN_SET(t2.id, t1.build)') From 9fce264d84abdec3cb4de89932720771b3ccbca7 Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:24:39 +0800 Subject: [PATCH 047/141] * Move user account setting of repo. --- module/mr/ui/linktask.html.php | 1 + module/repo/config/dtable.php | 2 +- module/repo/ui/linktask.html.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/module/mr/ui/linktask.html.php b/module/mr/ui/linktask.html.php index c013175ad3..eefd2514f5 100644 --- a/module/mr/ui/linktask.html.php +++ b/module/mr/ui/linktask.html.php @@ -46,6 +46,7 @@ div $lang->repo->unlinkedTasks . "({$pager->recTotal})" ) ); +$config->repo->taskDtable->fieldList['assignedTo']['currentUser'] = $app->user->account; $allTasks = initTableData($allTasks, $config->repo->taskDtable->fieldList); $data = array_values($allTasks); dtable diff --git a/module/repo/config/dtable.php b/module/repo/config/dtable.php index a7276dbcb2..380186e290 100644 --- a/module/repo/config/dtable.php +++ b/module/repo/config/dtable.php @@ -213,7 +213,7 @@ $config->repo->taskDtable->fieldList['assignedTo']['type'] = 'user'; $config->repo->taskDtable->fieldList['assignedTo']['sortType'] = true; $config->repo->taskDtable->fieldList['assignedTo']['show'] = true; $config->repo->taskDtable->fieldList['assignedTo']['group'] = 3; -$config->repo->taskDtable->fieldList['assignedTo']['currentUser'] = $app->user->account; +$config->repo->taskDtable->fieldList['assignedTo']['currentUser'] = ''; $config->repo->taskDtable->fieldList['assignedTo']['title'] = $lang->task->assignedTo; $config->repo->taskDtable->fieldList['assignedTo']['assignLink'] = array('module' => 'task', 'method' => 'assignTo', 'params' => 'executionID={execution}&taskID={id}'); diff --git a/module/repo/ui/linktask.html.php b/module/repo/ui/linktask.html.php index 6edb8a0837..3dcede34dc 100644 --- a/module/repo/ui/linktask.html.php +++ b/module/repo/ui/linktask.html.php @@ -44,6 +44,7 @@ div $lang->repo->unlinkedTasks . "({$pager->recTotal})" ) ); +$config->repo->taskDtable->fieldList['assignedTo']['currentUser'] = $app->user->account; $allTasks = initTableData($allTasks, $config->repo->taskDtable->fieldList); $data = array_values($allTasks); dtable From 741b4c8a79a8ccc2150c588503baac2c2381010a Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 22 Apr 2024 16:32:14 +0800 Subject: [PATCH 048/141] * Move user account setting from config to page. --- module/account/config/form.php | 3 --- module/account/control.php | 8 ++++++-- module/artifactrepo/config/form.php | 4 ---- module/artifactrepo/control.php | 8 ++++++-- module/gitfox/config/form.php | 3 --- module/gitfox/control.php | 8 ++++++-- module/mr/config/dtable.php | 2 +- module/mr/config/form.php | 3 --- module/mr/control.php | 2 ++ module/mr/ui/link.html.php | 4 +++- module/sonarqube/config/form.php | 3 --- module/sonarqube/control.php | 8 ++++++-- module/zahost/config/form.php | 4 +--- module/zahost/control.php | 9 +++++++-- 14 files changed, 38 insertions(+), 31 deletions(-) diff --git a/module/account/config/form.php b/module/account/config/form.php index ade8db8d40..fc30a45e93 100644 --- a/module/account/config/form.php +++ b/module/account/config/form.php @@ -1,5 +1,4 @@ account->form = new stdclass(); $config->account->form->create = array(); $config->account->form->create['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); @@ -12,7 +11,6 @@ $config->account->form->create['mobile'] = array('type' => 'string', 'requi $config->account->form->create['type'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); $config->account->form->create['status'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); $config->account->form->create['extra'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); -$config->account->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->account->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->account->form->edit = array(); @@ -26,5 +24,4 @@ $config->account->form->edit['mobile'] = array('type' => 'string', 'required $config->account->form->edit['type'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); $config->account->form->edit['status'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); $config->account->form->edit['extra'] = array('type' => 'string', 'required' => false, 'default' => '', 'filter' => 'trim'); -$config->account->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->account->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); diff --git a/module/account/control.php b/module/account/control.php index 38454784b9..6c1c7a6e5e 100644 --- a/module/account/control.php +++ b/module/account/control.php @@ -63,7 +63,9 @@ class account extends control { if($_POST) { - $account = form::data($this->config->account->form->create)->get(); + $account = form::data($this->config->account->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->account->create($account); @@ -90,7 +92,9 @@ class account extends control { if($_POST) { - $account = form::data($this->config->account->form->edit)->get(); + $account = form::data($this->config->account->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->account->update($accountID, $account); diff --git a/module/artifactrepo/config/form.php b/module/artifactrepo/config/form.php index 2717a607d1..864b8521a2 100644 --- a/module/artifactrepo/config/form.php +++ b/module/artifactrepo/config/form.php @@ -1,7 +1,6 @@ artifactrepo->form = new stdclass(); $config->artifactrepo->form->create = array(); $config->artifactrepo->form->create['name'] = array('required' => true, 'type' => 'string'); @@ -11,12 +10,9 @@ $config->artifactrepo->form->create['type'] = array('required' => true, $config->artifactrepo->form->create['status'] = array('required' => true, 'type' => 'string'); $config->artifactrepo->form->create['products'] = array('required' => false, 'type' => 'array', 'default' => array(), 'filter' => 'join'); $config->artifactrepo->form->create['format'] = array('required' => false, 'type' => 'string', 'default' => ''); -$config->artifactrepo->form->create['createdBy'] = array('required' => false, 'type' => 'string', 'default' => $app->user->account); -$config->artifactrepo->form->create['editedBy'] = array('required' => false, 'type' => 'string', 'default' => $app->user->account); $config->artifactrepo->form->create['createdDate'] = array('required' => false, 'type' => 'string', 'default' => helper::now()); $config->artifactrepo->form->edit = array(); $config->artifactrepo->form->edit['name'] = array('required' => true, 'type' => 'string'); $config->artifactrepo->form->edit['products'] = array('required' => false, 'type' => 'array', 'default' => array(), 'filter' => 'join'); -$config->artifactrepo->form->edit['editedBy'] = array('required' => false, 'type' => 'string', 'default' => $app->user->account); $config->artifactrepo->form->edit['editedDate'] = array('required' => false, 'type' => 'string', 'default' => helper::now()); diff --git a/module/artifactrepo/control.php b/module/artifactrepo/control.php index 2f26a03487..7b2d2aa32d 100644 --- a/module/artifactrepo/control.php +++ b/module/artifactrepo/control.php @@ -56,7 +56,9 @@ class artifactrepo extends control { if($_POST) { - $repo = form::data($this->config->artifactrepo->form->create)->get(); + $repo = form::data($this->config->artifactrepo->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); if($repo->products) $repo->products = ',' . $repo->products . ','; $repoID = $this->artifactrepo->create($repo); @@ -85,7 +87,9 @@ class artifactrepo extends control { if($_POST) { - $repo = form::data($this->config->artifactrepo->form->edit)->get(); + $repo = form::data($this->config->artifactrepo->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); if($repo->products) $repo->products = ',' . $repo->products . ','; $this->artifactrepo->update($repo, $artifactRepoID); diff --git a/module/gitfox/config/form.php b/module/gitfox/config/form.php index 111cbd4f88..3509d2d3ba 100644 --- a/module/gitfox/config/form.php +++ b/module/gitfox/config/form.php @@ -1,5 +1,4 @@ gitfox->form = new stdclass(); $config->gitfox->form->create = array(); $config->gitfox->form->create['appType'] = array('type' => 'string', 'required' => true, 'default' => 'gitfox'); @@ -7,7 +6,6 @@ $config->gitfox->form->create['type'] = array('type' => 'string', 'requ $config->gitfox->form->create['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitfox->form->create['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitfox->form->create['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gitfox->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gitfox->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->gitfox->form->create['private'] = array('type' => 'string', 'required' => false, 'default' => uniqid()); @@ -15,5 +13,4 @@ $config->gitfox->form->edit = array(); $config->gitfox->form->edit['name'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitfox->form->edit['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->gitfox->form->edit['token'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->gitfox->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->gitfox->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); diff --git a/module/gitfox/control.php b/module/gitfox/control.php index f0e4efc6da..3178633db7 100644 --- a/module/gitfox/control.php +++ b/module/gitfox/control.php @@ -22,7 +22,9 @@ class gitfox extends control { if($_POST) { - $gitfox = form::data($this->config->gitfox->form->create)->get(); + $gitfox = form::data($this->config->gitfox->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); $this->checkToken($gitfox); $gitfoxID = $this->loadModel('pipeline')->create($gitfox); @@ -51,7 +53,9 @@ class gitfox extends control if($_POST) { - $gitfox = form::data($this->config->gitfox->form->edit)->get(); + $gitfox = form::data($this->config->gitfox->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); $this->checkToken($gitfox, $gitfoxID); $this->loadModel('pipeline')->update($gitfoxID, $gitfox); $gitFox = $this->gitfox->fetchByID($gitfoxID); diff --git a/module/mr/config/dtable.php b/module/mr/config/dtable.php index be8c4a3d93..3847b75aa2 100644 --- a/module/mr/config/dtable.php +++ b/module/mr/config/dtable.php @@ -73,7 +73,7 @@ $config->mr->taskDtable->fieldList['pri']['show'] = true; $config->mr->taskDtable->fieldList['assignedTo']['type'] = 'desc'; $config->mr->taskDtable->fieldList['assignedTo']['title'] = $lang->task->assignedTo; -$config->mr->taskDtable->fieldList['assignedTo']['currentUser'] = $app->user->account; +$config->mr->taskDtable->fieldList['assignedTo']['currentUser'] = ''; $config->mr->taskDtable->fieldList['assignedTo']['sortType'] = true; $config->mr->taskDtable->fieldList['assignedTo']['show'] = true; diff --git a/module/mr/config/form.php b/module/mr/config/form.php index 78c38476b0..46eb0f0870 100644 --- a/module/mr/config/form.php +++ b/module/mr/config/form.php @@ -1,5 +1,4 @@ mr->form = new stdclass(); $config->mr->form->create = array(); $config->mr->form->create['hostID'] = array('type' => 'int', 'required' => true); @@ -16,7 +15,6 @@ $config->mr->form->create['removeSourceBranch'] = array('type' => 'int', 'req $config->mr->form->create['squash'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->mr->form->create['jobID'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->mr->form->create['description'] = array('type' => 'string', 'required' => false, 'default' => ''); -$config->mr->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->mr->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->mr->form->edit = array(); @@ -29,5 +27,4 @@ $config->mr->form->edit['removeSourceBranch'] = array('type' => 'int', 'requi $config->mr->form->edit['squash'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->mr->form->edit['jobID'] = array('type' => 'int', 'required' => false, 'default' => 0); $config->mr->form->edit['description'] = array('type' => 'string', 'required' => false, 'default' => ''); -$config->mr->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->mr->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); diff --git a/module/mr/control.php b/module/mr/control.php index bdf9b7d9ef..69fda4bd63 100644 --- a/module/mr/control.php +++ b/module/mr/control.php @@ -189,6 +189,7 @@ class mr extends control { $MR = form::data($this->config->mr->form->create) ->setIF($this->post->needCI == 0, 'jobID', 0) + ->add('createdBy', $this->app->user->acount) ->get(); $result = $this->mr->create($MR); return $this->send($result); @@ -253,6 +254,7 @@ class mr extends control { $MR = form::data($this->config->mr->form->edit) ->setIF($this->post->needCI == 0, 'jobID', 0) + ->add('editedBy', $this->app->user->acount) ->get(); $result = $this->mr->update($MRID, $MR); return $this->send($result); diff --git a/module/mr/ui/link.html.php b/module/mr/ui/link.html.php index 7a324f2d38..5aaed14798 100644 --- a/module/mr/ui/link.html.php +++ b/module/mr/ui/link.html.php @@ -59,7 +59,9 @@ $bugCols['title']['link'] = array('module' => 'bug', 'method' => 'view', $bugs = initTableData($bugs, $bugCols); $taskCols = $config->mr->taskDtable->fieldList; -$taskCols['actions'] = $actionMenu; +$taskCols['assignedTo']['currentUser'] = $app->user->account; + +$taskCols['actions'] = $actionMenu; $taskCols['actions']['list']['unlink']['data-confirm'] = $lang->mr->confirmUnlinkTask; $taskCols['actions']['list']['unlink']['url'] = $this->createLink('mr', 'unlink', "MRID=$MR->id&productID=$product->id&type=task&linkID={id}&confirm=yes"); diff --git a/module/sonarqube/config/form.php b/module/sonarqube/config/form.php index 72df3c8284..98b208cbe9 100644 --- a/module/sonarqube/config/form.php +++ b/module/sonarqube/config/form.php @@ -1,5 +1,4 @@ sonarqube->form = new stdclass(); $config->sonarqube->form->create = array(); $config->sonarqube->form->create['appType'] = array('type' => 'string', 'required' => true, 'default' => 'sonarqube'); @@ -8,7 +7,6 @@ $config->sonarqube->form->create['name'] = array('type' => 'string', 'req $config->sonarqube->form->create['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->sonarqube->form->create['account'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->sonarqube->form->create['password'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->sonarqube->form->create['createdBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->sonarqube->form->create['createdDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->sonarqube->form->create['private'] = array('type' => 'string', 'required' => false, 'default' => uniqid()); @@ -17,7 +15,6 @@ $config->sonarqube->form->edit['name'] = array('type' => 'string', 'requir $config->sonarqube->form->edit['url'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->sonarqube->form->edit['account'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->sonarqube->form->edit['password'] = array('type' => 'string', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->sonarqube->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account); $config->sonarqube->form->edit['editedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now()); $config->sonarqube->form->createProject['projectName'] = array('type' => 'string', 'required' => true); diff --git a/module/sonarqube/control.php b/module/sonarqube/control.php index 96077f6779..6c0a45864d 100644 --- a/module/sonarqube/control.php +++ b/module/sonarqube/control.php @@ -137,7 +137,9 @@ class sonarqube extends control { if($_POST) { - $sonarqube = form::data($this->config->sonarqube->form->create)->get(); + $sonarqube = form::data($this->config->sonarqube->form->create) + ->add('createdBy', $this->app->user->acount) + ->get(); $this->checkToken($sonarqube, 0); $sonarqubeID = $this->loadModel('pipeline')->create($sonarqube); @@ -199,7 +201,9 @@ class sonarqube extends control $oldSonarQube->password = $this->post->password; $this->checkToken($oldSonarQube, $sonarqubeID); - $sonarqube = form::data($this->config->sonarqube->form->edit)->get(); + $sonarqube = form::data($this->config->sonarqube->form->edit) + ->add('editedBy', $this->app->user->acount) + ->get(); $sonarqube->token = $oldSonarQube->token; $this->pipeline->update($sonarqubeID, $sonarqube); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); diff --git a/module/zahost/config/form.php b/module/zahost/config/form.php index 6b119439da..bbd2805cd3 100644 --- a/module/zahost/config/form.php +++ b/module/zahost/config/form.php @@ -1,6 +1,6 @@ zahost->form = new stdclass(); @@ -14,7 +14,6 @@ $config->zahost->form->create['memory'] = array('required' => true, 'type' $config->zahost->form->create['diskSize'] = array('required' => true, 'type' => 'float', 'default' => 0); $config->zahost->form->create['type'] = array('required' => false, 'type' => 'string', 'default' => 'zahost'); $config->zahost->form->create['status'] = array('required' => false, 'type' => 'string', 'default' => 'wait'); -$config->zahost->form->create['createdBy'] = array('required' => false, 'type' => 'string', 'default' => isset($app->user->account) ? $app->user->account : ''); $config->zahost->form->create['createdDate'] = array('required' => false, 'type' => 'date', 'default' => helper::now()); $config->zahost->form->create['desc'] = array('required' => false, 'type' => 'string', 'default' => '', 'control' => 'editor'); $config->zahost->form->create['zap'] = array('required' => false, 'type' => 'string', 'default' => $config->zahost->defaultPort); @@ -27,6 +26,5 @@ $config->zahost->form->edit['extranet'] = array('required' => true, 'type' => $config->zahost->form->edit['cpuCores'] = array('required' => true, 'type' => 'int', 'default' => 0); $config->zahost->form->edit['memory'] = array('required' => true, 'type' => 'float', 'default' => 0); $config->zahost->form->edit['diskSize'] = array('required' => true, 'type' => 'float', 'default' => 0); -$config->zahost->form->edit['editedBy'] = array('required' => false, 'type' => 'string', 'default' => isset($app->user->account) ? $app->user->account : ''); $config->zahost->form->edit['editedDate'] = array('required' => false, 'type' => 'date', 'default' => helper::now()); $config->zahost->form->edit['desc'] = array('required' => false, 'type' => 'string', 'default' => '', 'control' => 'editor'); diff --git a/module/zahost/control.php b/module/zahost/control.php index f72b3a46be..aac5430617 100644 --- a/module/zahost/control.php +++ b/module/zahost/control.php @@ -97,7 +97,9 @@ class zahost extends control { if($_POST) { - $hostInfo = form::data($this->config->zahost->form->create)->get(); + $hostInfo = form::data($this->config->zahost->form->create) + ->add('createdBy', isset($this->app->user->account) ? $this->app->user->account : '') + ->get(); $hostInfo->secret = md5($hostInfo->name . time()); $hostID = $this->zahost->create($hostInfo); @@ -124,7 +126,10 @@ class zahost extends control { if($_POST) { - $hostInfo = form::data($this->config->zahost->form->edit)->add('id', $hostID)->get(); + $hostInfo = form::data($this->config->zahost->form->edit) + ->add('id', $hostID) + ->add('editedBy', isset($this->app->user->account) ? $this->app->user->account : '') + ->get(); $changes = $this->zahost->update($hostInfo); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); From c21fe4423c4bfd3aa1863fa021d57f10f7584820 Mon Sep 17 00:00:00 2001 From: sunguangming Date: Mon, 22 Apr 2024 16:33:47 +0800 Subject: [PATCH 049/141] * Add upgrade sql. --- db/update20.0.beta2.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/update20.0.beta2.sql b/db/update20.0.beta2.sql index 8ab811ff39..af8da719a0 100644 --- a/db/update20.0.beta2.sql +++ b/db/update20.0.beta2.sql @@ -19,3 +19,5 @@ UPDATE `zt_chart` SET `sql` = 'SELECT YEAR(t1.date) AS `year`,IFNULL(t2.realname UPDATE `zt_chart` SET `sql` = 'SELECT t1.id, t1.NAME AS project, IFNULL( t2.NAME, \'/\') AS program, IFNULL( t3.story, 0 ) AS story, IFNULL( t3.estimate, 0 ) AS estimate, IFNULL( t4.execution, 0 ) AS execution, IFNULL( t5.workhour, 0 ) AS workhour FROM zt_project AS t1 LEFT JOIN zt_project AS t2 ON FIND_IN_SET( t2.id, t1.path ) AND t2.deleted = \'0\' AND t2.type = \'program\' AND t2.grade = 1 LEFT JOIN( SELECT t1.parent AS project, COUNT( 1 ) AS story, ROUND( SUM( t1.estimate ), 1 ) AS estimate FROM ( SELECT DISTINCT t1.parent, t3.id, t3.estimate FROM zt_project AS t1 LEFT JOIN zt_projectstory AS t2 ON t1.id = t2.project LEFT JOIN zt_story AS t3 ON t2.story = t3.id AND t3.deleted = \'0\' AND t3.stage NOT IN ( \'verified\', \'released\', \'closed\' ) WHERE t1.deleted = \'0\' AND t1.type IN ( \'sprint\', \'stage\', \'kanban\' ) AND t3.id IS NOT NULL ) AS t1 GROUP BY project ) AS t3 ON t1.id = t3.project LEFT JOIN ( SELECT parent AS project, COUNT( 1 ) AS execution FROM zt_project WHERE deleted = \'0\' AND type IN ( \'sprint\', \'stage\', \'kanban\' ) AND multiple = \'1\' AND STATUS NOT IN ( \'done\', \'closed\' ) GROUP BY project ) AS t4 ON t1.id = t4.project LEFT JOIN ( SELECT t1.parent AS project, ROUND( SUM( t2.LEFT ), 1 ) AS workhour FROM zt_project AS t1 LEFT JOIN zt_task AS t2 ON t1.id = t2.execution AND t2.deleted = \'0\' AND t2.parent < 1 WHERE t1.deleted = \'0\' AND t1.type IN ( \'sprint\', \'stage\', \'kanban\' ) AND t1.STATUS NOT IN ( \'done\', \'closed\' ) AND t2.id IS NOT NULL GROUP BY project ) AS t5 ON t1.id = t5.project WHERE t1.deleted = \'0\' AND t1.type = \'project\' AND t1.STATUS = \'doing\'' WHERE `name` = '年度进行中项目-项目剩余工作量透视表'; UPDATE `zt_grouppriv` SET `method` = 'recordWorkhour' WHERE `module` = 'task' AND `method` = 'recordEstimate'; +UPDATE `zt_grouppriv` SET `method` = 'editEffort' WHERE `module` = 'task' AND `method` = 'editEstimate'; +UPDATE `zt_grouppriv` SET `method` = 'deleteWorkhour' WHERE `module` = 'task' AND `method` = 'deleteEstimate'; From 1dc857b2b7684b8051e858ca3d61d6ff163c80e8 Mon Sep 17 00:00:00 2001 From: sunhao Date: Mon, 22 Apr 2024 16:32:14 +0800 Subject: [PATCH 050/141] * index: bug #47916, fix lang var conflict with xuanxuan extension. --- module/index/js/index.ui.js | 10 +++++----- module/index/ui/index.html.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/module/index/js/index.ui.js b/module/index/js/index.ui.js index b067671e37..bf7664d88e 100644 --- a/module/index/js/index.ui.js +++ b/module/index/js/index.ui.js @@ -667,8 +667,8 @@ function initAppsMenu(items) icon: 'icon-search', methodName: 'index', moduleName: 'search', - text: lang.search, - title: ' ' + lang.search, + text: langData.search, + title: ' ' + langData.search, url: '/index.php?m=search&f=index', vars: '' }; @@ -766,11 +766,11 @@ $(document).on('click', '.open-in-app,.show-in-app', function(e) if(!code) return; const app = apps.openedMap[code]; - const items = [{text: lang.open, disabled: app && getLastAppCode() === code, onClick: function(){showApp(code)}}]; + const items = [{text: langData.open, disabled: app && getLastAppCode() === code, onClick: function(){showApp(code)}}]; if(app) { - items.push({text: lang.reload, onClick: function(){reloadApp(code)}}); - if(code !== 'my') items.push({text: lang.close, onClick: function(){closeApp(code)}}); + items.push({text: langData.reload, onClick: function(){reloadApp(code)}}); + if(code !== 'my') items.push({text: langData.close, onClick: function(){closeApp(code)}}); } zui.ContextMenu.show({hideOthers: true, element: $btn[0], placement: $btn.closest('#appTabs').length ? 'top-start' : 'right-start', items: items, event: event, onClickItem: function(info){info.event.preventDefault();}}); diff --git a/module/index/ui/index.html.php b/module/index/ui/index.html.php index f579b421e3..15ecc7c0a9 100644 --- a/module/index/ui/index.html.php +++ b/module/index/ui/index.html.php @@ -28,7 +28,7 @@ jsVar('appsItems', $appsItems); jsVar('defaultOpen', !empty($open) ? $open : ''); jsVar('manualText', $lang->manual); jsVar('manualUrl', ((!empty($config->isINT)) ? $config->manualUrl['int'] : $config->manualUrl['home']) . '&theme=' . $_COOKIE['theme']); -jsVar('lang', array_merge(array('search' => $lang->index->search, 'searchAB' => $lang->searchAB), (array)$lang->index->dock)); +jsVar('langData', array_merge(array('search' => $lang->index->search, 'searchAB' => $lang->searchAB), (array)$lang->index->dock)); jsVar('browserMessage', $browserMessage); jsVar('pollTime', (!empty($config->message->browser->turnon) && isset($config->message->browser->pollTime)) ? $config->message->browser->pollTime : 600); jsVar('turnon', empty($config->message->browser->turnon) ? 0 : 1); From 1d882aed738fa49923d0607b18b8c1a29cf5f1de Mon Sep 17 00:00:00 2001 From: sunhao Date: Mon, 22 Apr 2024 16:38:09 +0800 Subject: [PATCH 051/141] * xuan: fix js error on creating xuanxuan instance. --- .../index/ext/ui/index.xuanxuan.html.hook.php | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php b/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php index 42d48b8470..86b406196a 100644 --- a/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php +++ b/extension/xuanxuan/extension/xuan/index/ext/ui/index.xuanxuan.html.hook.php @@ -69,8 +69,6 @@ if(isset($config->xuanxuan->turnon) && $config->xuanxuan->turnon && $xxdStatus = #xx-embed-container .xx-embed-body {min-height: initial!important;} getWebRoot() . 'data/xuanxuan/sdk/sdk.min.js'); ?> - -getClientLang()); ?> From ed481240806bb3810f5700a8a1391e66e1b49013 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 22 Apr 2024 16:38:30 +0800 Subject: [PATCH 052/141] + Fix bug #48194, show expect in mindmap. --- module/testcase/zen.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/module/testcase/zen.php b/module/testcase/zen.php index b6210d447e..b67b595ca8 100755 --- a/module/testcase/zen.php +++ b/module/testcase/zen.php @@ -2104,6 +2104,19 @@ class testcaseZen extends testcase foreach($reverseSteps as $step) { if(empty($step->id)) continue; + + if($step->type != 'group') + { + $descItem = array(); + $descItem['id'] = 'desc_' . $step->id; + $descItem['text'] = $step->expect; + $descItem['type'] = 'node'; + $descItem['parent'] = $step->id; + $descItem['subSide'] = 'right'; + + $parentSteps[$step->id][] = $descItem; + } + $stepItem = array(); $stepItem['id'] = $step->id; $stepItem['text'] = $step->step; From c99ec59a56b468ebf8ff31a6e980afcae5481273 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 16:38:39 +0800 Subject: [PATCH 053/141] * Fix bug #48111. --- module/execution/ui/build.html.php | 6 +++++- module/project/ui/build.html.php | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/module/execution/ui/build.html.php b/module/execution/ui/build.html.php index a1f4a0599e..daa3d34f87 100644 --- a/module/execution/ui/build.html.php +++ b/module/execution/ui/build.html.php @@ -44,7 +44,11 @@ jsVar('filePathTip', $lang->build->filePath); jsVar('confirmDelete', $lang->build->confirmDelete); $fieldList = $config->build->dtable->fieldList; -if($execution->type == 'kanban') unset($fieldList['actions']['list']['createTest']['data-app']); +if($execution->type == 'kanban') +{ + unset($fieldList['actions']['list']['createTest']['data-app']); + $fieldList['actions']['list']['viewBug']['url'] = $config->build->actionList['bugList']['url']; +} $builds = initTableData($builds, $fieldList, $this->build); dtable diff --git a/module/project/ui/build.html.php b/module/project/ui/build.html.php index 2f4d0e1893..2520b7a8bd 100644 --- a/module/project/ui/build.html.php +++ b/module/project/ui/build.html.php @@ -49,7 +49,11 @@ jsVar('integratedTip', $lang->build->integrated); jsVar('deletedTip', $lang->build->deleted); $fieldList = $config->build->dtable->fieldList; -if($project->model == 'kanban' && $this->app->rawModule == 'projectbuild') unset($fieldList['actions']['actionsMap']['createTest']['data-app']); +if($project->model == 'kanban' && $this->app->rawModule == 'projectbuild') +{ + unset($fieldList['actions']['list']['createTest']['data-app']); + $fieldList['actions']['list']['viewBug']['url'] = $config->build->actionList['projectBugList']['url']; +} $builds = initTableData($builds, $fieldList, $app->control->build); dtable From b1320108464b5037d41f10524984d467548905ee Mon Sep 17 00:00:00 2001 From: zhouxin Date: Mon, 22 Apr 2024 16:47:35 +0800 Subject: [PATCH 054/141] * Add missing feedback and user dataview. --- module/dataview/table/feedback.php | 18 ++++++++++++++++++ module/dataview/table/user.php | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 module/dataview/table/feedback.php create mode 100644 module/dataview/table/user.php diff --git a/module/dataview/table/feedback.php b/module/dataview/table/feedback.php new file mode 100644 index 0000000000..2bef823938 --- /dev/null +++ b/module/dataview/table/feedback.php @@ -0,0 +1,18 @@ +app->loadLang('feedback'); + +$schema = new stdclass(); + +$schema->primaryTable = 'feedback'; + +$schema->tables = array(); +$schema->tables['feedback'] = 'zt_feedback'; + +$schema->fields = array(); +$schema->fields['id'] = array('type' => 'number', 'name' => $this->lang->feedback->id); +$schema->fields['type'] = array('type' => 'option', 'name' => $this->lang->feedback->type, 'options' => $this->lang->feedback->typeList); +$schema->fields['status'] = array('type' => 'option', 'name' => $this->lang->feedback->status, 'options' => $this->lang->feedback->statusList); +$schema->fields['closedReason'] = array('type' => 'option', 'name' => $this->lang->feedback->closedReason, 'options' => $this->lang->feedback->closedReasonList); +$schema->fields['solution'] = array('type' => 'option', 'name' => $this->lang->feedback->solution, 'options' => $this->lang->feedback->solutionList); +$schema->fields['public'] = array('type' => 'option', 'name' => $this->lang->feedback->public, 'options' => $this->lang->feedback->publicList); + diff --git a/module/dataview/table/user.php b/module/dataview/table/user.php new file mode 100644 index 0000000000..c1bd324f4a --- /dev/null +++ b/module/dataview/table/user.php @@ -0,0 +1,18 @@ +app->loadLang('user'); +$this->app->loadLang('dept'); + +$schema = new stdclass(); + +$schema->primaryTable = 'user'; + +$schema->tables = array(); +$schema->tables['user'] = 'zt_user'; +$schema->tables['dept'] = 'zt_dept'; + +$schema->joins = array(); +$schema->joins['dept'] = 'dept.id = user.dept'; + +$schema->fields = array(); +$schema->fields['id'] = array('type' => 'number', 'name' => $this->lang->user->id); +$schema->fields['dept'] = array('type' => 'object', 'name' => $this->lang->user->dept, 'object' => 'dept', 'show' => 'dept.name'); From 1b432ccbd7c7912cdf50a3fbe3d4efacbbfa6318 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 22 Apr 2024 16:51:23 +0800 Subject: [PATCH 055/141] * Fix bug #48202. --- extension/lite/project/ext/ui/execution.html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extension/lite/project/ext/ui/execution.html.php b/extension/lite/project/ext/ui/execution.html.php index a876e2c4fb..b9d7066935 100644 --- a/extension/lite/project/ext/ui/execution.html.php +++ b/extension/lite/project/ext/ui/execution.html.php @@ -37,7 +37,7 @@ $fnGetKanbanTeams = function($kanbanID) use ($memberGroup, $users, $usersAvatar) $teamElements[] = div ( set::title(zget($users, $member->account)), - userAvatar(set::avatar(zget($usersAvatar, $member->account)), set::account($member->account), set::realname(zget($member, 'realname', ''))), + avatar(set::src(zget($usersAvatar, $member->account)), set::text(zget($member, 'realname', '')), set::size('sm'), set::className('ml-1')), ); } if(count($teams) > 4) $teamElements[] = span('… '); @@ -47,7 +47,7 @@ $fnGetKanbanTeams = function($kanbanID) use ($memberGroup, $users, $usersAvatar) $teamElements[] = div ( set::title(zget($users, $lastMember->account)), - userAvatar(set::avatar(zget($usersAvatar, $lastMember->account)), set::account($lastMember->account), set::realname(zget($lastMember, 'realname', '')), set::style(array('width' => '24px', 'height' => '24px'))), + avatar(set::src(zget($usersAvatar, $lastMember->account)), set::text(zget($lastMember, 'realname', '')), set::size('sm')), ); } return $teamElements; From d744b78bc9fba05b1e847bd2be85f3b4bffc584b Mon Sep 17 00:00:00 2001 From: qixinzhi Date: Mon, 22 Apr 2024 08:58:41 +0000 Subject: [PATCH 056/141] * Fix id continuous for zt_metriclib. --- module/metric/control.php | 1 + module/metric/model.php | 12 ++++++++++++ module/metric/tao.php | 22 ++++++++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/module/metric/control.php b/module/metric/control.php index da7a163481..d46dedaf24 100755 --- a/module/metric/control.php +++ b/module/metric/control.php @@ -204,6 +204,7 @@ class metric extends control $metrics = $this->metric->getExecutableMetric(); foreach($metrics as $code) $this->metric->deduplication($code); + $this->metric->rebuildPrimaryKey(); // 恢复之前的调试状态 $this->config->debug = $originalDebug; diff --git a/module/metric/model.php b/module/metric/model.php index fe282b6bf1..a54f10e3bb 100755 --- a/module/metric/model.php +++ b/module/metric/model.php @@ -833,6 +833,18 @@ class metricModel extends model return dao::isError(); } + /** + * 重建主键顺序。 + * Rebuild primary key order. + * + * @access public + * @return void + */ + public function rebuildPrimaryKey() + { + $this->metricTao->rebuildIdColumn(); + } + /** * 根据度量项收集周期来清理过期的度量库数据。 * Clear outdated metric records by cycle. diff --git a/module/metric/tao.php b/module/metric/tao.php index 87c7d9a226..123818c5a9 100644 --- a/module/metric/tao.php +++ b/module/metric/tao.php @@ -474,10 +474,11 @@ class metricTao extends metricModel $intersect = array_intersect($fields, array('year', 'month', 'week', 'day')); foreach($fields as $key => $field) $fields[$key] = "`$field`"; if(empty($intersect)) $fields[] = 'left(date, 10)'; + $table = TABLE_METRICLIB; $sql = "INSERT INTO `metriclib_distinct` (id) "; $sql .= "SELECT MAX(id) AS id "; - $sql .= "FROM zt_metriclib WHERE metricCode = '{$code}' "; + $sql .= "FROM $table WHERE metricCode = '{$code}' "; $sql .= "GROUP BY " . implode(',', $fields); $this->dao->exec($sql); @@ -493,7 +494,8 @@ class metricTao extends metricModel */ protected function deleteDuplicationRecord(string $code): void { - $sql = "DELETE FROM zt_metriclib "; + $table = TABLE_METRICLIB; + $sql = "DELETE FROM $table "; $sql .= "WHERE id NOT IN (SELECT id FROM metriclib_distinct) "; $sql .= "AND metricCode = '{$code}'"; @@ -511,4 +513,20 @@ class metricTao extends metricModel { $this->dao->exec("DROP TABLE IF EXISTS `metriclib_distinct`"); } + + /** + * 重建id列顺序。 + * Rebuild id column order. + * + * @access protected + * @return void + */ + protected function rebuildIdColumn(): void + { + $table = TABLE_METRICLIB; + $tableRowCount = $this->dao->select('COUNT(id) as rowcount')->from(TABLE_METRICLIB)->fetch('rowcount'); + $autoIncrement = $tableRowCount + 1; + $this->dao->exec("SET @count = 0;UPDATE $table SET `id` = @count:= @count + 1;"); + $this->dao->exec("ALTER TABLE $table AUTO_INCREMENT = $autoIncrement"); + } } From de805c312a996849798fa5388153c0d0f0bdb16b Mon Sep 17 00:00:00 2001 From: zhouxin Date: Mon, 22 Apr 2024 17:00:02 +0800 Subject: [PATCH 057/141] * Fix bug #48171. --- module/dataview/lang/de.php | 2 +- module/dataview/lang/en.php | 2 +- module/dataview/lang/fr.php | 2 +- module/dataview/lang/zh-cn.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/module/dataview/lang/de.php b/module/dataview/lang/de.php index 79cfcf936f..6c28aa6018 100644 --- a/module/dataview/lang/de.php +++ b/module/dataview/lang/de.php @@ -100,9 +100,9 @@ $lang->dataview->objects['testrun'] = 'testrun'; $lang->dataview->objects['testcase'] = 'testcase'; $lang->dataview->objects['testresult'] = 'result'; $lang->dataview->objects['casemodule'] = 'case module'; -$lang->dataview->objects['feedback'] = 'Feedback'; $lang->dataview->objects['action'] = 'Action'; $lang->dataview->objects['effort'] = 'Effort'; +if($this->config->edition != 'open') $lang->dataview->objects['feedback'] = 'Feedback'; $lang->dataview->tables = array(); $lang->dataview->tables['build'] = array('name' => 'Build', 'desc' => ''); diff --git a/module/dataview/lang/en.php b/module/dataview/lang/en.php index 79cfcf936f..6c28aa6018 100644 --- a/module/dataview/lang/en.php +++ b/module/dataview/lang/en.php @@ -100,9 +100,9 @@ $lang->dataview->objects['testrun'] = 'testrun'; $lang->dataview->objects['testcase'] = 'testcase'; $lang->dataview->objects['testresult'] = 'result'; $lang->dataview->objects['casemodule'] = 'case module'; -$lang->dataview->objects['feedback'] = 'Feedback'; $lang->dataview->objects['action'] = 'Action'; $lang->dataview->objects['effort'] = 'Effort'; +if($this->config->edition != 'open') $lang->dataview->objects['feedback'] = 'Feedback'; $lang->dataview->tables = array(); $lang->dataview->tables['build'] = array('name' => 'Build', 'desc' => ''); diff --git a/module/dataview/lang/fr.php b/module/dataview/lang/fr.php index 79cfcf936f..6c28aa6018 100644 --- a/module/dataview/lang/fr.php +++ b/module/dataview/lang/fr.php @@ -100,9 +100,9 @@ $lang->dataview->objects['testrun'] = 'testrun'; $lang->dataview->objects['testcase'] = 'testcase'; $lang->dataview->objects['testresult'] = 'result'; $lang->dataview->objects['casemodule'] = 'case module'; -$lang->dataview->objects['feedback'] = 'Feedback'; $lang->dataview->objects['action'] = 'Action'; $lang->dataview->objects['effort'] = 'Effort'; +if($this->config->edition != 'open') $lang->dataview->objects['feedback'] = 'Feedback'; $lang->dataview->tables = array(); $lang->dataview->tables['build'] = array('name' => 'Build', 'desc' => ''); diff --git a/module/dataview/lang/zh-cn.php b/module/dataview/lang/zh-cn.php index 8f819c490b..ca697ec1a9 100644 --- a/module/dataview/lang/zh-cn.php +++ b/module/dataview/lang/zh-cn.php @@ -100,9 +100,9 @@ $lang->dataview->objects['testrun'] = '测试执行'; $lang->dataview->objects['testcase'] = '测试用例'; $lang->dataview->objects['testresult'] = '执行结果'; $lang->dataview->objects['casemodule'] = '用例模块'; -$lang->dataview->objects['feedback'] = '反馈'; $lang->dataview->objects['action'] = '动态'; $lang->dataview->objects['effort'] = '日志'; +if($this->config->edition != 'open') $lang->dataview->objects['feedback'] = '反馈'; $lang->dataview->tables = array(); $lang->dataview->tables['build'] = array('name' => '版本数据', 'desc' => '包括版本名称、所属产品、所属项目、所属执行、创建人等'); From cf2150a78b9145b4f490bf07c327cdc82e2a56ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 22 Apr 2024 17:05:50 +0800 Subject: [PATCH 058/141] * Fix bug #48111. --- lib/zin/wg/backbtn/v1.php | 2 +- module/execution/tao.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zin/wg/backbtn/v1.php b/lib/zin/wg/backbtn/v1.php index e3fe5940db..77bfcb94bc 100644 --- a/lib/zin/wg/backbtn/v1.php +++ b/lib/zin/wg/backbtn/v1.php @@ -48,7 +48,7 @@ class backBtn extends btn 'bug' => 'bug-browse,project-bug,my-work,my-contribute,execution-bug,bug-view,qa-index,execution-task,product-track,execution-task,task-view,repo-view,story-change', 'testcase' => 'testcase-browse,project-testcase,my-work,my-contribute,execution-testcase,testtask-cases,testsuite-view,product-browse,testcase-view,qa-index,caselib-browse,product-track,story-change,my-index', 'testsuite' => 'testsuite-browse,testsuite-view,', - 'testtask' => 'testtask-browse,testtask-cases,qa-index,testcase-browse,my-index', + 'testtask' => 'testtask-browse,testtask-cases,qa-index,testcase-browse,execution-build,my-index', 'testreport' => 'testreport-browse,project-testreport,execution-testreport,execution-testtask', 'tree' => 'product-browse,project-browse,execution-task,bug-browse,projectstory-story,host-browse,execution-story,feedback-admin,testcase-browse,caselib-browse', 'doc' => 'doc-mySpace,doc-productSpace,doc-projectSpace,doc-teamSpace,doc-view,execution-doc', diff --git a/module/execution/tao.php b/module/execution/tao.php index 9e3683f2d1..3dbec2125f 100644 --- a/module/execution/tao.php +++ b/module/execution/tao.php @@ -278,7 +278,7 @@ class executionTao extends executionModel $this->lang->execution->menu = new stdclass(); $this->lang->execution->menu->kanban = array('link' => "{$this->lang->kanban->common}|execution|kanban|executionID=%s", 'subModule' => 'task'); $this->lang->execution->menu->CFD = array('link' => "{$this->lang->execution->CFD}|execution|cfd|executionID=%s"); - $this->lang->execution->menu->build = array('link' => "{$this->lang->build->common}|execution|build|executionID=%s"); + $this->lang->execution->menu->build = array('link' => "{$this->lang->build->common}|execution|build|executionID=%s", 'alias' => 'bug', 'subModule' => 'projectbuild,build,testcase,testtask,bug'); $this->lang->execution->menu->settings = array('link' => "{$this->lang->settings}|execution|view|executionID=%s", 'subModule' => 'personnel', 'alias' => 'edit,manageproducts,team,whitelist,addwhitelist,managemembers', 'class' => 'dropdown dropdown-hover'); $this->lang->execution->dividerMenu = ''; From 882627fb26eb9f10517ea8e784904e469e572b38 Mon Sep 17 00:00:00 2001 From: sunhao Date: Mon, 22 Apr 2024 17:06:37 +0800 Subject: [PATCH 059/141] * zin: bug #48180, close all modals after load new page content. --- www/js/zui3/zin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/js/zui3/zin.js b/www/js/zui3/zin.js index a0c97e2aaa..fe97144d80 100644 --- a/www/js/zui3/zin.js +++ b/www/js/zui3/zin.js @@ -139,6 +139,7 @@ timers.interval = []; timers.timeout = []; + zui.Modal.getAll().forEach(m => m.hide()); $('script.zin-page-js').replaceWith(data); } From 5807ac5195f508743050ce25e845a65a17cd0845 Mon Sep 17 00:00:00 2001 From: hufangzhou Date: Mon, 22 Apr 2024 17:08:42 +0800 Subject: [PATCH 060/141] * Fix bug #48185, limit the length of the document title. --- module/doc/ui/create.html.php | 1 + module/doc/ui/edit.html.php | 1 + 2 files changed, 2 insertions(+) diff --git a/module/doc/ui/create.html.php b/module/doc/ui/create.html.php index ac55f0be0a..f65371b2c8 100644 --- a/module/doc/ui/create.html.php +++ b/module/doc/ui/create.html.php @@ -88,6 +88,7 @@ else input ( set::name('title'), + set::maxlength(100), set::placeholder($lang->doc->titlePlaceholder) ) ), diff --git a/module/doc/ui/edit.html.php b/module/doc/ui/edit.html.php index bebee025bf..5dec9191ed 100644 --- a/module/doc/ui/edit.html.php +++ b/module/doc/ui/edit.html.php @@ -34,6 +34,7 @@ form ( set::name('title'), set::value($doc->title), + set::maxlength(100), set::placeholder($lang->doc->titlePlaceholder) ) ), From 69c386749dfcaa393c66873babde0f69f31241df Mon Sep 17 00:00:00 2001 From: sunhao Date: Mon, 22 Apr 2024 17:35:21 +0800 Subject: [PATCH 061/141] * zui: update zui3 lib. --- www/js/zui3/zui.zentao.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/js/zui3/zui.zentao.js b/www/js/zui3/zui.zentao.js index 0d53de03d7..b2a4b70c8a 100644 --- a/www/js/zui3/zui.zentao.js +++ b/www/js/zui3/zui.zentao.js @@ -1,3 +1,3 @@ var Ao=(w,tt,vt)=>{if(!tt.has(w))throw TypeError("Cannot "+vt)};var bt=(w,tt,vt)=>(Ao(w,tt,"read from private field"),vt?vt.call(w):tt.get(w)),$t=(w,tt,vt)=>{if(tt.has(w))throw TypeError("Cannot add the same private member more than once");tt instanceof WeakSet?tt.add(w):tt.set(w,vt)},It=(w,tt,vt,mi)=>(Ao(w,tt,"write to private field"),mi?mi.call(w,vt):tt.set(w,vt),vt);var Do=(w,tt,vt)=>(Ao(w,tt,"access private method"),vt);(function(w,tt){typeof exports=="object"&&typeof module<"u"?tt(exports):typeof define=="function"&&define.amd?define(["exports"],tt):(w=typeof globalThis<"u"?globalThis:w||self,tt(w.zui={}))})(this,function(w){var di,ui,Ls,Rs,Fs,zs,Os,Ws,fi,Vc,pi,Kc,ye,_e;"use strict";const tt="",vt="",mi="",Bf="",jf="",Uf="",Vf="",Kf="",Gf="",qf="",Yf="",Qf="",Gc="3.0.0-alpha.4",jt=document,Hs=window,Lo=jt.documentElement,be=jt.createElement.bind(jt),Ro=be("div"),gi=be("table"),qc=be("tbody"),Fo=be("tr"),{isArray:Bs,prototype:zo}=Array,{concat:Yc,filter:yi,indexOf:Oo,map:Wo,push:Qc,slice:Ho,some:_i,splice:Zc}=zo,Xc=/^#(?:[\w-]|\\.|[^\x00-\xa0])*$/,Jc=/^\.(?:[\w-]|\\.|[^\x00-\xa0])*$/,th=/<.+>/,eh=/^\w+$/;function bi(n,t){const e=sh(t);return!n||!e&&!ve(t)&&!nt(t)?[]:!e&&Jc.test(n)?t.getElementsByClassName(n.slice(1).replace(/\\/g,"")):!e&&eh.test(n)?t.getElementsByTagName(n):t.querySelectorAll(n)}class js{constructor(t,e){if(!t)return;if(vi(t))return t;let s=t;if(dt(t)){const i=e||jt;if(s=Xc.test(t)&&ve(i)?i.getElementById(t.slice(1).replace(/\\/g,"")):th.test(t)?Go(t):vi(i)?i.find(t):dt(i)?u(i).find(t):bi(t,i),!s)return}else if(we(t))return this.ready(t);(s.nodeType||s===Hs)&&(s=[s]),this.length=s.length;for(let i=0,r=this.length;i{for(;t.firstChild;)t.removeChild(t.firstChild)})};function Us(...n){const t=ih(n[0])?n.shift():!1,e=n.shift(),s=n.length;if(!e)return{};if(!s)return Us(t,u,e);for(let i=0;i{nt(r)&<(e,(o,a)=>{s?t?r.classList.add(a):r.classList.remove(a):r.classList.toggle(a)})})},M.addClass=function(n){return this.toggleClass(n,!0)},M.removeAttr=function(n){const t=Vs(n);return this.each((e,s)=>{nt(s)&<(t,(i,r)=>{s.removeAttribute(r)})})};function oh(n,t){if(n){if(dt(n)){if(arguments.length<2){if(!this[0]||!nt(this[0]))return;const e=this[0].getAttribute(n);return os(e)?void 0:e}return wt(t)?this:os(t)?this.removeAttr(n):this.each((e,s)=>{nt(s)&&s.setAttribute(n,t)})}for(const e in n)this.attr(e,n[e]);return this}}M.attr=oh,M.removeClass=function(n){return arguments.length?this.toggleClass(n,!1):this.attr("class","")},M.hasClass=function(n){return!!n&&_i.call(this,t=>nt(t)&&t.classList.contains(n))},M.get=function(n){return wt(n)?Ho.call(this):(n=Number(n),this[n<0?n+this.length:n])},M.eq=function(n){return u(this.get(n))},M.first=function(){return this.eq(0)},M.last=function(){return this.eq(-1)};function ah(n){return wt(n)?this.get().map(t=>nt(t)||nh(t)?t.textContent:"").join(""):this.each((t,e)=>{nt(e)&&(e.textContent=n)})}M.text=ah;function Ut(n,t,e){if(!nt(n))return;const s=Hs.getComputedStyle(n,null);return e?s.getPropertyValue(t)||void 0:s[t]||n.style[t]}function zt(n,t){return parseInt(Ut(n,t),10)||0}function jo(n,t){return zt(n,`border${t?"Left":"Top"}Width`)+zt(n,`padding${t?"Left":"Top"}`)+zt(n,`padding${t?"Right":"Bottom"}`)+zt(n,`border${t?"Right":"Bottom"}Width`)}const Ci={};function lh(n){if(Ci[n])return Ci[n];const t=be(n);jt.body.insertBefore(t,null);const e=Ut(t,"display");return jt.body.removeChild(t),Ci[n]=e!=="none"?e:"block"}function Uo(n){return Ut(n,"display")==="none"}function Vo(n,t){const e=n&&(n.matches||n.webkitMatchesSelector||n.msMatchesSelector);return!!e&&!!t&&e.call(n,t)}function Ks(n){return dt(n)?(t,e)=>Vo(e,n):we(n)?n:vi(n)?(t,e)=>n.is(e):n?(t,e)=>e===n:()=>!1}M.filter=function(n){const t=Ks(n);return u(yi.call(this,(e,s)=>t.call(e,s,e)))};function se(n,t){return t?n.filter(t):n}M.detach=function(n){return se(this,n).each((t,e)=>{e.parentNode&&e.parentNode.removeChild(e)}),this};const ch=/^\s*<(\w+)[^>]*>/,hh=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,Ko={"*":Ro,tr:qc,td:Fo,th:Fo,thead:gi,tbody:gi,tfoot:gi};function Go(n){if(!dt(n))return[];if(hh.test(n))return[be(RegExp.$1)];const t=ch.test(n)&&RegExp.$1,e=Ko[t]||Ko["*"];return e.innerHTML=n,u(e.childNodes).detach().get()}u.parseHTML=Go,M.has=function(n){const t=dt(n)?(e,s)=>bi(n,s).length:(e,s)=>s.contains(n);return this.filter(t)},M.not=function(n){const t=Ks(n);return this.filter((e,s)=>(!dt(n)||nt(s))&&!t.call(s,e,s))};function Vt(n,t,e,s){const i=[],r=we(t),o=s&&Ks(s);for(let a=0,l=n.length;at.selected&&!t.disabled&&!t.parentNode.disabled),"value"):n.value||""}function dh(n){return arguments.length?this.each((t,e)=>{const s=e.multiple&&e.options;if(s||ra.test(e.type)){const i=Bs(n)?Wo.call(n,String):os(n)?[]:[String(n)];s?lt(e.options,(r,o)=>{o.selected=i.indexOf(o.value)>=0},!0):e.checked=i.indexOf(e.value)>=0}else e.value=wt(n)||os(n)?"":n}):this[0]&&qo(this[0])}M.val=dh,M.is=function(n){const t=Ks(n);return _i.call(this,(e,s)=>t.call(e,s,e))},u.guid=1;function Ot(n){return n.length>1?yi.call(n,(t,e,s)=>Oo.call(s,t)===e):n}u.unique=Ot,M.add=function(n,t){return u(Ot(this.get().concat(u(n,t).get())))},M.children=function(n){return se(u(Ot(Vt(this,t=>t.children))),n)},M.parent=function(n){return se(u(Ot(Vt(this,"parentNode"))),n)},M.index=function(n){const t=n?u(n)[0]:this[0],e=n?this:u(t).parent().children();return Oo.call(e,t)},M.closest=function(n){const t=this.filter(n);if(t.length)return t;const e=this.parent();return e.length?e.closest(n):t},M.siblings=function(n){return se(u(Ot(Vt(this,t=>u(t).parent().children().not(t)))),n)},M.find=function(n){return u(Ot(Vt(this,t=>bi(n,t))))};const uh=/^\s*\s*$/g,fh=/^$|^module$|\/(java|ecma)script/i,ph=["type","src","nonce","noModule"];function mh(n,t){const e=u(n);e.filter("script").add(e.find("script")).each((s,i)=>{if(fh.test(i.type)&&Lo.contains(i)){const r=be("script");r.text=i.textContent.replace(uh,""),lt(ph,(o,a)=>{i[a]&&(r[a]=i[a])}),t.head.insertBefore(r,null),t.head.removeChild(r)}})}function gh(n,t,e,s,i){s?n.insertBefore(t,e?n.firstChild:null):n.nodeName==="HTML"?n.parentNode.replaceChild(t,n):n.parentNode.insertBefore(t,e?n:n.nextSibling),i&&mh(t,n.ownerDocument)}function ne(n,t,e,s,i,r,o,a){return lt(n,(l,c)=>{lt(u(c),(h,d)=>{lt(u(t),(p,f)=>{const g=e?d:f,y=e?f:d,_=e?h:p;gh(g,_?y.cloneNode(!0):y,s,i,!_)},a)},o)},r),t}M.after=function(){return ne(arguments,this,!1,!1,!1,!0,!0)},M.append=function(){return ne(arguments,this,!1,!1,!0)};function yh(n){if(!arguments.length)return this[0]&&this[0].innerHTML;if(wt(n))return this;const t=/]/.test(n);return this.each((e,s)=>{nt(s)&&(t?u(s).empty().append(n):s.innerHTML=n)})}M.html=yh,M.appendTo=function(n){return ne(arguments,this,!0,!1,!0)},M.wrapInner=function(n){return this.each((t,e)=>{const s=u(e),i=s.contents();i.length?i.wrapAll(n):s.append(n)})},M.before=function(){return ne(arguments,this,!1,!0)},M.wrapAll=function(n){let t=u(n),e=t[0];for(;e.children.length;)e=e.firstElementChild;return this.first().before(t),this.appendTo(e)},M.wrap=function(n){return this.each((t,e)=>{const s=u(n)[0];u(e).wrapAll(t?s.cloneNode(!0):s)})},M.insertAfter=function(n){return ne(arguments,this,!0,!1,!1,!1,!1,!0)},M.insertBefore=function(n){return ne(arguments,this,!0,!0)},M.prepend=function(){return ne(arguments,this,!1,!0,!0,!0,!0)},M.prependTo=function(n){return ne(arguments,this,!0,!0,!0,!1,!1,!0)},M.contents=function(){return u(Ot(Vt(this,n=>n.tagName==="IFRAME"?[n.contentDocument]:n.tagName==="TEMPLATE"?n.content.childNodes:n.childNodes)))},M.next=function(n,t,e){return se(u(Ot(Vt(this,"nextElementSibling",t,e))),n)},M.nextAll=function(n){return this.next(n,!0)},M.nextUntil=function(n,t){return this.next(t,!0,n)},M.parents=function(n,t){return se(u(Ot(Vt(this,"parentElement",!0,t))),n)},M.parentsUntil=function(n,t){return this.parents(t,n)},M.prev=function(n,t,e){return se(u(Ot(Vt(this,"previousElementSibling",t,e))),n)},M.prevAll=function(n){return this.prev(n,!0)},M.prevUntil=function(n,t){return this.prev(t,!0,n)},M.map=function(n){return u(Yc.apply([],Wo.call(this,(t,e)=>n.call(t,e,t))))},M.clone=function(){return this.map((n,t)=>t.cloneNode(!0))},M.offsetParent=function(){return this.map((n,t)=>{let e=t.offsetParent;for(;e&&Ut(e,"position")==="static";)e=e.offsetParent;return e||Lo})},M.slice=function(n,t){return u(Ho.call(this,n,t))};const _h=/-([a-z])/g;function ki(n){return n.replace(_h,(t,e)=>e.toUpperCase())}M.ready=function(n){const t=()=>setTimeout(n,0,u);return jt.readyState!=="loading"?t():jt.addEventListener("DOMContentLoaded",t),this},M.unwrap=function(){return this.parent().each((n,t)=>{if(t.tagName==="BODY")return;const e=u(t);e.replaceWith(e.children())}),this},M.offset=function(){const n=this[0];if(!n)return;const t=n.getBoundingClientRect();return{top:t.top+Hs.pageYOffset,left:t.left+Hs.pageXOffset}},M.position=function(){const n=this[0];if(!n)return;const t=Ut(n,"position")==="fixed",e=t?n.getBoundingClientRect():this.offset();if(!t){const s=n.ownerDocument;let i=n.offsetParent||s.documentElement;for(;(i===s.body||i===s.documentElement)&&Ut(i,"position")==="static";)i=i.parentNode;if(i!==n&&nt(i)){const r=u(i).offset();e.top-=r.top+zt(i,"borderTopWidth"),e.left-=r.left+zt(i,"borderLeftWidth")}}return{top:e.top-zt(n,"marginTop"),left:e.left-zt(n,"marginLeft")}};const Yo={class:"className",contenteditable:"contentEditable",for:"htmlFor",readonly:"readOnly",maxlength:"maxLength",tabindex:"tabIndex",colspan:"colSpan",rowspan:"rowSpan",usemap:"useMap"};M.prop=function(n,t){if(n){if(dt(n))return n=Yo[n]||n,arguments.length<2?this[0]&&this[0][n]:this.each((e,s)=>{s[n]=t});for(const e in n)this.prop(e,n[e]);return this}},M.removeProp=function(n){return this.each((t,e)=>{delete e[Yo[n]||n]})};const bh=/^--/;function xi(n){return bh.test(n)}const Si={},{style:vh}=Ro,wh=["webkit","moz","ms"];function Ch(n,t=xi(n)){if(t)return n;if(!Si[n]){const e=ki(n),s=`${e[0].toUpperCase()}${e.slice(1)}`,i=`${e} ${wh.join(`${s} `)}${s}`.split(" ");lt(i,(r,o)=>{if(o in vh)return Si[n]=o,!1})}return Si[n]}const kh={animationIterationCount:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0};function Qo(n,t,e=xi(n)){return!e&&!kh[n]&&Bo(t)?`${t}px`:t}function xh(n,t){if(dt(n)){const e=xi(n);return n=Ch(n,e),arguments.length<2?this[0]&&Ut(this[0],n,e):n?(t=Qo(n,t,e),this.each((s,i)=>{nt(i)&&(e?i.style.setProperty(n,t):i.style[n]=t)})):this}for(const e in n)this.css(e,n[e]);return this}M.css=xh;function Zo(n,t){try{return n(t)}catch{return t}}const Sh=/^\s+|\s+$/;function Xo(n,t){const e=n.dataset[t]||n.dataset[ki(t)];return Sh.test(e)?e:Zo(JSON.parse,e)}function $h(n,t,e){e=Zo(JSON.stringify,e),n.dataset[ki(t)]=e}function Th(n,t){if(!n){if(!this[0])return;const e={};for(const s in this[0].dataset)e[s]=Xo(this[0],s);return e}if(dt(n))return arguments.length<2?this[0]&&Xo(this[0],n):wt(t)?this:this.each((e,s)=>{$h(s,n,t)});for(const e in n)this.data(e,n[e]);return this}M.data=Th;function Jo(n,t){const e=n.documentElement;return Math.max(n.body[`scroll${t}`],e[`scroll${t}`],n.body[`offset${t}`],e[`offset${t}`],e[`client${t}`])}lt([!0,!1],(n,t)=>{lt(["Width","Height"],(e,s)=>{const i=`${t?"outer":"inner"}${s}`;M[i]=function(r){if(this[0])return Le(this[0])?t?this[0][`inner${s}`]:this[0].document.documentElement[`client${s}`]:ve(this[0])?Jo(this[0],s):this[0][`${t?"offset":"client"}${s}`]+(r&&t?zt(this[0],`margin${e?"Top":"Left"}`)+zt(this[0],`margin${e?"Bottom":"Right"}`):0)}})}),lt(["Width","Height"],(n,t)=>{const e=t.toLowerCase();M[e]=function(s){if(!this[0])return wt(s)?void 0:this;if(!arguments.length)return Le(this[0])?this[0].document.documentElement[`client${t}`]:ve(this[0])?Jo(this[0],t):this[0].getBoundingClientRect()[e]-jo(this[0],!n);const i=parseInt(s,10);return this.each((r,o)=>{if(!nt(o))return;const a=Ut(o,"boxSizing");o.style[e]=Qo(e,i+(a==="border-box"?jo(o,!n):0))})}});const ta="___cd";M.toggle=function(n){return this.each((t,e)=>{if(!nt(e))return;const s=Uo(e);(wt(n)?s:n)?(e.style.display=e[ta]||"",Uo(e)&&(e.style.display=lh(e.tagName))):s||(e[ta]=Ut(e,"display"),e.style.display="none")})},M.hide=function(){return this.toggle(!1)},M.show=function(){return this.toggle(!0)};const ea="___ce",$i=".",Ti={focus:"focusin",blur:"focusout"},sa={mouseenter:"mouseover",mouseleave:"mouseout"},Nh=/^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function Ni(n){return sa[n]||Ti[n]||n}function Mi(n){const t=n.split($i);return[t[0],t.slice(1).sort()]}M.trigger=function(n,t){if(dt(n)){const[s,i]=Mi(n),r=Ni(s);if(!r)return this;const o=Nh.test(r)?"MouseEvents":"HTMLEvents";n=jt.createEvent(o),n.initEvent(r,!0,!0),n.namespace=i.join($i),n.___ot=s}n.___td=t;const e=n.___ot in Ti;return this.each((s,i)=>{e&&we(i[n.___ot])&&(i[`___i${n.type}`]=!0,i[n.___ot](),i[`___i${n.type}`]=!1),i.dispatchEvent(n)})};function na(n){return n[ea]=n[ea]||{}}function Mh(n,t,e,s,i){const r=na(n);r[t]=r[t]||[],r[t].push([e,s,i]),n.addEventListener(t,i)}function ia(n,t){return!t||!_i.call(t,e=>n.indexOf(e)<0)}function Gs(n,t,e,s,i){const r=na(n);if(t)r[t]&&(r[t]=r[t].filter(([o,a,l])=>{if(i&&l.guid!==i.guid||!ia(o,e)||s&&s!==a)return!0;n.removeEventListener(t,l)}));else for(t in r)Gs(n,t,e,s,i)}M.off=function(n,t,e){if(wt(n))this.each((s,i)=>{!nt(i)&&!ve(i)&&!Le(i)||Gs(i)});else if(dt(n))we(t)&&(e=t,t=""),lt(Vs(n),(s,i)=>{const[r,o]=Mi(i),a=Ni(r);this.each((l,c)=>{!nt(c)&&!ve(c)&&!Le(c)||Gs(c,a,o,t,e)})});else for(const s in n)this.off(s,n[s]);return this},M.remove=function(n){return se(this,n).detach().off(),this},M.replaceWith=function(n){return this.before(n).remove()},M.replaceAll=function(n){return u(n).replaceWith(this),this};function Eh(n,t,e,s,i){if(!dt(n)){for(const r in n)this.on(r,t,e,n[r],i);return this}return dt(t)||(wt(t)||os(t)?t="":wt(e)?(e=t,t=""):(s=e,e=t,t="")),we(s)||(s=e,e=void 0),s?(lt(Vs(n),(r,o)=>{const[a,l]=Mi(o),c=Ni(a),h=a in sa,d=a in Ti;c&&this.each((p,f)=>{if(!nt(f)&&!ve(f)&&!Le(f))return;const g=function(y){if(y.target[`___i${y.type}`])return y.stopImmediatePropagation();if(y.namespace&&!ia(l,y.namespace.split($i))||!t&&(d&&(y.target!==f||y.___ot===c)||h&&y.relatedTarget&&f.contains(y.relatedTarget)))return;let _=f;if(t){let C=y.target;for(;!Vo(C,t);)if(C===f||(C=C.parentNode,!C))return;_=C}Object.defineProperty(y,"currentTarget",{configurable:!0,get(){return _}}),Object.defineProperty(y,"delegateTarget",{configurable:!0,get(){return f}}),Object.defineProperty(y,"data",{configurable:!0,get(){return e}});const b=s.call(_,y,y.___td);i&&Gs(f,c,l,t,g),b===!1&&(y.preventDefault(),y.stopPropagation())};g.guid=s.guid=s.guid||u.guid++,Mh(f,c,l,t,g)})}),this):this}M.on=Eh;function Ih(n,t,e,s){return this.on(n,t,e,s,!0)}M.one=Ih;const Ph=/\r?\n/g;function Ah(n,t){return`&${encodeURIComponent(n)}=${encodeURIComponent(t.replace(Ph,`\r -`))}`}const Dh=/file|reset|submit|button|image/i,ra=/radio|checkbox/i;M.serialize=function(){let n="";return this.each((t,e)=>{lt(e.elements||[e],(s,i)=>{if(i.disabled||!i.name||i.tagName==="FIELDSET"||Dh.test(i.type)||ra.test(i.type)&&!i.checked)return;const r=qo(i);if(!wt(r)){const o=Bs(r)?r:[r];lt(o,(a,l)=>{n+=Ah(i.name,l)})}})}),n.slice(1)},window.$=u;function oa(n,t){if(n==null)return[n,void 0];typeof t=="string"&&(t=t.split("."));const e=t.join(".");let s=n;const i=[s];for(;typeof s=="object"&&s!==null&&t.length;){let r=t.shift(),o;const a=r.indexOf("[");if(a>0&&a{const i=e[s]??"";n=n.replace(new RegExp(`\\{${s}\\}`,"g"),`${i}`)}),n}for(let e=0;e(n[n.B=1]="B",n[n.KB=1024]="KB",n[n.MB=1048576]="MB",n[n.GB=1073741824]="GB",n[n.TB=1099511627776]="TB",n))(Ei||{});function pt(n,t=2,e){return Number.isNaN(n)?"?KB":(e||(n<1024?e="B":n<1048576?e="KB":n<1073741824?e="MB":n<1099511627776?e="GB":e="TB"),(n/Ei[e]).toFixed(t)+e)}const Re=n=>{const t=/^[0-9]*(B|KB|MB|GB|TB)$/;n=n.toUpperCase();const e=n.match(t);if(!e)return 0;const s=e[1];return n=n.replace(s,""),Number.parseInt(n,10)*Ei[s]};let Ii=(document.documentElement.getAttribute("lang")||"zh_cn").toLowerCase().replace("-","_"),Kt;function Lh(){return Ii}function Rh(n){Ii=n.toLowerCase().replace("-","_")}function la(n,t){Kt||(Kt={}),typeof n=="string"&&(n={[n]:t??{}}),u.extend(!0,Kt,n)}function K(n,t,e,s,i,r){Array.isArray(n)?Kt&&n.unshift(Kt):n=Kt?[Kt,n]:[n],typeof e=="string"&&(r=i,i=s,s=e,e=void 0);const o=i||Ii;let a;for(const l of n){if(!l)continue;const c=l[o]||l.default;if(!c)continue;const h=r&&l===Kt?`${r}.${t}`:t;if(a=aa(c,h),a!==void 0)break}return a===void 0?s:e?U(a,...Array.isArray(e)?e:[e]):a}function Fh(n,t,e,s){return K(void 0,n,t,e,s)}K.addLang=la,K.getLang=Fh,K.getCode=Lh,K.setCode=Rh,K.map=Kt,la({zh_cn:{confirm:"确定",save:"保存",cancel:"取消",delete:"删除",reset:"重置",add:"添加"},zh_tw:{confirm:"確定",save:"儲存",cancel:"取消",delete:"刪除",reset:"重置",add:"添加"},en:{confirm:"Confirm",save:"Save",cancel:"Cancel",delete:"Delete",reset:"Reset",add:"Add"}});function ca(n,t,e){n instanceof Headers?n.set(t,e):Array.isArray(n)?n.push([t,e]):n[t]=e}function as(n,t,e){e!=null&&(Array.isArray(e)?e.forEach(s=>as(n,t,s)):n.append(t,e instanceof Blob?e:String(e)))}function zh(n,t){if(n){const e={text:"text/plain",html:"text/html",json:"application/json",...t};for(const[s,i]of Object.entries(e))if(i.split(",").map(r=>r.trim()).includes(n))return s}return"text"}function qs(n,t){const e=t||new FormData;return n&&(typeof n=="string"&&(n=new URLSearchParams(n)),n instanceof URLSearchParams?n.forEach((s,i)=>{as(e,i,s)}):Array.isArray(n)?n.forEach(([s,i])=>{as(e,s,i)}):n instanceof FormData?n.forEach((s,i)=>{as(e,i,s)}):u.isPlainObject(n)&&Object.entries(n).forEach(([s,i])=>{as(e,s,i)})),e}class Ys{get completed(){return this.data!==void 0||this.error!==void 0}get[Symbol.toStringTag](){return"Ajax"}constructor(t){this.setting=t,this._controller=new AbortController,this._callbacks={success:[],error:[],complete:[]}}on(t,e){return this._callbacks[t].push(e),this}success(t){return this.on("success",t)}done(t){return this.success(t)}fail(t){return this.on("error",t)}complete(t){return this.on("complete",t)}always(t){return this.complete(t)}then(t,e){return this.completed?e&&this.error?e(this.error):t(this.data):(this.success(s=>t(s)),e&&this.fail(e)),this}catch(t){return this.error?(t(this.error),this):this.on("error",e=>t(e))}finally(t){return this.completed?(t(),this):this.complete(()=>t())}abort(t){return this.completed?!1:(this._abortError=t,this._controller.abort(),!0)}getResponseHeader(t){var e;return(e=this.response)==null?void 0:e.headers.get(t)}_init(){if(this.completed)return;const{url:t,type:e,data:s,processData:i=!0,contentType:r,crossDomain:o,accepts:a,dataType:l,timeout:c,dataFilter:h,beforeSend:d,success:p,error:f,complete:g,...y}=this.setting;if((d==null?void 0:d(y))===!1)return;e&&(y.method=e);let _=s;_&&(i&&(_=qs(_)),y.body=_),o&&(y.mode="cors");const b=y.headers||{};ca(b,"X-Requested-With","XMLHttpRequest"),r&&ca(b,"Content-Type",r),y.headers=b,y.signal&&y.signal.addEventListener("abort",()=>{this.abort()}),p&&this.success(p),f&&this.fail(f),g&&this.complete(g),y.signal=this._controller.signal,this.url=t,this.request=y}_emit(t,...e){this._callbacks[t].forEach(s=>{s.call(this,...e)})}async send(){var h;if(this.completed)return[];this._init();const{timeout:t,dataType:e,accepts:s,dataFilter:i,throws:r,jsonParser:o}=this.setting;t&&(this._timeoutID=window.setTimeout(()=>{this.abort(new Error("timeout"))},t));let a,l,c;try{a=await fetch(this.url,this.request),this.response=a;const{statusText:d}=a;if(a.ok){const p=(h=a.headers.get("Content-Disposition"))==null?void 0:h.startsWith("attachment"),f=p?"blob":e||zh(a.headers.get("Content-Type"),s);p||f==="blob"||f==="file"?c=await a.blob():f==="json"?typeof o=="function"?(c=await a.text(),c=o(c)):c=await a.json():c=await a.text(),this.data=c;const g=(i==null?void 0:i(c,f))??c;this._emit("success",g,d,a)}else throw new Error(d)}catch(d){l=d;let p=!1;l.name==="AbortError"&&(this._abortError?l=this._abortError:p=!0),this.error=l,p||this._emit("error",l,a==null?void 0:a.statusText,l.message)}if(this._timeoutID&&clearTimeout(this._timeoutID),this._emit("complete",a,a==null?void 0:a.statusText),l&&r)throw l;return[c,l,a]}}u.ajax=(n,t)=>{t=t||{},typeof n=="string"?t.url=n:u.extend(t,n);const e=new Ys(t);return e.send(),e},u.getJSON=(n,t,e)=>(typeof t=="function"&&(e=t,t=void 0),u.ajax({url:n,data:t,success:e,dataType:"json"})),u.get=(n,t,e,s,i="GET")=>{let r,o;return typeof t=="function"?(r=t,o=void 0):o=t,typeof e=="function"?(r=e,s=void 0):s=e,u.ajax({method:i,url:n,data:o,success:r,dataType:s})},u.post=(n,t,e,s)=>u.get(n,t,e,s,"POST"),u.fn.load=function(n,t,e){typeof t=="function"&&(e=t,t=void 0);const[s,i]=n.split(" ");return u.get(s,t,(r,o,a)=>{i&&(r=u(r).find(i).html()),u(this).html(r),e==null||e.call(this,r,o,a)},"html"),this};async function Ce(n,t=[],e){const s={throws:!0,dataType:"json"};if(typeof n=="string")s.url=n;else if(typeof n=="object")u.extend(s,n);else if(typeof n=="function"){const o=n(...t);return o instanceof Promise?await o:o}e&&u.extend(s,typeof e=="function"?e(s):e);const i=new Ys(s),[r]=await i.send();return r}function Pi(n){return!!(n&&(typeof n=="string"||typeof n=="object"&&n.url||typeof n=="function"))}u.fetch=Ce;function mt(){return u.guid++}function Qs(n,t){if(n===t)return!1;if(n&&t&&typeof n=="object"&&typeof t=="object"){const e=Array.isArray(n),s=Array.isArray(t);if(e!==s)return!0;if(e&&s){if(n.length!==t.length)return!0;for(let o=0;oQs(s instanceof ke?s.value:s,e[i])))&&(this._value=this._compute(),this._lastDependencies=t.map(s=>s instanceof ke?s.cache:s)),this._value}}function Ai(...n){const t=[],e=new Map,s=(i,r)=>{if(Array.isArray(i)&&(r=i[1],i=i[0]),!i.length)return;const o=e.get(i);typeof o=="number"?t[o][1]=!!r:(e.set(i,t.length),t.push([i,!!r]))};return n.forEach(i=>{typeof i=="function"&&(i=i()),Array.isArray(i)?Ai(...i).forEach(s):i&&typeof i=="object"?Object.entries(i).forEach(s):typeof i=="string"&&i.split(" ").forEach(r=>s(r,!0))}),t.sort((i,r)=>(e.get(i[0])||0)-(e.get(r[0])||0))}const S=(...n)=>Ai(...n).reduce((t,[e,s])=>(s&&t.push(e),t),[]).join(" ");u.classes=S,u.fn.setClass=function(n,...t){return this.each((e,s)=>{const i=u(s);n===!0?i.attr("class",S(i.attr("class"),...t)):i.addClass(S(n,...t))})};const ls=new WeakMap;function Di(n,t,e){const s=ls.has(n),i=s?ls.get(n):{};typeof t=="string"?i[t]=e:t===null?Object.keys(i).forEach(r=>{delete i[r]}):Object.assign(i,t),Object.keys(i).forEach(r=>{i[r]===void 0&&delete i[r]}),Object.keys(i).length?(!s&&n instanceof Element&&Object.assign(i,u(n).dataset(),i),ls.set(n,i)):ls.delete(n)}function Li(n,t,e){let s=ls.get(n)||{};return!e&&n instanceof Element&&(s=Object.assign({},u(n).dataset(),s)),t===void 0?s:s[t]}u.fn.dataset=u.fn.data,u.fn.data=function(...n){const[t,e]=n;return!n.length||n.length===1&&typeof t=="string"?this.length?Li(this[0],t):void 0:this.each((s,i)=>Di(i,t,e))},u.fn.removeData=function(n=null){return this.each((t,e)=>Di(e,n))};function Zs(n,t="z-"){const e=u(n)[0];if(e)return Array.from(e.attributes).reduce((s,i)=>{let{name:r,value:o}=i;if(r.startsWith(t)){r=r.slice(t.length).replace(/-([a-z])/g,a=>a[1].toUpperCase());try{o.startsWith("RAWJS<")&&o.endsWith(">RAWJS")?o=new Function(`return ${o.substring(6,o.length-6)}`)():o=JSON.parse(o)}catch{}s[r]=o}return s},{})}function Ri(n,t,e="z-"){const s=u(n);Object.keys(t).forEach(i=>{let r=t[i];typeof r=="function"&&(r=`RAWJS<${r}>RAWJS`),typeof r!="string"&&(r=JSON.stringify(r)),i=i.replace(/[A-Z]/g,o=>`-${o.toLowerCase()}`),s.attr(`${e}${i}`,r)})}function Oh(...n){var e;const t=n.length;if(!t)return Zs(this);if(t===1){const[s]=n;return typeof s=="string"?(e=Zs(this))==null?void 0:e[s]:(u.isPlainObject(s)&&Ri(this,s),this)}return Ri(this,{[n[0]]:n[1]}),this}u.fn.z=Oh,u.fn._attr=u.fn.attr,u.fn.extend({attr(...n){const[t,e]=n;return!n.length||n.length===1&&typeof t=="string"?this._attr.apply(this,n):typeof t=="object"?(t&&Object.keys(t).forEach(s=>{const i=t[s];i===null?this.removeAttr(s):this._attr(s,i)}),this):e===null?this.removeAttr(t):this._attr(t,e)}}),u.Event=(n,t)=>{const[e,...s]=n.split("."),i=new Event(e,{bubbles:!0,cancelable:!0});return i.namespace=s.join("."),i.___ot=e,i.___td=t,i};const cs=(n,t)=>new Promise(e=>{const s=window.setTimeout(e,n);t&&t(s)}),ha={};u.share=ha;var Xs,q,da;w.isValidElement=void 0;var xe,ua,fa,Fi,hs={},pa=[],Wh=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Js=Array.isArray;function ie(n,t){for(var e in t)n[e]=t[e];return n}function ma(n){var t=n.parentNode;t&&t.removeChild(n)}function v(n,t,e){var s,i,r,o={};for(r in t)r=="key"?s=t[r]:r=="ref"?i=t[r]:o[r]=t[r];if(arguments.length>2&&(o.children=arguments.length>3?Xs.call(arguments,2):e),typeof n=="function"&&n.defaultProps!=null)for(r in n.defaultProps)o[r]===void 0&&(o[r]=n.defaultProps[r]);return tn(n,o,s,i,null)}function tn(n,t,e,s,i){var r={type:n,props:t,key:e,ref:s,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:i??++da,__i:-1,__u:0};return i==null&&q.vnode!=null&&q.vnode(r),r}function H(){return{current:null}}function re(n){return n.children}function B(n,t){this.props=n,this.context=t}function Fe(n,t){if(t==null)return n.__?Fe(n.__,n.__i+1):null;for(var e;tt&&xe.sort(Fi));en.__r=0}function _a(n,t,e,s,i,r,o,a,l,c,h){var d,p,f,g,y,_=s&&s.__k||pa,b=t.length;for(e.__d=l,Hh(e,t,_),l=e.__d,d=0;d0?tn(i.type,i.props,i.key,i.ref?i.ref:null,i.__v):i)!=null?(i.__=n,i.__b=n.__b+1,a=Bh(i,e,o=s+d,h),i.__i=a,r=null,a!==-1&&(h--,(r=e[a])&&(r.__u|=131072)),r==null||r.__v===null?(a==-1&&d--,typeof i.type!="function"&&(i.__u|=65536)):a!==o&&(a===o+1?d++:a>o?h>l-o?d+=a-o:d--:d=a(l!=null&&!(131072&l.__u)?1:0))for(;o>=0||a=0){if((l=t[o])&&!(131072&l.__u)&&i==l.key&&r===l.type)return o;o--}if(a{!e||typeof e!="object"||Object.keys(e).forEach(s=>{let i=e[s];const r=n[s];i!==r&&(r!==void 0&&(s==="className"||s.endsWith("Class")?i=[r,i]:s==="children"?i=[...sn(r),...sn(i)]:typeof r=="object"&&(s==="style"||s.endsWith("Style")||s==="attrs"||s.endsWith("Attrs")||s==="props")&&(i=u.extend(r,i))),n[s]=i)})}),n}function Hi(n){return Object.keys(n).forEach(t=>{n[t]===void 0&&delete n[t]}),n}const Oe=new Map;function ds(n){const{zui:t}=window;return(!Oe.size||n&&!Oe.has(n.toUpperCase()))&&Object.keys(t).forEach(e=>{const s=t[e];!s.NAME||!s.ZUI||Oe.set(e.toLowerCase(),s)}),n?Oe.get(n.toLowerCase()):void 0}function xa(n,t,e){const s=ds(n);return s?!s.MULTI_INSTANCE&&s.get(t)?(console.error(`[ZUI] cannot create component "${n}" on element which already has a component instance.`,{element:t,options:e}),null):new s(t,e):null}function Vh(n){if(n){const t=ds(n);t&&t.defineFn()}else ds(),Oe.forEach(t=>{t.defineFn()})}u.fn.zuiInit=function(){return this.find("[zui-create],[data-zui]").each(function(){const n=u(this);let t=Zs(n,"data-");const[e,s]=(t.zui||n.attr("zui-create")).split(":");n.zui(e)||(s?t=u.share[s]:delete t.zui,requestAnimationFrame(()=>xa(e,this,t)))}),this.find("[zui-init]").each(function(){const n=u(this);n.z("zuiInited")||u.runJS(n.z("zuiInited",!0).attr("zui-init"),["$element",n])}),this.find(".hide-before-init").removeClass("invisible hidden opacity-0"),this.find(".scroll-into-view").scrollIntoView(),this.find('[data-on="inited"]').each((n,t)=>{const e=u(t);e.zui()||e.trigger("inited")}),this},u.fn.zui=function(n,t){const e=this[0];if(!e)return;if(typeof n!="string"){const i=Li(e,void 0,!0),r={};let o;return Object.keys(i).forEach(a=>{if(a.startsWith("zui.")){const l=i[a];r[a]=l,(!o||o.gid{u("body").zuiInit()});function Sa(n,t=!0){const e=u(n),s=e[0],i="zui-disable-scroll";if(t){if(e.data(i))return;if((e.css("scrollbar-gutter")||"").includes("stable")){e.data(i,{overflow:e.css("overflow")}).css("overflow","hidden");return}const r=s===document.body||e.is("html")?window.innerWidth-document.body.clientWidth:s.offsetWidth-s.clientWidth;if(!r)return;const o=e.css("paddingRight")||"0";e.data(i,{paddingRight:o,overflow:e.css("overflow")}).css({paddingRight:`${r+Number.parseInt(o,10)}px`,overflow:"hidden"})}else{const r=e.data(i);if(!r)return;e.css(r).removeData(i)}}u.fn.disableScroll=function(n=!0){return this.each((t,e)=>{Sa(e,n)})},u.fn.enableScroll=function(n=!0){return this.disableScroll(!n)};function Kh(n){const t=u(this),e=t.dataset();if(!(e.on||"click").split(" ").includes(n.type))return;const s=e.selector?u(n.target).closest(e.selector):t;if(!s.length)return;const i=l=>l===""?!0:l,r=l=>{if(typeof l=="string")try{l=JSON.parse(l)}catch{}return l};if(i(e.once)){if(e.onceCalled)return;t.dataset("once-called",!0)}if(i(e.prevent)&&n.preventDefault(),i(e.stop)&&n.stopPropagation(),i(e.self)&&n.currentTarget!==n.target)return;const o=[["$element",t],["event",n],["options",e],["$target",s]];if(e.if&&!u.runJS(e.if,...o))return;const a=e.call;if(a){let l=window[a];const c=/^[$A-Z_][0-9A-Z_$.]*$/i.test(a);if(l||(l=u.runJS(a,...o)),!c||!u.isFunction(l))return;const h=[],d=e.params;e.params=h,typeof d=="string"&&d.length?d[0]==="["?h.push(...r(d)):h.push(...d.split(", ").map(p=>(p=p.trim(),p==="$element"?t:p==="event"?n:p==="options"?e:p.startsWith("$element.")||p.startsWith("event.")||p.startsWith("options.")?u.runJS(p,...o):r(p)))):h.push(d),l(...h)}e.do&&u.runJS(e.do,...o)}u(document).on("click.zui.global change.zui.global inited.zui.global","[data-on]",Kh);function We(n){if(typeof n=="function")return We(n());if(typeof n=="number")return[n];let t=n.match(/(\d+)(%|px)?/);return t?[parseInt(t[1]),t[2]]:(t=n.match(/(\d+)\/(\d+)/),t?[100*parseInt(t[1])/parseInt(t[2]),"%"]:[NaN])}function it(n){if(n==null)return null;const[t,e="px"]=We(n);return Number.isNaN(t)?typeof n=="string"?n:null:`${t}${e}`}async function rn(n,t){var s,i,r;if(n instanceof Blob){const o=document.createElement("a");return o.href=window.URL.createObjectURL(n),t&&(o.download=decodeURIComponent(t)),o.click(),o.remove(),n}if(n instanceof Response){const o=await n.blob();return t=t||((r=(i=(s=n.headers.get("Content-Disposition"))==null?void 0:s.split(";")[1])==null?void 0:i.split("=")[1])==null?void 0:r.replace(/"/g,"")),rn(o,t)}const e=await fetch(n);return rn(e)}class $a{constructor(t){this._$target=u(t)}on(...t){return this._$target.on(...t),this}one(...t){return this._$target.one(...t),this}off(...t){return this._$target.off(...t),this}trigger(...t){return this._$target.trigger(...t),this}}const Wt=new $a(document);u.bus=Wt,u.on=Wt.on.bind(Wt),u.one=Wt.one.bind(Wt),u.off=Wt.off.bind(Wt),u.trigger=Wt.trigger.bind(Wt);var Gh=["Shift","Meta","Alt","Control"],Ta=typeof navigator=="object"?navigator.platform:"",Na=/Mac|iPod|iPhone|iPad/.test(Ta),qh=Na?"Meta":"Control",Yh=Ta==="Win32"?["Control","Alt"]:Na?["Alt"]:[];function Bi(n,t){return typeof n.getModifierState=="function"&&(n.getModifierState(t)||Yh.includes(t)&&n.getModifierState("AltGraph"))}function Qh(n){return n.trim().split(" ").map(function(t){var e=t.split(/\b\+/),s=e.pop();return[e=e.map(function(i){return i==="$mod"?qh:i}),s]})}function Ma(n,t){var e;t===void 0&&(t={});var s=(e=t.timeout)!=null?e:1e3,i=Object.keys(n).map(function(a){return[Qh(a),n[a]]}),r=new Map,o=null;return function(a){a instanceof KeyboardEvent&&(i.forEach(function(l){var c=l[0],h=l[1],d=r.get(c)||c;(function(p,f){return!(f[1].toUpperCase()!==p.key.toUpperCase()&&f[1]!==p.code||f[0].find(function(g){return!Bi(p,g)})||Gh.find(function(g){return!f[0].includes(g)&&f[1]!==g&&Bi(p,g)}))})(a,d[0])?d.length>1?r.set(c,d.slice(1)):(r.delete(c),h(a)):Bi(a,a.key)||r.delete(c)}),o&&clearTimeout(o),o=setTimeout(r.clear.bind(r),s))}}function Zh(n,t,e){var s;e===void 0&&(e={});var i=(s=e.event)!=null?s:"keydown",r=Ma(t,e);return n.addEventListener(i,r),function(){n.removeEventListener(i,r)}}function ji(n,t={}){if(!n)return;const e=Object.keys(t).reduce((s,i)=>(t[i].optional||(s[i]={...t[i]}),s),{});return Object.keys(n).forEach(s=>{const i=n[s];i?i===!0?t[s]&&(e[s]={...t[s]}):e[s]=i:delete e[s]}),Object.keys(e).reduce((s,i)=>{const{keys:r,handler:o}=e[i];return typeof r=="string"?s[r]=o:r.forEach(a=>{s[a]=o}),s},{})}function Ui(n,t,e){const{timeout:s,event:i="keydown",scope:r,when:o}=e||{},a=Ma(t,{timeout:s});return u(n).on(`${i}.zui.hotkeys${r?`.${r}`:""}`,function(l){o&&o(l)===!1||a(l)})}function Vi(n,t){return u(n).off(`.zui.hotkeys${t?`.${t}`:""}`)}const Xh=Zh;u.fn.hotkeys=function(n,t){return Ui(this,n,t)},u.fn.unbindHotkeys=function(n){return Vi(this,n)},u.hotkeys=function(n,t){Ui(window,n,t)},u.unbindHotkeys=function(n){Vi(window,n)};function on(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement}async function Ea(n){(typeof n=="string"||n instanceof Element||n instanceof u)&&(n={target:n});const{target:t,onError:e,onSuccess:s,afterExit:i,afterEnter:r}=n,o=u(t),a=o[0];if(!a)return;const l=a.requestFullscreen||a.webkitRequestFullscreen||a.mozRequestFullScreen;if(!l){e==null||e.call(a,new Error("[ZUI] The browser does not support full screen feature."));return}try{await l.call(a),s==null||s.call(a),u(a).off(".zui.fullscreen"),i&&o.on("exitFullscreen.zui.fullscreen",i),r&&o.on("enterFullscreen.zui.fullscreen",r)}catch(c){e==null||e.call(a,c)}document.zuiBindFullscreenChange||(document.zuiBindFullscreenChange=!0,u(document).on("fullscreenchange.zui webkitfullscreenchange.zui mozfullscreenchange.zui",c=>{const h=on();let d=h;h?u(h).addClass("is-in-fullscreen"):(d=u(document).find(".is-in-fullscreen")[0]||document,u(d).removeClass("is-in-fullscreen")),u("body").toggleClass("has-in-fullscreen",!!h);const p={event:c,target:d,fullscreenElement:h};u(d).trigger(h?"enterFullscreen":"exitFullscreen",p).trigger("toggleFullscreen",p)}))}async function Ki(n){const t=on();return n===!1&&!!t===n?n:t?(document.exitFullscreen(),!1):(await Ea(n),!0)}u.fn.fullscreen=function(n){return Ki({target:this,...n})},u.getFullscreenElement=on,u.toggleFullscreen=Ki;function Se(n){return n.parentNode===document?!1:n.parentNode?Se(n.parentNode):!0}u.isDetached=Se,u.fn.isDetached=function(){const n=this[0];return!n||Se(n)};class X{constructor(t,e){this._inited=!1,this._autoDestory=0;const{KEY:s,DATA_KEY:i,DEFAULT:r,MULTI_INSTANCE:o,NAME:a}=this.constructor;if(!a)throw new Error('[ZUI] The component must have a "NAME" static property.');const l=u(t);if(l.data(s)&&!o)throw new Error("[ZUI] The component has been initialized on element.");const c=l[0],h=mt();this._gid=h,this._element=c;const d=l.parent();if(d.length&&(this._mobs=new MutationObserver(p=>{p.forEach(f=>{f.removedNodes.forEach(g=>{g===c&&(this._autoDestory&&clearTimeout(this._autoDestory),this._autoDestory=window.setTimeout(()=>{this._autoDestory=0,Se(c)&&this.destroy()},100))})})}),this._mobs.observe(d[0],{childList:!0,subtree:!1})),this._options={...r,...l.dataset()},this.setOptions(e),this._key=this.options.key??`__${h}`,l.data(s,this).attr(i,`${h}`),o){const p=`${s}:ALL`;let f=l.data(p);f||(f=new Map,l.data(p,f)),f.set(this._key,this)}this.init(),requestAnimationFrame(async()=>{this._inited=!0,await this.afterInit(),this.emit("inited",this.options)})}static get ZUI(){return this.NAME.replace(/(^[A-Z]+)/,t=>t.toLowerCase())}static get KEY(){return`zui.${this.NAME}`}static get NAMESPACE(){return`.zui.${this.ZUI}`}static get DATA_KEY(){return`data-zui-${this.NAME}`}static get SELECTOR(){return`[${this.DATA_KEY}]`}get inited(){return this._inited}get element(){return this._element}get key(){return this._key}get options(){return this._options}get gid(){return this._gid}get $element(){return u(this.element)}get $emitter(){return this.$element}get i18nData(){return[this.options.i18n,this.constructor.i18n]}init(){}afterInit(){}render(t){this.setOptions(t)}destroy(){var r;const{KEY:t,DATA_KEY:e,MULTI_INSTANCE:s}=this.constructor,{$element:i}=this;if(this.emit("destroyed"),(r=this._mobs)==null||r.disconnect(),i.off(this.namespace).removeData(t).attr(e,null),s){const o=this.$element.data(`${t}:ALL`);if(o)if(o.delete(this._key),o.size===0)this.$element.removeData(`${t}:ALL`);else{const a=o.values().next().value;i.data(t,a).attr(e,a.gid)}}}setOptions(t){return t&&u.extend(this._options,t),this._options}emit(t,...e){const s=u.Event(t);return s.__src=this,this.$emitter.trigger(s,[this,...e]),s}on(t,e,s){const i=this;this.$element[s!=null&&s.once?"one":"on"](this._wrapEvent(t),function(r,o){(!r.__src||r.__src===i)&&e.call(this,r,o)})}one(t,e){this.on(t,e,{once:!0})}off(t){this.$element.off(this._wrapEvent(t))}i18n(t,e,s){const{i18nData:i}=this;return K(i,t,e,s,this.options.lang,this.constructor.NAME)??K(i,t,e,s,this.options.lang)??`{i18n:${t}}`}get namespace(){return`${this.constructor.NAMESPACE}.${this._key}`}_wrapEvent(t){return t.split(" ").map(e=>e.includes(".")?e:`${e}${this.namespace}`).join(" ")}static get(t,e){const s=u(t);if(this.MULTI_INSTANCE&&e!==void 0){const i=s.data(`${this.KEY}:ALL`);return i?i.get(e):void 0}return s.data(this.KEY)}static ensure(t,e){const s=this.get(t,e==null?void 0:e.key);return s?(e&&s.setOptions(e),s):new this(t,e)}static getAll(t){const{MULTI_INSTANCE:e,SELECTOR:s}=this,i=[];return u(t||document).find(s).each((r,o)=>{if(e){const l=u(o).data(`${this.KEY}:ALL`);if(l){i.push(...l.values());return}}const a=u(o).data(this.KEY);a&&i.push(a)}),i.sort((r,o)=>r.gid-o.gid)}static query(t,e,s){if(t===void 0){let i=this.getAll();return s&&(i=i.filter(s)),i.pop()}return this.get(u(t).closest(this.SELECTOR),e)}static defineFn(t){let e=t||this.ZUI;u.fn[e]&&(e=`zui${this.NAME}`);const s=this;u.fn.extend({[e](i,...r){const o=typeof i=="object"?i:void 0,a=typeof i=="string"?i:void 0;let l;return this.each((c,h)=>{let d=s.get(h);if(d?o&&d.render(o):d=new s(h,o),a){let p=d[a],f=d;p===void 0&&(f=d.$,p=f[a]),typeof p=="function"?l=p.call(f,...r):l=p}}),l!==void 0?l:this}})}}X.DEFAULT={},X.MULTI_INSTANCE=!1;class Ia extends X{init(){const{offset:t=1,side:e,zIndex:s,pinnedClass:i="is-pinned"}=this.options,{$element:r}=this;r.css({position:"sticky",zIndex:s}),e&&r.css(e,-t),this._ob=new IntersectionObserver(([o])=>o.target.classList.toggle(i,o.intersectionRatio=l&&r>=c&&i+o<=h&&r+a<=d;const p=i<=h&&i+o>=l;return r<=d&&r+a>=c&&p}u.fn.isVisible=function(n){return an(this,n)};function Gi(n,t,e=!1){const s=u(n);if(t!==void 0){if(t.length){const i=`zui-runjs-${mt()}`;s.append(` - -control->loadModel('im'); -$xxdStatus = $im->getXxdStatus(); -if(isset($config->xuanxuan->turnon) && $config->xuanxuan->turnon && $xxdStatus == 'online') -{ - $xuanConfig = new stdclass(); - $token = $im->userGetAuthToken($app->user->id, 'zentaoweb'); - $clientUrl = isset($config->webClientUrl) ? $config->webClientUrl : 'data/xuanxuan/web/index.html'; - $backendUrl = $im->getServer('zentao'); - - $xuanConfig->clientUrl = $clientUrl; - $xuanConfig->server = ($config->xuanxuan->https == 'on' ? 'https' : 'http') . '://' . parse_url($backendUrl, PHP_URL_HOST) . ':' . $config->xuanxuan->commonPort; - $xuanConfig->account = $app->user->account; - $xuanConfig->authKey = $token->token; - $xuanConfig->debug = $config->debug; -} -?> - - -getWebRoot() . 'data/xuanxuan/sdk/sdk.min.js'); ?> - - From c235c491b719cc2c79e4b8af1cd09706491583d5 Mon Sep 17 00:00:00 2001 From: liugang Date: Tue, 23 Apr 2024 10:54:21 +0800 Subject: [PATCH 090/141] * install: unify the style of installation steps. --- module/install/css/showtableprogress.ui.css | 1 - module/install/css/step1.ui.css | 1 - module/install/css/step2.ui.css | 1 - module/install/css/step4.ui.css | 7 +--- module/install/css/step5.ui.css | 2 -- module/install/ui/app.html.php | 6 ++-- module/install/ui/index.html.php | 7 ++-- module/install/ui/license.html.php | 7 ++-- module/install/ui/progress.html.php | 6 ++-- module/install/ui/showtableprogress.html.php | 8 +++-- module/install/ui/step1.html.php | 6 ++-- module/install/ui/step2.html.php | 32 +++++++++--------- module/install/ui/step3.html.php | 7 ++-- module/install/ui/step4.html.php | 35 +++++++++++++------- module/install/ui/step5.html.php | 7 ++-- module/install/ui/step6.html.php | 6 ++-- 16 files changed, 77 insertions(+), 62 deletions(-) diff --git a/module/install/css/showtableprogress.ui.css b/module/install/css/showtableprogress.ui.css index dbf15d50bf..e69de29bb2 100644 --- a/module/install/css/showtableprogress.ui.css +++ b/module/install/css/showtableprogress.ui.css @@ -1 +0,0 @@ -.progress{overflow:hidden; height:400px; display: block; white-space: normal;} diff --git a/module/install/css/step1.ui.css b/module/install/css/step1.ui.css index 71fe0d6df6..e69de29bb2 100644 --- a/module/install/css/step1.ui.css +++ b/module/install/css/step1.ui.css @@ -1 +0,0 @@ -.panel .panel-heading {justify-content: flex-start; gap: 0.125rem;} diff --git a/module/install/css/step2.ui.css b/module/install/css/step2.ui.css index 97151af510..e69de29bb2 100644 --- a/module/install/css/step2.ui.css +++ b/module/install/css/step2.ui.css @@ -1 +0,0 @@ -.table.bordered > * > tr > th:first-child {text-align: right;} diff --git a/module/install/css/step4.ui.css b/module/install/css/step4.ui.css index 33285e5ae3..6e73cf040b 100644 --- a/module/install/css/step4.ui.css +++ b/module/install/css/step4.ui.css @@ -1,6 +1 @@ -.panel {width: 1000px; margin: auto; padding-bottom: 32px;} -.panel .panel-heading {justify-content: flex-start; padding: 24px 16px; gap: 0.125rem;} -.panel .panel-body {padding: 0px 16px;} -.panel .panel-body .table.bordered > thead {background-color: var(--color-gray-100); color: var(--color-gray-900);} -.table.bordered > * > tr > td {text-align: center;} -.table.bordered > * > tr > td:first-child {text-align: left;} +.panel .panel-body {padding-top: 0px;} diff --git a/module/install/css/step5.ui.css b/module/install/css/step5.ui.css index 6437ac8538..e69de29bb2 100644 --- a/module/install/css/step5.ui.css +++ b/module/install/css/step5.ui.css @@ -1,2 +0,0 @@ -#mainContent .panel {padding: 1rem; margin-top: 10%;} -#mainContent .panel-heading {width: 24rem; margin: auto; padding: 0.75rem;} diff --git a/module/install/ui/app.html.php b/module/install/ui/app.html.php index 12ceca941f..b6ce20c8b8 100644 --- a/module/install/ui/app.html.php +++ b/module/install/ui/app.html.php @@ -28,10 +28,12 @@ foreach($components->category as $item) jsVar('category', $category); div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), formPanel ( set::formID('solutionForm'), diff --git a/module/install/ui/index.html.php b/module/install/ui/index.html.php index 84478fb43c..b30f1236c5 100644 --- a/module/install/ui/index.html.php +++ b/module/install/ui/index.html.php @@ -17,11 +17,12 @@ foreach($app->config->langs as $key => $value) $langItems[] = array('text' => $v div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), - setClass('px-1 mt-2'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), panel ( setClass('p-8'), diff --git a/module/install/ui/license.html.php b/module/install/ui/license.html.php index a1210ad669..13baa73a55 100644 --- a/module/install/ui/license.html.php +++ b/module/install/ui/license.html.php @@ -16,11 +16,12 @@ jsVar('nextLink', $config->inQuickon ? inlink('step5') : inlink('step1')); div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), - setClass('px-1 mt-2'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), panel ( setClass('p-8'), diff --git a/module/install/ui/progress.html.php b/module/install/ui/progress.html.php index 862445a0a9..865b59b68d 100644 --- a/module/install/ui/progress.html.php +++ b/module/install/ui/progress.html.php @@ -74,10 +74,12 @@ if(!helper::isAjaxRequest('modal')) div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), h::importCss($app->getWebRoot() . 'js/xterm/xterm.css'), set('data-loading', $lang->solution->notices->uninstallingSolution), formPanel diff --git a/module/install/ui/showtableprogress.html.php b/module/install/ui/showtableprogress.html.php index d037a68560..21279e9a76 100644 --- a/module/install/ui/showtableprogress.html.php +++ b/module/install/ui/showtableprogress.html.php @@ -15,17 +15,19 @@ set::zui(true); jsVar('dbFinish', $lang->install->dbFinish); div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), panel ( setClass('py-2'), set::title($lang->install->dbProgress), form ( - h::pre(setID('progress'), setClass('progress')), + h::pre(setID('progress'), setClass('progress block overflow-hidden h-96')), set::actions(array(array('disabled' => true, 'text' => $lang->install->next, 'class' => 'primary next'))) ) ) diff --git a/module/install/ui/step1.html.php b/module/install/ui/step1.html.php index 39ed11150c..3d5389fb56 100644 --- a/module/install/ui/step1.html.php +++ b/module/install/ui/step1.html.php @@ -63,10 +63,12 @@ foreach($dirItems as $dirItem) div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), panel ( setClass('py-2'), diff --git a/module/install/ui/step2.html.php b/module/install/ui/step2.html.php index 26326950f5..58025f047f 100644 --- a/module/install/ui/step2.html.php +++ b/module/install/ui/step2.html.php @@ -16,10 +16,12 @@ set::zui(true); div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), panel ( setClass('py-2'), @@ -33,17 +35,13 @@ div setClass('table bordered'), h::tr ( - h::th - ( - width('1/5'), - $lang->install->key - ), + h::th(setClass('text-right w-1/5'), $lang->install->key), h::th($lang->install->value), h::th() ), h::tr ( - h::th($lang->install->timezone), + h::th(setClass('text-right'), $lang->install->timezone), h::td ( picker @@ -58,7 +56,7 @@ div ), h::tr ( - h::th($lang->install->defaultLang), + h::th(setClass('text-right'), $lang->install->defaultLang), h::td ( picker @@ -74,7 +72,7 @@ div $config->edition != 'open' ? h::tr ( $config->inQuickon ? setClass('hidden') : null, - h::th($lang->install->dbDriver), + h::th(setClass('text-right'), $lang->install->dbDriver), h::td ( picker @@ -95,7 +93,7 @@ div h::tr ( $config->inQuickon ? setClass('hidden') : null, - h::th($lang->install->dbHost), + h::th(setClass('text-right'), $lang->install->dbHost), h::td ( formGroup @@ -112,7 +110,7 @@ div h::tr ( $config->inQuickon ? setClass('hidden') : null, - h::th($lang->install->dbPort), + h::th(setClass('text-right'), $lang->install->dbPort), h::td ( formGroup @@ -128,7 +126,7 @@ div h::tr ( $config->inQuickon ? setClass('hidden') : null, - h::th($lang->install->dbEncoding), + h::th(setClass('text-right'), $lang->install->dbEncoding), h::td ( formGroup @@ -145,7 +143,7 @@ div h::tr ( $config->inQuickon ? setClass('hidden') : null, - h::th($lang->install->dbUser), + h::th(setClass('text-right'), $lang->install->dbUser), h::td ( formGroup @@ -162,7 +160,7 @@ div h::tr ( $config->inQuickon ? setClass('hidden') : null, - h::th($lang->install->dbPassword), + h::th(setClass('text-right'), $lang->install->dbPassword), h::td ( formGroup @@ -178,7 +176,7 @@ div ), h::tr ( - h::th($lang->install->dbName), + h::th(setClass('text-right'), $lang->install->dbName), h::td ( formGroup @@ -194,7 +192,7 @@ div ), h::tr ( - h::th($lang->install->dbPrefix), + h::th(setClass('text-right'), $lang->install->dbPrefix), h::td ( formGroup diff --git a/module/install/ui/step3.html.php b/module/install/ui/step3.html.php index bf1b90d394..ada579747e 100644 --- a/module/install/ui/step3.html.php +++ b/module/install/ui/step3.html.php @@ -45,11 +45,12 @@ if(is_writable($configRoot) && @file_put_contents($myConfigFile, $configContent) div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), - setClass('px-1 mt-2'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), panel ( set::title($lang->install->saveConfig), diff --git a/module/install/ui/step4.html.php b/module/install/ui/step4.html.php index 0a31dbe200..28853ff02b 100644 --- a/module/install/ui/step4.html.php +++ b/module/install/ui/step4.html.php @@ -25,7 +25,11 @@ foreach($disabledFeatures as $feature) if(is_array($feature) && empty($disabledScrumFeatures)) continue; $trs[] = h::tr ( - h::td(is_array($feature) && !empty($disabledScrumFeatures) ? sprintf($this->lang->custom->scrum->common, implode($lang->comma, $disabledScrumFeatures)) : $this->lang->custom->features[$feature]), + h::td + ( + setClass('text-left'), + is_array($feature) && !empty($disabledScrumFeatures) ? sprintf($lang->custom->scrum->common, implode($lang->comma, $disabledScrumFeatures)) : $lang->custom->features[$feature] + ), h::td ( icon @@ -51,7 +55,11 @@ foreach($config->custom->allFeatures as $feature) $trs[] = h::tr ( - h::td(($feature == 'scrumDetail' && !empty($enabledScrumFeatures)) ? sprintf($this->lang->custom->scrum->common, implode($lang->comma, $enabledScrumFeatures)) : $this->lang->custom->features[$feature]), + h::td + ( + setClass('text-left'), + ($feature == 'scrumDetail' && !empty($enabledScrumFeatures)) ? sprintf($lang->custom->scrum->common, implode($lang->comma, $enabledScrumFeatures)) : $lang->custom->features[$feature] + ), h::td ( icon @@ -73,18 +81,21 @@ foreach($config->custom->allFeatures as $feature) div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), formPanel ( - setClass('bg-canvas'), + setClass('bg-canvas m-auto pb-8'), set::title($lang->install->selectMode), set::titleClass('text-xl'), set::actions(array()), to::heading ( + setClass('justify-start gap-1'), span ( setClass('text-gray'), @@ -93,12 +104,12 @@ div setClass('text-warning px-1'), 'help' ), - $this->lang->upgrade->remarkDesc + $lang->upgrade->remarkDesc ) ), h::table ( - setClass('table bordered'), + setClass('table bordered text-center'), h::thead ( h::tr @@ -111,12 +122,12 @@ div h::td ( width('1/3'), - $this->lang->custom->modeList['light'] + $lang->custom->modeList['light'] ), h::td ( width('1/3'), - $this->lang->custom->modeList['ALM'] + $lang->custom->modeList['ALM'] ) ) ), @@ -124,9 +135,9 @@ div ( h::tr ( - h::td($lang->custom->usage), - h::td($this->lang->custom->modeIntroductionList['light']), - h::td($this->lang->custom->modeIntroductionList['ALM']), + h::td(setClass('text-left'), $lang->custom->usage), + h::td($lang->custom->modeIntroductionList['light']), + h::td($lang->custom->modeIntroductionList['ALM']), ), $trs, h::tr diff --git a/module/install/ui/step5.html.php b/module/install/ui/step5.html.php index 0d63777e04..3ca46e6300 100644 --- a/module/install/ui/step5.html.php +++ b/module/install/ui/step5.html.php @@ -21,10 +21,12 @@ if(isset($error)) div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), isset($success) ? panel ( set::title($lang->install->success), @@ -37,6 +39,7 @@ div ( setClass('bg-canvas m-auto mw-auto'), set::title($lang->install->getPriv), + set::headingClass('w-96 m-auto'), set::formClass('w-96 m-auto'), set::submitBtnText(!empty($config->inQuickon) ? $lang->install->next : $lang->save), formRow diff --git a/module/install/ui/step6.html.php b/module/install/ui/step6.html.php index fb2576e7d6..8f403d8f1e 100644 --- a/module/install/ui/step6.html.php +++ b/module/install/ui/step6.html.php @@ -16,10 +16,12 @@ $joinZentao = ($installFileDeleted ? $lang->install->successLabel : $lang->insta div ( - set::id('main'), + setID('main'), + setClass('flex justify-center'), div ( - set::id('mainContent'), + setID('mainContent'), + setClass('px-1 mt-2 w-full max-w-7xl'), panel ( setClass('p-2'), From 21fe47b6098df3d25e839df0ba40d62342435a6e Mon Sep 17 00:00:00 2001 From: liugang Date: Tue, 23 Apr 2024 10:57:34 +0800 Subject: [PATCH 091/141] - install: remove unused files. --- module/install/css/showtableprogress.ui.css | 0 module/install/css/step1.ui.css | 0 module/install/css/step2.ui.css | 0 module/install/css/step5.ui.css | 0 module/upgrade/config.php | 5 +++++ 5 files changed, 5 insertions(+) delete mode 100644 module/install/css/showtableprogress.ui.css delete mode 100644 module/install/css/step1.ui.css delete mode 100644 module/install/css/step2.ui.css delete mode 100644 module/install/css/step5.ui.css diff --git a/module/install/css/showtableprogress.ui.css b/module/install/css/showtableprogress.ui.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/module/install/css/step1.ui.css b/module/install/css/step1.ui.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/module/install/css/step2.ui.css b/module/install/css/step2.ui.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/module/install/css/step5.ui.css b/module/install/css/step5.ui.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/module/upgrade/config.php b/module/upgrade/config.php index ef3313c041..da1027671c 100644 --- a/module/upgrade/config.php +++ b/module/upgrade/config.php @@ -1182,6 +1182,11 @@ $config->delete['20_0_beta1'][] = 'module/metric/ui/view.html.php'; $config->delete['20_0_beta1'][] = 'module/metric/ui/viewphpmetric.html.php'; $config->delete['20_0_beta1'][] = 'module/metric/ui/viewsqlmetric.html.php'; +$config->delete['20_0_beta2'][] = 'module/install/css/showtableprogress.ui.css'; +$config->delete['20_0_beta2'][] = 'module/install/css/step1.ui.css'; +$config->delete['20_0_beta2'][] = 'module/install/css/step2.ui.css'; +$config->delete['20_0_beta2'][] = 'module/install/css/step5.ui.css'; + $config->upgrade->openModules = array('action', 'admin', 'ai', 'bi', 'aiapp', 'api', 'automation', 'backup', 'block', 'branch', 'budget', 'bug', 'build', 'caselib', 'chart', 'ci', 'client', 'common', 'company', 'compile', 'convert', 'cron', 'custom', 'datatable', 'dataview', 'dept', 'design', 'dev', 'dimension', 'doc', 'durationestimation', 'entry', 'execution', 'extension', 'file', 'git', 'gitlab', 'group', 'holiday', 'im', 'index', 'index.html', 'install', 'issue', 'jenkins', 'job', 'kanban', 'license', 'mail', 'message', 'metric', 'misc', 'mr', 'my', 'personnel', 'pipeline', 'product', 'productplan', 'productset', 'program', 'programplan', 'project', 'projectbuild', 'projectplan', 'projectrelease', 'projectstory', 'pivot', 'qa', 'release', 'repo', 'report', 'risk', 'score', 'screen', 'search', 'setting', 'sonarqube', 'sso', 'stage', 'stakeholder', 'story', 'subject', 'svn', 'task', 'testcase', 'testreport', 'testsuite', 'testtask', 'todo', 'tree', 'tutorial', 'upgrade', 'user', 'webhook', 'weekly', 'workestimation', 'gitea', 'gogs', 'transfer', 'zahost', 'zanode', 'editor', 'charter', 'roadmap', 'account', 'artifactrepo', 'cne', 'host', 'instance', 'ops', 'serverroom', 'space', 'store', 'system', 'solution', 'demand', 'gitfox'); $config->upgrade->unsetModules = array('design', 'program', 'programplan', 'projectbuild', 'projectrelease', 'stage', 'stakeholder', 'product', 'branch', 'productplan', 'release', 'build', 'qa', 'bug', 'testcase', 'testtask', 'testreport', 'testsuite', 'caselib', 'automation', 'repo', 'ci', 'compile', 'jenkins', 'job', 'svn', 'gitlab', 'sonarqube', 'mr', 'git', 'report', 'sqlbuilder', 'feedback', 'faq', 'attend', 'holiday', 'leave', 'makeup', 'overtime', 'lieu', 'ops', 'host', 'serverroom', 'account', 'domain', 'service', 'deploy', 'conference', 'traincourse', 'pssp', 'baseline', 'classify', 'cm', 'cmcl', 'auditcl', 'reviewcl', 'process', 'activity', 'zoutput', 'auditplan', 'nc', 'subject', 'weekly', 'workestimation', 'issue', 'durationestimation', 'risk', 'opportunity', 'trainplan', 'gapanalysis', 'researchplan', 'researchreport', 'meeting', 'meetingroom', 'budget', 'reviewissue', 'reviewsetting', 'review', 'milestone', 'measurement', 'measrecord', 'assetlib', 'setting', 'im', 'client', 'ldap', 'dev', 'api', 'gitea', 'gogs', 'zanode', 'zahost'); From ec61c89230285bebd84c8e122e9963d10607f055 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Tue, 23 Apr 2024 11:00:20 +0800 Subject: [PATCH 092/141] * Fix bug #47908. --- module/testtask/zen.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testtask/zen.php b/module/testtask/zen.php index b78fbe3b52..54abfe73e8 100644 --- a/module/testtask/zen.php +++ b/module/testtask/zen.php @@ -674,7 +674,7 @@ class testtaskZen extends testtask { if(!$automation) { - if(helper::isAjaxRequest()) return $this->send(array('load' => $cancelURL)); + if(helper::isAjaxRequest() && !isInModal()) return $this->send(array('load' => $cancelURL)); $this->locate($cancelURL); } $resultID = $this->testtask->initResultForAutomatedTest($runID, $caseID, $run->case->version, $automation->node); From 812aed678c63d3337ac0962c28cd96e4eca6485f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 23 Apr 2024 10:58:12 +0800 Subject: [PATCH 093/141] * Adjust code for error. --- extension/lite/common/ext/lang/de/lite.php | 1 - extension/lite/common/ext/lang/en/lite.php | 1 - extension/lite/common/ext/lang/fr/lite.php | 1 - extension/lite/common/ext/lang/zh-cn/lite.php | 1 - framework/base/router.class.php | 16 ++++++++-------- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/extension/lite/common/ext/lang/de/lite.php b/extension/lite/common/ext/lang/de/lite.php index d438dd50f7..f653cfe325 100644 --- a/extension/lite/common/ext/lang/de/lite.php +++ b/extension/lite/common/ext/lang/de/lite.php @@ -1,6 +1,5 @@ productLink); list($projectModule, $projectMethod) = explode('-', $config->projectLink); list($executionModule, $executionMethod) = explode('-', $config->executionLink); diff --git a/extension/lite/common/ext/lang/en/lite.php b/extension/lite/common/ext/lang/en/lite.php index d438dd50f7..f653cfe325 100644 --- a/extension/lite/common/ext/lang/en/lite.php +++ b/extension/lite/common/ext/lang/en/lite.php @@ -1,6 +1,5 @@ productLink); list($projectModule, $projectMethod) = explode('-', $config->projectLink); list($executionModule, $executionMethod) = explode('-', $config->executionLink); diff --git a/extension/lite/common/ext/lang/fr/lite.php b/extension/lite/common/ext/lang/fr/lite.php index d438dd50f7..f653cfe325 100644 --- a/extension/lite/common/ext/lang/fr/lite.php +++ b/extension/lite/common/ext/lang/fr/lite.php @@ -1,6 +1,5 @@ productLink); list($projectModule, $projectMethod) = explode('-', $config->projectLink); list($executionModule, $executionMethod) = explode('-', $config->executionLink); diff --git a/extension/lite/common/ext/lang/zh-cn/lite.php b/extension/lite/common/ext/lang/zh-cn/lite.php index df67dbfb7d..b7cbf9e966 100644 --- a/extension/lite/common/ext/lang/zh-cn/lite.php +++ b/extension/lite/common/ext/lang/zh-cn/lite.php @@ -1,6 +1,5 @@ productLink); list($projectModule, $projectMethod) = explode('-', $config->projectLink); list($executionModule, $executionMethod) = explode('-', $config->executionLink); diff --git a/framework/base/router.class.php b/framework/base/router.class.php index 4c3a405c3e..3e6a949954 100644 --- a/framework/base/router.class.php +++ b/framework/base/router.class.php @@ -470,17 +470,16 @@ class baseRouter if($this->config->framework->multiSite) $this->setSiteCode() && $this->loadExtraConfig(); if($this->config->framework->multiLanguage) $this->setClientLang(); + $this->setVision(); + + $needDetectDevice = zget($this->config->framework->detectDevice, $this->clientLang, false); + $this->clientDevice = $needDetectDevice ? $this->setClientDevice() : 'desktop'; if($this->config->framework->multiLanguage) $this->loadLang('common'); if($this->config->framework->multiTheme) $this->setClientTheme(); $this->setOpenApp(); $this->setSuperVars(); - - $this->setVision(); - - $needDetectDevice = zget($this->config->framework->detectDevice, $this->clientLang, false); - $this->clientDevice = $needDetectDevice ? $this->setClientDevice() : 'desktop'; } /** @@ -860,7 +859,7 @@ class baseRouter $account = isset($_SESSION['user']) ? $_SESSION['user']->account : ''; if(empty($account) and isset($_POST['account'])) $account = $_POST['account']; if(empty($account) and isset($_GET['account'])) $account = $_GET['account']; - if(empty($account)) $account = $this->cookie->za; + if(empty($account) and isset($_COOKIE['za'])) $account = $_COOKIE['za']; $vision = ''; $sql = new sql(); @@ -1309,8 +1308,9 @@ class baseRouter { $this->clientDevice = 'desktop'; - if($this->cookie->device == 'mobile') $this->clientDevice = 'mobile'; - if($this->cookie->device == 'desktop') $this->clientDevice = 'desktop'; + $cookieDevice = zget($_COOKIE, 'device', 'desktop'); + if($cookieDevice == 'mobile') $this->clientDevice = 'mobile'; + if($cookieDevice == 'desktop') $this->clientDevice = 'desktop'; if(empty($this->cookie->device) || !str_contains('mobile,desktop', (string) $this->cookie->device)) { From c540357ea001fabbfc07e0c463b4e58bdc1a89eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E8=BE=B0=E8=BD=A9?= Date: Tue, 23 Apr 2024 11:02:48 +0800 Subject: [PATCH 094/141] * Fix bug #48235. --- module/metric/css/preview.ui.css | 4 ++-- module/metric/js/preview.ui.js | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/module/metric/css/preview.ui.css b/module/metric/css/preview.ui.css index df9de03cba..d6e3e207bc 100644 --- a/module/metric/css/preview.ui.css +++ b/module/metric/css/preview.ui.css @@ -4,8 +4,8 @@ #mainContent .side {overflow-x: hidden; padding-right: 4px;} #mainContent .main {overflow-x: hidden;} -#featureBar .nav-feature li:last-child {padding-left: 4px;} -#featureBar .nav-feature li:nth-last-child(2):before {content: ""; position: absolute; left: 2px; top: 5px; right: 0; bottom: 5px; width: 1px; background-color: var(--color-gray-300);} +#featureBar .nav-feature li.divider-before {padding-left: 4px;} +#featureBar .nav-feature li.divider-before:before {content: ""; position: absolute; left: -1px; top: 5px; bottom: 5px; width: 1px; background-color: var(--color-gray-300);} .filter-btn {padding-left: 0.625rem !important; padding-right: 0.625rem !important;} diff --git a/module/metric/js/preview.ui.js b/module/metric/js/preview.ui.js index 3793df3cd4..adc01b2cd8 100644 --- a/module/metric/js/preview.ui.js +++ b/module/metric/js/preview.ui.js @@ -21,6 +21,7 @@ window.afterPageUpdate = function($target, info, options) } window.addTitle2Star(); + window.addDivider(); window.initFilterPanel(); } @@ -41,6 +42,13 @@ window.addTitle2Star = function() $('.metric-collect').attr('title', collectStar); } +window.addDivider = function() +{ + let features = $('#featureBar .nav-feature').find('li.nav-item'); + let lastItem = features[features.length - 1]; + $(lastItem).addClass('divider-before'); +} + /* 事件处理函数。 */ window.handleCheckboxChange = function($el) { From c4db188aecfadf728de111be24f6797c52eba256 Mon Sep 17 00:00:00 2001 From: xieqiyu Date: Tue, 23 Apr 2024 11:04:10 +0800 Subject: [PATCH 095/141] * Restore code. --- module/my/control.php | 1 + 1 file changed, 1 insertion(+) diff --git a/module/my/control.php b/module/my/control.php index 406f831e90..620c73a30f 100755 --- a/module/my/control.php +++ b/module/my/control.php @@ -140,6 +140,7 @@ class my extends control $this->session->set('todoList', $uri, 'my'); $this->session->set('bugList', $uri, 'my'); $this->session->set('taskList', $uri, 'my'); + $this->session->set('storyList', $uri, 'my'); $this->session->set('testtaskList', $uri, 'my'); /* Load pager. */ From e7b323b7efdec3ebc62751afd45d63938f19d1f4 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Tue, 23 Apr 2024 11:15:32 +0800 Subject: [PATCH 096/141] + Add min width for resolvedBuild picker items in bug::resolve. --- module/bug/ui/resolve.html.php | 1 + 1 file changed, 1 insertion(+) diff --git a/module/bug/ui/resolve.html.php b/module/bug/ui/resolve.html.php index 9531b6c55c..4091802c61 100644 --- a/module/bug/ui/resolve.html.php +++ b/module/bug/ui/resolve.html.php @@ -94,6 +94,7 @@ formPanel ( set::popWidth('auto'), set::popMaxWidth('300px'), + set::popMinWidth('145px'), set::name('resolvedBuild'), set::value(''), set::items($builds) From 811106d95c69447c7828983f631885d8e4ef6eab Mon Sep 17 00:00:00 2001 From: xieqiyu Date: Tue, 23 Apr 2024 11:19:06 +0800 Subject: [PATCH 097/141] * Fix bug#48164. --- module/story/config/form.php | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/module/story/config/form.php b/module/story/config/form.php index 0c5ebadb4d..f0f40c56b2 100644 --- a/module/story/config/form.php +++ b/module/story/config/form.php @@ -73,26 +73,26 @@ $config->story->form->edit['duplicateStory'] = array('type' => 'int', 'contr $config->story->form->edit['childStories'] = array('type' => 'array', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array(), 'filter' => 'join'); $config->story->form->batchCreate = array(); -$config->story->form->batchCreate['branch'] = array('ditto' => true, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => 0, 'options' => array()); -$config->story->form->batchCreate['module'] = array('ditto' => true, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => 0, 'options' => array()); -$config->story->form->batchCreate['plan'] = array('ditto' => true, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => 0, 'options' => array()); -$config->story->form->batchCreate['assignedTo'] = array('ditto' => false, 'type' => 'string', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => '', 'options' => 'users'); -$config->story->form->batchCreate['region'] = array('ditto' => false, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => 0, 'options' => array()); -$config->story->form->batchCreate['lane'] = array('ditto' => false, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => 0, 'options' => array()); -$config->story->form->batchCreate['title'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => true, 'width' => '240px', 'default' => '', 'filter' => 'trim', 'base' => true); -$config->story->form->batchCreate['color'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'default' => '', 'filter' => 'trim'); -$config->story->form->batchCreate['spec'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '240px', 'default' => ''); -$config->story->form->batchCreate['source'] = array('ditto' => true, 'type' => 'string', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => '', 'options' => $lang->story->sourceList); -$config->story->form->batchCreate['sourceNote'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '200px', 'default' => '', 'filter' => 'trim'); -$config->story->form->batchCreate['verify'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '200px', 'default' => ''); -$config->story->form->batchCreate['category'] = array('ditto' => true, 'type' => 'string', 'control' => 'select', 'required' => false, 'width' => '160px', 'default' => 'feature', 'options' => $lang->story->categoryList); -$config->story->form->batchCreate['pri'] = array('ditto' => false, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '92px', 'default' => $config->story->defaultPriority, 'options' => $lang->story->priList); -$config->story->form->batchCreate['estimate'] = array('ditto' => false, 'type' => 'float', 'control' => 'text', 'required' => false, 'width' => '76px', 'default' => 0); -$config->story->form->batchCreate['reviewer'] = array('ditto' => true, 'type' => 'array', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => '', 'multiple' => true, 'options' => array()); -$config->story->form->batchCreate['URS'] = array('ditto' => false, 'type' => 'array', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => '', 'multiple' => true); -$config->story->form->batchCreate['parent'] = array('ditto' => false, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => ''); -$config->story->form->batchCreate['keywords'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '200px', 'default' => ''); -$config->story->form->batchCreate['mailto'] = array('ditto' => false, 'type' => 'array', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => array(''), 'multiple' => true, 'options' => 'users', 'filter' => 'join'); +$config->story->form->batchCreate['branch'] = array('ditto' => true, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => 0, 'options' => array()); +$config->story->form->batchCreate['module'] = array('ditto' => true, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => 0, 'options' => array()); +$config->story->form->batchCreate['plan'] = array('ditto' => true, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => 0, 'options' => array()); +$config->story->form->batchCreate['assignedTo'] = array('ditto' => false, 'type' => 'string', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => '', 'options' => 'users'); +$config->story->form->batchCreate['region'] = array('ditto' => false, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => 0, 'options' => array()); +$config->story->form->batchCreate['lane'] = array('ditto' => false, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => 0, 'options' => array()); +$config->story->form->batchCreate['title'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => true, 'width' => '240px', 'default' => '', 'filter' => 'trim', 'base' => true); +$config->story->form->batchCreate['color'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'default' => '', 'filter' => 'trim'); +$config->story->form->batchCreate['spec'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '240px', 'default' => ''); +$config->story->form->batchCreate['source'] = array('ditto' => true, 'type' => 'string', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => '', 'options' => $lang->story->sourceList); +$config->story->form->batchCreate['sourceNote'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '200px', 'default' => '', 'filter' => 'trim'); +$config->story->form->batchCreate['verify'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '200px', 'default' => ''); +$config->story->form->batchCreate['category'] = array('ditto' => true, 'type' => 'string', 'control' => 'select', 'required' => false, 'width' => '160px', 'default' => 'feature', 'options' => $lang->story->categoryList); +$config->story->form->batchCreate['pri'] = array('ditto' => false, 'type' => 'int', 'control' => 'priPicker', 'required' => false, 'width' => '92px', 'default' => $config->story->defaultPriority, 'options' => $lang->story->priList); +$config->story->form->batchCreate['estimate'] = array('ditto' => false, 'type' => 'float', 'control' => 'text', 'required' => false, 'width' => '76px', 'default' => 0); +$config->story->form->batchCreate['reviewer'] = array('ditto' => true, 'type' => 'array', 'control' => 'select', 'required' => false, 'width' => '136px', 'default' => '', 'multiple' => true, 'options' => array()); +$config->story->form->batchCreate['URS'] = array('ditto' => false, 'type' => 'array', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => '', 'multiple' => true); +$config->story->form->batchCreate['parent'] = array('ditto' => false, 'type' => 'int', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => ''); +$config->story->form->batchCreate['keywords'] = array('ditto' => false, 'type' => 'string', 'control' => 'text', 'required' => false, 'width' => '200px', 'default' => ''); +$config->story->form->batchCreate['mailto'] = array('ditto' => false, 'type' => 'array', 'control' => 'select', 'required' => false, 'width' => '200px', 'default' => array(''), 'multiple' => true, 'options' => 'users', 'filter' => 'join'); $config->story->form->batchEdit = array(); $config->story->form->batchEdit['branch'] = array('type' => 'int', 'width' => '200px', 'control' => 'picker', 'required' => false, 'default' => 0, 'options' => array()); From d9c2ffc08adad1a335b73cd347adffe737ebb8bc Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Tue, 23 Apr 2024 13:02:02 +0800 Subject: [PATCH 098/141] * Adjust gitlab project path get logic. --- module/gitlab/model.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/module/gitlab/model.php b/module/gitlab/model.php index 9ce1d89118..9f3abe8f17 100644 --- a/module/gitlab/model.php +++ b/module/gitlab/model.php @@ -2332,18 +2332,18 @@ class gitlabModel extends model * @param int $projectID * @param int $repoID * @access public - * @return bool + * @return string */ - public function updateCodePath(int $gitlabID, int $projectID, int $repoID): bool + public function updateCodePath(int $gitlabID, int $projectID, int $repoID): string { $project = $this->apiGetSingleProject($gitlabID, $projectID); if(is_object($project) and !empty($project->web_url)) { $this->dao->update(TABLE_REPO)->set('path')->eq($project->web_url)->where('id')->eq($repoID)->exec(); - return true; + return $project->web_url; } - return false; + return ''; } /** @@ -2417,6 +2417,7 @@ class gitlabModel extends model if(!$gitlab) return array(); /* Compatible with HTTP and HTTPS domain. */ + if(strpos($repo->codePath, '/api/v4/projects')) $repo->codePath = $this->updateCodePath((int)$repo->serviceHost, (int)$repo->serviceProject, $repo->id); $repo->client = str_replace('https://', 'http://', $repo->client); $repo->codePath = str_replace('https://', 'http://', $repo->codePath); From 52e9e41e2f4ab36b09fa2fc8e9ef15c2c1f36126 Mon Sep 17 00:00:00 2001 From: tanghucheng Date: Tue, 23 Apr 2024 13:26:38 +0800 Subject: [PATCH 099/141] * Fix bug #47791. --- module/product/ui/browse.html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/product/ui/browse.html.php b/module/product/ui/browse.html.php index c6149aa899..5e99174ec8 100644 --- a/module/product/ui/browse.html.php +++ b/module/product/ui/browse.html.php @@ -327,8 +327,8 @@ featureBar toolbar ( - (!hasPriv('story', 'report') || !$productID) ? null : item(set(array('id' => 'reportBtn', 'text' => $lang->story->report->common, 'icon' => 'bar-chart', 'class' => 'ghost', 'url' => helper::createLink('story', 'report', "productID=$productID&branchID=$branch&storyType=$storyType&browseType=$browseType&moduleID=$moduleID&chartType=pie&projectID=$projectID") . ($app->tab == 'project' ? '#app=project' : '')))), - !hasPriv('story', 'export') ? null : item(set(array('id' => 'exportBtn', 'text' => $lang->export, 'icon' => 'export', 'class' => 'ghost', 'url' => helper::createLink('story', 'export', "productID=$productID&orderBy=$orderBy&executionID=$projectID&browseType=$browseType&storyType=$storyType"), 'data-toggle' => 'modal'))), + (!hasPriv('story', 'report') || !$productID) ? null : item(set(array('id' => 'reportBtn', 'icon' => 'bar-chart', 'class' => 'ghost', 'url' => helper::createLink('story', 'report', "productID=$productID&branchID=$branch&storyType=$storyType&browseType=$browseType&moduleID=$moduleID&chartType=pie&projectID=$projectID") . ($app->tab == 'project' ? '#app=project' : '')))), + !hasPriv('story', 'export') ? null : item(set(array('id' => 'exportBtn', 'icon' => 'export', 'class' => 'ghost', 'url' => helper::createLink('story', 'export', "productID=$productID&orderBy=$orderBy&executionID=$projectID&browseType=$browseType&storyType=$storyType"), 'data-toggle' => 'modal'))), $fnBuildCreateStoryButton(), $fnBuildLinkStoryButton() ); From 91270828ca27ae0cfd5c30c27f987afac026a209 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 23 Apr 2024 13:28:12 +0800 Subject: [PATCH 100/141] * Fix can't get user account problem. --- framework/router.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/router.class.php b/framework/router.class.php index ca90bddbec..a6871a87d1 100755 --- a/framework/router.class.php +++ b/framework/router.class.php @@ -296,7 +296,7 @@ class router extends baseRouter $config->executionLink = 'execution-task'; /* Get user preference. */ - $account = $this->session->user->account ?? ''; + $account = $_SESSION['user']->account ?? ''; $userSetting = array(); if($this->dbh and !empty($this->config->db->name) and $account) { From bda373dab2115bd9812f4601cdf91719f3d87d9b Mon Sep 17 00:00:00 2001 From: hufangzhou Date: Tue, 23 Apr 2024 13:39:04 +0800 Subject: [PATCH 101/141] * Fix bug #48174. --- module/block/zen.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/module/block/zen.php b/module/block/zen.php index 0b70983361..f1e20310f3 100644 --- a/module/block/zen.php +++ b/module/block/zen.php @@ -2147,6 +2147,9 @@ class blockZen extends block $this->view->depts = $this->loadModel('dept')->getOptionMenu(); } + /* Compatible with the logic of the back button on the old page. */ + $this->session->set('demandList', $this->createLink('my', 'index'), 'my'); + $this->view->users = $this->loadModel('user')->getPairs('all,noletter'); $this->view->isExternalCall = $this->isExternalCall(); $this->view->hasViewPriv = $hasViewPriv; From 544802161fd1841277f9ff65fd30a8996f8ed8e3 Mon Sep 17 00:00:00 2001 From: liugang Date: Tue, 23 Apr 2024 13:45:38 +0800 Subject: [PATCH 102/141] * treeModel: modify tables order to use index. --- module/tree/model.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/module/tree/model.php b/module/tree/model.php index d42f66fff8..c0325815b3 100644 --- a/module/tree/model.php +++ b/module/tree/model.php @@ -1020,15 +1020,15 @@ class treeModel extends model $table2 = TABLE_CASE; } - $paths = $this->dao->select("t3.{$field}")->from($table1)->alias('t1') - ->leftJoin($table2)->alias('t2')->on('t1.' . $linkObject . ' = t2.id') - ->leftJoin(TABLE_MODULE)->alias('t3')->on('t2.module = t3.id') - ->leftJoin(TABLE_PROJECT)->alias('t4')->on('t1.project = t4.id') + $paths = $this->dao->select("t4.{$field}")->from(TABLE_PROJECT)->alias('t1') + ->leftJoin($table1)->alias('t2')->on('t1.id=t2.project') + ->leftJoin($table2)->alias('t3')->on("t2.{$linkObject}=t3.id") + ->leftJoin(TABLE_MODULE)->alias('t4')->on('t3.module=t4.id') ->where('t3.deleted')->eq(0) - ->andWhere('t2.deleted')->eq(0) - ->andWhere("(t1.project = '{$executionID}' OR t4.project = '{$executionID}')") - ->beginIF(isset($extra['branchID']) && $branch !== 'all')->andWhere('t2.branch')->eq($branch)->fi() - ->fetchPairs($field, $field); + ->andWhere('t4.deleted')->eq(0) + ->andWhere('t1.project', true)->eq($executionID)->orWhere('t2.project')->eq($executionID)->markRight(1) + ->beginIF(isset($extra['branchID']) && $branch !== 'all')->andWhere('t3.branch')->eq($branch)->fi() + ->fetchPairs(); } elseif($linkObject == 'bug' && str_contains(',project,execution,', ",{$this->app->tab},")) { @@ -1038,7 +1038,7 @@ class treeModel extends model ->andWhere('t2.deleted')->eq(0) ->beginIF(isset($extra['branchID']) && $branch !== 'all')->andWhere('t1.branch')->eq($branch)->fi() ->andWhere("t1.{$this->app->tab}")->eq($executionID) - ->fetchPairs($field, $field); + ->fetchPairs(); } else { From de5df7fbc3354d91c847f6a39f6bed534bca564b Mon Sep 17 00:00:00 2001 From: liumengyi Date: Tue, 23 Apr 2024 13:49:25 +0800 Subject: [PATCH 103/141] * Fix bug. --- module/group/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/group/model.php b/module/group/model.php index e1ea4f5a4d..0678ecdd45 100644 --- a/module/group/model.php +++ b/module/group/model.php @@ -867,7 +867,7 @@ class groupModel extends model if(isset($privs[$dependPriv]) || in_array($dependPriv, $excludes)) continue; $privs[$dependPriv] = $dependPriv; - $dependPrivs = $this->processDepends($depends, $depends[$dependPriv], $excludes, $processedPrivs); + $dependPrivs = $this->processDepends($depends, zget($depends, $dependPriv, array()), $excludes, $processedPrivs); foreach($dependPrivs as $depend) { From b1270f87a07c4d535add740cb5d793eb12c21e1f Mon Sep 17 00:00:00 2001 From: liumengyi Date: Tue, 23 Apr 2024 14:00:07 +0800 Subject: [PATCH 104/141] * Fix bug #48132, show browse feedback pri package. --- module/group/lang/de.php | 1 + module/group/lang/en.php | 1 + module/group/lang/fr.php | 1 + module/group/lang/zh-cn.php | 1 + module/group/packagemanager.php | 1 + 5 files changed, 5 insertions(+) diff --git a/module/group/lang/de.php b/module/group/lang/de.php index f32d2683ad..491c62d393 100644 --- a/module/group/lang/de.php +++ b/module/group/lang/de.php @@ -315,6 +315,7 @@ $lang->group->package->lieu = 'Lieu'; $lang->group->package->holiday = 'Holiday'; $lang->group->package->exportOffice = 'Export Office'; $lang->group->package->browseFeedback = 'Browse Feedback'; +$lang->group->package->browseLiteFeedback = $lang->group->package->browseFeedback; $lang->group->package->manageFeedback = 'Manage Feedback'; $lang->group->package->importFeedback = 'Import Feedback'; $lang->group->package->handleFeedback = 'Handle Feedback'; diff --git a/module/group/lang/en.php b/module/group/lang/en.php index ea357ed1a1..7878db6f51 100644 --- a/module/group/lang/en.php +++ b/module/group/lang/en.php @@ -315,6 +315,7 @@ $lang->group->package->lieu = 'Lieu'; $lang->group->package->holiday = 'Holiday'; $lang->group->package->exportOffice = 'Export Office'; $lang->group->package->browseFeedback = 'Browse Feedback'; +$lang->group->package->browseLiteFeedback = $lang->group->package->browseFeedback; $lang->group->package->manageFeedback = 'Manage Feedback'; $lang->group->package->importFeedback = 'Import Feedback'; $lang->group->package->handleFeedback = 'Handle Feedback'; diff --git a/module/group/lang/fr.php b/module/group/lang/fr.php index 6678bd154e..70fcd36088 100644 --- a/module/group/lang/fr.php +++ b/module/group/lang/fr.php @@ -315,6 +315,7 @@ $lang->group->package->lieu = 'Lieu'; $lang->group->package->holiday = 'Holiday'; $lang->group->package->exportOffice = 'Export Office'; $lang->group->package->browseFeedback = 'Browse Feedback'; +$lang->group->package->browseLiteFeedback = $lang->group->package->browseFeedback; $lang->group->package->manageFeedback = 'Manage Feedback'; $lang->group->package->importFeedback = 'Import Feedback'; $lang->group->package->handleFeedback = 'Handle Feedback'; diff --git a/module/group/lang/zh-cn.php b/module/group/lang/zh-cn.php index 0532aea15e..b3a37b3f3e 100644 --- a/module/group/lang/zh-cn.php +++ b/module/group/lang/zh-cn.php @@ -315,6 +315,7 @@ $lang->group->package->lieu = '个人调休'; $lang->group->package->holiday = '节假日'; $lang->group->package->exportOffice = '办公导出'; $lang->group->package->browseFeedback = '浏览反馈'; +$lang->group->package->browseLiteFeedback = $lang->group->package->browseFeedback; $lang->group->package->manageFeedback = '创建维护反馈'; $lang->group->package->importFeedback = '导入导出反馈'; $lang->group->package->handleFeedback = '处理反馈'; diff --git a/module/group/packagemanager.php b/module/group/packagemanager.php index b32812e939..4c090e8c80 100644 --- a/module/group/packagemanager.php +++ b/module/group/packagemanager.php @@ -1519,6 +1519,7 @@ $config->group->package->browseLiteFeedback->subset = 'feedback'; $config->group->package->browseLiteFeedback->privs = array(); $config->group->package->browseLiteFeedback->privs['feedback-view'] = array('edition' => 'biz,max,ipd', 'vision' => 'lite', 'order' => 25, 'depend' => array('feedback-browse'), 'recommend' => array('feedback-create', 'feedback-edit')); $config->group->package->browseLiteFeedback->privs['feedback-browse'] = array('edition' => 'biz,max,ipd', 'vision' => 'lite', 'order' => 30, 'depend' => array(), 'recommend' => array('feedback-view')); + $config->group->package->manageFeedback = new stdclass(); $config->group->package->manageFeedback->order = 10; $config->group->package->manageFeedback->subset = 'feedback'; From 7a5791fa62c4348fa4e81f4cc5ac5b0006e83824 Mon Sep 17 00:00:00 2001 From: liugang Date: Tue, 23 Apr 2024 14:02:57 +0800 Subject: [PATCH 105/141] + baseHelper: cache loaded directories to improve effeciency. --- framework/base/helper.class.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/framework/base/helper.class.php b/framework/base/helper.class.php index 2f39a16bd8..a1eb4cfca2 100644 --- a/framework/base/helper.class.php +++ b/framework/base/helper.class.php @@ -15,6 +15,17 @@ declare(strict_types=1); */ class baseHelper { + + /** + * 已加载的目录. + * The loaded directories. + * + * @static + * @var array + * @access public + */ + static $loadedDirs = array(); + /** * 设置一个对象的成员变量。 * Set the member's value of one object. @@ -665,6 +676,7 @@ class baseHelper static public function ls($dir, $pattern = '') { if(empty($dir)) return array(); + if(isset(self::$loadedDirs[$dir][$pattern])) return self::$loadedDirs[$dir][$pattern]; $files = array(); $dir = realpath($dir); @@ -672,7 +684,10 @@ class baseHelper if($dir === false) return array(); if(is_dir($dir)) $files = glob($dir . DIRECTORY_SEPARATOR . '*' . $pattern); - return empty($files) ? array() : $files; + + self::$loadedDirs[$dir][$pattern] = $files ?: array(); + + return self::$loadedDirs[$dir][$pattern]; } /** From 3489d4245980810eabeb067f2bea30c5fee02779 Mon Sep 17 00:00:00 2001 From: liugang Date: Tue, 23 Apr 2024 14:03:44 +0800 Subject: [PATCH 106/141] + baseRouter: cache loaded modules to improve effeciency. --- framework/base/router.class.php | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/framework/base/router.class.php b/framework/base/router.class.php index 3e6a949954..72a1b6e3ff 100644 --- a/framework/base/router.class.php +++ b/framework/base/router.class.php @@ -287,6 +287,16 @@ class baseRouter */ static $loadedLangs = array(); + /** + * 已加载的模块. + * Modules loaded. + * + * @static + * @var array + * @access public + */ + static $loadedModules = array(); + /** * 全局$lang对象。 * The global $lang object. @@ -2918,30 +2928,35 @@ class baseRouter * 加载语言文件,返回全局$lang对象。 * Load lang and return it as the global lang object. * - * @param string $moduleName the module name + * @param string $moduleName the module name * @param string $appName the app name * @access public - * @return bool|object the lang object or false. + * @return object the lang object */ - public function loadLang(string $moduleName, string $appName = ''): bool|object + public function loadLang(string $moduleName, string $appName = ''): object { - /* 计算最终要加载的语言文件。 Get the lang files to be loaded. */ - $langFilesToLoad = $this->getMainAndExtFiles($moduleName, $appName, 'lang'); - if(empty($langFilesToLoad)) return false; - /* 加载语言文件。Load lang files. */ global $lang; if(!is_object($lang)) $lang = new language(); if(!isset($lang->$moduleName)) $lang->$moduleName = new stdclass(); + if(isset(self::$loadedModules[$moduleName])) return $lang; + + self::$loadedModules[$moduleName] = $moduleName; + + /* 计算最终要加载的语言文件。 Get the lang files to be loaded. */ + $langFilesToLoad = $this->getMainAndExtFiles($moduleName, $appName, 'lang'); + if(empty($langFilesToLoad)) return $lang; + foreach($langFilesToLoad as $langFile) { - if(in_array($langFile, self::$loadedLangs)) continue; + if(isset(self::$loadedLangs[$langFile])) continue; include $langFile; - self::$loadedLangs[] = $langFile; + self::$loadedLangs[$langFile] = $langFile; } $this->lang = $lang; + return $lang; } From 298c687ea70d586bcd67f6793e2657e1b8a0d471 Mon Sep 17 00:00:00 2001 From: liugang Date: Tue, 23 Apr 2024 14:08:40 +0800 Subject: [PATCH 107/141] * router: compatible with baseRouter. --- framework/router.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/router.class.php b/framework/router.class.php index a6871a87d1..82bd9b707e 100755 --- a/framework/router.class.php +++ b/framework/router.class.php @@ -122,9 +122,9 @@ class router extends baseRouter * @param string $moduleName the module name * @param string $appName the app name * @access public - * @return bool|object the lang object or false. + * @return object the lang object or false. */ - public function loadLang($moduleName, $appName = ''): bool|object + public function loadLang($moduleName, $appName = ''): object { global $lang; if(!is_object($lang)) $lang = new language(); From 164b92947cfdcf4d7de26b3d0de70ceced70d149 Mon Sep 17 00:00:00 2001 From: xieqiyu Date: Tue, 23 Apr 2024 14:12:10 +0800 Subject: [PATCH 108/141] * Fix bug#46975. --- module/story/ui/view.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/story/ui/view.html.php b/module/story/ui/view.html.php index 333663caca..b23188993c 100644 --- a/module/story/ui/view.html.php +++ b/module/story/ui/view.html.php @@ -195,7 +195,7 @@ foreach($actions as $key => $action) continue; } - if(isset($action['url'])) $actions[$key]['url'] = str_replace(array('{id}', '{type}', '{product}', '{branch}', '{module}', '{execution}'), array($story->id, $story->type, $story->product, $story->branch, $story->module, $executionID), $action['url']); + if(isset($action['url'])) $actions[$key]['url'] = str_replace(array('{id}', '{type}', '{product}', '{branch}', '{module}', '{execution}'), array($story->id, $story->type, $story->product, $story->branch, $story->module, $projectID), $action['url']); if(isset($action['items'])) { foreach($action['items'] as $itemKey => $itemAction) From e42dc9570d058749ffc4bf574589b2ce8d92e6e6 Mon Sep 17 00:00:00 2001 From: hufangzhou Date: Tue, 23 Apr 2024 14:20:22 +0800 Subject: [PATCH 109/141] - Fix bug #48155. --- module/my/ui/task.html.php | 1 - 1 file changed, 1 deletion(-) diff --git a/module/my/ui/task.html.php b/module/my/ui/task.html.php index 02377dcb63..157bac5005 100644 --- a/module/my/ui/task.html.php +++ b/module/my/ui/task.html.php @@ -32,7 +32,6 @@ $footToolbar = array('items' => array $canBatchClose ? array('text' => $lang->close, 'className' => 'batch-btn ajax-btn', 'data-url' => helper::createLink('task', 'batchClose')) : null ), 'btnProps' => array('size' => 'sm', 'btnType' => 'secondary')); -if($type == 'bySearch') $type = $this->session->myTaskType; if($type == 'assignedTo') unset($config->my->task->dtable->fieldList['assignedTo']); if($type == 'openedBy') unset($config->my->task->dtable->fieldList['openedBy']); if($type == 'finishedBy') unset($config->my->task->dtable->fieldList['finishedBy']); From 64395c5e628a35029274dd522539d81cc007da31 Mon Sep 17 00:00:00 2001 From: xieqiyu Date: Tue, 23 Apr 2024 14:26:40 +0800 Subject: [PATCH 110/141] * Fix bug#46975. --- module/story/ui/view.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/story/ui/view.html.php b/module/story/ui/view.html.php index b23188993c..b817b84583 100644 --- a/module/story/ui/view.html.php +++ b/module/story/ui/view.html.php @@ -195,7 +195,7 @@ foreach($actions as $key => $action) continue; } - if(isset($action['url'])) $actions[$key]['url'] = str_replace(array('{id}', '{type}', '{product}', '{branch}', '{module}', '{execution}'), array($story->id, $story->type, $story->product, $story->branch, $story->module, $projectID), $action['url']); + if(isset($action['url'])) $actions[$key]['url'] = str_replace(array('{id}', '{type}', '{product}', '{branch}', '{module}', '{execution}'), array($story->id, $story->type, $story->product, $story->branch, $story->module, isset($projectID) ? $projectID : 0), $action['url']); if(isset($action['items'])) { foreach($action['items'] as $itemKey => $itemAction) From a4ee3bc02d0b365c73d1d684bfe93d2ea7fc823a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 23 Apr 2024 14:27:13 +0800 Subject: [PATCH 111/141] * Code for bug #48107. --- module/backup/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/backup/model.php b/module/backup/model.php index cdc50b700c..852d7f89be 100644 --- a/module/backup/model.php +++ b/module/backup/model.php @@ -439,7 +439,7 @@ class backupModel extends model if(!file_exists($dir)) return 0; if(!is_readable($dir)) return 0; $totalSize = 0; - $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)); + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD); foreach($iterator as $file) $totalSize += $file->getSize(); return $totalSize; From cfa7f30f3bfb8b608b31009c9afe43740ac5e19d Mon Sep 17 00:00:00 2001 From: wangyuting Date: Tue, 23 Apr 2024 14:28:09 +0800 Subject: [PATCH 112/141] * Fix project review title link. bug #48139. --- module/block/ui/assigntomeblock.html.php | 5 +++-- module/my/js/audit.ui.js | 4 ++++ module/my/ui/audit.html.php | 21 ++------------------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/module/block/ui/assigntomeblock.html.php b/module/block/ui/assigntomeblock.html.php index 92bdef8632..20412dd0aa 100644 --- a/module/block/ui/assigntomeblock.html.php +++ b/module/block/ui/assigntomeblock.html.php @@ -88,14 +88,15 @@ foreach($hasViewPriv as $type => $bool) $statusList = array(); foreach($data as $review) { - $review->module = $review->type; - $reviewType = $review->type; if($reviewType == 'projectreview') $reviewType = 'review'; + $review->module = $reviewType; + $typeName = ''; if(isset($lang->{$review->type}->common)) $typeName = $lang->{$review->type}->common; if($reviewType == 'story') $typeName = $review->storyType == 'story' ? $lang->SRCommon : $lang->URCommon; + if($review->type == 'projectreview') $typeName = $lang->project->common; if(isset($lang->$reviewType->statusList)) $statusList = array_merge($statusList, $lang->$reviewType->statusList); if($reviewType == 'attend') $statusList = array_merge($statusList, $lang->attend->reviewStatusList); diff --git a/module/my/js/audit.ui.js b/module/my/js/audit.ui.js index 9c54163578..6b2b11477a 100644 --- a/module/my/js/audit.ui.js +++ b/module/my/js/audit.ui.js @@ -17,6 +17,10 @@ window.onRenderCell = function(result, {row, col}) delete result[0].props.items[0]['href']; } } + if(result && col.name == 'title' && row.data.module == 'review') + { + result[0].props['data-toggle'] = 'normal'; + } return result; } diff --git a/module/my/ui/audit.html.php b/module/my/ui/audit.html.php index b753a01daf..284f0a9bbb 100644 --- a/module/my/ui/audit.html.php +++ b/module/my/ui/audit.html.php @@ -35,10 +35,10 @@ if($rawMethod != 'contribute' || $browseType != 'reviewedbyme') unset($config->m foreach($reviewList as $review) { - $type = $review->type == 'prejectreview' ? 'review' : $review->type; + $type = $review->type == 'projectreview' ? 'review' : $review->type; $isOAObject = strpos(",{$config->my->oaObjectType},", ",$type,") !== false ? true : false; - $review->module = $review->type; + $review->module = $type; if(isset($lang->{$review->type}->common)) $typeName = $lang->{$review->type}->common; if($type == 'story') $typeName = $review->storyType == 'story' ? $lang->SRCommon : $lang->URCommon; @@ -71,23 +71,6 @@ foreach($reviewList as $review) $review->result = zget($reviewResultList, $review->result); } - - $module = $type; - $method = 'review'; - $params = "id=$review->id"; - - if($isOAObject) $method = 'view'; - if(!in_array($module, array('demand', 'story', 'testcase', 'feedback'))) $method = 'approvalreview'; - - if($module == 'review') - { - $method = 'assess'; - $params .= "&from={$rawMethod}"; - - unset($config->my->audit->actionList['review']['data-toggle']); - } - - $config->my->audit->actionList['review']['url'] = createLink($module, 'view', "id={$review->id}"); } $reviewList = initTableData($reviewList, $config->my->audit->dtable->fieldList, $this->my); From c654a285d55b4c4cbcfc918a11f113c2ca115fdb Mon Sep 17 00:00:00 2001 From: liugang Date: Tue, 23 Apr 2024 14:29:38 +0800 Subject: [PATCH 113/141] * testcaseUI: display link to create scene if the browseType is onlyscene and there's no scene, fix bug #48068. --- module/testcase/lang/zh-cn.php | 2 +- module/testcase/ui/browse.html.php | 6 +++--- module/testcase/ui/header.html.php | 13 ++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/module/testcase/lang/zh-cn.php b/module/testcase/lang/zh-cn.php index ba9ac75ba6..7cb17501a7 100644 --- a/module/testcase/lang/zh-cn.php +++ b/module/testcase/lang/zh-cn.php @@ -352,7 +352,7 @@ $lang->testcase->onlyAutomated = '仅自动化'; $lang->testcase->onlyScene = '仅场景'; $lang->testcase->iScene = '所属场景'; $lang->testcase->generalTitle = '标题'; -$lang->testcase->noScene = '暂时没有场景'; +$lang->testcase->noScene = '暂时没有场景。'; $lang->testcase->rowIndex = '行索引'; $lang->testcase->nestTotal = '嵌套总数'; $lang->testcase->normal = '正常'; diff --git a/module/testcase/ui/browse.html.php b/module/testcase/ui/browse.html.php index 80e894351b..5cf058087d 100644 --- a/module/testcase/ui/browse.html.php +++ b/module/testcase/ui/browse.html.php @@ -150,9 +150,9 @@ div( set::nested(true), set::footToolbar($footToolbar), set::footPager(usePager()), - set::emptyTip($lang->testcase->noCase), - set::createTip($lang->testcase->create), - set::createLink($canModify && hasPriv('testcase', 'create') ? createLink('testcase', 'create', 'productID=' . zget($product, 'id', 0) . "&branch={$branch}&moduleID={$moduleID}" . ($app->tab == 'project' ? "&from=project¶m={$projectID}" : '')) : ''), + set::emptyTip($browseType == 'onlyscene' ? $lang->testcase->noScene : $lang->testcase->noCase), + set::createTip($browseType == 'onlyscene' ? $lang->testcase->createScene : $lang->testcase->create), + set::createLink($browseType == 'onlyscene' ? ($canCreateScene ? $createSceneLink : '') : ($canCreateCase ? $createCaseLink : '')), set::customData(array('isOnlyScene' => $isOnlyScene, 'pageSummary' => $summary, 'modules' => $modulePairs)) ) ); diff --git a/module/testcase/ui/header.html.php b/module/testcase/ui/header.html.php index e9a048552e..635a91bd37 100644 --- a/module/testcase/ui/header.html.php +++ b/module/testcase/ui/header.html.php @@ -227,21 +227,20 @@ if(!empty($productID)) $createItems = array(); if($canCreateCase) { - $params = "productID={$productID}&branch={$branch}&moduleID={$moduleID}"; - if($app->tab == 'project') $params .= "&from=project¶m={$projectID}"; - $createItems[] = array('text' => $lang->testcase->create, 'url' => createLink('testcase', 'create', $params), 'data-app' => $app->tab); + $createCaseLink = createLink('testcase', 'create', "productID={$productID}&branch={$branch}&moduleID={$moduleID}" . ($app->tab == 'project' ? "&from=project¶m={$projectID}" : '')); + $createItems[] = array('text' => $lang->testcase->create, 'url' => $createCaseLink, 'data-app' => $app->tab); } if($canBatchCreateCase) { - $link = createLink('testcase', 'batchCreate', "productID=$productID&branch=$branch&moduleID=$moduleID"); - $createItems[] = array('text' => $lang->testcase->batchCreate, 'url' => $link, 'data-app' => $app->tab); + $batchCreateCaseLink = createLink('testcase', 'batchCreate', "productID=$productID&branch=$branch&moduleID=$moduleID"); + $createItems[] = array('text' => $lang->testcase->batchCreate, 'url' => $batchCreateCaseLink, 'data-app' => $app->tab); } if($canCreateScene) { - $link = createLink('testcase', 'createScene', "productID=$productID&branch=$branch&moduleID=$moduleID"); - $createItems[] = array('text' => $lang->testcase->newScene, 'url' => $link, 'data-app' => $app->tab); + $createSceneLink = createLink('testcase', 'createScene', "productID=$productID&branch=$branch&moduleID=$moduleID"); + $createItems[] = array('text' => $lang->testcase->newScene, 'url' => $createSceneLink, 'data-app' => $app->tab); } $currentCreateItem = current($createItems); From ef63d8a984737aba213cfead2ad25de5be59687e Mon Sep 17 00:00:00 2001 From: wangyuting Date: Tue, 23 Apr 2024 14:29:32 +0800 Subject: [PATCH 114/141] * Adjust normal to empty. --- module/my/js/audit.ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/my/js/audit.ui.js b/module/my/js/audit.ui.js index 6b2b11477a..6bf185dad9 100644 --- a/module/my/js/audit.ui.js +++ b/module/my/js/audit.ui.js @@ -19,7 +19,7 @@ window.onRenderCell = function(result, {row, col}) } if(result && col.name == 'title' && row.data.module == 'review') { - result[0].props['data-toggle'] = 'normal'; + result[0].props['data-toggle'] = ''; } return result; } From f43c138a46967aa4700766c4d1872b3574d7d630 Mon Sep 17 00:00:00 2001 From: xieqiyu Date: Tue, 23 Apr 2024 14:40:21 +0800 Subject: [PATCH 115/141] * Fix bug#47948. --- module/story/ui/edit.html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/story/ui/edit.html.php b/module/story/ui/edit.html.php index 6bcc6c00c4..01758319ab 100644 --- a/module/story/ui/edit.html.php +++ b/module/story/ui/edit.html.php @@ -394,13 +394,13 @@ detailBody item ( set::name(' '), - !empty($story->linkStoryTitles) ? h::ul + !empty($story->linkStoryTitles) ? div ( setID('linkedStories'), array_values(array_map(function($linkStoryID, $linkStoryTitle) use($story) { $linkStoryField = $story->type == 'story' ? 'linkStories' : 'linkRequirements'; - return h::li + return div ( set::title($linkStoryTitle), checkbox(set::name($linkStoryField . '[]'), set::rootClass('inline'), set::value($linkStoryID), set::checked(true)), From 533e8e60b84489242ee00ce5cc815478786a185c Mon Sep 17 00:00:00 2001 From: sunhao Date: Tue, 23 Apr 2024 14:42:19 +0800 Subject: [PATCH 116/141] * my: fix main menu not update after update dtable. --- module/my/js/common.ui.js | 43 ++++++++++++++++++++++-------------- module/my/ui/header.html.php | 17 ++++++++------ 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/module/my/js/common.ui.js b/module/my/js/common.ui.js index dde83f23b8..13705ac3b1 100644 --- a/module/my/js/common.ui.js +++ b/module/my/js/common.ui.js @@ -1,20 +1,31 @@ -$(function() +window.updateMainNavbarBadges = function(options) { - if(typeof mode === 'string') + const rawMethod = options.rawMethod; + const mode = options.mode; + const isIPD = options.isIPD; + const isMax = options.isMax; + const isBiz = options.isBiz; + const isOpenedURAndSR = options.isOpenedURAndSR; + const todoCount = options.todoCount; + + if(typeof mode !== 'string') return; + + const $mainNavbar = $('#mainNavbar'); + $mainNavbar.find('.nav-item > a[data-id=' + mode + ']').addClass('active'); + if(rawMethod == 'work') { - const $mainNavbar = $('#mainNavbar'); - $mainNavbar.find('.nav-item > a[data-id=' + mode + ']').addClass('active'); - if(typeof rawMethod === 'string' && rawMethod == 'work') + const countMap = {task: 'task', story: 'story', bug: 'bug', testcase: 'case', testtask: 'testtask'}; + if(isOpenedURAndSR !== 0) $.extend(countMap, {requirement: 'requirement'}); + if(isBiz !== 0 || isMax !== 0 || isIPD !== 0) $.extend(countMap, {feedback: 'feedback', ticket: 'ticket'}); + if(isMax !== 0 || isIPD !== 0) $.extend(countMap, {issue: 'issue', risk: 'risk', nc: 'qa', myMeeting: 'meeting'}); + if(isIPD !== 0) $.extend(countMap, {demand: 'demand'}); + + $.each(countMap, (name, key) => { - if($mainNavbar.find('.nav-item > a[data-id=task] .label').length) return false; - - const countMap = {task: 'task', story: 'story', bug: 'bug', testcase: 'case', testtask: 'testtask'}; - if(isOpenedURAndSR !== 0) $.extend(countMap, {requirement: 'requirement'}); - if(isBiz !== 0 || isMax !== 0 || isIPD !== 0) $.extend(countMap, {feedback: 'feedback', ticket: 'ticket'}); - if(isMax !== 0 || isIPD !== 0) $.extend(countMap, {issue: 'issue', risk: 'risk', nc: 'qa', myMeeting: 'meeting'}); - if(isIPD !== 0) $.extend(countMap, {demand: 'demand'}); - - $.each(countMap, (name, key) => $mainNavbar.find('.nav-item > a[data-id=' + name + ']').append('' + todoCount[key] + '')); - } + const $item = $mainNavbar.find('.nav-item > a[data-id=' + name + ']'); + const $label = $item.find('.label'); + if($label.length) $label.text(todoCount[key]); + else $item.append('' + todoCount[key] + ''); + }); } -}); +}; diff --git a/module/my/ui/header.html.php b/module/my/ui/header.html.php index 8bce147579..b5f197d2f6 100644 --- a/module/my/ui/header.html.php +++ b/module/my/ui/header.html.php @@ -10,10 +10,13 @@ declare(strict_types=1); */ namespace zin; -jsVar('mode', $mode); -jsVar('todoCount', $todoCount); -jsVar('isIPD', $isIPD); -jsVar('isMax', $isMax); -jsVar('isBiz', $isBiz); -jsVar('isOpenedURAndSR', $isOpenedURAndSR); -jsVar('rawMethod', $app->rawMethod); +$badgesOptions = array(); +$badgesOptions['mode'] = $mode; +$badgesOptions['todoCount'] = $todoCount; +$badgesOptions['isIPD'] = $isIPD; +$badgesOptions['isMax'] = $isMax; +$badgesOptions['isBiz'] = $isBiz; +$badgesOptions['isOpenedURAndSR'] = $isOpenedURAndSR; +$badgesOptions['rawMethod'] = $app->rawMethod; + +query('#featureBar')->append(on::init()->call('updateMainNavbarBadges', $badgesOptions)); From 3e1ad4e86689483ec923489dbfc9fdd4e4edf6a5 Mon Sep 17 00:00:00 2001 From: wangyuting Date: Tue, 23 Apr 2024 14:52:47 +0800 Subject: [PATCH 117/141] * hide start tutorial btn of not rnd vision. --- module/block/ui/guideblock.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/block/ui/guideblock.html.php b/module/block/ui/guideblock.html.php index e1224c90a5..2cd8529107 100644 --- a/module/block/ui/guideblock.html.php +++ b/module/block/ui/guideblock.html.php @@ -95,7 +95,7 @@ blockPanel setClass('guide-block'), to::heading ( - !commonModel::isTutorialMode() ? btn + !commonModel::isTutorialMode() && $config->vision == 'rnd' ? btn ( set::url('tutorial', 'start'), set::type('warning'), From edc8f04de909fb3581d2bc8abf1230c44d1f2f50 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 23 Apr 2024 15:00:54 +0800 Subject: [PATCH 118/141] * Fix bug #45092. --- module/todo/js/batchcreate.ui.js | 32 ++++++++--------------------- module/todo/ui/batchcreate.html.php | 3 +-- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/module/todo/js/batchcreate.ui.js b/module/todo/js/batchcreate.ui.js index b5b9da176e..bc353f0eb3 100644 --- a/module/todo/js/batchcreate.ui.js +++ b/module/todo/js/batchcreate.ui.js @@ -66,27 +66,20 @@ window.initTime = function(e) const options = $picker.options; const items = options.items; const isBegin = options.name.indexOf('begin') === 0; + const index = parseInt($tr.data('index')); - const index = parseInt($tr.data('index')); if(isBegin) { let endValue = ''; - if(!value) + items.forEach(function(item, timeIndex) { - endValue = items[0].value; - } - else - { - items.forEach(function(item, timeIndex) + if(item.value == value) { - if(item.value == value) - { - endIndex = timeIndex + 3; - endValue = items.length <= endIndex ? '' : items[endIndex].value; - return; - } - }); - } + endIndex = timeIndex + 3; + endValue = items.length <= endIndex ? items[items.length - 1].value : items[endIndex].value; + return; + } + }); $end.zui('picker').$.setValue(endValue); if(typeof endIndex != 'undefined') value = endIndex; } @@ -106,17 +99,10 @@ window.initTime = function(e) return; } }); + if(value == '2350') value='6000'; $(this).find('[data-name="beginAndEnd"] [data-name="begin"]').zui('picker').$.setValue(value); $(this).find('[data-name="beginAndEnd"] [data-name="end"]').zui('picker').$.setValue(endValue); if(typeof endIndex != 'undefined') value = endIndex; } }); } - -window.togglePending = function(e) -{ - $(e.target).closest('.input-group').find('.time-input').each(function() - { - $(this).zui('picker').render({disabled: e.target.checked}); - }); -} diff --git a/module/todo/ui/batchcreate.html.php b/module/todo/ui/batchcreate.html.php index bee084d187..309b22863b 100644 --- a/module/todo/ui/batchcreate.html.php +++ b/module/todo/ui/batchcreate.html.php @@ -40,7 +40,7 @@ formBatchPanel on::change('[data-name="type"]', 'changeType'), on::change('.time-input', 'initTime'), - on::click('.time-check', "window.togglePending"), + on::click('.time-check', "window.changFuture"), on::click('.form-batch-row-actions .btn', 'initTime'), to::heading @@ -72,7 +72,6 @@ formBatchPanel setID('futureDate'), set::name('futureDate'), $lang->todo->periods['future'], - on::click('window.changFuture') ) ) ) From 4b132da824274d30a3052605015809c812350ae9 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 23 Apr 2024 15:07:23 +0800 Subject: [PATCH 119/141] * Fix bug #48252. --- module/my/ui/todo.html.php | 5 ++++- module/todo/css/batchcreate.ui.css | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/module/my/ui/todo.html.php b/module/my/ui/todo.html.php index 0f6306a26b..46d5a1cee7 100644 --- a/module/my/ui/todo.html.php +++ b/module/my/ui/todo.html.php @@ -70,6 +70,9 @@ toolbar setClass('btn primary'), set::icon('plus'), set::url(helper::createLink('todo', 'batchCreate')), + setData('toggle', 'modal'), + setData('size', 'lg'), + setData('class-name', 'batchCreateTodoModal'), $lang->todo->batchCreate ), $canCreate && $canBatchCreate ? dropdown @@ -78,7 +81,7 @@ toolbar set::items(array ( array('text' => $lang->todo->create, 'url' => helper::createLink('todo', 'create'), 'data-toggle' => 'modal'), - array('text' => $lang->todo->batchCreate, 'url' => helper::createLink('todo', 'batchCreate'), 'data-toggle' => 'modal', 'data-size' => 'lg') + array('text' => $lang->todo->batchCreate, 'url' => helper::createLink('todo', 'batchCreate'), 'data-toggle' => 'modal', 'data-size' => 'lg', 'data-class-name' => 'batchCreateTodoModal') )), set::placement('bottom-end') ) : null diff --git a/module/todo/css/batchcreate.ui.css b/module/todo/css/batchcreate.ui.css index f675b2e011..8369d1cefd 100644 --- a/module/todo/css/batchcreate.ui.css +++ b/module/todo/css/batchcreate.ui.css @@ -1 +1,2 @@ +.batchCreateTodoModal .modal-body {overflow-y: hidden;} #batchCreateTodoForm .panel-actions {margin-right: 18px; margin-top: -18px;} From a3bdfee49fddbd4f13ac48b33a45b56a8155efc1 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Tue, 23 Apr 2024 15:06:55 +0800 Subject: [PATCH 120/141] * Fix bug #48066. --- module/testtask/js/runcase.ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/testtask/js/runcase.ui.js b/module/testtask/js/runcase.ui.js index 8b86337fb0..72ffb1c5e2 100644 --- a/module/testtask/js/runcase.ui.js +++ b/module/testtask/js/runcase.ui.js @@ -4,9 +4,9 @@ $(function() loadResult(); }); -$('#runCaseModal').closest('.modal').on('hide.zui.modal', function() +$('#runCaseModal').closest('.modal').off('hide.zui.modal').on('hide.zui.modal', function() { - if($('#casesResults').length == 0) loadCurrentPage(); + loadCurrentPage(); }); /** From 558581ceafd696852ca79f8ba33530361436cc9f Mon Sep 17 00:00:00 2001 From: daitingting Date: Tue, 23 Apr 2024 07:31:04 +0000 Subject: [PATCH 121/141] * Fix bug #43077. --- module/screen/css/browse.ui.css | 1 + 1 file changed, 1 insertion(+) diff --git a/module/screen/css/browse.ui.css b/module/screen/css/browse.ui.css index 9a42948bd6..5f205ecacc 100644 --- a/module/screen/css/browse.ui.css +++ b/module/screen/css/browse.ui.css @@ -1 +1,2 @@ #firstGuide .py-6 {padding: 24px !important;} +#pick-pop-dropmenu-menu{background-color: rgba(255, 255, 255, 1)!important} From eddf53a6b20f915d9db69478cb412e784bbad7f2 Mon Sep 17 00:00:00 2001 From: sunhao Date: Tue, 23 Apr 2024 15:35:55 +0800 Subject: [PATCH 122/141] * zin: only close modal dialog after update page. --- www/js/zui3/zin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/zui3/zin.js b/www/js/zui3/zin.js index fe97144d80..5770549a05 100644 --- a/www/js/zui3/zin.js +++ b/www/js/zui3/zin.js @@ -139,7 +139,7 @@ timers.interval = []; timers.timeout = []; - zui.Modal.getAll().forEach(m => m.hide()); + zui.Modal.getAll().forEach(m => m.options.modal && m.hide()); $('script.zin-page-js').replaceWith(data); } From 1fd7b1000423fcbd6d3e9d404ef983a30815ef0f Mon Sep 17 00:00:00 2001 From: sunhao Date: Tue, 23 Apr 2024 15:40:17 +0800 Subject: [PATCH 123/141] * zin: fix close modal after update page. --- www/js/zui3/zin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/zui3/zin.js b/www/js/zui3/zin.js index 5770549a05..24313fb758 100644 --- a/www/js/zui3/zin.js +++ b/www/js/zui3/zin.js @@ -139,7 +139,7 @@ timers.interval = []; timers.timeout = []; - zui.Modal.getAll().forEach(m => m.options.modal && m.hide()); + zui.Modal.getAll().forEach(m => !m.options.modal && m.hide()); $('script.zin-page-js').replaceWith(data); } From f20b599e55bb206c667424cc191fabe9d426a6ad Mon Sep 17 00:00:00 2001 From: sunhao Date: Tue, 23 Apr 2024 15:46:54 +0800 Subject: [PATCH 124/141] * zin: support to show alert on precesss ajax submit result. --- www/js/zui3/zin.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/www/js/zui3/zin.js b/www/js/zui3/zin.js index 24313fb758..6d79017750 100644 --- a/www/js/zui3/zin.js +++ b/www/js/zui3/zin.js @@ -1455,6 +1455,14 @@ else $(document).trigger('locate.zt', data.cancelled); }); } + if(data.alert) + { + return zui.Modal.alert(data.alert).then(function() + { + if(data.modal) loadModal(data.modal); + if(data.locate) openUrl(data.locate); + }); + } if(data.load) return openUrl(data); if(data.app) return openPage(data.url + (data.selector ? (' ' + data.selector) : ''), data.app); loadPage(data); From a013d105bc610668b64589a4095dcdbe371d91e6 Mon Sep 17 00:00:00 2001 From: wangyuting Date: Tue, 23 Apr 2024 15:52:10 +0800 Subject: [PATCH 125/141] * Optimize code. --- module/build/model.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/build/model.php b/module/build/model.php index 8b6a60ad7c..426fdebbae 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -391,9 +391,9 @@ class buildModel extends model * 获取关联的发布。 * Get releated release. * - * @param array $productIdList - * @param string $buildIdList - * @param array $shadows + * @param array|int $productIdList + * @param string $buildIdList + * @param array|bool $shadows * @access public * @return array */ From 77a96b703baf69789601d50679a2e921043439f5 Mon Sep 17 00:00:00 2001 From: sunhao Date: Tue, 23 Apr 2024 15:56:06 +0800 Subject: [PATCH 126/141] * zui: update zui3 lib. --- www/js/zui3/zui.zentao.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/www/js/zui3/zui.zentao.js b/www/js/zui3/zui.zentao.js index b2a4b70c8a..8dffd2bf87 100644 --- a/www/js/zui3/zui.zentao.js +++ b/www/js/zui3/zui.zentao.js @@ -1,3 +1,3 @@ -var Ao=(w,tt,vt)=>{if(!tt.has(w))throw TypeError("Cannot "+vt)};var bt=(w,tt,vt)=>(Ao(w,tt,"read from private field"),vt?vt.call(w):tt.get(w)),$t=(w,tt,vt)=>{if(tt.has(w))throw TypeError("Cannot add the same private member more than once");tt instanceof WeakSet?tt.add(w):tt.set(w,vt)},It=(w,tt,vt,mi)=>(Ao(w,tt,"write to private field"),mi?mi.call(w,vt):tt.set(w,vt),vt);var Do=(w,tt,vt)=>(Ao(w,tt,"access private method"),vt);(function(w,tt){typeof exports=="object"&&typeof module<"u"?tt(exports):typeof define=="function"&&define.amd?define(["exports"],tt):(w=typeof globalThis<"u"?globalThis:w||self,tt(w.zui={}))})(this,function(w){var di,ui,Ls,Rs,Fs,zs,Os,Ws,fi,Vc,pi,Kc,ye,_e;"use strict";const tt="",vt="",mi="",Bf="",jf="",Uf="",Vf="",Kf="",Gf="",qf="",Yf="",Qf="",Gc="3.0.0-alpha.4",jt=document,Hs=window,Lo=jt.documentElement,be=jt.createElement.bind(jt),Ro=be("div"),gi=be("table"),qc=be("tbody"),Fo=be("tr"),{isArray:Bs,prototype:zo}=Array,{concat:Yc,filter:yi,indexOf:Oo,map:Wo,push:Qc,slice:Ho,some:_i,splice:Zc}=zo,Xc=/^#(?:[\w-]|\\.|[^\x00-\xa0])*$/,Jc=/^\.(?:[\w-]|\\.|[^\x00-\xa0])*$/,th=/<.+>/,eh=/^\w+$/;function bi(n,t){const e=sh(t);return!n||!e&&!ve(t)&&!nt(t)?[]:!e&&Jc.test(n)?t.getElementsByClassName(n.slice(1).replace(/\\/g,"")):!e&&eh.test(n)?t.getElementsByTagName(n):t.querySelectorAll(n)}class js{constructor(t,e){if(!t)return;if(vi(t))return t;let s=t;if(dt(t)){const i=e||jt;if(s=Xc.test(t)&&ve(i)?i.getElementById(t.slice(1).replace(/\\/g,"")):th.test(t)?Go(t):vi(i)?i.find(t):dt(i)?u(i).find(t):bi(t,i),!s)return}else if(we(t))return this.ready(t);(s.nodeType||s===Hs)&&(s=[s]),this.length=s.length;for(let i=0,r=this.length;i{for(;t.firstChild;)t.removeChild(t.firstChild)})};function Us(...n){const t=ih(n[0])?n.shift():!1,e=n.shift(),s=n.length;if(!e)return{};if(!s)return Us(t,u,e);for(let i=0;i{nt(r)&<(e,(o,a)=>{s?t?r.classList.add(a):r.classList.remove(a):r.classList.toggle(a)})})},M.addClass=function(n){return this.toggleClass(n,!0)},M.removeAttr=function(n){const t=Vs(n);return this.each((e,s)=>{nt(s)&<(t,(i,r)=>{s.removeAttribute(r)})})};function oh(n,t){if(n){if(dt(n)){if(arguments.length<2){if(!this[0]||!nt(this[0]))return;const e=this[0].getAttribute(n);return os(e)?void 0:e}return wt(t)?this:os(t)?this.removeAttr(n):this.each((e,s)=>{nt(s)&&s.setAttribute(n,t)})}for(const e in n)this.attr(e,n[e]);return this}}M.attr=oh,M.removeClass=function(n){return arguments.length?this.toggleClass(n,!1):this.attr("class","")},M.hasClass=function(n){return!!n&&_i.call(this,t=>nt(t)&&t.classList.contains(n))},M.get=function(n){return wt(n)?Ho.call(this):(n=Number(n),this[n<0?n+this.length:n])},M.eq=function(n){return u(this.get(n))},M.first=function(){return this.eq(0)},M.last=function(){return this.eq(-1)};function ah(n){return wt(n)?this.get().map(t=>nt(t)||nh(t)?t.textContent:"").join(""):this.each((t,e)=>{nt(e)&&(e.textContent=n)})}M.text=ah;function Ut(n,t,e){if(!nt(n))return;const s=Hs.getComputedStyle(n,null);return e?s.getPropertyValue(t)||void 0:s[t]||n.style[t]}function zt(n,t){return parseInt(Ut(n,t),10)||0}function jo(n,t){return zt(n,`border${t?"Left":"Top"}Width`)+zt(n,`padding${t?"Left":"Top"}`)+zt(n,`padding${t?"Right":"Bottom"}`)+zt(n,`border${t?"Right":"Bottom"}Width`)}const Ci={};function lh(n){if(Ci[n])return Ci[n];const t=be(n);jt.body.insertBefore(t,null);const e=Ut(t,"display");return jt.body.removeChild(t),Ci[n]=e!=="none"?e:"block"}function Uo(n){return Ut(n,"display")==="none"}function Vo(n,t){const e=n&&(n.matches||n.webkitMatchesSelector||n.msMatchesSelector);return!!e&&!!t&&e.call(n,t)}function Ks(n){return dt(n)?(t,e)=>Vo(e,n):we(n)?n:vi(n)?(t,e)=>n.is(e):n?(t,e)=>e===n:()=>!1}M.filter=function(n){const t=Ks(n);return u(yi.call(this,(e,s)=>t.call(e,s,e)))};function se(n,t){return t?n.filter(t):n}M.detach=function(n){return se(this,n).each((t,e)=>{e.parentNode&&e.parentNode.removeChild(e)}),this};const ch=/^\s*<(\w+)[^>]*>/,hh=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,Ko={"*":Ro,tr:qc,td:Fo,th:Fo,thead:gi,tbody:gi,tfoot:gi};function Go(n){if(!dt(n))return[];if(hh.test(n))return[be(RegExp.$1)];const t=ch.test(n)&&RegExp.$1,e=Ko[t]||Ko["*"];return e.innerHTML=n,u(e.childNodes).detach().get()}u.parseHTML=Go,M.has=function(n){const t=dt(n)?(e,s)=>bi(n,s).length:(e,s)=>s.contains(n);return this.filter(t)},M.not=function(n){const t=Ks(n);return this.filter((e,s)=>(!dt(n)||nt(s))&&!t.call(s,e,s))};function Vt(n,t,e,s){const i=[],r=we(t),o=s&&Ks(s);for(let a=0,l=n.length;at.selected&&!t.disabled&&!t.parentNode.disabled),"value"):n.value||""}function dh(n){return arguments.length?this.each((t,e)=>{const s=e.multiple&&e.options;if(s||ra.test(e.type)){const i=Bs(n)?Wo.call(n,String):os(n)?[]:[String(n)];s?lt(e.options,(r,o)=>{o.selected=i.indexOf(o.value)>=0},!0):e.checked=i.indexOf(e.value)>=0}else e.value=wt(n)||os(n)?"":n}):this[0]&&qo(this[0])}M.val=dh,M.is=function(n){const t=Ks(n);return _i.call(this,(e,s)=>t.call(e,s,e))},u.guid=1;function Ot(n){return n.length>1?yi.call(n,(t,e,s)=>Oo.call(s,t)===e):n}u.unique=Ot,M.add=function(n,t){return u(Ot(this.get().concat(u(n,t).get())))},M.children=function(n){return se(u(Ot(Vt(this,t=>t.children))),n)},M.parent=function(n){return se(u(Ot(Vt(this,"parentNode"))),n)},M.index=function(n){const t=n?u(n)[0]:this[0],e=n?this:u(t).parent().children();return Oo.call(e,t)},M.closest=function(n){const t=this.filter(n);if(t.length)return t;const e=this.parent();return e.length?e.closest(n):t},M.siblings=function(n){return se(u(Ot(Vt(this,t=>u(t).parent().children().not(t)))),n)},M.find=function(n){return u(Ot(Vt(this,t=>bi(n,t))))};const uh=/^\s*\s*$/g,fh=/^$|^module$|\/(java|ecma)script/i,ph=["type","src","nonce","noModule"];function mh(n,t){const e=u(n);e.filter("script").add(e.find("script")).each((s,i)=>{if(fh.test(i.type)&&Lo.contains(i)){const r=be("script");r.text=i.textContent.replace(uh,""),lt(ph,(o,a)=>{i[a]&&(r[a]=i[a])}),t.head.insertBefore(r,null),t.head.removeChild(r)}})}function gh(n,t,e,s,i){s?n.insertBefore(t,e?n.firstChild:null):n.nodeName==="HTML"?n.parentNode.replaceChild(t,n):n.parentNode.insertBefore(t,e?n:n.nextSibling),i&&mh(t,n.ownerDocument)}function ne(n,t,e,s,i,r,o,a){return lt(n,(l,c)=>{lt(u(c),(h,d)=>{lt(u(t),(p,f)=>{const g=e?d:f,y=e?f:d,_=e?h:p;gh(g,_?y.cloneNode(!0):y,s,i,!_)},a)},o)},r),t}M.after=function(){return ne(arguments,this,!1,!1,!1,!0,!0)},M.append=function(){return ne(arguments,this,!1,!1,!0)};function yh(n){if(!arguments.length)return this[0]&&this[0].innerHTML;if(wt(n))return this;const t=/]/.test(n);return this.each((e,s)=>{nt(s)&&(t?u(s).empty().append(n):s.innerHTML=n)})}M.html=yh,M.appendTo=function(n){return ne(arguments,this,!0,!1,!0)},M.wrapInner=function(n){return this.each((t,e)=>{const s=u(e),i=s.contents();i.length?i.wrapAll(n):s.append(n)})},M.before=function(){return ne(arguments,this,!1,!0)},M.wrapAll=function(n){let t=u(n),e=t[0];for(;e.children.length;)e=e.firstElementChild;return this.first().before(t),this.appendTo(e)},M.wrap=function(n){return this.each((t,e)=>{const s=u(n)[0];u(e).wrapAll(t?s.cloneNode(!0):s)})},M.insertAfter=function(n){return ne(arguments,this,!0,!1,!1,!1,!1,!0)},M.insertBefore=function(n){return ne(arguments,this,!0,!0)},M.prepend=function(){return ne(arguments,this,!1,!0,!0,!0,!0)},M.prependTo=function(n){return ne(arguments,this,!0,!0,!0,!1,!1,!0)},M.contents=function(){return u(Ot(Vt(this,n=>n.tagName==="IFRAME"?[n.contentDocument]:n.tagName==="TEMPLATE"?n.content.childNodes:n.childNodes)))},M.next=function(n,t,e){return se(u(Ot(Vt(this,"nextElementSibling",t,e))),n)},M.nextAll=function(n){return this.next(n,!0)},M.nextUntil=function(n,t){return this.next(t,!0,n)},M.parents=function(n,t){return se(u(Ot(Vt(this,"parentElement",!0,t))),n)},M.parentsUntil=function(n,t){return this.parents(t,n)},M.prev=function(n,t,e){return se(u(Ot(Vt(this,"previousElementSibling",t,e))),n)},M.prevAll=function(n){return this.prev(n,!0)},M.prevUntil=function(n,t){return this.prev(t,!0,n)},M.map=function(n){return u(Yc.apply([],Wo.call(this,(t,e)=>n.call(t,e,t))))},M.clone=function(){return this.map((n,t)=>t.cloneNode(!0))},M.offsetParent=function(){return this.map((n,t)=>{let e=t.offsetParent;for(;e&&Ut(e,"position")==="static";)e=e.offsetParent;return e||Lo})},M.slice=function(n,t){return u(Ho.call(this,n,t))};const _h=/-([a-z])/g;function ki(n){return n.replace(_h,(t,e)=>e.toUpperCase())}M.ready=function(n){const t=()=>setTimeout(n,0,u);return jt.readyState!=="loading"?t():jt.addEventListener("DOMContentLoaded",t),this},M.unwrap=function(){return this.parent().each((n,t)=>{if(t.tagName==="BODY")return;const e=u(t);e.replaceWith(e.children())}),this},M.offset=function(){const n=this[0];if(!n)return;const t=n.getBoundingClientRect();return{top:t.top+Hs.pageYOffset,left:t.left+Hs.pageXOffset}},M.position=function(){const n=this[0];if(!n)return;const t=Ut(n,"position")==="fixed",e=t?n.getBoundingClientRect():this.offset();if(!t){const s=n.ownerDocument;let i=n.offsetParent||s.documentElement;for(;(i===s.body||i===s.documentElement)&&Ut(i,"position")==="static";)i=i.parentNode;if(i!==n&&nt(i)){const r=u(i).offset();e.top-=r.top+zt(i,"borderTopWidth"),e.left-=r.left+zt(i,"borderLeftWidth")}}return{top:e.top-zt(n,"marginTop"),left:e.left-zt(n,"marginLeft")}};const Yo={class:"className",contenteditable:"contentEditable",for:"htmlFor",readonly:"readOnly",maxlength:"maxLength",tabindex:"tabIndex",colspan:"colSpan",rowspan:"rowSpan",usemap:"useMap"};M.prop=function(n,t){if(n){if(dt(n))return n=Yo[n]||n,arguments.length<2?this[0]&&this[0][n]:this.each((e,s)=>{s[n]=t});for(const e in n)this.prop(e,n[e]);return this}},M.removeProp=function(n){return this.each((t,e)=>{delete e[Yo[n]||n]})};const bh=/^--/;function xi(n){return bh.test(n)}const Si={},{style:vh}=Ro,wh=["webkit","moz","ms"];function Ch(n,t=xi(n)){if(t)return n;if(!Si[n]){const e=ki(n),s=`${e[0].toUpperCase()}${e.slice(1)}`,i=`${e} ${wh.join(`${s} `)}${s}`.split(" ");lt(i,(r,o)=>{if(o in vh)return Si[n]=o,!1})}return Si[n]}const kh={animationIterationCount:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0};function Qo(n,t,e=xi(n)){return!e&&!kh[n]&&Bo(t)?`${t}px`:t}function xh(n,t){if(dt(n)){const e=xi(n);return n=Ch(n,e),arguments.length<2?this[0]&&Ut(this[0],n,e):n?(t=Qo(n,t,e),this.each((s,i)=>{nt(i)&&(e?i.style.setProperty(n,t):i.style[n]=t)})):this}for(const e in n)this.css(e,n[e]);return this}M.css=xh;function Zo(n,t){try{return n(t)}catch{return t}}const Sh=/^\s+|\s+$/;function Xo(n,t){const e=n.dataset[t]||n.dataset[ki(t)];return Sh.test(e)?e:Zo(JSON.parse,e)}function $h(n,t,e){e=Zo(JSON.stringify,e),n.dataset[ki(t)]=e}function Th(n,t){if(!n){if(!this[0])return;const e={};for(const s in this[0].dataset)e[s]=Xo(this[0],s);return e}if(dt(n))return arguments.length<2?this[0]&&Xo(this[0],n):wt(t)?this:this.each((e,s)=>{$h(s,n,t)});for(const e in n)this.data(e,n[e]);return this}M.data=Th;function Jo(n,t){const e=n.documentElement;return Math.max(n.body[`scroll${t}`],e[`scroll${t}`],n.body[`offset${t}`],e[`offset${t}`],e[`client${t}`])}lt([!0,!1],(n,t)=>{lt(["Width","Height"],(e,s)=>{const i=`${t?"outer":"inner"}${s}`;M[i]=function(r){if(this[0])return Le(this[0])?t?this[0][`inner${s}`]:this[0].document.documentElement[`client${s}`]:ve(this[0])?Jo(this[0],s):this[0][`${t?"offset":"client"}${s}`]+(r&&t?zt(this[0],`margin${e?"Top":"Left"}`)+zt(this[0],`margin${e?"Bottom":"Right"}`):0)}})}),lt(["Width","Height"],(n,t)=>{const e=t.toLowerCase();M[e]=function(s){if(!this[0])return wt(s)?void 0:this;if(!arguments.length)return Le(this[0])?this[0].document.documentElement[`client${t}`]:ve(this[0])?Jo(this[0],t):this[0].getBoundingClientRect()[e]-jo(this[0],!n);const i=parseInt(s,10);return this.each((r,o)=>{if(!nt(o))return;const a=Ut(o,"boxSizing");o.style[e]=Qo(e,i+(a==="border-box"?jo(o,!n):0))})}});const ta="___cd";M.toggle=function(n){return this.each((t,e)=>{if(!nt(e))return;const s=Uo(e);(wt(n)?s:n)?(e.style.display=e[ta]||"",Uo(e)&&(e.style.display=lh(e.tagName))):s||(e[ta]=Ut(e,"display"),e.style.display="none")})},M.hide=function(){return this.toggle(!1)},M.show=function(){return this.toggle(!0)};const ea="___ce",$i=".",Ti={focus:"focusin",blur:"focusout"},sa={mouseenter:"mouseover",mouseleave:"mouseout"},Nh=/^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function Ni(n){return sa[n]||Ti[n]||n}function Mi(n){const t=n.split($i);return[t[0],t.slice(1).sort()]}M.trigger=function(n,t){if(dt(n)){const[s,i]=Mi(n),r=Ni(s);if(!r)return this;const o=Nh.test(r)?"MouseEvents":"HTMLEvents";n=jt.createEvent(o),n.initEvent(r,!0,!0),n.namespace=i.join($i),n.___ot=s}n.___td=t;const e=n.___ot in Ti;return this.each((s,i)=>{e&&we(i[n.___ot])&&(i[`___i${n.type}`]=!0,i[n.___ot](),i[`___i${n.type}`]=!1),i.dispatchEvent(n)})};function na(n){return n[ea]=n[ea]||{}}function Mh(n,t,e,s,i){const r=na(n);r[t]=r[t]||[],r[t].push([e,s,i]),n.addEventListener(t,i)}function ia(n,t){return!t||!_i.call(t,e=>n.indexOf(e)<0)}function Gs(n,t,e,s,i){const r=na(n);if(t)r[t]&&(r[t]=r[t].filter(([o,a,l])=>{if(i&&l.guid!==i.guid||!ia(o,e)||s&&s!==a)return!0;n.removeEventListener(t,l)}));else for(t in r)Gs(n,t,e,s,i)}M.off=function(n,t,e){if(wt(n))this.each((s,i)=>{!nt(i)&&!ve(i)&&!Le(i)||Gs(i)});else if(dt(n))we(t)&&(e=t,t=""),lt(Vs(n),(s,i)=>{const[r,o]=Mi(i),a=Ni(r);this.each((l,c)=>{!nt(c)&&!ve(c)&&!Le(c)||Gs(c,a,o,t,e)})});else for(const s in n)this.off(s,n[s]);return this},M.remove=function(n){return se(this,n).detach().off(),this},M.replaceWith=function(n){return this.before(n).remove()},M.replaceAll=function(n){return u(n).replaceWith(this),this};function Eh(n,t,e,s,i){if(!dt(n)){for(const r in n)this.on(r,t,e,n[r],i);return this}return dt(t)||(wt(t)||os(t)?t="":wt(e)?(e=t,t=""):(s=e,e=t,t="")),we(s)||(s=e,e=void 0),s?(lt(Vs(n),(r,o)=>{const[a,l]=Mi(o),c=Ni(a),h=a in sa,d=a in Ti;c&&this.each((p,f)=>{if(!nt(f)&&!ve(f)&&!Le(f))return;const g=function(y){if(y.target[`___i${y.type}`])return y.stopImmediatePropagation();if(y.namespace&&!ia(l,y.namespace.split($i))||!t&&(d&&(y.target!==f||y.___ot===c)||h&&y.relatedTarget&&f.contains(y.relatedTarget)))return;let _=f;if(t){let C=y.target;for(;!Vo(C,t);)if(C===f||(C=C.parentNode,!C))return;_=C}Object.defineProperty(y,"currentTarget",{configurable:!0,get(){return _}}),Object.defineProperty(y,"delegateTarget",{configurable:!0,get(){return f}}),Object.defineProperty(y,"data",{configurable:!0,get(){return e}});const b=s.call(_,y,y.___td);i&&Gs(f,c,l,t,g),b===!1&&(y.preventDefault(),y.stopPropagation())};g.guid=s.guid=s.guid||u.guid++,Mh(f,c,l,t,g)})}),this):this}M.on=Eh;function Ih(n,t,e,s){return this.on(n,t,e,s,!0)}M.one=Ih;const Ph=/\r?\n/g;function Ah(n,t){return`&${encodeURIComponent(n)}=${encodeURIComponent(t.replace(Ph,`\r -`))}`}const Dh=/file|reset|submit|button|image/i,ra=/radio|checkbox/i;M.serialize=function(){let n="";return this.each((t,e)=>{lt(e.elements||[e],(s,i)=>{if(i.disabled||!i.name||i.tagName==="FIELDSET"||Dh.test(i.type)||ra.test(i.type)&&!i.checked)return;const r=qo(i);if(!wt(r)){const o=Bs(r)?r:[r];lt(o,(a,l)=>{n+=Ah(i.name,l)})}})}),n.slice(1)},window.$=u;function oa(n,t){if(n==null)return[n,void 0];typeof t=="string"&&(t=t.split("."));const e=t.join(".");let s=n;const i=[s];for(;typeof s=="object"&&s!==null&&t.length;){let r=t.shift(),o;const a=r.indexOf("[");if(a>0&&a{const i=e[s]??"";n=n.replace(new RegExp(`\\{${s}\\}`,"g"),`${i}`)}),n}for(let e=0;e(n[n.B=1]="B",n[n.KB=1024]="KB",n[n.MB=1048576]="MB",n[n.GB=1073741824]="GB",n[n.TB=1099511627776]="TB",n))(Ei||{});function pt(n,t=2,e){return Number.isNaN(n)?"?KB":(e||(n<1024?e="B":n<1048576?e="KB":n<1073741824?e="MB":n<1099511627776?e="GB":e="TB"),(n/Ei[e]).toFixed(t)+e)}const Re=n=>{const t=/^[0-9]*(B|KB|MB|GB|TB)$/;n=n.toUpperCase();const e=n.match(t);if(!e)return 0;const s=e[1];return n=n.replace(s,""),Number.parseInt(n,10)*Ei[s]};let Ii=(document.documentElement.getAttribute("lang")||"zh_cn").toLowerCase().replace("-","_"),Kt;function Lh(){return Ii}function Rh(n){Ii=n.toLowerCase().replace("-","_")}function la(n,t){Kt||(Kt={}),typeof n=="string"&&(n={[n]:t??{}}),u.extend(!0,Kt,n)}function K(n,t,e,s,i,r){Array.isArray(n)?Kt&&n.unshift(Kt):n=Kt?[Kt,n]:[n],typeof e=="string"&&(r=i,i=s,s=e,e=void 0);const o=i||Ii;let a;for(const l of n){if(!l)continue;const c=l[o]||l.default;if(!c)continue;const h=r&&l===Kt?`${r}.${t}`:t;if(a=aa(c,h),a!==void 0)break}return a===void 0?s:e?U(a,...Array.isArray(e)?e:[e]):a}function Fh(n,t,e,s){return K(void 0,n,t,e,s)}K.addLang=la,K.getLang=Fh,K.getCode=Lh,K.setCode=Rh,K.map=Kt,la({zh_cn:{confirm:"确定",save:"保存",cancel:"取消",delete:"删除",reset:"重置",add:"添加"},zh_tw:{confirm:"確定",save:"儲存",cancel:"取消",delete:"刪除",reset:"重置",add:"添加"},en:{confirm:"Confirm",save:"Save",cancel:"Cancel",delete:"Delete",reset:"Reset",add:"Add"}});function ca(n,t,e){n instanceof Headers?n.set(t,e):Array.isArray(n)?n.push([t,e]):n[t]=e}function as(n,t,e){e!=null&&(Array.isArray(e)?e.forEach(s=>as(n,t,s)):n.append(t,e instanceof Blob?e:String(e)))}function zh(n,t){if(n){const e={text:"text/plain",html:"text/html",json:"application/json",...t};for(const[s,i]of Object.entries(e))if(i.split(",").map(r=>r.trim()).includes(n))return s}return"text"}function qs(n,t){const e=t||new FormData;return n&&(typeof n=="string"&&(n=new URLSearchParams(n)),n instanceof URLSearchParams?n.forEach((s,i)=>{as(e,i,s)}):Array.isArray(n)?n.forEach(([s,i])=>{as(e,s,i)}):n instanceof FormData?n.forEach((s,i)=>{as(e,i,s)}):u.isPlainObject(n)&&Object.entries(n).forEach(([s,i])=>{as(e,s,i)})),e}class Ys{get completed(){return this.data!==void 0||this.error!==void 0}get[Symbol.toStringTag](){return"Ajax"}constructor(t){this.setting=t,this._controller=new AbortController,this._callbacks={success:[],error:[],complete:[]}}on(t,e){return this._callbacks[t].push(e),this}success(t){return this.on("success",t)}done(t){return this.success(t)}fail(t){return this.on("error",t)}complete(t){return this.on("complete",t)}always(t){return this.complete(t)}then(t,e){return this.completed?e&&this.error?e(this.error):t(this.data):(this.success(s=>t(s)),e&&this.fail(e)),this}catch(t){return this.error?(t(this.error),this):this.on("error",e=>t(e))}finally(t){return this.completed?(t(),this):this.complete(()=>t())}abort(t){return this.completed?!1:(this._abortError=t,this._controller.abort(),!0)}getResponseHeader(t){var e;return(e=this.response)==null?void 0:e.headers.get(t)}_init(){if(this.completed)return;const{url:t,type:e,data:s,processData:i=!0,contentType:r,crossDomain:o,accepts:a,dataType:l,timeout:c,dataFilter:h,beforeSend:d,success:p,error:f,complete:g,...y}=this.setting;if((d==null?void 0:d(y))===!1)return;e&&(y.method=e);let _=s;_&&(i&&(_=qs(_)),y.body=_),o&&(y.mode="cors");const b=y.headers||{};ca(b,"X-Requested-With","XMLHttpRequest"),r&&ca(b,"Content-Type",r),y.headers=b,y.signal&&y.signal.addEventListener("abort",()=>{this.abort()}),p&&this.success(p),f&&this.fail(f),g&&this.complete(g),y.signal=this._controller.signal,this.url=t,this.request=y}_emit(t,...e){this._callbacks[t].forEach(s=>{s.call(this,...e)})}async send(){var h;if(this.completed)return[];this._init();const{timeout:t,dataType:e,accepts:s,dataFilter:i,throws:r,jsonParser:o}=this.setting;t&&(this._timeoutID=window.setTimeout(()=>{this.abort(new Error("timeout"))},t));let a,l,c;try{a=await fetch(this.url,this.request),this.response=a;const{statusText:d}=a;if(a.ok){const p=(h=a.headers.get("Content-Disposition"))==null?void 0:h.startsWith("attachment"),f=p?"blob":e||zh(a.headers.get("Content-Type"),s);p||f==="blob"||f==="file"?c=await a.blob():f==="json"?typeof o=="function"?(c=await a.text(),c=o(c)):c=await a.json():c=await a.text(),this.data=c;const g=(i==null?void 0:i(c,f))??c;this._emit("success",g,d,a)}else throw new Error(d)}catch(d){l=d;let p=!1;l.name==="AbortError"&&(this._abortError?l=this._abortError:p=!0),this.error=l,p||this._emit("error",l,a==null?void 0:a.statusText,l.message)}if(this._timeoutID&&clearTimeout(this._timeoutID),this._emit("complete",a,a==null?void 0:a.statusText),l&&r)throw l;return[c,l,a]}}u.ajax=(n,t)=>{t=t||{},typeof n=="string"?t.url=n:u.extend(t,n);const e=new Ys(t);return e.send(),e},u.getJSON=(n,t,e)=>(typeof t=="function"&&(e=t,t=void 0),u.ajax({url:n,data:t,success:e,dataType:"json"})),u.get=(n,t,e,s,i="GET")=>{let r,o;return typeof t=="function"?(r=t,o=void 0):o=t,typeof e=="function"?(r=e,s=void 0):s=e,u.ajax({method:i,url:n,data:o,success:r,dataType:s})},u.post=(n,t,e,s)=>u.get(n,t,e,s,"POST"),u.fn.load=function(n,t,e){typeof t=="function"&&(e=t,t=void 0);const[s,i]=n.split(" ");return u.get(s,t,(r,o,a)=>{i&&(r=u(r).find(i).html()),u(this).html(r),e==null||e.call(this,r,o,a)},"html"),this};async function Ce(n,t=[],e){const s={throws:!0,dataType:"json"};if(typeof n=="string")s.url=n;else if(typeof n=="object")u.extend(s,n);else if(typeof n=="function"){const o=n(...t);return o instanceof Promise?await o:o}e&&u.extend(s,typeof e=="function"?e(s):e);const i=new Ys(s),[r]=await i.send();return r}function Pi(n){return!!(n&&(typeof n=="string"||typeof n=="object"&&n.url||typeof n=="function"))}u.fetch=Ce;function mt(){return u.guid++}function Qs(n,t){if(n===t)return!1;if(n&&t&&typeof n=="object"&&typeof t=="object"){const e=Array.isArray(n),s=Array.isArray(t);if(e!==s)return!0;if(e&&s){if(n.length!==t.length)return!0;for(let o=0;oQs(s instanceof ke?s.value:s,e[i])))&&(this._value=this._compute(),this._lastDependencies=t.map(s=>s instanceof ke?s.cache:s)),this._value}}function Ai(...n){const t=[],e=new Map,s=(i,r)=>{if(Array.isArray(i)&&(r=i[1],i=i[0]),!i.length)return;const o=e.get(i);typeof o=="number"?t[o][1]=!!r:(e.set(i,t.length),t.push([i,!!r]))};return n.forEach(i=>{typeof i=="function"&&(i=i()),Array.isArray(i)?Ai(...i).forEach(s):i&&typeof i=="object"?Object.entries(i).forEach(s):typeof i=="string"&&i.split(" ").forEach(r=>s(r,!0))}),t.sort((i,r)=>(e.get(i[0])||0)-(e.get(r[0])||0))}const S=(...n)=>Ai(...n).reduce((t,[e,s])=>(s&&t.push(e),t),[]).join(" ");u.classes=S,u.fn.setClass=function(n,...t){return this.each((e,s)=>{const i=u(s);n===!0?i.attr("class",S(i.attr("class"),...t)):i.addClass(S(n,...t))})};const ls=new WeakMap;function Di(n,t,e){const s=ls.has(n),i=s?ls.get(n):{};typeof t=="string"?i[t]=e:t===null?Object.keys(i).forEach(r=>{delete i[r]}):Object.assign(i,t),Object.keys(i).forEach(r=>{i[r]===void 0&&delete i[r]}),Object.keys(i).length?(!s&&n instanceof Element&&Object.assign(i,u(n).dataset(),i),ls.set(n,i)):ls.delete(n)}function Li(n,t,e){let s=ls.get(n)||{};return!e&&n instanceof Element&&(s=Object.assign({},u(n).dataset(),s)),t===void 0?s:s[t]}u.fn.dataset=u.fn.data,u.fn.data=function(...n){const[t,e]=n;return!n.length||n.length===1&&typeof t=="string"?this.length?Li(this[0],t):void 0:this.each((s,i)=>Di(i,t,e))},u.fn.removeData=function(n=null){return this.each((t,e)=>Di(e,n))};function Zs(n,t="z-"){const e=u(n)[0];if(e)return Array.from(e.attributes).reduce((s,i)=>{let{name:r,value:o}=i;if(r.startsWith(t)){r=r.slice(t.length).replace(/-([a-z])/g,a=>a[1].toUpperCase());try{o.startsWith("RAWJS<")&&o.endsWith(">RAWJS")?o=new Function(`return ${o.substring(6,o.length-6)}`)():o=JSON.parse(o)}catch{}s[r]=o}return s},{})}function Ri(n,t,e="z-"){const s=u(n);Object.keys(t).forEach(i=>{let r=t[i];typeof r=="function"&&(r=`RAWJS<${r}>RAWJS`),typeof r!="string"&&(r=JSON.stringify(r)),i=i.replace(/[A-Z]/g,o=>`-${o.toLowerCase()}`),s.attr(`${e}${i}`,r)})}function Oh(...n){var e;const t=n.length;if(!t)return Zs(this);if(t===1){const[s]=n;return typeof s=="string"?(e=Zs(this))==null?void 0:e[s]:(u.isPlainObject(s)&&Ri(this,s),this)}return Ri(this,{[n[0]]:n[1]}),this}u.fn.z=Oh,u.fn._attr=u.fn.attr,u.fn.extend({attr(...n){const[t,e]=n;return!n.length||n.length===1&&typeof t=="string"?this._attr.apply(this,n):typeof t=="object"?(t&&Object.keys(t).forEach(s=>{const i=t[s];i===null?this.removeAttr(s):this._attr(s,i)}),this):e===null?this.removeAttr(t):this._attr(t,e)}}),u.Event=(n,t)=>{const[e,...s]=n.split("."),i=new Event(e,{bubbles:!0,cancelable:!0});return i.namespace=s.join("."),i.___ot=e,i.___td=t,i};const cs=(n,t)=>new Promise(e=>{const s=window.setTimeout(e,n);t&&t(s)}),ha={};u.share=ha;var Xs,q,da;w.isValidElement=void 0;var xe,ua,fa,Fi,hs={},pa=[],Wh=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Js=Array.isArray;function ie(n,t){for(var e in t)n[e]=t[e];return n}function ma(n){var t=n.parentNode;t&&t.removeChild(n)}function v(n,t,e){var s,i,r,o={};for(r in t)r=="key"?s=t[r]:r=="ref"?i=t[r]:o[r]=t[r];if(arguments.length>2&&(o.children=arguments.length>3?Xs.call(arguments,2):e),typeof n=="function"&&n.defaultProps!=null)for(r in n.defaultProps)o[r]===void 0&&(o[r]=n.defaultProps[r]);return tn(n,o,s,i,null)}function tn(n,t,e,s,i){var r={type:n,props:t,key:e,ref:s,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:i??++da,__i:-1,__u:0};return i==null&&q.vnode!=null&&q.vnode(r),r}function H(){return{current:null}}function re(n){return n.children}function B(n,t){this.props=n,this.context=t}function Fe(n,t){if(t==null)return n.__?Fe(n.__,n.__i+1):null;for(var e;tt&&xe.sort(Fi));en.__r=0}function _a(n,t,e,s,i,r,o,a,l,c,h){var d,p,f,g,y,_=s&&s.__k||pa,b=t.length;for(e.__d=l,Hh(e,t,_),l=e.__d,d=0;d0?tn(i.type,i.props,i.key,i.ref?i.ref:null,i.__v):i)!=null?(i.__=n,i.__b=n.__b+1,a=Bh(i,e,o=s+d,h),i.__i=a,r=null,a!==-1&&(h--,(r=e[a])&&(r.__u|=131072)),r==null||r.__v===null?(a==-1&&d--,typeof i.type!="function"&&(i.__u|=65536)):a!==o&&(a===o+1?d++:a>o?h>l-o?d+=a-o:d--:d=a(l!=null&&!(131072&l.__u)?1:0))for(;o>=0||a=0){if((l=t[o])&&!(131072&l.__u)&&i==l.key&&r===l.type)return o;o--}if(a{!e||typeof e!="object"||Object.keys(e).forEach(s=>{let i=e[s];const r=n[s];i!==r&&(r!==void 0&&(s==="className"||s.endsWith("Class")?i=[r,i]:s==="children"?i=[...sn(r),...sn(i)]:typeof r=="object"&&(s==="style"||s.endsWith("Style")||s==="attrs"||s.endsWith("Attrs")||s==="props")&&(i=u.extend(r,i))),n[s]=i)})}),n}function Hi(n){return Object.keys(n).forEach(t=>{n[t]===void 0&&delete n[t]}),n}const Oe=new Map;function ds(n){const{zui:t}=window;return(!Oe.size||n&&!Oe.has(n.toUpperCase()))&&Object.keys(t).forEach(e=>{const s=t[e];!s.NAME||!s.ZUI||Oe.set(e.toLowerCase(),s)}),n?Oe.get(n.toLowerCase()):void 0}function xa(n,t,e){const s=ds(n);return s?!s.MULTI_INSTANCE&&s.get(t)?(console.error(`[ZUI] cannot create component "${n}" on element which already has a component instance.`,{element:t,options:e}),null):new s(t,e):null}function Vh(n){if(n){const t=ds(n);t&&t.defineFn()}else ds(),Oe.forEach(t=>{t.defineFn()})}u.fn.zuiInit=function(){return this.find("[zui-create],[data-zui]").each(function(){const n=u(this);let t=Zs(n,"data-");const[e,s]=(t.zui||n.attr("zui-create")).split(":");n.zui(e)||(s?t=u.share[s]:delete t.zui,requestAnimationFrame(()=>xa(e,this,t)))}),this.find("[zui-init]").each(function(){const n=u(this);n.z("zuiInited")||u.runJS(n.z("zuiInited",!0).attr("zui-init"),["$element",n])}),this.find(".hide-before-init").removeClass("invisible hidden opacity-0"),this.find(".scroll-into-view").scrollIntoView(),this.find('[data-on="inited"]').each((n,t)=>{const e=u(t);e.zui()||e.trigger("inited")}),this},u.fn.zui=function(n,t){const e=this[0];if(!e)return;if(typeof n!="string"){const i=Li(e,void 0,!0),r={};let o;return Object.keys(i).forEach(a=>{if(a.startsWith("zui.")){const l=i[a];r[a]=l,(!o||o.gid{u("body").zuiInit()});function Sa(n,t=!0){const e=u(n),s=e[0],i="zui-disable-scroll";if(t){if(e.data(i))return;if((e.css("scrollbar-gutter")||"").includes("stable")){e.data(i,{overflow:e.css("overflow")}).css("overflow","hidden");return}const r=s===document.body||e.is("html")?window.innerWidth-document.body.clientWidth:s.offsetWidth-s.clientWidth;if(!r)return;const o=e.css("paddingRight")||"0";e.data(i,{paddingRight:o,overflow:e.css("overflow")}).css({paddingRight:`${r+Number.parseInt(o,10)}px`,overflow:"hidden"})}else{const r=e.data(i);if(!r)return;e.css(r).removeData(i)}}u.fn.disableScroll=function(n=!0){return this.each((t,e)=>{Sa(e,n)})},u.fn.enableScroll=function(n=!0){return this.disableScroll(!n)};function Kh(n){const t=u(this),e=t.dataset();if(!(e.on||"click").split(" ").includes(n.type))return;const s=e.selector?u(n.target).closest(e.selector):t;if(!s.length)return;const i=l=>l===""?!0:l,r=l=>{if(typeof l=="string")try{l=JSON.parse(l)}catch{}return l};if(i(e.once)){if(e.onceCalled)return;t.dataset("once-called",!0)}if(i(e.prevent)&&n.preventDefault(),i(e.stop)&&n.stopPropagation(),i(e.self)&&n.currentTarget!==n.target)return;const o=[["$element",t],["event",n],["options",e],["$target",s]];if(e.if&&!u.runJS(e.if,...o))return;const a=e.call;if(a){let l=window[a];const c=/^[$A-Z_][0-9A-Z_$.]*$/i.test(a);if(l||(l=u.runJS(a,...o)),!c||!u.isFunction(l))return;const h=[],d=e.params;e.params=h,typeof d=="string"&&d.length?d[0]==="["?h.push(...r(d)):h.push(...d.split(", ").map(p=>(p=p.trim(),p==="$element"?t:p==="event"?n:p==="options"?e:p.startsWith("$element.")||p.startsWith("event.")||p.startsWith("options.")?u.runJS(p,...o):r(p)))):h.push(d),l(...h)}e.do&&u.runJS(e.do,...o)}u(document).on("click.zui.global change.zui.global inited.zui.global","[data-on]",Kh);function We(n){if(typeof n=="function")return We(n());if(typeof n=="number")return[n];let t=n.match(/(\d+)(%|px)?/);return t?[parseInt(t[1]),t[2]]:(t=n.match(/(\d+)\/(\d+)/),t?[100*parseInt(t[1])/parseInt(t[2]),"%"]:[NaN])}function it(n){if(n==null)return null;const[t,e="px"]=We(n);return Number.isNaN(t)?typeof n=="string"?n:null:`${t}${e}`}async function rn(n,t){var s,i,r;if(n instanceof Blob){const o=document.createElement("a");return o.href=window.URL.createObjectURL(n),t&&(o.download=decodeURIComponent(t)),o.click(),o.remove(),n}if(n instanceof Response){const o=await n.blob();return t=t||((r=(i=(s=n.headers.get("Content-Disposition"))==null?void 0:s.split(";")[1])==null?void 0:i.split("=")[1])==null?void 0:r.replace(/"/g,"")),rn(o,t)}const e=await fetch(n);return rn(e)}class $a{constructor(t){this._$target=u(t)}on(...t){return this._$target.on(...t),this}one(...t){return this._$target.one(...t),this}off(...t){return this._$target.off(...t),this}trigger(...t){return this._$target.trigger(...t),this}}const Wt=new $a(document);u.bus=Wt,u.on=Wt.on.bind(Wt),u.one=Wt.one.bind(Wt),u.off=Wt.off.bind(Wt),u.trigger=Wt.trigger.bind(Wt);var Gh=["Shift","Meta","Alt","Control"],Ta=typeof navigator=="object"?navigator.platform:"",Na=/Mac|iPod|iPhone|iPad/.test(Ta),qh=Na?"Meta":"Control",Yh=Ta==="Win32"?["Control","Alt"]:Na?["Alt"]:[];function Bi(n,t){return typeof n.getModifierState=="function"&&(n.getModifierState(t)||Yh.includes(t)&&n.getModifierState("AltGraph"))}function Qh(n){return n.trim().split(" ").map(function(t){var e=t.split(/\b\+/),s=e.pop();return[e=e.map(function(i){return i==="$mod"?qh:i}),s]})}function Ma(n,t){var e;t===void 0&&(t={});var s=(e=t.timeout)!=null?e:1e3,i=Object.keys(n).map(function(a){return[Qh(a),n[a]]}),r=new Map,o=null;return function(a){a instanceof KeyboardEvent&&(i.forEach(function(l){var c=l[0],h=l[1],d=r.get(c)||c;(function(p,f){return!(f[1].toUpperCase()!==p.key.toUpperCase()&&f[1]!==p.code||f[0].find(function(g){return!Bi(p,g)})||Gh.find(function(g){return!f[0].includes(g)&&f[1]!==g&&Bi(p,g)}))})(a,d[0])?d.length>1?r.set(c,d.slice(1)):(r.delete(c),h(a)):Bi(a,a.key)||r.delete(c)}),o&&clearTimeout(o),o=setTimeout(r.clear.bind(r),s))}}function Zh(n,t,e){var s;e===void 0&&(e={});var i=(s=e.event)!=null?s:"keydown",r=Ma(t,e);return n.addEventListener(i,r),function(){n.removeEventListener(i,r)}}function ji(n,t={}){if(!n)return;const e=Object.keys(t).reduce((s,i)=>(t[i].optional||(s[i]={...t[i]}),s),{});return Object.keys(n).forEach(s=>{const i=n[s];i?i===!0?t[s]&&(e[s]={...t[s]}):e[s]=i:delete e[s]}),Object.keys(e).reduce((s,i)=>{const{keys:r,handler:o}=e[i];return typeof r=="string"?s[r]=o:r.forEach(a=>{s[a]=o}),s},{})}function Ui(n,t,e){const{timeout:s,event:i="keydown",scope:r,when:o}=e||{},a=Ma(t,{timeout:s});return u(n).on(`${i}.zui.hotkeys${r?`.${r}`:""}`,function(l){o&&o(l)===!1||a(l)})}function Vi(n,t){return u(n).off(`.zui.hotkeys${t?`.${t}`:""}`)}const Xh=Zh;u.fn.hotkeys=function(n,t){return Ui(this,n,t)},u.fn.unbindHotkeys=function(n){return Vi(this,n)},u.hotkeys=function(n,t){Ui(window,n,t)},u.unbindHotkeys=function(n){Vi(window,n)};function on(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement}async function Ea(n){(typeof n=="string"||n instanceof Element||n instanceof u)&&(n={target:n});const{target:t,onError:e,onSuccess:s,afterExit:i,afterEnter:r}=n,o=u(t),a=o[0];if(!a)return;const l=a.requestFullscreen||a.webkitRequestFullscreen||a.mozRequestFullScreen;if(!l){e==null||e.call(a,new Error("[ZUI] The browser does not support full screen feature."));return}try{await l.call(a),s==null||s.call(a),u(a).off(".zui.fullscreen"),i&&o.on("exitFullscreen.zui.fullscreen",i),r&&o.on("enterFullscreen.zui.fullscreen",r)}catch(c){e==null||e.call(a,c)}document.zuiBindFullscreenChange||(document.zuiBindFullscreenChange=!0,u(document).on("fullscreenchange.zui webkitfullscreenchange.zui mozfullscreenchange.zui",c=>{const h=on();let d=h;h?u(h).addClass("is-in-fullscreen"):(d=u(document).find(".is-in-fullscreen")[0]||document,u(d).removeClass("is-in-fullscreen")),u("body").toggleClass("has-in-fullscreen",!!h);const p={event:c,target:d,fullscreenElement:h};u(d).trigger(h?"enterFullscreen":"exitFullscreen",p).trigger("toggleFullscreen",p)}))}async function Ki(n){const t=on();return n===!1&&!!t===n?n:t?(document.exitFullscreen(),!1):(await Ea(n),!0)}u.fn.fullscreen=function(n){return Ki({target:this,...n})},u.getFullscreenElement=on,u.toggleFullscreen=Ki;function Se(n){return n.parentNode===document?!1:n.parentNode?Se(n.parentNode):!0}u.isDetached=Se,u.fn.isDetached=function(){const n=this[0];return!n||Se(n)};class X{constructor(t,e){this._inited=!1,this._autoDestory=0;const{KEY:s,DATA_KEY:i,DEFAULT:r,MULTI_INSTANCE:o,NAME:a}=this.constructor;if(!a)throw new Error('[ZUI] The component must have a "NAME" static property.');const l=u(t);if(l.data(s)&&!o)throw new Error("[ZUI] The component has been initialized on element.");const c=l[0],h=mt();this._gid=h,this._element=c;const d=l.parent();if(d.length&&(this._mobs=new MutationObserver(p=>{p.forEach(f=>{f.removedNodes.forEach(g=>{g===c&&(this._autoDestory&&clearTimeout(this._autoDestory),this._autoDestory=window.setTimeout(()=>{this._autoDestory=0,Se(c)&&this.destroy()},100))})})}),this._mobs.observe(d[0],{childList:!0,subtree:!1})),this._options={...r,...l.dataset()},this.setOptions(e),this._key=this.options.key??`__${h}`,l.data(s,this).attr(i,`${h}`),o){const p=`${s}:ALL`;let f=l.data(p);f||(f=new Map,l.data(p,f)),f.set(this._key,this)}this.init(),requestAnimationFrame(async()=>{this._inited=!0,await this.afterInit(),this.emit("inited",this.options)})}static get ZUI(){return this.NAME.replace(/(^[A-Z]+)/,t=>t.toLowerCase())}static get KEY(){return`zui.${this.NAME}`}static get NAMESPACE(){return`.zui.${this.ZUI}`}static get DATA_KEY(){return`data-zui-${this.NAME}`}static get SELECTOR(){return`[${this.DATA_KEY}]`}get inited(){return this._inited}get element(){return this._element}get key(){return this._key}get options(){return this._options}get gid(){return this._gid}get $element(){return u(this.element)}get $emitter(){return this.$element}get i18nData(){return[this.options.i18n,this.constructor.i18n]}init(){}afterInit(){}render(t){this.setOptions(t)}destroy(){var r;const{KEY:t,DATA_KEY:e,MULTI_INSTANCE:s}=this.constructor,{$element:i}=this;if(this.emit("destroyed"),(r=this._mobs)==null||r.disconnect(),i.off(this.namespace).removeData(t).attr(e,null),s){const o=this.$element.data(`${t}:ALL`);if(o)if(o.delete(this._key),o.size===0)this.$element.removeData(`${t}:ALL`);else{const a=o.values().next().value;i.data(t,a).attr(e,a.gid)}}}setOptions(t){return t&&u.extend(this._options,t),this._options}emit(t,...e){const s=u.Event(t);return s.__src=this,this.$emitter.trigger(s,[this,...e]),s}on(t,e,s){const i=this;this.$element[s!=null&&s.once?"one":"on"](this._wrapEvent(t),function(r,o){(!r.__src||r.__src===i)&&e.call(this,r,o)})}one(t,e){this.on(t,e,{once:!0})}off(t){this.$element.off(this._wrapEvent(t))}i18n(t,e,s){const{i18nData:i}=this;return K(i,t,e,s,this.options.lang,this.constructor.NAME)??K(i,t,e,s,this.options.lang)??`{i18n:${t}}`}get namespace(){return`${this.constructor.NAMESPACE}.${this._key}`}_wrapEvent(t){return t.split(" ").map(e=>e.includes(".")?e:`${e}${this.namespace}`).join(" ")}static get(t,e){const s=u(t);if(this.MULTI_INSTANCE&&e!==void 0){const i=s.data(`${this.KEY}:ALL`);return i?i.get(e):void 0}return s.data(this.KEY)}static ensure(t,e){const s=this.get(t,e==null?void 0:e.key);return s?(e&&s.setOptions(e),s):new this(t,e)}static getAll(t){const{MULTI_INSTANCE:e,SELECTOR:s}=this,i=[];return u(t||document).find(s).each((r,o)=>{if(e){const l=u(o).data(`${this.KEY}:ALL`);if(l){i.push(...l.values());return}}const a=u(o).data(this.KEY);a&&i.push(a)}),i.sort((r,o)=>r.gid-o.gid)}static query(t,e,s){if(t===void 0){let i=this.getAll();return s&&(i=i.filter(s)),i.pop()}return this.get(u(t).closest(this.SELECTOR),e)}static defineFn(t){let e=t||this.ZUI;u.fn[e]&&(e=`zui${this.NAME}`);const s=this;u.fn.extend({[e](i,...r){const o=typeof i=="object"?i:void 0,a=typeof i=="string"?i:void 0;let l;return this.each((c,h)=>{let d=s.get(h);if(d?o&&d.render(o):d=new s(h,o),a){let p=d[a],f=d;p===void 0&&(f=d.$,p=f[a]),typeof p=="function"?l=p.call(f,...r):l=p}}),l!==void 0?l:this}})}}X.DEFAULT={},X.MULTI_INSTANCE=!1;class Ia extends X{init(){const{offset:t=1,side:e,zIndex:s,pinnedClass:i="is-pinned"}=this.options,{$element:r}=this;r.css({position:"sticky",zIndex:s}),e&&r.css(e,-t),this._ob=new IntersectionObserver(([o])=>o.target.classList.toggle(i,o.intersectionRatio=l&&r>=c&&i+o<=h&&r+a<=d;const p=i<=h&&i+o>=l;return r<=d&&r+a>=c&&p}u.fn.isVisible=function(n){return an(this,n)};function Gi(n,t,e=!1){const s=u(n);if(t!==void 0){if(t.length){const i=`zui-runjs-${mt()}`;s.append(`