diff --git a/module/testcase/model.php b/module/testcase/model.php
index 4c1bd3b93d..6c56093528 100644
--- a/module/testcase/model.php
+++ b/module/testcase/model.php
@@ -429,7 +429,8 @@ class testcaseModel extends model
{
$case = $this->dao->findById($caseID)->from(TABLE_CASE)->fetch();
if(!$case) return false;
- foreach($case as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $case->$key = '';
+
+ foreach($case as $key => $value) if(strpos($key, 'Date') !== false and $value && !(int)substr($value, 0, 4)) $case->$key = '';
/* Get project and execution. */
if($this->app->tab == 'project')
diff --git a/module/testsuite/config/table.php b/module/testsuite/config/table.php
index 52adfc8453..386086787f 100644
--- a/module/testsuite/config/table.php
+++ b/module/testsuite/config/table.php
@@ -146,10 +146,10 @@ $config->testsuite->linkcase->dtable->fieldList['pri'] = $config->testcase->d
$config->testsuite->linkcase->dtable->fieldList['type'] = $config->testcase->dtable->fieldList['type'];
$config->testsuite->linkcase->dtable->fieldList['status'] = $config->testcase->dtable->fieldList['status'];
-$config->testsuite->linkcase->dtable->fieldList['status']['name'] = 'version';
-$config->testsuite->linkcase->dtable->fieldList['status']['title'] = $lang->testsuite->linkVersion;
-$config->testsuite->linkcase->dtable->fieldList['status']['type'] = 'text';
-$config->testsuite->linkcase->dtable->fieldList['status']['group'] = 'version';
+$config->testsuite->linkcase->dtable->fieldList['version']['name'] = 'version';
+$config->testsuite->linkcase->dtable->fieldList['version']['title'] = $lang->testsuite->linkVersion;
+$config->testsuite->linkcase->dtable->fieldList['version']['type'] = 'text';
+$config->testsuite->linkcase->dtable->fieldList['version']['group'] = 'version';
$config->testsuite->linkcase->dtable->fieldList['openedBy'] = $config->testcase->dtable->fieldList['openedBy'];
unset($config->testsuite->linkcase->dtable->fieldList['title']['nestedToggle']);
diff --git a/module/testsuite/control.php b/module/testsuite/control.php
index 450cdee245..609c99b674 100644
--- a/module/testsuite/control.php
+++ b/module/testsuite/control.php
@@ -317,6 +317,7 @@ class testsuite extends control
if(!empty($_POST))
{
$this->testsuite->linkCase($suiteID);
+ if(dao::isError()) return $this->send(array('result' => 'success', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('view', "suiteID=$suiteID")));
}
diff --git a/module/testsuite/ui/linkcase.html.php b/module/testsuite/ui/linkcase.html.php
index c042cf491f..76bdc649c2 100644
--- a/module/testsuite/ui/linkcase.html.php
+++ b/module/testsuite/ui/linkcase.html.php
@@ -36,7 +36,7 @@ div
$lang->testsuite->unlinkedCases . "({$pager->recTotal})"
)
);
-$cases = initTableData($cases, $config->testcase->dtable->fieldList, $this->testcase);
+$cases = initTableData($cases, $config->testsuite->linkcase->dtable->fieldList, $this->testcase);
$data = array_values($cases);
dtable
(
diff --git a/module/testtask/config/table.php b/module/testtask/config/table.php
index 8af7ff4662..99e18ddbb8 100644
--- a/module/testtask/config/table.php
+++ b/module/testtask/config/table.php
@@ -82,3 +82,22 @@ $config->testtask->cases->dtable->fieldList['actions']['title'] = $lang->actions
$config->testtask->cases->dtable->fieldList['actions']['type'] = 'actions';
$config->testtask->cases->dtable->fieldList['actions']['list'] = $config->testtask->cases->actionList;
$config->testtask->cases->dtable->fieldList['actions']['menu'] = array(array('confirmChange'), array('createBug', 'runCase', 'results', 'unlinkCase'));
+
+$config->testtask->linkcase = new stdclass();
+$config->testtask->linkcase->dtable = new stdclass();
+$config->testtask->linkcase->dtable->fieldList['id'] = $config->testcase->dtable->fieldList['id'];
+$config->testtask->linkcase->dtable->fieldList['title'] = $config->testcase->dtable->fieldList['title'];
+$config->testtask->linkcase->dtable->fieldList['pri'] = $config->testcase->dtable->fieldList['pri'];
+$config->testtask->linkcase->dtable->fieldList['type'] = $config->testcase->dtable->fieldList['type'];
+$config->testtask->linkcase->dtable->fieldList['status'] = $config->testcase->dtable->fieldList['status'];
+
+$config->testtask->linkcase->dtable->fieldList['version']['name'] = 'version';
+$config->testtask->linkcase->dtable->fieldList['version']['title'] = $lang->testtask->linkVersion;
+$config->testtask->linkcase->dtable->fieldList['version']['type'] = 'text';
+$config->testtask->linkcase->dtable->fieldList['version']['group'] = 'version';
+
+$config->testtask->linkcase->dtable->fieldList['openedBy'] = $config->testcase->dtable->fieldList['openedBy'];
+$config->testtask->linkcase->dtable->fieldList['lastRunner'] = $config->testcase->dtable->fieldList['lastRunner'];
+$config->testtask->linkcase->dtable->fieldList['lastRunDate'] = $config->testcase->dtable->fieldList['lastRunDate'];
+$config->testtask->linkcase->dtable->fieldList['lastRunResult'] = $config->testcase->dtable->fieldList['lastRunResult'];
+unset($config->testtask->linkcase->dtable->fieldList['title']['nestedToggle']);
diff --git a/module/testtask/control.php b/module/testtask/control.php
index 5bef0953bc..b2927296b3 100644
--- a/module/testtask/control.php
+++ b/module/testtask/control.php
@@ -1068,7 +1068,8 @@ class testtask extends control
if(!empty($_POST))
{
$this->testtask->linkCase($taskID, $type);
- $this->locate(inlink('cases', "taskID=$taskID"));
+ if(dao::isError()) return $this->send(array('result' => 'success', 'message' => dao::getError()));
+ $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('cases', "taskID={$taskID}")));
}
/* Save session. */
diff --git a/module/testtask/js/linkcase.ui.js b/module/testtask/js/linkcase.ui.js
new file mode 100644
index 0000000000..71e484365a
--- /dev/null
+++ b/module/testtask/js/linkcase.ui.js
@@ -0,0 +1,60 @@
+$(document).off('click', '.batch-btn').on('click', '.batch-btn', function()
+{
+ const dtable = zui.DTable.query($(this).target);
+ const checkedList = dtable.$.getChecks();
+ if(!checkedList.length) return;
+
+ const url = $(this).data('url');
+ const form = new FormData();
+ checkedList.forEach((id) =>
+ {
+ form.append('cases[]', id);
+ form.append('versions[' + id + ']', $('#versions' + id).val());
+ });
+
+ if($(this).hasClass('ajax-btn'))
+ {
+ $.ajaxSubmit({url, data: form});
+ }
+ else
+ {
+ postAndLoadPage(url, form);
+ }
+});
+
+/**
+ * 对列进行重定义。
+ * Redefine the column.
+ *
+ * @param array result
+ * @param array info
+ * @access public
+ * @return string|array
+ */
+window.renderCell = function(result, info)
+{
+ if(info.col.name == 'title' && result[0])
+ {
+ const testcase = info.row.data;
+
+ let html = '(';
+ for(i = 1; i <= testcase.version; i++)
+ {
+ html += "#" + i + "";
+ }
+ html += ')';
+ result.push({html});
+ }
+ if(info.col.name == 'version' && result[0])
+ {
+ const testcase = info.row.data;
+ let html = "";
+ result[0] = {html};
+ }
+ return result;
+}
diff --git a/module/testtask/lang/zh-cn.php b/module/testtask/lang/zh-cn.php
index 9fff60026a..a081bd1ddb 100644
--- a/module/testtask/lang/zh-cn.php
+++ b/module/testtask/lang/zh-cn.php
@@ -208,6 +208,12 @@ $lang->testtask->featureBar['browse']['done'] = $lang->testtask->done;
$lang->testtask->featureBar['cases']['all'] = $lang->testtask->allCases;
$lang->testtask->featureBar['cases']['assignedtome'] = $lang->testtask->assignedToMe;
+$lang->testtask->featureBar['linkcase']['all'] = $lang->all;
+$lang->testtask->featureBar['linkcase']['bystory'] = $lang->testtask->linkByStory;
+$lang->testtask->featureBar['linkcase']['bysuite'] = $lang->testtask->linkBySuite;
+$lang->testtask->featureBar['linkcase']['bybuild'] = $lang->testtask->linkByBuild;
+$lang->testtask->featureBar['linkcase']['bybug'] = $lang->testtask->linkByBug;
+
$lang->testtask->unitTag['all'] = '所有';
$lang->testtask->unitTag['newest'] = '最近';
$lang->testtask->unitTag['thisWeek'] = '本周';
diff --git a/module/testtask/ui/linkcase.html.php b/module/testtask/ui/linkcase.html.php
new file mode 100644
index 0000000000..c161d0da49
--- /dev/null
+++ b/module/testtask/ui/linkcase.html.php
@@ -0,0 +1,96 @@
+
+ * @package testsuite
+ * @link https://www.zentao.net
+ */
+namespace zin;
+
+$items = array();
+foreach($lang->testtask->featureBar['linkcase'] as $key => $label)
+{
+ $isActive = $key == $type;
+ if($key == 'bysuite' || $key == 'bybuild')
+ {
+ if($isActive) $label = $key == 'bysuite' ? $suiteList[$param]->name : zget($testTask, $param);
+ $subItems = array();
+ $dataList = $key == 'bysuite' ? $suiteList : $testTask;
+ foreach($dataList as $dataID => $data)
+ {
+ $text = $key == 'bysuite' ? $data->name : $data;
+ $subItems[] = array
+ (
+ 'text' => $text,
+ 'active' => $key == $type && $dataID == $param,
+ 'url' => createLink('testtask', 'linkCase', "taskID={$taskID}&type={$key}¶m={$dataID}"),
+ 'badge' => $dataID == $param && !empty($pager->recTotal) ? array('text' => $pager->recTotal, 'class' => 'size-sm rounded-full white') : null,
+ 'props' => ['data-id' => $text, 'data-load' => 'table']
+ );
+ }
+ $items[] = array
+ (
+ 'text' => $label,
+ 'active' => $isActive,
+ 'type' => 'dropdown',
+ 'caret' => 'down',
+ 'items' => $subItems,
+ 'badge' => $isActive && !empty($pager->recTotal) ? array('text' => $pager->recTotal, 'class' => 'size-sm rounded-full white') : null,
+ 'props' => array('data-id' => $label)
+ );
+ }
+ else
+ {
+ $items[] = array
+ (
+ 'text' => $label,
+ 'active' => $isActive,
+ 'url' => createLink('testtask', 'linkCase', "taskID={$taskID}&type={$key}"),
+ 'badge' => $isActive && !empty($pager->recTotal) ? array('text' => $pager->recTotal, 'class' => 'size-sm rounded-full white') : null,
+ 'props' => ['data-id' => $label, 'data-load' => 'table']
+ );
+ }
+}
+featureBar
+(
+ set::items($items),
+ set::current($type),
+ set::linkParams("taskID=$taskID&type={key}"),
+ to::before(a(set::href(createLink('testtask', 'browse', "product={$task->product}")), set::class('btn secondary'), icon('back'), $lang->goback)),
+ li(searchToggle())
+);
+
+$footToolbar = array('items' => array
+(
+ array('text' => $lang->save, 'className' => 'batch-btn ajax-btn', 'data-url' => helper::createLink('testtask', 'linkCase', "taskID={$taskID}&type={$type}¶m={$param}"))
+), 'btnProps' => array('size' => 'sm', 'btnType' => 'secondary'));
+
+div
+(
+ set('class', 'mb-2'),
+ icon('unlink'),
+ span
+ (
+ set('class', 'font-semibold ml-2'),
+ $lang->testtask->unlinkedCases . "({$pager->recTotal})"
+ )
+);
+$cases = initTableData($cases, $config->testtask->linkcase->dtable->fieldList, $this->testcase);
+$data = array_values($cases);
+dtable
+(
+ set::userMap($users),
+ set::data($data),
+ set::cols($config->testtask->linkcase->dtable->fieldList),
+ set::fixedLeftWidth('33%'),
+ set::checkable(true),
+ set::footToolbar($footToolbar),
+ set::onRenderCell(jsRaw('window.renderCell')),
+ set::footPager(usePager()),
+);
+
+render();
+