Merge branch 'main' into feature/relation
This commit is contained in:
@@ -122,7 +122,7 @@ class executionEntry extends entry
|
||||
$useCode = $this->checkCodeUsed();
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'project,name,begin,end,lifetime,desc,days,acl,status,PO,PM,QD,RD';
|
||||
if($useCode) $fields .= 'code';
|
||||
if($useCode) $fields .= ',code';
|
||||
$this->batchSetPost($fields, $oldExecution);
|
||||
|
||||
$this->setPost('whitelist', $this->request('whitelist', explode(',', $oldExecution->whitelist)));
|
||||
|
||||
@@ -81,7 +81,7 @@ class executionsEntry extends entry
|
||||
$useCode = $this->checkCodeUsed();
|
||||
|
||||
$fields = 'project,name,begin,end,lifetime,desc,days,percent,parent';
|
||||
if($useCode) $fields .= 'code';
|
||||
if($useCode) $fields .= ',code';
|
||||
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class storiesEntry extends entry
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList');
|
||||
$result[] = $this->format($story, 'title:decodeHtml,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList');
|
||||
}
|
||||
return $this->send(201, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result, 'requirements' => $requirements));
|
||||
}
|
||||
|
||||
+1
-165
@@ -27,171 +27,7 @@ IF "%pmsRoot%"=="" (
|
||||
|
||||
:: get pmsRoot
|
||||
if "%pmsRoot:~-1%" == "/" SET pmsRoot=%pmsRoot:~0,-1%
|
||||
:: get requestType
|
||||
SET requestType= 'PATH_INFO'
|
||||
for /f "tokens=3" %%f in ('find /c "'PATH_INFO'" "%baseDir%..\config\my.php"') do set count=%%f
|
||||
if not defined count set count=1
|
||||
if %count% == 0 SET requestType='GET'
|
||||
|
||||
:: create ztcli
|
||||
SET ztcli= %phpcli% %baseDir%ztcli %%*
|
||||
echo %ztcli% > %baseDir%ztcli.bat
|
||||
echo ztcli.bat ok
|
||||
|
||||
:: create backup.bat
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET backup= %phpcli% %baseDir%ztcli "%pmsRoot%/backup-backup.html"
|
||||
)else (
|
||||
SET backup= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=backup&f=backup"
|
||||
)
|
||||
echo %backup% > %baseDir%backup.bat
|
||||
echo backup.bat ok
|
||||
|
||||
:: create dailyreminder.bat
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET computeburn= %phpcli% %baseDir%ztcli "%pmsRoot%/report-remind"
|
||||
)else (
|
||||
SET computeburn= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=report&f=remind"
|
||||
)
|
||||
echo %computeburn% > %baseDir%dailyreminder.bat
|
||||
echo dailyreminder.bat ok
|
||||
|
||||
:: create computeburn.bat
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET computeburn= %phpcli% %baseDir%ztcli "%pmsRoot%/execution-computeburn"
|
||||
)else (
|
||||
SET computeburn= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=execution&f=computeburn"
|
||||
)
|
||||
echo %computeburn% > %baseDir%computeburn.bat
|
||||
echo computeburn.bat ok
|
||||
|
||||
:: create computetaskeffort.bat
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET computetaskeffort= %phpcli% %baseDir%ztcli "%pmsRoot%/execution-computetaskeffort"
|
||||
)else (
|
||||
SET computetaskeffort= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=execution&f=computetaskeffort"
|
||||
)
|
||||
echo %computetaskeffort% > %baseDir%computetaskeffort.bat
|
||||
echo computetaskeffort.bat ok
|
||||
|
||||
:: create checkdb.bat
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET checkdb= %phpcli% %baseDir%ztcli "%pmsRoot%/admin-checkdb"
|
||||
)else (
|
||||
SET checkdb= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=admin&f=checkdb"
|
||||
)
|
||||
echo %checkdb% > %baseDir%checkdb.bat
|
||||
echo checkdb.bat ok
|
||||
|
||||
:: create syncsvn.bat
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET syncsvn= %phpcli% %baseDir%ztcli "%pmsRoot%/svn-run"
|
||||
)else (
|
||||
SET syncsvn= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=svn&f=run"
|
||||
)
|
||||
echo %syncsvn% > %baseDir%syncsvn.bat
|
||||
echo syncsvn.bat ok
|
||||
|
||||
:: create syncgit.bat.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET syncgit= %phpcli% %baseDir%ztcli "%pmsRoot%/git-run"
|
||||
)else (
|
||||
SET syncgit= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=git&f=run"
|
||||
)
|
||||
echo %syncgit% > %baseDir%syncgit.bat
|
||||
echo syncgit.bat ok
|
||||
|
||||
:: async send mail.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET sendmail= %phpcli% %baseDir%ztcli "%pmsRoot%/mail-asyncSend"
|
||||
)else (
|
||||
SET sendmail= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=mail&f=asyncSend"
|
||||
)
|
||||
echo %sendmail% > %baseDir%sendmail.bat
|
||||
echo sendmail.bat ok
|
||||
|
||||
:: async send webhook.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET sendwebhook= %phpcli% %baseDir%ztcli "%pmsRoot%/webhook-asyncSend"
|
||||
)else (
|
||||
SET sendwebhook= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=webhook&f=asyncSend"
|
||||
)
|
||||
echo %sendwebhook% > %baseDir%sendwebhook.bat
|
||||
echo sendwebhook.bat ok
|
||||
|
||||
:: create cycle todo.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET createcycle= %phpcli% %baseDir%ztcli "%pmsRoot%/todo-createCycle"
|
||||
)else (
|
||||
SET createcycle= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=todo&f=createCycle"
|
||||
)
|
||||
echo %createcycle% > %baseDir%createcycle.bat
|
||||
echo createcycle.bat ok
|
||||
|
||||
:: init queue.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET initqueue= %phpcli% %baseDir%ztcli "%pmsRoot%/ci-initQueue"
|
||||
)else (
|
||||
SET initqueue= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=ci&f=initQueue"
|
||||
)
|
||||
echo %initqueue% > %baseDir%initqueue.bat
|
||||
echo initqueue.bat ok
|
||||
|
||||
:: check build status.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET checkbuildstatus= %phpcli% %baseDir%ztcli "%pmsRoot%/ci-checkBuildStatus"
|
||||
)else (
|
||||
SET checkbuildstatus= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=ci&f=checkBuildStatus"
|
||||
)
|
||||
echo %checkbuildstatus% > %baseDir%checkbuildstatus.bat
|
||||
echo checkbuildstatus.bat ok
|
||||
|
||||
:: execute compile.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET execcompile= %phpcli% %baseDir%ztcli "%pmsRoot%/ci-exec"
|
||||
)else (
|
||||
SET execcompile= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=ci&f=exec"
|
||||
)
|
||||
echo %execcompile% > %baseDir%execcompile.bat
|
||||
echo execcompile.bat ok
|
||||
|
||||
:: delete log.
|
||||
if %requestType% == 'PATH_INFO' (
|
||||
SET deletelog= %phpcli% %baseDir%ztcli "%pmsRoot%/admin-deleteLog"
|
||||
)else (
|
||||
SET deletelog= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=admin&f=deleteLog"
|
||||
)
|
||||
echo %deletelog% > %baseDir%deletelog.bat
|
||||
echo deletelog.bat ok
|
||||
|
||||
:: encrypt.
|
||||
if exist "%baseDir%php\encrypt.php" (
|
||||
SET encrypt= %phpcli% %baseDir%php\encrypt.php %%*
|
||||
echo %encrypt% > %baseDir%encrypt.bat
|
||||
echo encrypt.bat ok
|
||||
)
|
||||
|
||||
:: create crond.bat
|
||||
SET cron= %phpcli% %baseDir%php\crond.php
|
||||
echo %cron% > %baseDir%crond.bat
|
||||
echo crond.bat ok
|
||||
|
||||
:: create system cron.
|
||||
if not exist %cronDir% md %cronDir%
|
||||
echo # system cron. > %sysCron%
|
||||
echo #min hour day month week command. >> %sysCron%
|
||||
echo 0 1 * * * %baseDir%dailyreminder.bat # daily reminder. >> %sysCron%
|
||||
echo 1 1 * * * %baseDir%backup.bat # backup database and file. >> %sysCron%
|
||||
echo 1 23 * * * %baseDir%computeburn.bat # compute burndown chart. >> %sysCron%
|
||||
echo 1-59/2 * * * * %baseDir%syncsvn.bat # sync subversion. >> %sysCron%
|
||||
echo 1-59/2 * * * * %baseDir%syncgit.bat # sync git. >> %sysCron%
|
||||
echo 1-59/5 * * * * %baseDir%sendmail.bat # async send mail. >> %sysCron%
|
||||
echo 1-59/5 * * * * %baseDir%sendwebhook.bat # async send webhook. >> %sysCron%
|
||||
echo 1 1 * * * %baseDir%createcycle.bat # create cycle todo. >> %sysCron%
|
||||
echo 30 1 * * * %baseDir%deletelog.bat # delete log. >> %sysCron%
|
||||
echo 1 0 * * * %baseDir%initqueue.bat # init queue. >> %sysCron%
|
||||
echo 1-59/5 * * * * %baseDir%checkbuildstatus.bat # check build status. >> %sysCron%
|
||||
echo 1-59/5 * * * * %baseDir%execcompile.bat # execute compile. >> %sysCron%
|
||||
%phpcli% %baseDir%php\init.php %phpcli% %pmsRoot%
|
||||
|
||||
:: return 0 when success.
|
||||
exit /b 0
|
||||
|
||||
+1
-168
@@ -28,174 +28,7 @@ if [ ! -n "$2" ]; then
|
||||
fi
|
||||
|
||||
pmsRoot=`echo "$pmsRoot" | sed 's/[/]$//g'`
|
||||
cat $basePath/../config/my.php |awk '$1!~/^\/\//&& $1~/\$config\->requestType/{requestType = $0} END{print requestType}'| grep -c 'PATH_INFO' > ./init.tmp
|
||||
if [ "`cat ./init.tmp`" != 0 ];then
|
||||
requestType='PATH_INFO';
|
||||
else
|
||||
requestType='GET';
|
||||
fi
|
||||
rm ./init.tmp
|
||||
|
||||
# ztcli
|
||||
ztcli="$phpcli $basePath/ztcli \$*"
|
||||
echo $ztcli > $basePath/ztcli.sh
|
||||
echo "ztcli.sh ok"
|
||||
|
||||
# backup database
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
backup="$phpcli $basePath/ztcli '$pmsRoot/backup-backup.html'";
|
||||
else
|
||||
backup="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=backup&f=backup'";
|
||||
fi
|
||||
echo $backup > $basePath/backup.sh
|
||||
echo "backup.sh ok"
|
||||
|
||||
# computeburn
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
computeburn="$phpcli $basePath/ztcli '$pmsRoot/execution-computeburn'";
|
||||
else
|
||||
computeburn="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=execution&f=computeburn'";
|
||||
fi
|
||||
echo $computeburn > $basePath/computeburn.sh
|
||||
echo "computeburn.sh ok"
|
||||
|
||||
# compute task effort.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
computetaskeffort="$phpcli $basePath/ztcli '$pmsRoot/execution-computetaskeffort'";
|
||||
else
|
||||
computetaskeffort="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=execution&f=computetaskeffort'";
|
||||
fi
|
||||
echo $computetaskeffort > $basePath/computetaskeffort.sh
|
||||
echo "computetaskeffort.sh ok"
|
||||
|
||||
# daily remind
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
checkdb="$phpcli $basePath/ztcli '$pmsRoot/report-remind'";
|
||||
else
|
||||
checkdb="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=report&f=remind'";
|
||||
fi
|
||||
echo $checkdb > $basePath/dailyreminder.sh
|
||||
echo "dailyreminder.sh ok"
|
||||
|
||||
# check database
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
checkdb="$phpcli $basePath/ztcli '$pmsRoot/admin-checkdb'";
|
||||
else
|
||||
checkdb="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=admin&f=checkdb'";
|
||||
fi
|
||||
echo $checkdb > $basePath/checkdb.sh
|
||||
echo "checkdb.sh ok"
|
||||
|
||||
# syncsvn.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
syncsvn="$phpcli $basePath/ztcli '$pmsRoot/svn-run'";
|
||||
else
|
||||
syncsvn="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=svn&f=run'";
|
||||
fi
|
||||
echo $syncsvn > $basePath/syncsvn.sh
|
||||
echo "syncsvn.sh ok"
|
||||
|
||||
# syncgit.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
syncgit="$phpcli $basePath/ztcli '$pmsRoot/git-run'";
|
||||
else
|
||||
syncgit="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=git&f=run'";
|
||||
fi
|
||||
echo $syncgit > $basePath/syncgit.sh
|
||||
echo "syncgit.sh ok"
|
||||
|
||||
# async send mail.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
mailsend="$phpcli $basePath/ztcli '$pmsRoot/mail-asyncSend'";
|
||||
else
|
||||
mailsend="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=mail&f=asyncSend'";
|
||||
fi
|
||||
echo $mailsend > $basePath/sendmail.sh
|
||||
echo "sendmail.sh ok"
|
||||
|
||||
# async send webhook.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
sendwebhook="$phpcli $basePath/ztcli '$pmsRoot/webhook-asyncSend'";
|
||||
else
|
||||
sendwebhook="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=webhook&f=asyncSend'";
|
||||
fi
|
||||
echo $sendwebhook > $basePath/sendwebhook.sh
|
||||
echo "sendwebhook.sh ok"
|
||||
|
||||
# create cycle todo.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
createcycle="$phpcli $basePath/ztcli '$pmsRoot/todo-createCycle'";
|
||||
else
|
||||
createcycle="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=todo&f=createCycle'";
|
||||
fi
|
||||
echo $createcycle > $basePath/createcycle.sh
|
||||
echo "createcycle.sh ok"
|
||||
|
||||
# init queue.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
initqueue="$phpcli $basePath/ztcli '$pmsRoot/ci-initQueue'";
|
||||
else
|
||||
initqueue="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=ci&f=initQueue'";
|
||||
fi
|
||||
echo $initqueue > $basePath/initqueue.sh
|
||||
echo "initqueue.sh ok"
|
||||
|
||||
# check build status.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
checkbuildstatus="$phpcli $basePath/ztcli '$pmsRoot/ci-checkBuildStatus'";
|
||||
else
|
||||
checkbuildstatus="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=ci&f=checkBuildStatus'";
|
||||
fi
|
||||
echo $checkbuildstatus > $basePath/checkbuildstatus.sh
|
||||
echo "checkbuildstatus.sh ok"
|
||||
|
||||
# execute compile.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
execcompile="$phpcli $basePath/ztcli '$pmsRoot/ci-exec'";
|
||||
else
|
||||
execcompile="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=ci&f=exec'";
|
||||
fi
|
||||
echo $execcompile > $basePath/execcompile.sh
|
||||
echo "execcompile.sh ok"
|
||||
|
||||
# delete log.
|
||||
if [ $requestType == 'PATH_INFO' ]; then
|
||||
deletelog="$phpcli $basePath/ztcli '$pmsRoot/admin-deleteLog'";
|
||||
else
|
||||
deletelog="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=admin&f=deleteLog'";
|
||||
fi
|
||||
echo $deletelog > $basePath/deletelog.sh
|
||||
echo "deletelog.sh ok"
|
||||
|
||||
# encrypt.
|
||||
if [ -f "$basePath/php/encrypt.php" ]; then
|
||||
encrypt="$phpcli $basePath/php/encrypt.php \$*"
|
||||
echo $encrypt > $basePath/encrypt.sh
|
||||
echo "encrypt.sh ok"
|
||||
fi
|
||||
|
||||
# cron
|
||||
if [ ! -d "$basePath/cron" ]; then
|
||||
mkdir $basePath/cron
|
||||
fi
|
||||
echo "# system cron." > $basePath/cron/sys.cron
|
||||
echo "#min hour day month week command." >> $basePath/cron/sys.cron
|
||||
echo "0 1 * * * $basePath/dailyreminder.sh # dailyreminder." >> $basePath/cron/sys.cron
|
||||
echo "1 1 * * * $basePath/backup.sh # backup database and file." >> $basePath/cron/sys.cron
|
||||
echo "1 23 * * * $basePath/computeburn.sh # compute burndown chart." >> $basePath/cron/sys.cron
|
||||
echo "1-59/5 * * * * $basePath/syncsvn.sh # sync subversion." >> $basePath/cron/sys.cron
|
||||
echo "1-59/5 * * * * $basePath/syncgit.sh # sync git." >> $basePath/cron/sys.cron
|
||||
echo "1-59/5 * * * * $basePath/sendmail.sh # async send mail." >> $basePath/cron/sys.cron
|
||||
echo "1-59/5 * * * * $basePath/sendwebhook.sh # async send webhook." >> $basePath/cron/sys.cron
|
||||
echo "1 1 * * * $basePath/createcycle.sh # create cycle todo." >> $basePath/cron/sys.cron
|
||||
echo "30 1 * * * $basePath/deletelog.sh # delete log." >> $basePath/cron/sys.cron
|
||||
echo "1 0 * * * $basePath/initqueue.sh # init queue." >> $basePath/cron/sys.cron
|
||||
echo "1-59/5 * * * * $basePath/checkbuildstatus.sh # check build status." >> $basePath/cron/sys.cron
|
||||
echo "1-59/5 * * * * $basePath/execcompile.sh # execute compile." >> $basePath/cron/sys.cron
|
||||
cron="$phpcli $basePath/php/crond.php"
|
||||
echo $cron > $basePath/cron.sh
|
||||
echo "cron.sh ok"
|
||||
|
||||
$phpcli "$basePath/php/init.php" $phpcli $pmsRoot;
|
||||
chmod 755 $basePath/*.sh
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
$phpcli = $argv[1];
|
||||
$pmsRoot = $argv[2];
|
||||
|
||||
$basePath = dirname(__FILE__, 3);
|
||||
chdir($basePath);
|
||||
|
||||
include './framework/router.class.php';
|
||||
include './framework/control.class.php';
|
||||
include './framework/model.class.php';
|
||||
include './framework/helper.class.php';
|
||||
|
||||
try
|
||||
{
|
||||
$app = router::createApp('pms', $basePath, 'router');
|
||||
}
|
||||
catch (Exception $exception)
|
||||
{
|
||||
die("Connect database fail. Please open mysql service.\n");
|
||||
}
|
||||
|
||||
$suffix = stripos(PHP_OS, 'WIN') !== false ? '.bat' : '.sh';
|
||||
$requestType = $app->config->requestType;
|
||||
$binPath = $basePath . '/bin';
|
||||
$crond = "# system cron.\n";
|
||||
$crond .= "#min \t hour \t day \t month \t week \t command.\n";
|
||||
|
||||
/* Remove old cron. */
|
||||
foreach(glob("$binPath/*{$suffix}") as $file)
|
||||
{
|
||||
$fileName = basename($file);
|
||||
if($fileName == "init{$suffix}") continue;
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
$crons = $app->dbh->query('SELECT * FROM ' . TABLE_CRON . " WHERE `type`='zentao' AND `status`='normal' AND `buildin`='1'")->fetchAll();
|
||||
foreach($crons as $cron)
|
||||
{
|
||||
parse_str($cron->command, $params);
|
||||
if(empty($params)) continue;
|
||||
|
||||
$command = '';
|
||||
if($requestType == 'PATH_INFO')
|
||||
{
|
||||
$command = "$phpcli $binPath/ztcli '$pmsRoot/{$params['moduleName']}-{$params['methodName']}.html'";
|
||||
}
|
||||
else
|
||||
{
|
||||
$command = "$phpcli $binPath/ztcli '$pmsRoot/index.php?m={$params['moduleName']}&f={$params['methodName']}'";
|
||||
}
|
||||
|
||||
$cronFile = strtolower($params['moduleName']) . strtolower($params['methodName']) . $suffix;
|
||||
file_put_contents($binPath . '/' . $cronFile, $command);
|
||||
|
||||
$crond .= "{$cron->m} \t {$cron->h} \t {$cron->dom} \t {$cron->mon} \t {$cron->dow} \t $binPath/$cronFile \t #{$cron->remark}\n";
|
||||
echo "{$cronFile} ok.\n";
|
||||
}
|
||||
|
||||
if(!is_dir("$binPath/cron")) mkdir("$binPath/cron", 0777, true);
|
||||
file_put_contents("$binPath/cron/sys.cron", $crond);
|
||||
file_put_contents("$binPath/cron" . $suffix, "$phpcli $binPath/php/crond.php\n");
|
||||
echo "cron{$suffix} ok\n";
|
||||
|
||||
file_put_contents("$binPath/ztcli{$suffix}", "$phpcli $binPath/ztcli " . ($suffix == '.bat' ? '%' : '$') . "*\n");
|
||||
echo "ztcli{$suffix} ok\n";
|
||||
+1
-1
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
|
||||
if(!function_exists('getWebRoot')){function getWebRoot(){}}
|
||||
|
||||
/* 基本设置。Basic settings. */
|
||||
$config->version = '20.7'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->version = '20.7.1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->liteVersion = '1.2'; // 迅捷版版本。 The version of Lite.
|
||||
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
|
||||
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
|
||||
|
||||
@@ -398,6 +398,7 @@ $filter->testcase->browse->cookie['onlyScene'] = 'code';
|
||||
$filter->todo->export->cookie['checkedItem'] = 'reg::checked';
|
||||
|
||||
$filter->user->login->cookie['keepLogin'] = 'equal::on';
|
||||
$filter->user->login->cookie['logout'] = 'equal::1';
|
||||
$filter->user->export->cookie['checkedItem'] = 'reg::any';
|
||||
|
||||
$filter->block->default->get['hash'] = 'reg::md5';
|
||||
|
||||
@@ -714,6 +714,7 @@ $config->objectTables['market'] = TABLE_MARKET;
|
||||
$config->objectTables['marketreport'] = TABLE_MARKETREPORT;
|
||||
$config->objectTables['marketresearch'] = TABLE_PROJECT;
|
||||
$config->objectTables['researchstage'] = TABLE_PROJECT;
|
||||
$config->objectTables['productline'] = TABLE_MODULE;
|
||||
|
||||
$config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme', 'visions', 'aiPrompts', 'promptDesign', 'promptExec');
|
||||
$config->disabledFeatures = '';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -30,7 +30,8 @@ CREATE TABLE IF NOT EXISTS `zt_sqlbuilder` (
|
||||
DELETE t1
|
||||
FROM `zt_workflowlayout` t1
|
||||
LEFT JOIN `zt_workflowfield` t2 ON t1.field = t2.field AND t1.module = t2.module
|
||||
WHERE t2.buildin = '1' AND t2.role = 'buildin';
|
||||
LEFT JOIN `zt_workflowaction` t3 ON t1.module = t3.module AND t1.action = t3.action
|
||||
WHERE t2.buildin = '1' AND t2.role = 'buildin' AND t3.buildin = '1';
|
||||
|
||||
ALTER TABLE `zt_dataview` ADD `mode` enum('text', 'builder') not NULL default 'builder' AFTER `code`;
|
||||
UPDATE `zt_dataview` SET `mode` = 'text';
|
||||
|
||||
@@ -28,3 +28,14 @@ CREATE INDEX `deleted` ON `zt_metriclib` (`deleted`);
|
||||
|
||||
ALTER TABLE `zt_pipeline` ADD `instanceID` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `private`;
|
||||
ALTER TABLE `zt_mr` ADD `isFlow` ENUM('0', '1') NOT NULL DEFAULT '0' AFTER `squash`;
|
||||
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'task', 'recordWorkhour' FROM `zt_grouppriv` WHERE `module` = 'task' AND `method` = 'recordEstimate';
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'task', 'editEffort' FROM `zt_grouppriv` WHERE `module` = 'task' AND `method` = 'editEstimate';
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'task', 'deleteWorkhour' FROM `zt_grouppriv` WHERE `module` = 'task' AND `method` = 'deleteEstimate';
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'bug', 'confirm' FROM `zt_grouppriv` WHERE `module` = 'bug' AND `method` = 'confirmBug';
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'testcase', 'batchChangeType' FROM `zt_grouppriv` WHERE `module` = 'testcase' AND `method` = 'batchCaseTypeChange';
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'ops', 'provider' FROM `zt_grouppriv` WHERE `module` = 'ops' AND `method` = 'provide';
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'projectstory', 'importToLib' FROM `zt_grouppriv` WHERE `module` = 'story' AND `method` = 'importToLib';
|
||||
REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) SELECT `group`, 'projectstory', 'batchImportToLib' FROM `zt_grouppriv` WHERE `module` = 'story' AND `method` = 'batchImportToLib';
|
||||
|
||||
CREATE UNIQUE INDEX `account_openID` ON `zt_oauth`(`account`,`openID`,`providerType`,`providerID`);
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
USE `__TABLE__`;
|
||||
|
||||
DROP FUNCTION IF EXISTS `get_monday`;
|
||||
CREATE FUNCTION `get_monday`(day date) RETURNS date
|
||||
begin if date_format(day, '%w') = 0 then return subdate(day, date_format(day, '%w') - 6)__DELIMITER__
|
||||
else return subdate(day, date_format(day, '%w') -1)__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `get_sunday`;
|
||||
CREATE FUNCTION `get_sunday`(day date) RETURNS date
|
||||
begin
|
||||
if date_format(day, '%w') = 0 then return day__DELIMITER__
|
||||
else return subdate(day, date_format(day, '%w') - 7)__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_cminited`;
|
||||
CREATE FUNCTION qc_cminited($project int, $category varchar(30)) returns int
|
||||
begin
|
||||
declare products int default 0__DELIMITER__
|
||||
declare objects int default 0__DELIMITER__
|
||||
select COUNT(1) from zt_projectproduct where project = $project into products__DELIMITER__
|
||||
select COUNT(DISTINCT product) from zt_object where project = $project and category = $category and type = 'taged' and product in (select product from zt_projectproduct where project = $project) into objects__DELIMITER__
|
||||
IF products = objects THEN
|
||||
return 1__DELIMITER__
|
||||
ELSEIF products != objects THEN
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_initscale`;
|
||||
CREATE FUNCTION qc_initscale($project int, $category varchar(30), $estimateType varchar(30)) RETURNS float(10,2)
|
||||
BEGIN
|
||||
declare $estimate int default 0__DELIMITER__
|
||||
declare $storyEst varchar(30) default 'storyEst'__DELIMITER__
|
||||
declare $requestEst varchar(30) default 'requestEst'__DELIMITER__
|
||||
if($estimateType = $storyEst) THEN SELECT sum(storyEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = $category and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
if($estimateType = $requestEst) THEN SELECT sum(requestEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = $category and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
RETURN @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmplanscale`;
|
||||
CREATE FUNCTION `qc_pgmplanscale`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
declare programScale float (10,2) default 0__DELIMITER__
|
||||
select `scale` from zt_workestimation where project = $project into @programScale__DELIMITER__
|
||||
return @programScale__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmsrinitscale`;
|
||||
CREATE FUNCTION `qc_pgmsrinitscale`($project int) RETURNS float(10,2)
|
||||
begin
|
||||
declare scale int default 0__DELIMITER__
|
||||
declare inited int default 0__DELIMITER__
|
||||
select qc_cminited($project, 'SRS') into inited__DELIMITER__
|
||||
IF inited = 1 THEN
|
||||
select qc_initscale($project, 'SRS', 'storyEst') into scale __DELIMITER__
|
||||
return scale __DELIMITER__
|
||||
ELSE
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmsrrealscale`;
|
||||
CREATE FUNCTION `qc_pgmsrrealscale`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
declare totalEstimate float(10,2) default 0__DELIMITER__
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_story where id in (select story from zt_projectstory where project=$project) and type='story' and deleted='0' and closedReason not in ('subdivided', 'duplicate', 'willnotdo', 'cancel', 'bydesign') into totalEstimate__DELIMITER__
|
||||
return totalEstimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmurinitscale`;
|
||||
CREATE FUNCTION `qc_pgmurinitscale`($project int) RETURNS float(10,2)
|
||||
begin
|
||||
declare scale int default 0__DELIMITER__
|
||||
declare inited int default 0__DELIMITER__
|
||||
select qc_cminited($project, 'URS') into inited__DELIMITER__
|
||||
IF inited = 1 THEN
|
||||
select qc_initscale($project, 'URS', 'requestEst') into scale__DELIMITER__
|
||||
return scale__DELIMITER__
|
||||
ELSE
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmurrealscale`;
|
||||
CREATE FUNCTION `qc_pgmurrealscale`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
declare totalEstimate float(10,2) default 0__DELIMITER__
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_story where project=$project and type='requirement' and deleted='0' and closedReason not in ('subdivided', 'duplicate', 'willnotdo', 'cancel', 'bydesign') into totalEstimate__DELIMITER__
|
||||
return totalEstimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmallrequirementstage`;
|
||||
CREATE FUNCTION `qc_pgmallrequirementstage`($project int) RETURNS int(1)
|
||||
BEGIN
|
||||
-- 获取项目产品总数
|
||||
select COUNT(1) AS products from zt_projectproduct where project = $project into @totalproduct__DELIMITER__
|
||||
-- 获取已经设置需求阶段的产品总数
|
||||
select COUNT(1) AS product from (select product from zt_projectproduct where project in (select id from zt_project where project = $project and type = 'stage' and attribute = 'request' and deleted = '0') GROUP BY product) as product into @product__DELIMITER__
|
||||
-- 让项目产品总数和已设置需求阶段产品总数比较,都设置返回1,否则返回0
|
||||
if @totalproduct = @product then return 1__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
RETURN 0__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesigntplandays`;
|
||||
CREATE FUNCTION `qc_pgmdesigntplandays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesigntrealdays`;
|
||||
CREATE FUNCTION `qc_pgmdesigntrealdays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelplandays`;
|
||||
CREATE FUNCTION `qc_pgmdevelplandays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelrealdays`;
|
||||
CREATE FUNCTION `qc_pgmdevelrealdays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestplandays`;
|
||||
CREATE FUNCTION `qc_pgmrequestplandays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestrealdays`;
|
||||
CREATE FUNCTION `qc_pgmrequestrealdays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmspecifiedtypeactualdays`;
|
||||
CREATE FUNCTION `qc_pgmspecifiedtypeactualdays`($project int,$attribute varchar(50)) RETURNS int(10)
|
||||
BEGIN
|
||||
-- 查询某类型的阶段总数
|
||||
select COUNT(1) from zt_project where project = $project and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @totalstory__DELIMITER__
|
||||
-- 查询某类型已设置实际工期的阶段总数
|
||||
select COUNT(1) from zt_project where project = $project and attribute = $attribute and deleted = '0' and realDuration > 0 and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @setstory__DELIMITER__
|
||||
-- 查询项目下某类型阶段实际工期总数
|
||||
select sum(realDuration) as realDuration from zt_project where project = $project and attribute = $attribute and deleted = '0' and realDuration > 0 and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @days__DELIMITER__
|
||||
-- 判断项目下某类型的阶段是否都已设置实际工期
|
||||
if @totalstory != @setstory then
|
||||
set @days = 0__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmspecifiedtypeplanneddays`;
|
||||
CREATE FUNCTION `qc_pgmspecifiedtypeplanneddays`($project int,$attribute varchar(50)) RETURNS int(10)
|
||||
BEGIN
|
||||
select sum(planDuration) as planDuration from zt_project where project = $project and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmstageactualduration`;
|
||||
CREATE FUNCTION `qc_pgmstageactualduration`($product int, $attribute varchar(50)) RETURNS int(10)
|
||||
BEGIN
|
||||
-- 查找某类型的阶段总数
|
||||
select COUNT(1) as totalduration from zt_project where id in (select project from zt_projectproduct where product = $product) and type = 'stage' and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) into @totalduration__DELIMITER__
|
||||
-- 查某类型阶段已设置实际工期的总数
|
||||
select COUNT(1) as setduration from zt_project where id in (select project from zt_projectproduct where product = $product) and type = 'stage' and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) and realDuration > 0 into @setduration__DELIMITER__
|
||||
-- 指定产品下某类型的阶段实际工期总和
|
||||
select sum(realDuration) as duration from zt_project where id in (select project from zt_projectproduct where product = $product) and type = 'stage' and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) and realDuration > 0 into @duration__DELIMITER__
|
||||
-- 需要判断该类型阶段都已设置实际工期,否则不统计
|
||||
if @totalduration != @setduration then
|
||||
set @duration = 0__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
return @duration__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmstageplannedduration`;
|
||||
CREATE FUNCTION `qc_pgmstageplannedduration`($product int, $attribute varchar(50)) RETURNS int(10)
|
||||
BEGIN
|
||||
-- 查找某产品对应阶段
|
||||
select sum(planDuration) as duration from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) and planDuration > 0 into @duration__DELIMITER__
|
||||
RETURN @duration__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestplandays`;
|
||||
CREATE FUNCTION `qc_pgmtestplandays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestrealdays`;
|
||||
CREATE FUNCTION `qc_pgmtestrealdays`($project int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddesigntplandays`;
|
||||
CREATE FUNCTION `qc_prddesigntplandays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddesigntrealdays`;
|
||||
CREATE FUNCTION `qc_prddesigntrealdays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddevelplandays`;
|
||||
CREATE FUNCTION `qc_prddevelplandays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddevelrealdays`;
|
||||
CREATE FUNCTION `qc_prddevelrealdays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdrequestplandays`;
|
||||
CREATE FUNCTION `qc_prdrequestplandays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdrequestrealdays`;
|
||||
CREATE FUNCTION `qc_prdrequestrealdays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdtestplandays`;
|
||||
CREATE FUNCTION `qc_prdtestplandays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdtestrealdays`;
|
||||
CREATE FUNCTION `qc_prdtestrealdays`($project int, $product int) RETURNS int(10)
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesgignrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmdesgignrealesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'design')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesignrealhours`;
|
||||
CREATE FUNCTION `qc_pgmdesignrealhours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'design')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmdevelrealesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'devel')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelrealhours`;
|
||||
CREATE FUNCTION `qc_pgmdevelrealhours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'devel')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmrealesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_task where project=$project and parent >= 0 and status != 'cancel' and deleted = '0' into @estimate__DELIMITER__
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmesthoursbytype`;
|
||||
CREATE FUNCTION `qc_pgmesthoursbytype`($project int, $type char(30)) RETURNS float(10,2)
|
||||
BEGIN
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_task where project=$project and type = $type and parent >= 0 and status != 'cancel' and deleted = '0' into @estimate__DELIMITER__
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrealhours`;
|
||||
CREATE FUNCTION `qc_pgmrealhours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
select CAST(sum(consumed) as DECIMAL(10,2)) as consumed from zt_task where project=$project and parent >= 0 and status != 'cancel' and deleted = '0' into @consumed__DELIMITER__
|
||||
return @consumed__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrealhoursbytype`;
|
||||
CREATE FUNCTION `qc_pgmrealhoursbytype`($project int, $type char(30)) RETURNS float(10,2)
|
||||
BEGIN
|
||||
select CAST(sum(consumed) as DECIMAL(10,2)) as consumed from zt_task where project=$project and type = $type and parent >= 0 and status != 'cancel' and deleted = '0' into @consumed__DELIMITER__
|
||||
return @consumed__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmrequestrealesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'request')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestrealhours`;
|
||||
CREATE FUNCTION `qc_pgmrequestrealhours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'request')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmtestrealesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'test')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestrealhours`;
|
||||
CREATE FUNCTION `qc_pgmtestrealhours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'test')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdevelfirstesthours`;
|
||||
CREATE FUNCTION `qc_getdevelfirstesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(devEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdesignfirstesthours`;
|
||||
CREATE FUNCTION `qc_getdesignfirstesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(designEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getstoryfirstesthours`;
|
||||
CREATE FUNCTION `qc_getstoryfirstesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(requestEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_gettestfirstesthours`;
|
||||
CREATE FUNCTION `qc_gettestfirstesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(testEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getfirstesthours`;
|
||||
CREATE FUNCTION `qc_getfirstesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(taskEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdevlastesthours`;
|
||||
CREATE FUNCTION `qc_getdevlastesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(devEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getrequestlastesthours`;
|
||||
CREATE FUNCTION `qc_getrequestlastesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(requestEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_gettestlastesthours`;
|
||||
CREATE FUNCTION `qc_gettestlastesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(testEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdesignlastesthours`;
|
||||
CREATE FUNCTION `qc_getdesignlastesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(designEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getlastesthours`;
|
||||
CREATE FUNCTION `qc_getlastesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
SELECT sum(taskEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmlastesthours`;
|
||||
CREATE FUNCTION `qc_pgmlastesthours`($project int) RETURNS float(10,2)
|
||||
BEGIN
|
||||
declare estimate float(10,2) default 0__DELIMITER__
|
||||
declare inited int default 0__DELIMITER__
|
||||
select qc_cminited($project,'PP') into inited__DELIMITER__
|
||||
IF inited = 1 THEN
|
||||
select qc_getlastesthours($project) into estimate__DELIMITER__
|
||||
return estimate__DELIMITER__
|
||||
ELSE
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
+12
-490
@@ -1285,6 +1285,7 @@ CREATE TABLE IF NOT EXISTS `zt_oauth` (
|
||||
CREATE INDEX `account` ON `zt_oauth` (`account`);
|
||||
CREATE INDEX `providerType` ON `zt_oauth` (`providerType`);
|
||||
CREATE INDEX `providerID` ON `zt_oauth` (`providerID`);
|
||||
CREATE UNIQUE INDEX `account_openID` ON `zt_oauth`(`account`,`openID`,`providerType`,`providerID`);
|
||||
|
||||
-- DROP TABLE IF EXISTS `zt_pipeline`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_pipeline` (
|
||||
@@ -3364,7 +3365,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(1, 'bug', 'batchResolve'),
|
||||
(1, 'bug', 'browse'),
|
||||
(1, 'bug', 'close'),
|
||||
(1, 'bug', 'confirmBug'),
|
||||
(1, 'bug', 'confirm'),
|
||||
(1, 'bug', 'confirmStoryChange'),
|
||||
(1, 'bug', 'create'),
|
||||
(1, 'bug', 'delete'),
|
||||
@@ -4797,7 +4798,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(2, 'bug', 'batchResolve'),
|
||||
(2, 'bug', 'browse'),
|
||||
(2, 'bug', 'close'),
|
||||
(2, 'bug', 'confirmBug'),
|
||||
(2, 'bug', 'confirm'),
|
||||
(2, 'bug', 'confirmStoryChange'),
|
||||
(2, 'bug', 'create'),
|
||||
(2, 'bug', 'delete'),
|
||||
@@ -5582,7 +5583,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(3, 'bug', 'batchResolve'),
|
||||
(3, 'bug', 'browse'),
|
||||
(3, 'bug', 'close'),
|
||||
(3, 'bug', 'confirmBug'),
|
||||
(3, 'bug', 'confirm'),
|
||||
(3, 'bug', 'confirmStoryChange'),
|
||||
(3, 'bug', 'create'),
|
||||
(3, 'bug', 'delete'),
|
||||
@@ -6225,7 +6226,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(4, 'bug', 'batchResolve'),
|
||||
(4, 'bug', 'browse'),
|
||||
(4, 'bug', 'close'),
|
||||
(4, 'bug', 'confirmBug'),
|
||||
(4, 'bug', 'confirm'),
|
||||
(4, 'bug', 'confirmStoryChange'),
|
||||
(4, 'bug', 'create'),
|
||||
(4, 'bug', 'delete'),
|
||||
@@ -7297,7 +7298,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(5, 'bug', 'batchResolve'),
|
||||
(5, 'bug', 'browse'),
|
||||
(5, 'bug', 'close'),
|
||||
(5, 'bug', 'confirmBug'),
|
||||
(5, 'bug', 'confirm'),
|
||||
(5, 'bug', 'confirmStoryChange'),
|
||||
(5, 'bug', 'create'),
|
||||
(5, 'bug', 'delete'),
|
||||
@@ -8236,7 +8237,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(6, 'bug', 'batchResolve'),
|
||||
(6, 'bug', 'browse'),
|
||||
(6, 'bug', 'close'),
|
||||
(6, 'bug', 'confirmBug'),
|
||||
(6, 'bug', 'confirm'),
|
||||
(6, 'bug', 'confirmStoryChange'),
|
||||
(6, 'bug', 'create'),
|
||||
(6, 'bug', 'delete'),
|
||||
@@ -9047,7 +9048,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(7, 'bug', 'batchResolve'),
|
||||
(7, 'bug', 'browse'),
|
||||
(7, 'bug', 'close'),
|
||||
(7, 'bug', 'confirmBug'),
|
||||
(7, 'bug', 'confirm'),
|
||||
(7, 'bug', 'confirmStoryChange'),
|
||||
(7, 'bug', 'create'),
|
||||
(7, 'bug', 'delete'),
|
||||
@@ -9877,7 +9878,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(8, 'bug', 'batchResolve'),
|
||||
(8, 'bug', 'browse'),
|
||||
(8, 'bug', 'close'),
|
||||
(8, 'bug', 'confirmBug'),
|
||||
(8, 'bug', 'confirm'),
|
||||
(8, 'bug', 'confirmStoryChange'),
|
||||
(8, 'bug', 'create'),
|
||||
(8, 'bug', 'delete'),
|
||||
@@ -10736,7 +10737,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(9, 'bug', 'batchResolve'),
|
||||
(9, 'bug', 'browse'),
|
||||
(9, 'bug', 'close'),
|
||||
(9, 'bug', 'confirmBug'),
|
||||
(9, 'bug', 'confirm'),
|
||||
(9, 'bug', 'confirmStoryChange'),
|
||||
(9, 'bug', 'create'),
|
||||
(9, 'bug', 'delete'),
|
||||
@@ -11449,7 +11450,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(10, 'bug', 'batchResolve'),
|
||||
(10, 'bug', 'browse'),
|
||||
(10, 'bug', 'close'),
|
||||
(10, 'bug', 'confirmBug'),
|
||||
(10, 'bug', 'confirm'),
|
||||
(10, 'bug', 'confirmStoryChange'),
|
||||
(10, 'bug', 'create'),
|
||||
(10, 'bug', 'edit'),
|
||||
@@ -11962,7 +11963,7 @@ REPLACE INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
|
||||
(11, 'bug', 'batchResolve'),
|
||||
(11, 'bug', 'browse'),
|
||||
(11, 'bug', 'close'),
|
||||
(11, 'bug', 'confirmBug'),
|
||||
(11, 'bug', 'confirm'),
|
||||
(11, 'bug', 'confirmStoryChange'),
|
||||
(11, 'bug', 'create'),
|
||||
(11, 'bug', 'edit'),
|
||||
@@ -15378,49 +15379,6 @@ REPLACE INTO `zt_zoutput` (`id`, `activity`, `name`, `content`, `optional`, `tai
|
||||
(493, 328, '项目度量数据库', '', 'yes', '', '', 'admin', '2020-01-09 14:55:08', '', NULL, 615, '0'),
|
||||
(494, 329, '《量化项目计划及跟踪表》', '', 'no', '', '', 'admin', '2020-01-09 14:59:04', '', NULL, 630, '0');
|
||||
|
||||
REPLACE INTO `zt_basicmeas` (`id`, `purpose`, `scope`, `object`, `name`, `code`, `unit`, `configure`, `params`, `definition`, `source`, `collectType`, `collectConf`, `execTime`, `collectedBy`, `createdBy`, `createdDate`, `editedBy`, `editedDate`, `order`, `deleted`) VALUES
|
||||
(2,'scale','project','userRequest','项目用户需求初始规模','pgmURInitScale','故事点或功能点','CREATE FUNCTION qc_pgmurinitscale($project int) returns float (10,2)\r\nbegin\r\n declare scale float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'URS\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_initscale($project, \'URS\',\'requestEst\') into scale__DELIMITER__\r\n return scale__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nend','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目每个产品的第一个用户需求规格说明书基线版本的规模之和','从基线表中查询该项目下面每个产品的第一个用户需求规模说明书版本,然后查询对应的需求,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 14:19:41',10,'0'),
|
||||
(3,'scale','project','softRequest','项目软件需求初始规模','pgmSRInitScale','故事点或功能点','CREATE FUNCTION qc_pgmsrinitscale($project int) returns float (10,2)\r\nbegin\r\n declare scale float (10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'SRS\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_initscale($project, \'SRS\',\'storyEst\') into scale __DELIMITER__\r\n return scale __DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nend','{\"$project\":{\"showName\":\"\\u6240\\u9700\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目每个产品的第一个软件需求规格说明书基线版本的规模之和','从基线表中查询该项目下面每个产品的第一个软件需求规模说明书版本,然后查询对应的需求,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 14:21:53',15,'0'),
|
||||
(4,'scale','project','userRequest','项目用户需求实时规模','pgmURRealScale','故事点或功能点','CREATE FUNCTION `qc_pgmurrealscale`($project int) RETURNS float (10,2)\r\nBEGIN\r\n declare totalEstimate float(10,2) default 0__DELIMITER__\r\n select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_story where project=$project and type=\'requirement\' and deleted=\'0\' and closedReason not in (\'subdivided\', \'duplicate\', \'willnotdo\', \'cancel\', \'bydesign\') into totalEstimate__DELIMITER__\r\n return totalEstimate__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目用户需求实际的规模','从需求表中查询该项目下的所有用户需求,对规模进行求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 14:22:17',20,'0'),
|
||||
(5,'scale','project','softRequest','项目软件需求实时规模','pgmSRRealScale','故事点或功能点','CREATE FUNCTION `qc_pgmsrrealscale`($project int) RETURNS float (10,2)\r\nBEGIN\r\n declare totalEstimate float (10,2) default 0__DELIMITER__\r\n select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_story where id in (select story from zt_projectstory where project=$project) and type=\'story\' and deleted=\'0\' and closedReason not in (\'subdivided\', \'duplicate\', \'willnotdo\', \'cancel\', \'bydesign\') into totalEstimate__DELIMITER__\r\n return totalEstimate__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":false,\"options\":\"project\",\"defaultValue\":\"702\"}}','项目软件需求实际的规模','从需求表中查询该项目下的所有软件需求,对规模进行求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 14:28:01',25,'0'),
|
||||
(6,'scale','project','program','项目估算规模','pgmPlanScale','故事点或功能点','CREATE FUNCTION `qc_pgmplanscale`($project int) RETURNS float (10,2)\r\nBEGIN\r\n declare programScale float (10,2) default 0__DELIMITER__\r\n select `scale` from zt_workestimation where project = $project into programScale__DELIMITER__\r\n return programScale__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目最初估算时估计的规模','从项目估算表里面查询项目的估算规模。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 14:26:01',30,'0'),
|
||||
(8,'duration','project','stage','项目需求阶段计划天数','pgmRequestPlanDays','天','CREATE FUNCTION `qc_pgmrequestplandays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeplanneddays($project,\'request\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有需求阶段计划天数的和','从阶段表里面统计该项目下面所有类型为需求的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',40,'0'),
|
||||
(9,'duration','project','stage','项目设计阶段计划天数','pgmDesigntPlanDays','天','CREATE FUNCTION `qc_pgmdesigntplandays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeplanneddays($project,\'design\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有设计阶段计划天数的和','从阶段表里面统计该项目下面所有类型为设计的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',45,'0'),
|
||||
(10,'duration','project','stage','项目开发阶段计划天数','pgmDevelPlanDays','天','CREATE FUNCTION `qc_pgmdevelplandays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeplanneddays($project,\'dev\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有研发阶段计划天数的和','从阶段表里面统计该项目下面所有类型为开发的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',50,'0'),
|
||||
(11,'duration','project','stage','项目测试阶段计划天数','pgmTestPlanDays','天','CREATE FUNCTION `qc_pgmtestplandays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeplanneddays($project,\'qa\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有测试阶段计划天数的和','从阶段表里面统计该项目下面所有类型为测试的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',55,'0'),
|
||||
(12,'duration','project','stage','项目需求阶段实际天数','pgmRequestRealDays','天','CREATE FUNCTION `qc_pgmrequestrealdays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeactualdays($project,\'request\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有需求阶段实际天数的和','从阶段表里面统计该项目下面所有类型为需求的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',60,'0'),
|
||||
(13,'duration','project','stage','项目设计阶段实际天数','pgmDesigntRealDays','天','CREATE FUNCTION `qc_pgmdesigntrealdays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeactualdays($project,\'design\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有设计阶段实际天数的和','从阶段表里面统计该项目下面所有类型为设计的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',65,'0'),
|
||||
(14,'duration','project','stage','项目开发阶段实际天数','pgmDevelRealDays','天','CREATE FUNCTION `qc_pgmdevelrealdays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeactualdays($project,\'dev\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有研发阶段实际天数的和','从阶段表里面统计该项目下面所有类型为开发的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',70,'0'),
|
||||
(15,'duration','project','stage','项目测试阶段实际天数','pgmTestRealDays','天','CREATE FUNCTION `qc_pgmtestrealdays`($project int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmspecifiedtypeactualdays($project,\'qa\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"3\"}}','项目下面所有测试阶段实际天数的和','从阶段表里面统计该项目下面所有类型为测试的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',75,'0'),
|
||||
(26,'duration','product','stage','分产品需求阶段计划天数','prdRequestPlanDays','天','CREATE FUNCTION `qc_prdrequestplandays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageplannedduration($product, \'request\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"\"}}','产品下面所有需求阶段计划天数的和','从阶段表里面统计该产品在该项目下所有类型为需求的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',130,'0'),
|
||||
(27,'duration','product','stage','分产品设计阶段计划天数','prdDesigntPlanDays','天','CREATE FUNCTION `qc_prddesigntplandays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageplannedduration($product, \'design\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"\"}}','产品下面所有设计阶段计划天数的和','从阶段表里面统计该产品在该项目下所有类型为设计的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',135,'0'),
|
||||
(28,'duration','product','stage','分产品开发阶段计划天数','prdDevelPlanDays','天','CREATE FUNCTION `qc_prddevelplandays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageplannedduration($product, \'dev\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"1\"}}','产品下面所有研发阶段计划天数的和','从阶段表里面统计该产品在该项目下所有类型为开发的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',140,'0'),
|
||||
(29,'duration','product','stage','分产品测试阶段计划天数','prdTestPlanDays','天','CREATE FUNCTION `qc_prdtestplandays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageplannedduration($product, \'qa\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"\"}}','产品下面所有测试阶段计划天数的和','从阶段表里面统计该产品在该项目下所有类型为测试的阶段的计划天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',145,'0'),
|
||||
(30,'duration','product','stage','分产品需求阶段实际天数','prdRequestRealDays','天','CREATE FUNCTION `qc_prdrequestrealdays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageactualduration($product,\'request\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"\"}}','产品下面所有需求阶段实际天数的和','从阶段表里面统计该产品在该项目下所有类型为需求的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',150,'0'),
|
||||
(31,'duration','product','stage','分产品设计阶段实际天数','prdDesigntRealDays','天','CREATE FUNCTION `qc_prddesigntrealdays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageactualduration($product, \'design\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"\"}}','产品下面所有设计阶段实际天数的和','从阶段表里面统计该产品在该项目下所有类型为设计的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',155,'0'),
|
||||
(32,'duration','product','stage','分产品开发阶段实际天数','prdDevelRealDays','天','CREATE FUNCTION `qc_prddevelrealdays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageactualduration($product, \'dev\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"\"}}','产品下面所有研发阶段实际天数的和','从阶段表里面统计该产品在该项目下所有类型为开发的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',160,'0'),
|
||||
(33,'duration','product','stage','分产品测试阶段实际天数','prdTestRealDays','天','CREATE FUNCTION `qc_prdtestrealdays`($product int) RETURNS int(11)\r\nBEGIN\r\n select qc_pgmstageactualduration($product, \'qa\') as days into @days__DELIMITER__\r\n return @days__DELIMITER__\r\nEND','{\"$product\":{\"showName\":\"\\u6240\\u5c5e\\u4ea7\\u54c1\",\"varName\":\"$product\",\"varType\":\"select\",\"options\":\"product\",\"defaultValue\":\"1\"}}','产品下面所有测试阶段实际天数的和','从阶段表里面统计该产品在该项目下所有类型为测试的阶段的实际天数,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','','1970-01-01 00:00:01',165,'0'),
|
||||
(34,'workload','project','finance','项目任务实时预计工时数','pgmRealEstHours','小时','CREATE FUNCTION `qc_pgmrealesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n select sum(estimate) from zt_task where project=$project and parent >= 0 and status != \'cancel\' and deleted = \'0\' into @estimate__DELIMITER__\r\nreturn @estimate__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有任务的最初预计工时和','从任务表中查询该项目的所有任务,统计最初预计工>时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 19:51:39',170,'0'),
|
||||
(35,'workload','project','finance','项目需求工作实时总预计工时数','pgmRequestRealEstHours','小时','CREATE FUNCTION `qc_pgmrequestrealesthours`($project int) RETURNS float (10,2)\r\nBEGIN\r\nreturn qc_pgmesthoursbytype($project, \'request\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有需求相关任务的最初预计工时和','从任务表中查询该项目所有任务类型为需求的任务,统计最初预计工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-23 13:49:17',175,'0'),
|
||||
(36,'workload','project','finance','项目设计工作实时总预计工时数','pgmDesgignRealEstHours','小时','CREATE FUNCTION `qc_pgmdesgignrealesthours`($project int) RETURNS float (10,2)\r\nBEGIN\r\nreturn qc_pgmesthoursbytype($project, \'design\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有设计相关任务的最初预计工时和','从任务表中查询该项目所有任务类型为设计的任务,统计最初预计工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-23 13:45:32',180,'0'),
|
||||
(37,'workload','project','finance','项目开发工作实时总预计工时数','pgmDevelRealEstHours','小时','CREATE FUNCTION `qc_pgmdevelrealesthours`($project int) RETURNS float (10,2)\r\nBEGIN\r\nreturn qc_pgmesthoursbytype($project, \'devel\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有开发相关任务的最初预计工时和','从任务表中查询该项目所有任务类型为开发的任务,统计最初预计工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-23 13:46:53',185,'0'),
|
||||
(38,'workload','project','finance','项目测试工作实时总预计工时数','pgmTestRealEstHours','小时','CREATE FUNCTION `qc_pgmtestrealesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\nreturn qc_pgmesthoursbytype($project, \'test\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有测试相关任务的最初预计工时和','从任务表中查询该项目所有任务类型为测试的任务,统计最初预计工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-23 13:44:13',190,'0'),
|
||||
(39,'workload','project','finance','项目任务实际消耗工时数','pgmRealHours','小时','CREATE FUNCTION `qc_pgmrealhours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n select CAST(sum(consumed) as DECIMAL(10,2)) as consumed from zt_task where project=$project and parent >= 0 and status != \'cancel\' and deleted = \'0\' into @consumed__DELIMITER__\r\n return @consumed__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目下面所有任务的实际消耗工时和','从任务表中查询该项目的所有任务,统计实际消耗工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 19:49:32',195,'0'),
|
||||
(40,'workload','project','finance','项目需求工作实际消耗工时数','pgmRequestRealHours','小时','CREATE FUNCTION `qc_pgmrequestrealhours`($project int) RETURNS float(10,2)\r\nBEGIN\r\nreturn qc_pgmrealhoursbytype($project, \'request\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有需求相关任务的实际消耗工时和','从任务表中查询该项目所有任务类型为需求的任务,统计实际消耗工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 19:49:03',200,'0'),
|
||||
(41,'workload','project','finance','项目设计工作实际消耗工时数','pgmDesignRealHours','小时','CREATE FUNCTION `qc_pgmdesignrealhours`($project int) RETURNS float(10,2)\r\nBEGIN\r\nreturn qc_pgmrealhoursbytype($project, \'design\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有设计相关任务的实际消耗工时和','从任务表中查询该项目所有任务类型为设计的任务,统计实际消耗工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 19:48:35',205,'0'),
|
||||
(42,'workload','project','finance','项目开发工作实际消耗工时数','pgmDevelRealHours','小时','CREATE FUNCTION `qc_pgmdevelrealhours`($project int) RETURNS float(10,2)\r\nBEGIN\r\nreturn qc_pgmrealhoursbytype($project, \'devel\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有开发相关任务的实际消耗工时和','从任务表中查询该项目所有任务类型为开发的任务,统计实际消耗工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 18:34:51',210,'0'),
|
||||
(43,'workload','project','finance','项目测试工作实际消耗工时数','pgmTestRealHours','小时','CREATE FUNCTION `qc_pgmtestrealhours`($project int) RETURNS float(10, 2)\r\nBEGIN\r\nreturn qc_pgmrealhoursbytype($project, \'test\')__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目所有测试相关任务的实际消耗工时和','从任务表中查询该项目所有任务类型为测试的任务,统计实际消耗工时,求和。','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','system','1970-01-01 00:00:01','admin','2020-07-07 18:09:01',215,'0'),
|
||||
(44,'workload','project','finance','项目开发工作最初总预计工时数','pgmDevelFirstEstHours','小时','CREATE FUNCTION `qc_pgmdevelfirstesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getdevelfirstesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划第一个基线版本中所有开发相关工作最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-22 13:13:51','','1970-01-01 00:00:01',220,'0'),
|
||||
(45,'workload','project','finance','项目设计工作最初总预计工时数','pgmDesignFirstEstHours','小时','CREATE FUNCTION `qc_pgmdesignfirstesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getdesignfirstesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划第一个基线版本中所有设计相关工作最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-22 16:33:20','admin','2020-07-23 10:31:23',225,'0'),
|
||||
(46,'workload','project','finance','项目测试工作最初总预计工时数','pgmTestFirstEstHours','小时','CREATE FUNCTION `qc_pgmtestfirstesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_gettestfirstesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划第一个基线版本中所有测试相关工作最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 10:31:17','','1970-01-01 00:00:01',230,'0'),
|
||||
(47,'workload','project','finance','项目需求工作最初总预计工时数','pgmRequestFirstEstHours','小时','CREATE FUNCTION `qc_pgmrequestfirstesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getstoryfirstesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划第一个基线版本中所有需求相关工作最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 10:53:09','','1970-01-01 00:00:01',235,'0'),
|
||||
(48,'workload','project','finance','项目任务最初总预计工时数','pgmFirstEstHours','小时','CREATE FUNCTION `qc_pgmfirstesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getfirstesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划第一个基线版本中所有任务最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 13:06:59','','1970-01-01 00:00:01',240,'0'),
|
||||
(49,'workload','project','finance','项目开发工作最终总预计工时数','pgmDevelLastEstHours','小时','CREATE FUNCTION `qc_pgmdevellastesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project, \'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getdevlastesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划最后一个基线版本中所有开发相关任务最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 13:41:38','','1970-01-01 00:00:01',245,'0'),
|
||||
(50,'workload','project','finance','项目需求工作最终总预计工时数','pgmRequestLastEstHours','小时','CREATE FUNCTION `qc_pgmrequestlastesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project,\'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getrequestlastesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划最后一个基线版本中所有需求相关任务最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 14:00:58','','1970-01-01 00:00:01',250,'0'),
|
||||
(51,'workload','project','finance','项目测试工作最终总预计工时数','pgmTestLastEstHours','小时','CREATE FUNCTION `qc_pgmtestlastesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project,\'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_gettestlastesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划最后一个基线版本中所有测试相关任务最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 14:10:12','','1970-01-01 00:00:01',255,'0'),
|
||||
(52,'workload','project','finance','项目设计工作最终总预计工时数','pgmDesignLastEstHours','小时','CREATE FUNCTION `qc_pgmdesignlastesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project,\'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getdesignlastesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划最后一个基线版本中所有设计相关任务最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 14:33:00','','1970-01-01 00:00:01',260,'0'),
|
||||
(53,'workload','project','finance','项目任务最终总预计工时数','pgmLastEstHours','小时','CREATE FUNCTION `qc_pgmlastesthours`($project int) RETURNS float(10,2)\r\nBEGIN\r\n declare estimate float(10,2) default 0__DELIMITER__\r\n declare inited int default 0__DELIMITER__\r\n select qc_cminited($project,\'PP\') into inited__DELIMITER__\r\n IF inited = 1 THEN\r\n select qc_getlastesthours($project) into estimate__DELIMITER__\r\n return estimate__DELIMITER__\r\n ELSE \r\n return 0__DELIMITER__\r\n END IF__DELIMITER__\r\nEND','{\"$project\":{\"showName\":\"\\u6240\\u5c5e\\u9879\\u76ee\",\"varName\":\"$project\",\"varType\":\"select\",\"options\":\"project\",\"defaultValue\":\"\"}}','项目计划最后一个基线版本中所有任务最初预计工时和','','crontab','{\"week\":\"1,2,3,4,5,6,0\",\"type\":\"week\"}','00:00','','admin','2020-07-23 14:54:42','','1970-01-01 00:00:01',265,'0');
|
||||
|
||||
REPLACE INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`) VALUES
|
||||
('1','0','*','*','*','moduleName=weekly&methodName=computeWeekly','更新项目周报','zentao',0,'normal');
|
||||
|
||||
@@ -15641,442 +15599,6 @@ CREATE TABLE IF NOT EXISTS `zt_solution` (
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
DROP FUNCTION IF EXISTS `get_monday`;
|
||||
CREATE FUNCTION `get_monday`(day date) RETURNS date READS SQL DATA
|
||||
begin if date_format(day, '%w') = 0 then return subdate(day, date_format(day, '%w') - 6)__DELIMITER__
|
||||
else return subdate(day, date_format(day, '%w') -1)__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `get_sunday`;
|
||||
CREATE FUNCTION `get_sunday`(day date) RETURNS date READS SQL DATA
|
||||
begin
|
||||
if date_format(day, '%w') = 0 then return day__DELIMITER__
|
||||
else return subdate(day, date_format(day, '%w') - 7)__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_cminited`;
|
||||
CREATE FUNCTION qc_cminited($project int, $category varchar(30)) returns int READS SQL DATA
|
||||
begin
|
||||
declare products int default 0__DELIMITER__
|
||||
declare objects int default 0__DELIMITER__
|
||||
select COUNT(1) from zt_projectproduct where project = $project into products__DELIMITER__
|
||||
select COUNT(DISTINCT product) from zt_object where project = $project and category = $category and type = 'taged' and product in (select product from zt_projectproduct where project = $project) into objects__DELIMITER__
|
||||
IF products = objects THEN
|
||||
return 1__DELIMITER__
|
||||
ELSEIF products != objects THEN
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_initscale`;
|
||||
CREATE FUNCTION qc_initscale($project int, $category varchar(30), $estimateType varchar(30)) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
declare $estimate int default 0__DELIMITER__
|
||||
declare $storyEst varchar(30) default 'storyEst'__DELIMITER__
|
||||
declare $requestEst varchar(30) default 'requestEst'__DELIMITER__
|
||||
if($estimateType = $storyEst) THEN SELECT sum(storyEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = $category and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
if($estimateType = $requestEst) THEN SELECT sum(requestEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = $category and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
RETURN @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmplanscale`;
|
||||
CREATE FUNCTION `qc_pgmplanscale`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
declare programScale float (10,2) default 0__DELIMITER__
|
||||
select `scale` from zt_workestimation where project = $project into @programScale__DELIMITER__
|
||||
return @programScale__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmsrinitscale`;
|
||||
CREATE FUNCTION `qc_pgmsrinitscale`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
begin
|
||||
declare scale int default 0__DELIMITER__
|
||||
declare inited int default 0__DELIMITER__
|
||||
select qc_cminited($project, 'SRS') into inited__DELIMITER__
|
||||
IF inited = 1 THEN
|
||||
select qc_initscale($project, 'SRS', 'storyEst') into scale __DELIMITER__
|
||||
return scale __DELIMITER__
|
||||
ELSE
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmsrrealscale`;
|
||||
CREATE FUNCTION `qc_pgmsrrealscale`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
declare totalEstimate float(10,2) default 0__DELIMITER__
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_story where id in (select story from zt_projectstory where project=$project) and type='story' and deleted='0' and closedReason not in ('subdivided', 'duplicate', 'willnotdo', 'cancel', 'bydesign') into totalEstimate__DELIMITER__
|
||||
return totalEstimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmurinitscale`;
|
||||
CREATE FUNCTION `qc_pgmurinitscale`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
begin
|
||||
declare scale int default 0__DELIMITER__
|
||||
declare inited int default 0__DELIMITER__
|
||||
select qc_cminited($project, 'URS') into inited__DELIMITER__
|
||||
IF inited = 1 THEN
|
||||
select qc_initscale($project, 'URS', 'requestEst') into scale__DELIMITER__
|
||||
return scale__DELIMITER__
|
||||
ELSE
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmurrealscale`;
|
||||
CREATE FUNCTION `qc_pgmurrealscale`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
declare totalEstimate float(10,2) default 0__DELIMITER__
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_story where project=$project and type='requirement' and deleted='0' and closedReason not in ('subdivided', 'duplicate', 'willnotdo', 'cancel', 'bydesign') into totalEstimate__DELIMITER__
|
||||
return totalEstimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmallrequirementstage`;
|
||||
CREATE FUNCTION `qc_pgmallrequirementstage`($project int) RETURNS int(1) READS SQL DATA
|
||||
BEGIN
|
||||
-- 获取项目产品总数
|
||||
select COUNT(1) AS products from zt_projectproduct where project = $project into @totalproduct__DELIMITER__
|
||||
-- 获取已经设置需求阶段的产品总数
|
||||
select COUNT(1) AS product from (select product from zt_projectproduct where project in (select id from zt_project where project = $project and type = 'stage' and attribute = 'request' and deleted = '0') GROUP BY product) as product into @product__DELIMITER__
|
||||
-- 让项目产品总数和已设置需求阶段产品总数比较,都设置返回1,否则返回0
|
||||
if @totalproduct = @product then return 1__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
RETURN 0__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesigntplandays`;
|
||||
CREATE FUNCTION `qc_pgmdesigntplandays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesigntrealdays`;
|
||||
CREATE FUNCTION `qc_pgmdesigntrealdays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelplandays`;
|
||||
CREATE FUNCTION `qc_pgmdevelplandays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelrealdays`;
|
||||
CREATE FUNCTION `qc_pgmdevelrealdays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestplandays`;
|
||||
CREATE FUNCTION `qc_pgmrequestplandays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestrealdays`;
|
||||
CREATE FUNCTION `qc_pgmrequestrealdays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmspecifiedtypeactualdays`;
|
||||
CREATE FUNCTION `qc_pgmspecifiedtypeactualdays`($project int,$attribute varchar(50)) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
-- 查询某类型的阶段总数
|
||||
select COUNT(1) from zt_project where project = $project and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @totalstory__DELIMITER__
|
||||
-- 查询某类型已设置实际工期的阶段总数
|
||||
select COUNT(1) from zt_project where project = $project and attribute = $attribute and deleted = '0' and realDuration > 0 and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @setstory__DELIMITER__
|
||||
-- 查询项目下某类型阶段实际工期总数
|
||||
select sum(realDuration) as realDuration from zt_project where project = $project and attribute = $attribute and deleted = '0' and realDuration > 0 and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @days__DELIMITER__
|
||||
-- 判断项目下某类型的阶段是否都已设置实际工期
|
||||
if @totalstory != @setstory then
|
||||
set @days = 0__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmspecifiedtypeplanneddays`;
|
||||
CREATE FUNCTION `qc_pgmspecifiedtypeplanneddays`($project int,$attribute varchar(50)) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select sum(planDuration) as planDuration from zt_project where project = $project and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where project = $project and attribute = $attribute and grade = 2 group by parent) into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmstageactualduration`;
|
||||
CREATE FUNCTION `qc_pgmstageactualduration`($product int, $attribute varchar(50)) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
-- 查找某类型的阶段总数
|
||||
select COUNT(1) AS totalduration from zt_project where id in (select project from zt_projectproduct where product = $product) and type = 'stage' and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) into @totalduration__DELIMITER__
|
||||
-- 查某类型阶段已设置实际工期的总数
|
||||
select COUNT(1) AS setduration from zt_project where id in (select project from zt_projectproduct where product = $product) and type = 'stage' and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) and realDuration > 0 into @setduration__DELIMITER__
|
||||
-- 指定产品下某类型的阶段实际工期总和
|
||||
select sum(realDuration) as duration from zt_project where id in (select project from zt_projectproduct where product = $product) and type = 'stage' and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) and realDuration > 0 into @duration__DELIMITER__
|
||||
-- 需要判断该类型阶段都已设置实际工期,否则不统计
|
||||
if @totalduration != @setduration then
|
||||
set @duration = 0__DELIMITER__
|
||||
end if__DELIMITER__
|
||||
return @duration__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmstageplannedduration`;
|
||||
CREATE FUNCTION `qc_pgmstageplannedduration`($product int, $attribute varchar(50)) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
-- 查找某产品对应阶段
|
||||
select sum(planDuration) as duration from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and deleted = '0' and id not in (select parent from zt_project where id in (select project from zt_projectproduct where product = $product) and attribute = $attribute and grade = 2 group by parent) and planDuration > 0 into @duration__DELIMITER__
|
||||
RETURN @duration__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestplandays`;
|
||||
CREATE FUNCTION `qc_pgmtestplandays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeplanneddays($project,'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestrealdays`;
|
||||
CREATE FUNCTION `qc_pgmtestrealdays`($project int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmspecifiedtypeactualdays($project,'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddesigntplandays`;
|
||||
CREATE FUNCTION `qc_prddesigntplandays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddesigntrealdays`;
|
||||
CREATE FUNCTION `qc_prddesigntrealdays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'design') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddevelplandays`;
|
||||
CREATE FUNCTION `qc_prddevelplandays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prddevelrealdays`;
|
||||
CREATE FUNCTION `qc_prddevelrealdays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'dev') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdrequestplandays`;
|
||||
CREATE FUNCTION `qc_prdrequestplandays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdrequestrealdays`;
|
||||
CREATE FUNCTION `qc_prdrequestrealdays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'request') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdtestplandays`;
|
||||
CREATE FUNCTION `qc_prdtestplandays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageplannedduration($project, $product, 'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_prdtestrealdays`;
|
||||
CREATE FUNCTION `qc_prdtestrealdays`($project int, $product int) RETURNS int(11) READS SQL DATA
|
||||
BEGIN
|
||||
select qc_pgmstageactualduration($project, $product, 'qa') as days into @days__DELIMITER__
|
||||
return @days__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesgignrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmdesgignrealesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'design')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdesignrealhours`;
|
||||
CREATE FUNCTION `qc_pgmdesignrealhours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'design')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmdevelrealesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'devel')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmdevelrealhours`;
|
||||
CREATE FUNCTION `qc_pgmdevelrealhours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'devel')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmrealesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_task where project=$project and parent >= 0 and status != 'cancel' and deleted = '0' into @estimate__DELIMITER__
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmesthoursbytype`;
|
||||
CREATE FUNCTION `qc_pgmesthoursbytype`($project int, $type char(30)) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
select CAST(sum(estimate) as DECIMAL(10,2)) as estimate from zt_task where project=$project and type = $type and parent >= 0 and status != 'cancel' and deleted = '0' into @estimate__DELIMITER__
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrealhours`;
|
||||
CREATE FUNCTION `qc_pgmrealhours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
select CAST(sum(consumed) as DECIMAL(10,2)) as consumed from zt_task where project=$project and parent >= 0 and status != 'cancel' and deleted = '0' into @consumed__DELIMITER__
|
||||
return @consumed__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrealhoursbytype`;
|
||||
CREATE FUNCTION `qc_pgmrealhoursbytype`($project int, $type char(30)) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
select CAST(sum(consumed) as DECIMAL(10,2)) as consumed from zt_task where project=$project and type = $type and parent >= 0 and status != 'cancel' and deleted = '0' into @consumed__DELIMITER__
|
||||
return @consumed__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmrequestrealesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'request')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmrequestrealhours`;
|
||||
CREATE FUNCTION `qc_pgmrequestrealhours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'request')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestrealesthours`;
|
||||
CREATE FUNCTION `qc_pgmtestrealesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmesthoursbytype($project, 'test')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmtestrealhours`;
|
||||
CREATE FUNCTION `qc_pgmtestrealhours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
return qc_pgmrealhoursbytype($project, 'test')__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdevelfirstesthours`;
|
||||
CREATE FUNCTION `qc_getdevelfirstesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(devEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdesignfirstesthours`;
|
||||
CREATE FUNCTION `qc_getdesignfirstesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(designEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getstoryfirstesthours`;
|
||||
CREATE FUNCTION `qc_getstoryfirstesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(requestEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_gettestfirstesthours`;
|
||||
CREATE FUNCTION `qc_gettestfirstesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(testEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getfirstesthours`;
|
||||
CREATE FUNCTION `qc_getfirstesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(taskEst) as estimate FROM zt_object WHERE id in(SELECT MIN(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdevlastesthours`;
|
||||
CREATE FUNCTION `qc_getdevlastesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(devEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getrequestlastesthours`;
|
||||
CREATE FUNCTION `qc_getrequestlastesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(requestEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_gettestlastesthours`;
|
||||
CREATE FUNCTION `qc_gettestlastesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(testEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getdesignlastesthours`;
|
||||
CREATE FUNCTION `qc_getdesignlastesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(designEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_getlastesthours`;
|
||||
CREATE FUNCTION `qc_getlastesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
SELECT sum(taskEst) as estimate FROM zt_object WHERE id in(SELECT MAX(id) FROM zt_object WHERE project = $project and category = 'PP' and type = 'taged' and product in (select product from zt_projectproduct where project = $project) group by `product`) into @estimate__DELIMITER__
|
||||
|
||||
return @estimate__DELIMITER__
|
||||
END;
|
||||
|
||||
DROP FUNCTION IF EXISTS `qc_pgmlastesthours`;
|
||||
CREATE FUNCTION `qc_pgmlastesthours`($project int) RETURNS float(10,2) READS SQL DATA
|
||||
BEGIN
|
||||
declare estimate float(10,2) default 0__DELIMITER__
|
||||
declare inited int default 0__DELIMITER__
|
||||
select qc_cminited($project,'PP') into inited__DELIMITER__
|
||||
IF inited = 1 THEN
|
||||
select qc_getlastesthours($project) into estimate__DELIMITER__
|
||||
return estimate__DELIMITER__
|
||||
ELSE
|
||||
return 0__DELIMITER__
|
||||
END IF__DELIMITER__
|
||||
END;
|
||||
|
||||
-- DROP TABLE IF EXISTS `zt_demandpool`;
|
||||
CREATE TABLE `zt_demandpool` (
|
||||
`id` int(8) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
2024-09-30 20.7.1
|
||||
完成的需求
|
||||
修复的Bug
|
||||
|
||||
2024-09-14 20.7
|
||||
完成的需求
|
||||
开源版:
|
||||
|
||||
@@ -3,14 +3,16 @@ class myMisc extends misc
|
||||
{
|
||||
/**
|
||||
* Ajax get client package size.
|
||||
*
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $fileName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetPackageSize()
|
||||
public function ajaxGetPackageSize($type = 'client', $fileName = 'zentaoclient.zip')
|
||||
{
|
||||
$account = $this->app->user->account;
|
||||
$packageFile = $this->app->wwwRoot . 'data/client/' . $account . '/zentaoclient.zip';
|
||||
$packageFile = $this->app->wwwRoot . "data/{$type}/{$account}/{$fileName}";
|
||||
|
||||
$size = 0;
|
||||
if(file_exists($packageFile))
|
||||
|
||||
@@ -854,4 +854,55 @@ class dbh
|
||||
$lastAction = $this->pdo->query($sql)->fetch();
|
||||
return $lastAction ? (int)$lastAction->id : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装时检查数据库用户权限。
|
||||
* Check user privilege.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function checkUserPriv(): string
|
||||
{
|
||||
if($this->config->driver == 'mysql')
|
||||
{
|
||||
$user = $this->config->user;
|
||||
$host = ($this->config->host == 'localhost' || $this->config->host == '127.0.0.1') ? 'localhost' : '%';
|
||||
|
||||
// 获取当前用户的所有权限
|
||||
$privPairs = array();
|
||||
$privList = $this->pdo->query("SELECT PRIVILEGE_TYPE FROM information_schema.USER_PRIVILEGES WHERE GRANTEE LIKE '%$user%';")->fetchAll();
|
||||
foreach($privList as $priv)
|
||||
{
|
||||
$privPairs[$priv->PRIVILEGE_TYPE] = 1;
|
||||
}
|
||||
|
||||
// 禅道所需的权限
|
||||
$requiredPrivs = array('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE', 'ALTER', 'INDEX', 'CREATE VIEW');
|
||||
|
||||
$missingPrivs = array();
|
||||
foreach($requiredPrivs as $priv)
|
||||
{
|
||||
if(!isset($privPairs[$priv])) $missingPrivs[] = $priv;
|
||||
}
|
||||
|
||||
$sql = '';
|
||||
if(!empty($missingPrivs))
|
||||
{
|
||||
$sql .= 'GRANT ';
|
||||
foreach($missingPrivs as $priv)
|
||||
{
|
||||
$sql .= $priv . ',';
|
||||
}
|
||||
|
||||
$sql = rtrim($sql, ',');
|
||||
$sql .= " ON *.* TO '$user'@'$host';" . '\n';
|
||||
$sql .= 'FLUSH PRIVILEGES;';
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,7 @@ class duckdb
|
||||
$sql = preg_replace($ztpattern, $replace, $sql);
|
||||
$sql = preg_replace($ztvpattern, $replace, $sql);
|
||||
|
||||
$sql = str_replace('zt_action.parquet', 'zt_action_*.parquet', $sql);
|
||||
$sql = str_replace('__biPath__', $this->tmpPath, $sql);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class zdb
|
||||
while($table = $stmt->fetch(PDO::FETCH_ASSOC))
|
||||
{
|
||||
$tableType = strtolower($table['Table_type']);
|
||||
if($type == 'base' and $tableType != 'base table') continue;
|
||||
if($type == 'base' && $tableType != 'base table' && $tableType != 'table') continue;
|
||||
|
||||
$tableName = $table["Tables_in_{$config->db->name}"];
|
||||
$allTables[$tableName] = $tableType == 'base table' ? 'table' : $tableType;
|
||||
|
||||
@@ -60,7 +60,7 @@ class backBtn extends btn
|
||||
'projectstory' => 'projectstory-story',
|
||||
'build' => 'execution-build,build-view,project-index,kanban-view,testtask-browse,projectbuild-browse,my-effort,my-index,project-dynamic,execution-dynamic,project-view,execution-view',
|
||||
'projectbuild' => 'projectbuild-browse,projectbuild-view,project-index',
|
||||
'repo' => 'repo-maintain,repo-log,repo-browse,repo-view,repo-review,mr-view,repo-browsewebhooks',
|
||||
'repo' => 'repo-maintain,repo-log,repo-browse,repo-view,repo-review,mr-view,repo-browsewebhooks,repo-browserule',
|
||||
'mr' => 'pullreq-browse,mr-browse',
|
||||
'pullreq' => 'pullreq-browse',
|
||||
'compile' => 'compile-browse',
|
||||
|
||||
@@ -109,6 +109,7 @@ class bugRelatedList extends relatedList
|
||||
|
||||
/* Linked MR. */
|
||||
$linkMRList = isset($bug->linkMRTitles) ? $bug->linkMRTitles :array();
|
||||
$linkedPRs = $this->prop('linkedPRs', data('linkedPRs'));
|
||||
if(helper::hasFeature('devops'))
|
||||
{
|
||||
$data['mr'] = array
|
||||
@@ -128,6 +129,26 @@ class bugRelatedList extends relatedList
|
||||
}
|
||||
);
|
||||
|
||||
if($linkedPRs)
|
||||
{
|
||||
$data['pr'] = array
|
||||
(
|
||||
'title' => $lang->bug->linkPR,
|
||||
'items' => $linkedPRs,
|
||||
'url' => hasPriv('pullreq', 'view') ? createLink('pullreq', 'view', 'MRID={id}') : false,
|
||||
'props' => array('data-app' => 'devops'),
|
||||
'onRender' => function($item, $mr) use($lang)
|
||||
{
|
||||
$item['titleClass'] = 'w-0 flex-1';
|
||||
$statusClass = $mr->status;
|
||||
if($mr->status == 'opened') $statusClass = 'draft';
|
||||
if($mr->status == 'merged') $statusClass = 'done';
|
||||
$item['content'] = array('html' => "<span class='status-{$statusClass}'>" . zget($lang->mr->statusList, $mr->status) . '</span>');
|
||||
return $item;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$data['linkCommit'] = array
|
||||
(
|
||||
'title' => $lang->bug->linkCommit,
|
||||
|
||||
@@ -166,7 +166,8 @@ class caseBasicInfo extends wg
|
||||
$case = $this->prop('case', data('case'));
|
||||
if(!$case) return array();
|
||||
|
||||
$isLibCase = $this->prop('isLibCase', data('isLibCase'));
|
||||
$isLibCase = $this->prop('isLibCase', data('isLibCase'));
|
||||
$scenes = $this->prop('scenes', data('scenes'));
|
||||
|
||||
$items = array();
|
||||
if($isLibCase)
|
||||
@@ -184,6 +185,7 @@ class caseBasicInfo extends wg
|
||||
if($case->product && !$product->shadow) $items[$lang->testcase->product] = hasPriv('product', 'view') ? array('control' => 'link', 'url' => createLink('product', 'view', "productID={$case->product}"), 'text' => $product->name) : $product->name;
|
||||
if($case->branch && $product->type != 'normal') $items[$branchLabel] = hasPriv('testcase', 'browse') ? array('control' => 'link', 'url' => createLink('testcase', 'browse', "productID={$case->product}&branch={$case->branch}"), 'text' => $branchName) : $branchName;
|
||||
$items[$lang->testcase->module] = array('children' => wg($this->getModule($case)));
|
||||
$items[$lang->testcase->scene] = array('control' => 'text', 'text' => zget($scenes, $case->scene, ''));
|
||||
$items[$lang->testcase->story] = array('children' => wg($this->getStory($case)));
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class filter extends wg
|
||||
|
||||
protected function buildControl(string $type): node|array
|
||||
{
|
||||
if($type == 'select') return $this->buildPicker();
|
||||
if($type == 'select' || $type == 'multipleselect') return $this->buildPicker();
|
||||
if($type == 'date') return $this->buildDatePicker();
|
||||
if($type == 'datetime') return $this->buildDatetimePicker();
|
||||
return $this->buildInput();
|
||||
|
||||
@@ -65,8 +65,7 @@ class formPanel extends panel
|
||||
'pinnedItems?: array|string', // 固定显示的表单项。
|
||||
'customBtn?: array|bool', // 是否显示表单自定义按钮。
|
||||
'customFields?: array=[]', // @deprecated 自定义表单项。
|
||||
'showExtra?: bool=true', // 是否显示工作流字段。
|
||||
'submitDisabledValue?: bool=false' // 是否将disabled的字段传入后端。
|
||||
'showExtra?: bool=true' // 是否显示工作流字段。
|
||||
);
|
||||
|
||||
public static function getPageJS(): ?string
|
||||
@@ -295,7 +294,6 @@ class formPanel extends panel
|
||||
(
|
||||
set::id($formID),
|
||||
set::className($this->prop('formClass')),
|
||||
set::ajax(array('submitDisabledValue' => $this->prop('submitDisabledValue'))),
|
||||
set($this->props->pick($formProps)),
|
||||
$this->children(),
|
||||
$this->prop('showExtra') && !$fields ? $this->buildExtraMain() : null,
|
||||
|
||||
@@ -57,6 +57,8 @@ class queryFilterModal extends wg
|
||||
)
|
||||
);
|
||||
|
||||
$defaultWgList = array('date' => 'datePicker', 'datetime' => 'datetimePicker', 'input' => 'input', 'select' => 'picker', 'multipleselect' => 'picker');
|
||||
|
||||
$type = $this->buildControl
|
||||
(
|
||||
'type',
|
||||
@@ -73,7 +75,7 @@ class queryFilterModal extends wg
|
||||
),
|
||||
picker
|
||||
(
|
||||
setClass(array('hidden' => $value['type'] !== 'select')),
|
||||
setClass(array('hidden' => $defaultWgList[$value['type']] !== 'picker')),
|
||||
set::name("typeOption"),
|
||||
set::items($lang->dataview->varFilter->selectList),
|
||||
set::value($value['typeOption'])
|
||||
@@ -81,15 +83,13 @@ class queryFilterModal extends wg
|
||||
)
|
||||
);
|
||||
|
||||
$defaultWgList = array('date' => 'datePicker', 'datetime' => 'datetimePicker', 'input' => 'input', 'select' => 'picker');
|
||||
|
||||
list($defaultType, $defaultItems, $defaultValue) = array($value['type'], $value['items'], $value['default']);
|
||||
|
||||
$default = $this->buildControl
|
||||
(
|
||||
'default',
|
||||
'basis-48',
|
||||
createWg($defaultWgList[$defaultType], set(array('name' => 'default', 'items' => $defaultItems, 'value' => $defaultValue)))
|
||||
createWg($defaultWgList[$defaultType], set(array('name' => 'default', 'items' => $defaultItems, 'value' => $defaultValue, 'multiple' => ($defaultType == 'multipleselect' ? true : false))))
|
||||
);
|
||||
|
||||
return formRow
|
||||
|
||||
@@ -37,7 +37,7 @@ window.changeBuilderTable = function(event)
|
||||
|
||||
if(name == 'from')
|
||||
{
|
||||
from.table = value;
|
||||
from.table = value;
|
||||
from.select = [];
|
||||
}
|
||||
if(name.startsWith('left'))
|
||||
|
||||
@@ -177,7 +177,7 @@ class sqlBuilder extends wg
|
||||
btn
|
||||
(
|
||||
setID('addJoinTable'),
|
||||
setClass('p-0 ml-4'),
|
||||
setClass('ml-2 text-primary'),
|
||||
set('data-index', -1),
|
||||
set::type('ghost'),
|
||||
set::icon('plus'),
|
||||
|
||||
@@ -14,6 +14,7 @@ class storyRelatedList extends relatedList
|
||||
'releases' => '?array', // 关联的发布列表。
|
||||
'storyProducts' => '?array', // 需求产品信息。
|
||||
'linkedMRs' => '?array', // 需求 MR 信息。
|
||||
'linkedPRs' => '?array', // 需求 PR 信息。
|
||||
'linkedCommits' => '?linkedCommits', // 需求提交信息。
|
||||
'story' => '?object' // 当前需求。
|
||||
);
|
||||
@@ -36,6 +37,7 @@ class storyRelatedList extends relatedList
|
||||
$builds = $this->prop('builds', data('builds'));
|
||||
$releases = $this->prop('releases', data('releases'));
|
||||
$linkedMRs = $this->prop('linkedMRs', data('linkedMRs'));
|
||||
$linkedPRs = $this->prop('linkedPRs', data('linkedPRs'));
|
||||
$linkedCommits = $this->prop('linkedCommits', data('linkedCommits'));
|
||||
$data = array();
|
||||
|
||||
@@ -108,6 +110,26 @@ class storyRelatedList extends relatedList
|
||||
}
|
||||
);
|
||||
|
||||
if($linkedPRs)
|
||||
{
|
||||
$data['pr'] = array
|
||||
(
|
||||
'title' => $lang->story->linkPR,
|
||||
'items' => $linkedPRs,
|
||||
'url' => hasPriv('pullreq', 'view') ? createLink('pullreq', 'view', 'MRID={id}') : false,
|
||||
'props' => array('data-app' => 'devops'),
|
||||
'onRender' => function($item, $mr) use($lang)
|
||||
{
|
||||
$item['titleClass'] = 'w-0 flex-1';
|
||||
$statusClass = $mr->status;
|
||||
if($mr->status == 'opened') $statusClass = 'draft';
|
||||
if($mr->status == 'merged') $statusClass = 'done';
|
||||
$item['content'] = array('html' => "<span class='status-{$statusClass}'>" . zget($lang->mr->statusList, $mr->status) . '</span>');
|
||||
return $item;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$data['commit'] = array
|
||||
(
|
||||
'title' => $lang->story->linkCommit,
|
||||
|
||||
@@ -25,6 +25,7 @@ class taskMiscInfo extends relatedList
|
||||
{
|
||||
$canViewMR = common::hasPriv('mr', 'view');
|
||||
$linkMRList = $this->prop('linkMRTitles', data('linkMRTitles'));
|
||||
$linkedPRs = $this->prop('linkedPRs', data('linkedPRs'));
|
||||
$data['mr'] = array
|
||||
(
|
||||
'title' => $lang->task->linkMR,
|
||||
@@ -42,6 +43,26 @@ class taskMiscInfo extends relatedList
|
||||
}
|
||||
);
|
||||
|
||||
if($linkedPRs)
|
||||
{
|
||||
$data['pr'] = array
|
||||
(
|
||||
'title' => $lang->task->linkPR,
|
||||
'items' => $linkedPRs,
|
||||
'url' => hasPriv('pullreq', 'view') ? createLink('pullreq', 'view', 'MRID={id}') : false,
|
||||
'props' => array('data-app' => 'devops'),
|
||||
'onRender' => function($item, $mr) use($lang)
|
||||
{
|
||||
$item['titleClass'] = 'w-0 flex-1';
|
||||
$statusClass = $mr->status;
|
||||
if($mr->status == 'opened') $statusClass = 'draft';
|
||||
if($mr->status == 'merged') $statusClass = 'done';
|
||||
$item['content'] = array('html' => "<span class='status-{$statusClass}'>" . zget($lang->mr->statusList, $mr->status) . '</span>');
|
||||
return $item;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$linkedCommits = $this->prop('linkCommits', data('linkCommits'));
|
||||
$data['linkCommit'] = array
|
||||
(
|
||||
|
||||
+181
-31
@@ -9,7 +9,7 @@ const colors = ['#CFE7FE', '#DCEFF9', '#E0EBFC', '#DBE9FA', '#D4EEE9', '#E4DFF7'
|
||||
*/
|
||||
function getModelColors()
|
||||
{
|
||||
const model = $('.model-canvas').data('model');
|
||||
const model = $(`#canvas_${model3cKey}`).closest('.model-canvas').data('model');
|
||||
let modelColors = colors;
|
||||
const colorGroup = {};
|
||||
if(colorGroup[`color${model}`] && Array.isArray(colorGroup[`color${model}`])) modelColors = colorGroup[`color${model}`];
|
||||
@@ -26,10 +26,10 @@ function getModelColors()
|
||||
*/
|
||||
window.initThinkCanvas = function()
|
||||
{
|
||||
const canvas = $('#canvas')[0];
|
||||
const canvas = $(`#canvas_${model3cKey}`)[0];
|
||||
const ctx = canvas.getContext('2d');
|
||||
const image = new Image();
|
||||
const model = $('.model-canvas').data('model');
|
||||
const {model, mode} = $(`#canvas_${model3cKey}`).closest('.model-canvas').data();
|
||||
|
||||
image.src = `data/thinmory/thumbnail/init${model}.png`;
|
||||
image.onload = function()
|
||||
@@ -49,28 +49,36 @@ window.initThinkCanvas = function()
|
||||
const pixelData = data.pixelData;
|
||||
|
||||
displayColoredImage(data.image);
|
||||
renderRegionInput(coloredRegions);
|
||||
|
||||
/* 点击画布外区域取消高亮。*/
|
||||
/* Click on the area outside the canvas to unhighlight.*/
|
||||
$(document).on('click', function(event)
|
||||
if(mode == 'preview')
|
||||
{
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const canvasX = rect.left;
|
||||
const canvasY = rect.top;
|
||||
const mouseX = event.clientX;
|
||||
const mouseY = event.clientY;
|
||||
renderRegionInput(coloredRegions);
|
||||
|
||||
/* 恢复整个画布的原始状态。 */
|
||||
ctx.putImageData(pixelData, 0, 0);
|
||||
|
||||
/* 检测鼠标位置是否在特定区域内。 */
|
||||
/* Check if the mouse position is within a specific area. */
|
||||
if(mouseX >= canvasX && mouseX <= (canvasX + canvas.width) && mouseY >= canvasY && mouseY <= (canvasY + canvas.height))
|
||||
/* 点击画布外区域取消高亮。*/
|
||||
/* Click on the area outside the canvas to unhighlight.*/
|
||||
$(document).on('click', function(event)
|
||||
{
|
||||
handleCanvasClick(mouseX, mouseY, canvas, ctx, coloredRegions);
|
||||
}
|
||||
});
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const canvasX = rect.left;
|
||||
const canvasY = rect.top;
|
||||
const mouseX = event.clientX;
|
||||
const mouseY = event.clientY;
|
||||
|
||||
/* 恢复整个画布的原始状态。 */
|
||||
ctx.putImageData(pixelData, 0, 0);
|
||||
|
||||
/* 检测鼠标位置是否在特定区域内。 */
|
||||
/* Check if the mouse position is within a specific area. */
|
||||
if(mouseX >= canvasX && mouseX <= (canvasX + canvas.width) && mouseY >= canvasY && mouseY <= (canvasY + canvas.height))
|
||||
{
|
||||
handleCanvasClick(mouseX, mouseY, canvas, ctx, coloredRegions);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
renderRegionTitles(coloredRegions);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -79,6 +87,65 @@ window.initThinkCanvas = function()
|
||||
if(image.complete && image.naturalWidth != 0) image.onload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算卡片位置。
|
||||
* Calculate card position.
|
||||
*
|
||||
* @param object region
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function calculateCardPosition(region)
|
||||
{
|
||||
const h = 300; // 卡片高度
|
||||
const minW = 256; // 最小宽度
|
||||
const maxW = 400; // 最大宽度
|
||||
const d = 10; // 间距
|
||||
const rows = flattenData(region.rows);
|
||||
const rowsCount = rows.length;
|
||||
|
||||
let r = 0;
|
||||
while (r < rowsCount)
|
||||
{
|
||||
let totalWidth = 0;
|
||||
let validStartRow = -1;
|
||||
|
||||
for(let i = r; i < r + h && i < rowsCount; i++)
|
||||
{
|
||||
if(rows[i]?.right) totalWidth += rows[i].right - rows[i].left;
|
||||
if(totalWidth >= minW)
|
||||
{
|
||||
validStartRow = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(validStartRow !== -1)
|
||||
{
|
||||
let left = rows[validStartRow]?.left || 0;
|
||||
let right = rows[Math.min(validStartRow + h - 1, rowsCount - 1)]?.right || 0;
|
||||
let rowN = Math.floor((right - left + d) / (minW + d));
|
||||
let w = (right - left + d) / rowN;
|
||||
|
||||
for(let i = 0; i < rowN; i++)
|
||||
{
|
||||
let blockLeft = left + i * (w + d);
|
||||
let blockTop = rows[validStartRow].top;
|
||||
let blockWidth = Math.min(w, maxW);
|
||||
let blockHeight = h;
|
||||
|
||||
// TODO: 绘制卡片
|
||||
console.log(`Block ${i + 1}: Left: ${blockLeft}, Top: ${blockTop}, Width: ${blockWidth}, Height: ${blockHeight}`);
|
||||
}
|
||||
r += h;
|
||||
}
|
||||
else
|
||||
{
|
||||
r++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理画布点击。
|
||||
* handle canvas click.
|
||||
@@ -105,7 +172,7 @@ function handleCanvasClick(mouseX, mouseY, canvas, ctx, coloredRegions)
|
||||
|
||||
if(isInRegion)
|
||||
{
|
||||
if($(`#input_${index}`).length) $(`#input_${index}`)[0].focus();
|
||||
if($(`#input_${model3cKey}_${index}`).length) $(`#input_${model3cKey}_${index}`)[0].focus();
|
||||
renderHighlightedRegion(index, coloredRegions[index], ctx);
|
||||
}
|
||||
});
|
||||
@@ -172,6 +239,11 @@ function binarizeImage(imageData)
|
||||
*/
|
||||
function getCanvasSize(width = 0, height = 0)
|
||||
{
|
||||
if(model3cKey == 'link') return {width: 420, height: 400};
|
||||
|
||||
const mode = $(`#canvas_${model3cKey}`).closest('.model-canvas').data('mode');
|
||||
if(mode == 'view') return {width: 2000, height: 2000};
|
||||
|
||||
const maxWidth = $('.think-model-content').length ? ($('.think-model-content').width() - 50) : 400;
|
||||
const maxHeight = maxWidth;
|
||||
|
||||
@@ -265,7 +337,8 @@ function findRegions(pixels, width, height)
|
||||
{
|
||||
const visited = {};
|
||||
const regions = [];
|
||||
|
||||
const mode = $(`#canvas_${model3cKey}`).closest('.model-canvas').data('mode');
|
||||
const minArea = mode == 'view' ? 500 : 100;
|
||||
for(let y = 0; y < height; y++)
|
||||
{
|
||||
for(let x = 0; x < width; x++)
|
||||
@@ -277,7 +350,7 @@ function findRegions(pixels, width, height)
|
||||
|
||||
/* 过滤掉小区域。 */
|
||||
/* Filter out small regions. */
|
||||
if(region.area > 100)
|
||||
if(region.area > minArea)
|
||||
{
|
||||
region.rows.forEach((row, key) => {
|
||||
region.rows[key] = processRegionRows(row);
|
||||
@@ -383,6 +456,7 @@ window.drawRegionInput = function(canvas, region, colorIndex, clientLang, blocks
|
||||
const centerY = (region.minY + region.maxY) / 2;
|
||||
const boxWidth = 60;
|
||||
const boxHeight = 32;
|
||||
const disabled = $(`#canvas_${model3cKey}`).closest('.model-canvas').data('disabled');
|
||||
|
||||
let left = centerX - boxWidth / 2;
|
||||
let top = centerY - boxHeight / 2;
|
||||
@@ -424,9 +498,10 @@ window.drawRegionInput = function(canvas, region, colorIndex, clientLang, blocks
|
||||
input.type = 'text';
|
||||
input.value = value;
|
||||
input.title = value;
|
||||
input.id = `input_${colorIndex}`;
|
||||
input.id = `input_${model3cKey}_${colorIndex}`;
|
||||
input.name = `blocks[]`;
|
||||
input.placeholder = blockName;
|
||||
input.disabled = disabled;
|
||||
input.setAttribute('data-index', colorIndex);
|
||||
input.setAttribute('data-block', value);
|
||||
Object.assign(input.style, styles);
|
||||
@@ -434,6 +509,83 @@ window.drawRegionInput = function(canvas, region, colorIndex, clientLang, blocks
|
||||
canvas.parentNode.appendChild(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制区域标题。
|
||||
* Draw a region title.
|
||||
*
|
||||
* @param object canvas
|
||||
* @param object region
|
||||
* @param number colorIndex
|
||||
* @param array blocks
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.drawRegionTitle = function(canvas, region, colorIndex, blocks)
|
||||
{
|
||||
const centerX = (region.minX + region.maxX) / 2;
|
||||
const centerY = (region.minY + region.maxY) / 2;
|
||||
const boxWidth = 120;
|
||||
const boxHeight = 48;
|
||||
|
||||
let left = centerX - boxWidth / 2;
|
||||
let top = centerY - boxHeight / 2;
|
||||
let bottom = 0;
|
||||
|
||||
const positionMap = {
|
||||
0: {left: left, top: 40},
|
||||
1: {left: left - 40, top: top + 180},
|
||||
2: {left: left + 100, top: top + 180},
|
||||
3: {left: left, top: top - 240},
|
||||
4: {left: left + 260, top: top - 450},
|
||||
5: {left: left - 240, top: top - 450},
|
||||
6: {left: left, top: 0, bottom: 160}
|
||||
};
|
||||
|
||||
if(colorIndex in positionMap)
|
||||
{
|
||||
const {left: newLeft, top: newTop, bottom: newBottom = 'unset'} = positionMap[colorIndex];
|
||||
left = newLeft;
|
||||
top = newTop;
|
||||
bottom = newBottom;
|
||||
}
|
||||
|
||||
const styles = {
|
||||
left: left ? `${left}px` : 'unset',
|
||||
top: top ? `${top}px` : 'unset',
|
||||
bottom: bottom ? `${bottom}px` : 'unset'
|
||||
};
|
||||
|
||||
const block = String.fromCharCode(97 + colorIndex);
|
||||
const $title = document.createElement('div');
|
||||
const value = typeof blocks[colorIndex] == 'string' ? blocks[colorIndex] : block;
|
||||
$title.innerHTML = value;
|
||||
$title.id = `title_${colorIndex}`;
|
||||
$title.className = 'w-28 h-12 p-1 item-step-title text-clip text-center absolute';
|
||||
Object.assign($title.style, styles);
|
||||
|
||||
canvas.parentNode.appendChild($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染区域标题。
|
||||
* Render region titles.
|
||||
*
|
||||
* @param array regions
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function renderRegionTitles(regions)
|
||||
{
|
||||
const {model, blocks} = $(`#canvas_${model3cKey}`).closest('.model-canvas').data();
|
||||
let drawTitleFunc = `drawRegionTitleOf${model}`;
|
||||
drawTitleFunc = (drawTitleFunc in window) ? window[drawTitleFunc] : window['drawRegionTitle'];
|
||||
const canvas = $(`#canvas_${model3cKey}`)[0];
|
||||
|
||||
regions.forEach((region, index) => {
|
||||
if(!$(`#title_${index}`).length) drawTitleFunc(canvas, region, index, blocks);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染区域输入框。
|
||||
* Render region inputs.
|
||||
@@ -444,15 +596,13 @@ window.drawRegionInput = function(canvas, region, colorIndex, clientLang, blocks
|
||||
*/
|
||||
function renderRegionInput(regions)
|
||||
{
|
||||
const model = $('.model-canvas').data('model');
|
||||
const clientLang = $('.model-canvas').data('clientLang');
|
||||
const blocks = $('.model-canvas').data('blocks');
|
||||
const {model, blocks, clientLang} = $(`#canvas_${model3cKey}`).closest('.model-canvas').data();
|
||||
let drawInputFunc = `drawRegionInputOf${model}`;
|
||||
drawInputFunc = (drawInputFunc in window) ? window[drawInputFunc] : window['drawRegionInput'];
|
||||
const canvas = $('#canvas')[0];
|
||||
const canvas = $(`#canvas_${model3cKey}`)[0];
|
||||
|
||||
regions.forEach((region, index) => {
|
||||
if(!$(`#input_${index}`).length) drawInputFunc(canvas, region, index, clientLang, blocks);
|
||||
if(!$(`#input_${model3cKey}_${index}`).length) drawInputFunc(canvas, region, index, clientLang, blocks);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -514,7 +664,7 @@ function colorRegions(binaryImageData)
|
||||
*/
|
||||
function displayColoredImage(coloredImageData)
|
||||
{
|
||||
const canvas = $('#canvas')[0];
|
||||
const canvas = $(`#canvas_${model3cKey}`)[0];
|
||||
const ctx = canvas.getContext('2d');
|
||||
const img = new Image();
|
||||
|
||||
|
||||
@@ -6,6 +6,11 @@ requireWg('thinkModel');
|
||||
|
||||
class think3c extends thinkModel
|
||||
{
|
||||
protected static array $defineProps = array
|
||||
(
|
||||
'key?: string="view"',
|
||||
'disabled?=false: bool',
|
||||
);
|
||||
public static function getPageCSS(): ?string
|
||||
{
|
||||
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
|
||||
@@ -20,17 +25,15 @@ class think3c extends thinkModel
|
||||
{
|
||||
global $lang, $app;
|
||||
|
||||
list($blocks, $mode, $disabled, $key) = $this->prop(array('blocks', 'mode', 'disabled', 'key'));
|
||||
jsVar('blockName', $lang->thinkwizard->placeholder->blockName);
|
||||
list($blocks, $mode) = $this->prop(array('blocks', 'mode'));
|
||||
jsVar('model3cKey', $key);
|
||||
|
||||
return div
|
||||
(
|
||||
setData('clientLang', $app->getClientLang()),
|
||||
setData('model', '3c'),
|
||||
setData('mode', $mode),
|
||||
setData('blocks', $blocks),
|
||||
setClass('model-canvas relative flex justify-center'),
|
||||
h::canvas(setID('canvas')),
|
||||
setData(array('clientLang' => $app->getClientLang(), 'model' => '3c', 'mode' => $mode, 'blocks' => $blocks, 'disabled' => $disabled)),
|
||||
setClass('model-canvas relative flex justify-center', "model-canvas-$key"),
|
||||
h::canvas(setID('canvas_' . $key)),
|
||||
on::blur('.model-canvas input')->do('
|
||||
const index = $(this).data("index");
|
||||
const block = $(this).data("block");
|
||||
|
||||
@@ -44,7 +44,9 @@ class thinkStep extends wg
|
||||
$title = $action == 'detail' ? sprintf($lang->thinkstep->info, $lang->thinkstep->$basicType) : sprintf($lang->thinkstep->formTitle[$type], $lang->thinkstep->$typeLang);
|
||||
$canEdit = common::hasPriv('thinkstep', 'edit');
|
||||
$canDelete = common::hasPriv('thinkstep', 'delete');
|
||||
$canLink = $wizard->model === '3c' && ($type === 'checkbox' || $type === 'radio' || $type === 'multicolumn');
|
||||
$linkType = $type === 'checkbox' || $type === 'radio' || $type === 'multicolumn';
|
||||
$linkmodel = !$isRun && $wizard->model === '3c';
|
||||
$canLink = common::hasPriv('thinkstep', 'link') && $linkmodel && $linkType;
|
||||
|
||||
return div
|
||||
(
|
||||
@@ -65,7 +67,8 @@ class thinkStep extends wg
|
||||
(
|
||||
setClass('btn ghost text-gray w-5 h-5 mr-1'),
|
||||
set::icon('link'),
|
||||
set::url(createLink('thinkstep', 'link')),
|
||||
set::url(createLink('thinkstep', 'link', "marketID={$marketID}&stepID={$item->id}")),
|
||||
set::hint($lang->thinkstep->actions['link']),
|
||||
set('data-toggle', 'modal'),
|
||||
set('data-dismiss', 'modal'),
|
||||
set('data-size', 'sm'),
|
||||
@@ -78,12 +81,14 @@ class thinkStep extends wg
|
||||
(
|
||||
setClass('btn ghost text-gray w-5 h-5'),
|
||||
set::icon('edit'),
|
||||
set::hint($lang->thinkstep->actions['edit']),
|
||||
set::url(createLink('thinkstep', 'edit', "marketID={$marketID}&stepID={$item->id}")),
|
||||
) : null,
|
||||
$canDelete ? ((!$item->existNotNode && empty($quotedQuestions)) ? btn
|
||||
(
|
||||
setClass('btn ghost text-gray w-5 h-5 ml-1 ajax-submit'),
|
||||
set::icon('trash'),
|
||||
set::hint($lang->thinkstep->actions['delete']),
|
||||
setData('url', createLink('thinkstep', 'delete', "marketID={$marketID}&stepID={$item->id}")),
|
||||
setData('confirm', $lang->thinkstep->deleteTips[$basicType])
|
||||
) : icon
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/* 进入页面,树结构为展开状态。*/
|
||||
/* Entering the page, the step tree is in an expanded state.*/
|
||||
setTimeout(function(){if(from && !localStorage.getItem('thinkTreeFrom')) localStorage.setItem('thinkTreeFrom', from);}, 15);
|
||||
setTimeout(function()
|
||||
{
|
||||
const from = $('.think-node-menu').data('from');
|
||||
if(from && !localStorage.getItem('thinkTreeFrom')) localStorage.setItem('thinkTreeFrom', from);
|
||||
}, 15);
|
||||
setTimeout(function()
|
||||
{
|
||||
const thinkTreeFrom = localStorage.getItem('thinkTreeFrom');
|
||||
@@ -100,6 +104,7 @@ window.addQuestion = function(stepID, parentID, type, questionType = '')
|
||||
const style = `style="margin-bottom: 6px; margin-left: calc(${parent == parentID ? 12 : 3} * (-4px)); padding-left: 12px;"`;
|
||||
const className = parent == parentID ? '' : 'mt-2';
|
||||
const $title = `<li class="tree-item tree-item-uncreated ${className}"><div class="listitem item-inner tree-item-inner selected text-primary font-bold" ${style}>${untitledLangs[type]}</div></li>`;
|
||||
const marketID = $('.think-node-menu').data('marketID');
|
||||
|
||||
/* 当父节点为收起状态时,展开子节点。 */
|
||||
/* When the parent node is in a collapsed state, expand the child nodes. */
|
||||
@@ -131,6 +136,7 @@ window.saveStep = function()
|
||||
if(!name) return $(this).closest('.tree-item').remove();
|
||||
const {id, addType, parent, order, wizard} = $(this).data();
|
||||
const currentParent = addType == 'same' ? parent : 0;
|
||||
const marketID = $('.think-node-menu').data('marketID');
|
||||
|
||||
$.ajaxSubmit({
|
||||
url: $.createLink('thinkstep', 'ajaxCreate', `marketID=${marketID}¤tParent=${currentParent}¤tOrder=${order}`),
|
||||
|
||||
@@ -11,6 +11,8 @@ class thinkStepMenu extends wg
|
||||
protected static array $defineProps = array(
|
||||
'modules: array',
|
||||
'wizard: object',
|
||||
'marketID?: int',
|
||||
'from?: string',
|
||||
'activeKey?: int',
|
||||
'hover?: bool=true',
|
||||
'showAction?: bool=true',
|
||||
@@ -51,7 +53,6 @@ class thinkStepMenu extends wg
|
||||
|
||||
private function buildMenuTree(array $items, int $parentID = 0): array
|
||||
{
|
||||
jsVar('from', data('from') ?? '');
|
||||
if(empty($items)) $items = $this->modules;
|
||||
if(empty($items)) return array();
|
||||
|
||||
@@ -158,6 +159,7 @@ class thinkStepMenu extends wg
|
||||
$canCreate = common::hasPriv('thinkstep', 'create');
|
||||
$canEdit = common::hasPriv('thinkstep', 'edit');
|
||||
$canDelete = common::hasPriv('thinkstep', 'delete');
|
||||
$canLink = common::hasPriv('thinkstep', 'link');
|
||||
$parentID = $item->type != 'node' ? $item->parent : $item->id;
|
||||
$confirmTips = $this->lang->thinkstep->deleteTips[$item->type];
|
||||
$menus = array();
|
||||
@@ -186,7 +188,7 @@ class thinkStepMenu extends wg
|
||||
);
|
||||
}
|
||||
|
||||
$marketID = data('marketID');
|
||||
$marketID = $this->prop('marketID');
|
||||
$itemHasQuoted = empty($item->hasQuoted) || $item->hasQuoted == 0;
|
||||
$deleteItem = (!$item->existNotNode && $itemHasQuoted) ? array(
|
||||
'key' => 'deleteNode',
|
||||
@@ -203,8 +205,8 @@ class thinkStepMenu extends wg
|
||||
'hint' => $item->existNotNode ? $this->lang->thinkstep->cannotDeleteNode : $this->lang->thinkstep->cannotDeleteQuestion,
|
||||
);
|
||||
$options = $item->type === 'question' ? json_decode($item->options) : null;
|
||||
$canLink = !empty($options) && ($options->questionType == 'checkbox' || $options->questionType === 'radio' || $options->questionType === 'multicolumn');
|
||||
$linkItem = $canLink && $options->required ? array(
|
||||
$linkType = !empty($options) && ($options->questionType == 'checkbox' || $options->questionType === 'radio' || $options->questionType === 'multicolumn');
|
||||
$linkItem = ($canLink && $linkType && $options->required) ? array(
|
||||
'key' => 'linkNode',
|
||||
'icon' => 'link',
|
||||
'text' => $this->lang->thinkstep->actions['link'],
|
||||
@@ -228,7 +230,7 @@ class thinkStepMenu extends wg
|
||||
'url' => createLink('thinkstep', 'edit', "marketID={$marketID}&stepID={$item->id}")
|
||||
) : null,
|
||||
$canDelete ? $deleteItem : null,
|
||||
$wizard-> model === '3c' && $canLink ? $linkItem : null
|
||||
$wizard->model === '3c' && $item->type == 'question' && $canLink ? $linkItem : null
|
||||
), $transitionAction);
|
||||
|
||||
if($canCreate && (($showQuestionOfNode && $item->type == 'node') || $item->hasSameQuestion || $item->type == 'question')) $menus = array_merge($menus, array(
|
||||
@@ -269,12 +271,14 @@ class thinkStepMenu extends wg
|
||||
$treeProps = $this->props->pick(array('items', 'activeClass', 'activeIcon', 'activeKey', 'onClickItem', 'defaultNestedShow', 'changeActiveKey', 'isDropdownMenu', 'checkbox', 'checkOnClick', 'onCheck', 'sortable', 'onSort'));
|
||||
$isInSidebar = $this->parent instanceof sidebar;
|
||||
$treeType = (!empty($treeProps['onSort']) || !empty($treeProps['sortable'])) ? 'sortableTree' : 'tree';
|
||||
list($marketID, $from) = $this->prop(array('marketID', 'from'));
|
||||
|
||||
return array
|
||||
(
|
||||
div
|
||||
(
|
||||
setClass('think-node-menu rounded bg-white col bg-canvas pb-3 h-full no-morph'),
|
||||
setData(array('marketID' => $marketID, 'from' => $from ?? '')),
|
||||
zui::$treeType
|
||||
(
|
||||
set::_id('thinkNodeMenu'),
|
||||
|
||||
@@ -38,24 +38,23 @@ function setLineIndex(canAddRows, fieldsCount)
|
||||
* 添加行。
|
||||
* Add rows.
|
||||
*
|
||||
* @param event $e
|
||||
* @access public
|
||||
* @returns void
|
||||
*/
|
||||
window.addRow = function(e)
|
||||
$(document).off('click', '.think-step .btn-add').on('click', '.think-step .btn-add', function()
|
||||
{
|
||||
const canAddRows = $(e.target).data('canAddRows');
|
||||
const fieldsCount = $(e.target).data('fieldsCount');
|
||||
const canAddRows = $(this).data('canAddRows');
|
||||
const fieldsCount = $(this).data('fieldsCount');
|
||||
if($('.rows-group').length >= canAddRows) return;
|
||||
|
||||
const parentFormGroup = $(e.target || e).closest('.form-group');
|
||||
const parentFormGroup = $(this).closest('.form-group');
|
||||
const $newRow = $('.rows-template').clone();
|
||||
$newRow.find('.btn-add').attr('onclick', 'addRow(this)');
|
||||
$newRow.removeClass('rows-template').removeClass('hidden').addClass('rows-group');
|
||||
$newRow.find('textarea').val('');
|
||||
parentFormGroup.after($newRow);
|
||||
$newRow.find('#customFields').trigger("focus");
|
||||
setLineIndex(canAddRows, fieldsCount);
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 删除行。
|
||||
@@ -64,7 +63,7 @@ window.addRow = function(e)
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
$(document).on('click', '.think-step .btn-delete', function()
|
||||
$(document).off('click', '.think-step .btn-delete').on('click', '.think-step .btn-delete', function()
|
||||
{
|
||||
const canAddRows = $(this).data('canAddRows');
|
||||
const fieldsCount = $(this).data('fieldsCount');
|
||||
|
||||
@@ -79,7 +79,6 @@ class thinkTableInput extends thinkQuestion
|
||||
(
|
||||
'plus',
|
||||
setClass('mr-1 btn-add ml-2 text-sm text-primary add-rows cursor-pointer', $disabledAdd ? 'disabled' : ''),
|
||||
on::click('addRow(event)'),
|
||||
setData('canAddRows', $canAddRows),
|
||||
setData('fieldsCount', count($fields)),
|
||||
set::title(sprintf($lang->thinkrun->tips->add, $canAddRows)),
|
||||
@@ -130,7 +129,6 @@ class thinkTableInput extends thinkQuestion
|
||||
(
|
||||
'plus',
|
||||
setClass('mr-1 btn-add ml-2 text-sm text-primary add-rows', $disabledAdd ? 'disabled' : ''),
|
||||
on::click('addRow(event)'),
|
||||
setData('canAddRows', $canAddRows),
|
||||
setData('fieldsCount', count($fields)),
|
||||
set::title(sprintf($lang->thinkrun->tips->add, $canAddRows)),
|
||||
@@ -178,7 +176,6 @@ class thinkTableInput extends thinkQuestion
|
||||
(
|
||||
'plus',
|
||||
setClass('mr-1 btn-add ml-2 text-sm text-primary add-rows cursor-pointer'),
|
||||
on::click('addRow(event)'),
|
||||
setData('canAddRows', $canAddRows),
|
||||
setData('fieldsCount', count($fields)),
|
||||
set::title(sprintf($lang->thinkrun->tips->add, $canAddRows)),
|
||||
|
||||
@@ -77,6 +77,11 @@ class visionSwitcher extends wg
|
||||
$userVisions = array_filter(explode(',', $user->visions));
|
||||
$configVisions = array_filter(explode(',', trim($config->visions, ',')));
|
||||
|
||||
pageJS(<<<JS
|
||||
window.getUserVisions = () => '{$user->visions}'.split(',');
|
||||
window.getCurrentVision = () => '{$currentVision}';
|
||||
JS);
|
||||
|
||||
/* The standalone lite version removes the lite interface button */
|
||||
if(trim($config->visions, ',') == 'lite') return;
|
||||
|
||||
@@ -111,11 +116,6 @@ class visionSwitcher extends wg
|
||||
);
|
||||
}
|
||||
|
||||
pageJS(<<<JS
|
||||
window.getUserVisions = () => '{$user->visions}'.split(',');
|
||||
window.getCurrentVision = () => '{$currentVision}';
|
||||
JS);
|
||||
|
||||
$dropdown = new dropdown
|
||||
(
|
||||
new btn
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
$config->action->objectNameFields['product'] = 'name';
|
||||
$config->action->objectNameFields['productline'] = 'name';
|
||||
$config->action->objectNameFields['epic'] = 'title';
|
||||
$config->action->objectNameFields['story'] = 'title';
|
||||
$config->action->objectNameFields['requirement'] = 'title';
|
||||
@@ -85,7 +86,7 @@ $config->action->majorList['doc'] = array('releaseddoc');
|
||||
|
||||
$config->action->needGetProjectType = 'build,task,bug,case,testcase,caselib,testtask,testsuite,testreport,doc,issue,release,risk,design,opportunity,trainplan,gapanalysis,researchplan,researchreport,';
|
||||
$config->action->needGetRelateField = ',branch,story,epic,requirement,productplan,release,task,build,bug,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,module,review,';
|
||||
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,instance,gitea,gogs,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,repo,pivot,scene,boardspace,auditplan,auditresult,';
|
||||
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,instance,gitea,gogs,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,repo,pivot,scene,boardspace,auditplan,auditresult,productline,';
|
||||
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn';
|
||||
$config->action->ignoreActions4Dynamic = 'disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan,editmr,removemr';
|
||||
|
||||
@@ -94,7 +95,7 @@ $config->action->latestDateList = array('today', 'yesterday', 'thisWeek', 'lastW
|
||||
$config->action->preferredTypeNum = 10;
|
||||
|
||||
$config->action->preferredType = new stdclass();
|
||||
$config->action->preferredType->ALM = array('user', 'story', 'task', 'bug', 'case', 'board', 'boardspace', 'doc', 'program', 'product', 'project', 'execution');
|
||||
$config->action->preferredType->ALM = array('user', 'story', 'task', 'bug', 'case', 'board', 'boardspace', 'doc', 'program', 'product', 'productline', 'project', 'execution');
|
||||
$config->action->preferredType->light = array('user', 'story', 'task', 'bug', 'case', 'board', 'boardspace', 'doc', 'product', 'project', 'execution');
|
||||
|
||||
global $app, $lang;
|
||||
|
||||
@@ -187,6 +187,7 @@ $lang->action->objectTypes['metric'] = 'Metric';
|
||||
$lang->action->objectTypes['projectbuild'] = 'Build';
|
||||
$lang->action->objectTypes['board'] = 'Board';
|
||||
$lang->action->objectTypes['boardspace'] = 'Board Space';
|
||||
$lang->action->objectTypes['productline'] = 'Product Line';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -187,6 +187,7 @@ $lang->action->objectTypes['metric'] = 'Metric';
|
||||
$lang->action->objectTypes['projectbuild'] = 'Build';
|
||||
$lang->action->objectTypes['board'] = 'Board';
|
||||
$lang->action->objectTypes['boardspace'] = 'Board Space';
|
||||
$lang->action->objectTypes['productline'] = 'Product Line';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -187,6 +187,7 @@ $lang->action->objectTypes['metric'] = 'Metric';
|
||||
$lang->action->objectTypes['projectbuild'] = 'Build';
|
||||
$lang->action->objectTypes['board'] = 'Board';
|
||||
$lang->action->objectTypes['boardspace'] = 'Board Space';
|
||||
$lang->action->objectTypes['productline'] = 'Product Line';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -187,6 +187,7 @@ $lang->action->objectTypes['metric'] = '度量';
|
||||
$lang->action->objectTypes['projectbuild'] = '版本';
|
||||
$lang->action->objectTypes['board'] = '白板';
|
||||
$lang->action->objectTypes['boardspace'] = '白板空间';
|
||||
$lang->action->objectTypes['productline'] = '产品线';
|
||||
|
||||
/* 用来描述操作历史记录。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -14,6 +14,8 @@ $config->bi->conditionList['NOT IN'] = 'NOT IN';
|
||||
$config->bi->conditionList['IS NOT NULL'] = 'IS NOT NULL';
|
||||
$config->bi->conditionList['IS NULL'] = 'IS NULL';
|
||||
|
||||
$config->bi->duckdbExcludeTables = array('metriclib', 'repofiles', 'repohistory', 'queue', 'duckdbqueue', 'action');
|
||||
|
||||
$config->bi->builtin = new stdclass();
|
||||
$config->bi->builtin->modules = new stdclass();
|
||||
$config->bi->builtin->screens = array(1, 2, 3, 4, 5, 6, 7, 8,1001);
|
||||
|
||||
@@ -2605,6 +2605,7 @@ and t1.resolution!=''
|
||||
and (case when \$startDate='' then 1 else cast(t1.resolvedDate as date)>=cast(\$startDate as date) end)
|
||||
and (case when \$endDate='' then 1 else cast(t1.resolvedDate as date)<=cast(\$endDate as date) end)
|
||||
and (case when \$product = '' then 1 else t1.product=\$product end)
|
||||
and not (\$product='' and \$startDate='' and \$endDate='')
|
||||
EOT,
|
||||
'settings' => array
|
||||
(
|
||||
|
||||
@@ -35,6 +35,22 @@ class bi extends control
|
||||
echo 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
* Init parquet.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function initParquet()
|
||||
{
|
||||
$startTime = microtime(true);
|
||||
$this->bi->initParquet();
|
||||
$endTime = microtime(true);
|
||||
$runTime = $endTime - $startTime;
|
||||
echo "$runTime \n";
|
||||
echo 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax: get object options.
|
||||
*
|
||||
|
||||
+115
-23
@@ -1127,6 +1127,86 @@ class biModel extends model
|
||||
return $duckdbTmpPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sql by month.
|
||||
*
|
||||
* @param string $month
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getSqlByMonth($year = 'Y', $month = 'm')
|
||||
{
|
||||
$sqls = array();
|
||||
$prefix = $this->config->db->prefix;
|
||||
$year = date($year);
|
||||
$month = date($month);
|
||||
|
||||
$begin = date("{$year}-{$month}-01 00:00:00");
|
||||
$end = date("{$year}-{$month}-t 23:59:59", strtotime("$year-$month-01"));
|
||||
$sqls[$prefix . "action_{$year}_{$month}"] = "select * from zt_action where date >= TIMESTAMP '$begin' and date <= TIMESTAMP '$end'";
|
||||
|
||||
return $sqls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get action sync sql.
|
||||
*
|
||||
* @param string $range
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getActionSyncSql($range = 'current')
|
||||
{
|
||||
if($range == 'current') return $this->getSqlByMonth();
|
||||
|
||||
$actionDate = $this->biTao->fetchActionDate();
|
||||
$begin = new DateTime($actionDate->minDate);
|
||||
$end = new DateTime($actionDate->maxDate);
|
||||
|
||||
$sqls = array();
|
||||
while($begin <= $end)
|
||||
{
|
||||
$year = $begin->format('Y');
|
||||
$month = $begin->format('m');
|
||||
$sqls += $this->getSqlByMonth($year, $month);
|
||||
$begin->modify('+1 month');
|
||||
}
|
||||
|
||||
return $sqls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init parquet.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function initParquet()
|
||||
{
|
||||
$duckdb = $this->getDuckDBPath();
|
||||
if(!$duckdb) return $this->lang->bi->binNotExists;
|
||||
|
||||
$duckdbTmpPath = $this->getDuckDBTmpDir();
|
||||
if(!$duckdbTmpPath) return sprintf($this->lang->bi->tmpPermissionDenied, $this->getDuckDBTmpDir(true), $this->getDuckDBTmpDir(true));
|
||||
|
||||
$tables = $this->biTao->fetchAllTables();
|
||||
$copySQLs = array();
|
||||
foreach($tables as $table) $copySQLs[] = "copy (select * from {$table}) to '{$duckdbTmpPath}{$table}.parquet'";
|
||||
|
||||
$date = date("Y-m-01 00:00:00");
|
||||
$prefix = $this->config->db->prefix;
|
||||
|
||||
$copySQLs[] = "copy (select * from {$prefix}action where date < TIMESTAMP '$date') to '{$duckdbTmpPath}{$prefix}action_" . date('Y_m', strtotime('-1 month')) . ".parquet'";
|
||||
|
||||
$copySQL = implode(';', $copySQLs);
|
||||
if(empty($copySQL)) return true;
|
||||
|
||||
$command = $this->prepareSyncCommand($duckdb->bin, $duckdb->extension, $copySQL);
|
||||
$output = shell_exec($command);
|
||||
$this->saveLogs("Sync command: $command");
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 准备同步数据库所需的复制SQL。
|
||||
* Prepare copy SQL for sync.
|
||||
@@ -1137,26 +1217,17 @@ class biModel extends model
|
||||
*/
|
||||
public function prepareCopySQL($duckdbTmpPath)
|
||||
{
|
||||
$duckdbQueue = $this->dao->select('*')->from(TABLE_DUCKDBQUEUE)
|
||||
->where('updatedTime >= syncTime')
|
||||
->orWhere('syncTime IS NULL')
|
||||
->fetchAll('object');
|
||||
$tables = $this->biTao->fetchTableQueue();
|
||||
|
||||
if(empty($duckdbQueue)) return '';
|
||||
if(empty($tables)) return '';
|
||||
|
||||
$tables = array_keys($duckdbQueue);
|
||||
$copySQLs = array();
|
||||
foreach($tables as $table) $copySQLs[] = "copy (select * from {$table}) to '{$duckdbTmpPath}{$table}.parquet'";
|
||||
|
||||
$copySQLs = array();
|
||||
foreach($tables as $table)
|
||||
{
|
||||
$sql = "select * from {$table}";
|
||||
$copySQLs[] = "copy ($sql) to '{$duckdbTmpPath}{$table}.parquet'";
|
||||
}
|
||||
$actions = $this->getActionSyncSql();
|
||||
foreach($actions as $table => $sql) $copySQLs[] = "copy ({$sql}) to '{$duckdbTmpPath}{$table}.parquet'";
|
||||
|
||||
$this->dao->update(TABLE_DUCKDBQUEUE)
|
||||
->set('syncTime')->eq(helper::now())
|
||||
->where('object')->in($tables)
|
||||
->exec();
|
||||
$this->biTao->updateSyncTime($tables);
|
||||
|
||||
return implode(';', $copySQLs);
|
||||
}
|
||||
@@ -1265,8 +1336,9 @@ class biModel extends model
|
||||
if(empty($filter['default'])) continue;
|
||||
if(!isset($filter['from']) || $filter['from'] != 'query') continue;
|
||||
|
||||
$filters[$index]['default'] = $this->loadModel('pivot')->processDateVar($filter['default']);
|
||||
if($filters[$index]['type'] == 'datetime') $filters[$index]['default'] .= ':00.000000000';
|
||||
if($filter['type'] == 'date' || $filter['type'] == 'datetime') $filters[$index]['default'] = $this->loadModel('pivot')->processDateVar($filter['default']);
|
||||
if($filter['type'] == 'datetime') $filters[$index]['default'] .= ':00.000000000';
|
||||
if($filter['type'] == 'multipleselect' && is_array($filter['default'])) $filters[$index]['default'] = implode("','", $filter['default']);
|
||||
|
||||
if($emptyValue) $filters[$index]['default'] = '';
|
||||
}
|
||||
@@ -1283,12 +1355,16 @@ class biModel extends model
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function sql2Statement($sql)
|
||||
public function sql2Statement($sql, $mode = 'text')
|
||||
{
|
||||
$this->app->loadClass('sqlparser', true);
|
||||
$parser = new sqlparser($sql);
|
||||
|
||||
if($parser->statementsCount == 0) return $this->lang->dataview->empty;
|
||||
if($parser->statementsCount == 0)
|
||||
{
|
||||
if($mode == 'builder') return $this->lang->dataview->emptyBuilder;
|
||||
return $this->lang->dataview->empty;
|
||||
}
|
||||
if($parser->statementsCount > 1) return $this->lang->dataview->onlyOne;
|
||||
|
||||
if(!$parser->isSelect) return $this->lang->dataview->allowSelect;
|
||||
@@ -1594,7 +1670,7 @@ class biModel extends model
|
||||
|
||||
$stateObj->beforeQuerySql();
|
||||
|
||||
$statement = $this->sql2Statement($sql);
|
||||
$statement = $this->sql2Statement($sql, $stateObj->mode);
|
||||
if(is_string($statement)) return $stateObj->setError($statement);
|
||||
|
||||
$checked = $this->validateSql($sql, $driver);
|
||||
@@ -1641,6 +1717,7 @@ class biModel extends model
|
||||
public function getTableList()
|
||||
{
|
||||
$originTableTreeMenu = $this->loadModel('dataview')->getOriginTreeMenu();
|
||||
$dataviewTreeMenu = $this->loadModel('tree')->getGroupTree(0, 'dataview');
|
||||
|
||||
$tableList = array();
|
||||
foreach($originTableTreeMenu as $menu)
|
||||
@@ -1652,11 +1729,26 @@ class biModel extends model
|
||||
if(!is_array($item))
|
||||
{
|
||||
$text = $item->key == 'story' ? $this->lang->story->common : $item->text;
|
||||
$tableList[$item->key] = $text;
|
||||
$tableList[$this->config->db->prefix . $item->key] = $text;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($item->items as $subItem) $tableList[$subItem->key] = $subItem->text;
|
||||
foreach($item->items as $subItem) $tableList[$this->config->db->prefix . $subItem->key] = $subItem->text;
|
||||
}
|
||||
}
|
||||
foreach($dataviewTreeMenu as $menu)
|
||||
{
|
||||
if(empty($menu->items)) continue;
|
||||
|
||||
foreach($menu->items as $item)
|
||||
{
|
||||
if(!is_array($item))
|
||||
{
|
||||
$tableList['ztv_' . $item->key] = $item->text;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($item->items as $subItem) $tableList['ztv_' . $subItem->key] = $subItem->text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
class biTao extends biModel
|
||||
{
|
||||
/**
|
||||
* Fetch tables.
|
||||
*
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchAllTables()
|
||||
{
|
||||
$prefix = $this->config->db->prefix;
|
||||
$excludes = $this->config->bi->duckdbExcludeTables;
|
||||
foreach($excludes as $index => $table) $excludes[$index] = $prefix . $table;
|
||||
|
||||
return $this->dao->select("table_name as 'table'")
|
||||
->from('information_schema.tables')
|
||||
->where('table_type')->eq('BASE TABLE')
|
||||
->andWhere('table_schema')->eq($this->config->db->name)
|
||||
->andWhere('table_name')->notin($excludes)
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch table queue.
|
||||
*
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchTableQueue()
|
||||
{
|
||||
$prefix = $this->config->db->prefix;
|
||||
$excludes = $this->config->bi->duckdbExcludeTables;
|
||||
foreach($excludes as $index => $table) $excludes[$index] = $prefix . $table;
|
||||
|
||||
return $this->dao->select('object')->from(TABLE_DUCKDBQUEUE)
|
||||
->where('object')->notin($excludes)
|
||||
->andWhere('updatedTime >= syncTime', true)
|
||||
->orWhere('syncTime IS NULL')
|
||||
->markRight(1)
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update sync time.
|
||||
*
|
||||
* @param array $tables
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function updateSyncTime($tables)
|
||||
{
|
||||
$this->dao->update(TABLE_DUCKDBQUEUE)
|
||||
->set('syncTime')->eq(helper::now())
|
||||
->where('object')->in($tables)
|
||||
->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch action date.
|
||||
*
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function fetchActionDate()
|
||||
{
|
||||
return $this->dao->select('min(date) as minDate, max(date) as maxDate')
|
||||
->from(TABLE_ACTION)
|
||||
->where('date')->ge('2009-01-01')
|
||||
->fetch();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -95,7 +95,7 @@ $lang->block->confirmRemoveBlock = 'Möchten Sie den Block löschen?';
|
||||
$lang->block->noticeNewBlock = 'ZenTao 10.+ hat neue Layouts für jeden View. Möchten Sie die neue Ansicht nutzen?';
|
||||
$lang->block->confirmReset = 'Möchten Sie das Dashboard zurücksetzen?';
|
||||
$lang->block->closeForever = 'Dauerhaft schließen';
|
||||
$lang->block->confirmClose = 'Möchten Sie den Block dauerhaft schlißen? Nach der Ausführung ist der Block nicht mehr verfügbar. Er kann unter Admin->Custom aber wieder aktiviert werden.';
|
||||
$lang->block->confirmClose = 'Möchten Sie den Block dauerhaft schlißen? Nach der Ausführung ist der Block nicht mehr verfügbar. Er kann unter Admin->Feature->My->Block aber wieder aktiviert werden.';
|
||||
$lang->block->remove = 'Entfernen';
|
||||
$lang->block->refresh = 'Aktualisieren';
|
||||
$lang->block->nbsp = '';
|
||||
|
||||
@@ -95,7 +95,7 @@ $lang->block->confirmRemoveBlock = 'Do you want to remove the Block?';
|
||||
$lang->block->noticeNewBlock = 'A new layout is available. Do you want to switch to the new one?';
|
||||
$lang->block->confirmReset = 'Do you want to reset the layout?';
|
||||
$lang->block->closeForever = 'Permanent Close';
|
||||
$lang->block->confirmClose = 'Do you want to permanently close this block? Once done, it is not available to anyone. It can be activiated at Admin->Custom.';
|
||||
$lang->block->confirmClose = 'Do you want to permanently close this block? Once done, it is not available to anyone. It can be activiated at Admin->Feature->My->Block.';
|
||||
$lang->block->remove = 'Remove';
|
||||
$lang->block->refresh = 'Refresh';
|
||||
$lang->block->nbsp = ' ';
|
||||
|
||||
@@ -95,7 +95,7 @@ $lang->block->confirmRemoveBlock = '确定隐藏区块吗?';
|
||||
$lang->block->noticeNewBlock = '10.0版本以后各个视图主页提供了全新的视图,您要启用新的视图布局吗?';
|
||||
$lang->block->confirmReset = '是否恢复默认布局?';
|
||||
$lang->block->closeForever = '永久关闭';
|
||||
$lang->block->confirmClose = '确定永久关闭该区块吗?关闭后所有人都将无法使用该区块,可以在后台自定义中打开。';
|
||||
$lang->block->confirmClose = '确定永久关闭该区块吗?关闭后所有人都将无法使用该区块,可以在[后台-功能配置-地盘-区块]中打开。';
|
||||
$lang->block->remove = '移除';
|
||||
$lang->block->refresh = '刷新';
|
||||
$lang->block->nbsp = '';
|
||||
|
||||
@@ -36,7 +36,7 @@ function printSystemMode()
|
||||
div
|
||||
(
|
||||
set('class', 'px-4 pb-2'),
|
||||
div(set('class', 'pb-2'), span(set('class', 'font-bold'), $modeName)),
|
||||
div(set('class', 'pb-2'), span(set('class', 'font-bold text-black'), $modeName)),
|
||||
span(set('class', 'text-sm text-gray'), $lang->block->customModeTip->{$mode})
|
||||
)
|
||||
),
|
||||
|
||||
@@ -19,7 +19,7 @@ $productItems = array();
|
||||
foreach($products as $id => $productName)
|
||||
{
|
||||
$url = createLink('block', 'printBlock', "blockID={$block->id}¶ms=" . helper::safe64Encode("module={$block->module}&productID={$id}"));
|
||||
$productItems[] = array('text' => $productName, 'data-url' => $url, 'data-on' => 'click', 'data-do' => "loadBlock('$block->id', options.url)");
|
||||
$productItems[] = array('text' => $productName, 'data-url' => $url, 'active' => $productID == $id, 'data-on' => 'click', 'data-do' => "loadBlock('$block->id', options.url)");
|
||||
}
|
||||
panel
|
||||
(
|
||||
|
||||
+6
-29
@@ -405,35 +405,12 @@ class blockZen extends block
|
||||
$welcomeType = '19:00';
|
||||
foreach($this->lang->block->welcomeList as $type => $name) $welcomeType = $time >= $type ? $type : $welcomeType;
|
||||
|
||||
/* 获取禅道陪伴当前用户总天数。 */
|
||||
if(!empty($this->config->installedDate))
|
||||
{
|
||||
$firstUseDate = $this->config->global->installedDate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$firstUseDate = $this->dao->select('date')->from(TABLE_ACTION)
|
||||
->where('date')->gt('1971-01-01')
|
||||
->andWhere('actor')->eq($this->app->user->account)
|
||||
->orderBy('date_asc')
|
||||
->limit('1')
|
||||
->fetch('date');
|
||||
}
|
||||
|
||||
if($firstUseDate)
|
||||
{
|
||||
$usageDays = '';
|
||||
$usageDateInfo = helper::getDateInterval($firstUseDate);
|
||||
if(!empty($usageDateInfo->year)) $usageDays .= $usageDateInfo->year . ' ' . $this->lang->year . ' ';
|
||||
if(!empty($usageDateInfo->month)) $usageDays .= $usageDateInfo->month . ' ' . $this->lang->month . ' ';
|
||||
if(!empty($usageDateInfo->day)) $usageDays .= $usageDateInfo->day . ' ' . $this->lang->day . ' ';
|
||||
|
||||
if(!$usageDays) $usageDays .= "0 {$this->lang->day}";
|
||||
}
|
||||
else
|
||||
{
|
||||
$usageDays = ' 1 ' . $this->lang->day; // 最小陪伴天数是一天。
|
||||
}
|
||||
$usageDays = '';
|
||||
$dateUsed = $this->loadModel('admin')->genDateUsed();
|
||||
if(!empty($dateUsed->year)) $usageDays .= $dateUsed->year . ' ' . $this->lang->year . ' ';
|
||||
if(!empty($dateUsed->month)) $usageDays .= $dateUsed->month . ' ' . $this->lang->month . ' ';
|
||||
if(!empty($dateUsed->day)) $usageDays .= $dateUsed->day . ' ' . $this->lang->day . ' ';
|
||||
if(!$usageDays) $usageDays = "0 {$this->lang->day}";
|
||||
if(strpos($this->app->getClientLang(), 'zh') !== false) $usageDays = str_replace(' ', '', $usageDays);
|
||||
|
||||
$yesterday = strtotime("-1 day");
|
||||
|
||||
@@ -316,7 +316,11 @@ class branchModel extends model
|
||||
->where('id')->eq($branchID)
|
||||
->exec();
|
||||
|
||||
if(dao::isError()) dao::$errors[] = 'branch#' . ($index + 1) . dao::getError(true);
|
||||
if(dao::isError())
|
||||
{
|
||||
dao::$errors["name[$index]"] = dao::getError(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
$changes[$branchID] = common::createChanges($oldBranchList[$branchID], $branch);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class batchEditBranchTester extends tester
|
||||
{
|
||||
/**
|
||||
* 批量编辑分支
|
||||
* batch edit branch
|
||||
*
|
||||
* @param $editBranch 分支数据
|
||||
* @param $productID 产品ID
|
||||
* @return mixed
|
||||
*/
|
||||
public function batchEditBranch($editBranch, $productID)
|
||||
{
|
||||
$form = $this->initForm('branch', 'manage', $productID, 'appIframe-product');
|
||||
$form->dom->allTab->click();
|
||||
$form->wait(1);
|
||||
$form->dom->selectAllBtn->click();//全选分支
|
||||
$form->dom->batchEditBtn->click();//点击编辑按钮
|
||||
$form->wait(2);
|
||||
$secID = $form->dom->id_static_1->getText();//获取第二个ID
|
||||
$nameDom = "name[{$secID}]";
|
||||
$descDom = "desc[{$secID}]";
|
||||
$tipDom = "name[{$secID}]Tip";
|
||||
//设置表单字段
|
||||
if (isset($editBranch->name)) $form->dom->$nameDom->setValue($editBranch->name);
|
||||
if (isset($editBranch->desc)) $form->dom->$descDom->setValue($editBranch->desc);
|
||||
$form->dom->btn($this->lang->save)->click();
|
||||
$form->wait(2);
|
||||
//判断批量编辑结果
|
||||
if ($form->dom->allTab === false)
|
||||
{
|
||||
$nameTip = $form->dom->$tipDom->getText();
|
||||
$nameEmptyTip = sprintf($this->lang->error->notempty, $this->lang->branch->name);
|
||||
if ($nameTip === $nameEmptyTip) return $this->success('分支名称必填提示信息正确');
|
||||
if ($editBranch->name != '' && $form->dom->$tipDom)
|
||||
{
|
||||
$nameExistTip = str_replace('@branch@', $this->lang->branch->common, $this->lang->branch->existName);
|
||||
return ($nameTip === $nameExistTip)
|
||||
? $this->success('分支已存在提示信息正确')
|
||||
: $this->failed('分支已存在提示信息不正确');
|
||||
}
|
||||
return $this->failed('分支名称必填提示信息不正确');
|
||||
}
|
||||
else
|
||||
{
|
||||
$branchName = $form->dom->secName->getText();
|
||||
$branchDesc = $form->dom->secDesc->getText();
|
||||
return ($branchName === $editBranch->name && $branchDesc === $editBranch->desc)
|
||||
? $this->success('批量编辑分支成功')
|
||||
: $this->failed('批量编辑分支失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class createBranchTester extends tester
|
||||
{
|
||||
/**
|
||||
* 创建分支
|
||||
* Create branch
|
||||
*
|
||||
* @param $branch 分支数据
|
||||
* @param $productID 产品ID
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function createBranch($branch, $productID)
|
||||
{
|
||||
$form = $this->initForm('branch', 'manage', $productID, 'appIframe-product');
|
||||
$form->dom->btn($this->lang->branch->createAction)->click();
|
||||
$form->waitElement($form->dom->branchName);
|
||||
//设置表单字段值
|
||||
if (isset($branch->name)) $form->dom->branchName->setValue($branch->name);
|
||||
if (isset($branch->desc)) $form->dom->branchDesc->setValue($branch->desc);
|
||||
$form->dom->save->click();
|
||||
$form->wait(2);
|
||||
if ($form->dom->createBranchForm)
|
||||
{
|
||||
if ($this->checkFormTips('branch')) return $this->success('分支名称必填提示信息正确');
|
||||
if ($branch->name != '' && $form->dom->nameTip)
|
||||
{
|
||||
//分支已存在
|
||||
$nameTip = str_replace('@branch@', $this->lang->branch->common, $this->lang->branch->existName);
|
||||
return ($form->dom->nameTip->getText() == $nameTip)
|
||||
? $this->success('分支已存在提示信息正确')
|
||||
: $this->failed('分支已存在提示信息不正确');
|
||||
}
|
||||
return $this->failed('分支名称必填提示信息不正确');
|
||||
}
|
||||
return $this->success('创建分支成功');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class editBranchTester extends tester
|
||||
{
|
||||
/**
|
||||
* 编辑分支
|
||||
* edit branch
|
||||
*
|
||||
* @param $editBranch 分支数据
|
||||
* @param $productID 产品ID
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function editBranch($editBranch, $productID)
|
||||
{
|
||||
$form = $this->initForm('branch', 'manage', $productID, 'appIframe-product');
|
||||
$form->dom->allTab->click();
|
||||
$form->dom->editBtn->click();
|
||||
//设置表单字段值
|
||||
if (isset($editBranch->name)) $form->dom->editName->setValue($editBranch->name);
|
||||
if (isset($editBranch->desc)) $form->dom->editDesc->setValue($editBranch->desc);
|
||||
$form->dom->editSave->click();
|
||||
$form->wait(2);
|
||||
if ($form->dom->zin_branch_edit_1_form)
|
||||
{
|
||||
if ($this->checkFormTips('branch')) return $this->success('分支名称必填提示信息正确');
|
||||
if (isset($editBranch->name) && ($form->dom->nameTip))
|
||||
{
|
||||
//分支已存在
|
||||
$nameTip = str_replace('@branch@', $this->lang->branch->common, $this->lang->branch->existName);
|
||||
return ($form->dom->nameTip->getText() == $nameTip)
|
||||
? $this->success('分支已存在提示信息正确')
|
||||
: $this->failed('分支已存在提示信息不正确');
|
||||
}
|
||||
return $this->failed('分支名称必填提示信息不正确');
|
||||
}
|
||||
return ($form->dom->secName->getText() == $editBranch->name)
|
||||
? $this->success('编辑分支成功')
|
||||
: $this->failed('编辑分支失败');
|
||||
}
|
||||
}
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
title=批量编辑分支测试
|
||||
timeout=0
|
||||
cid=0
|
||||
|
||||
-校验分支名称必填
|
||||
-测试结果 @分支名称必填提示信息正确
|
||||
-最终测试状态 @SUCCESS
|
||||
-校验分支重复
|
||||
-测试结果 @分支已存在提示信息正确
|
||||
-最终测试状态 @SUCCESS
|
||||
-校验分支正常编辑
|
||||
-测试结果 @批量编辑分支成功
|
||||
-最终测试状态 @SUCCESS
|
||||
|
||||
*/
|
||||
chdir(__DIR__);
|
||||
include '../lib/batcheditbranch.ui.class.php';
|
||||
|
||||
$product = zenData('product');
|
||||
$product->id->range('11');
|
||||
$product->name->range('多分支产品');
|
||||
$product->status->range('normal');
|
||||
$product->type->range('branch');
|
||||
$product->gen(1);
|
||||
|
||||
$branch = zenData('branch');
|
||||
$branch->id->range('1-2');
|
||||
$branch->product->range('11');
|
||||
$branch->name->range('分支01,分支02');
|
||||
$branch->desc->range('分支描述01,分支描述02');
|
||||
$branch->gen(2);
|
||||
|
||||
$tester = new batchEditBranchTester();
|
||||
$tester->login();
|
||||
|
||||
$productID['productID'] = 11;
|
||||
$editBranch = new stdClass();
|
||||
$editBranch->name = '';
|
||||
r($tester->batchEditBranch($editBranch, $productID)) && p('message,status') && e('分支名称必填提示信息正确,SUCCESS');
|
||||
|
||||
$editBranch->name = '分支02';
|
||||
r($tester->batchEditBranch($editBranch, $productID)) && p('message,status') && e('分支已存在提示信息正确,SUCCESS');
|
||||
|
||||
$editBranch->name = '分支test编辑';
|
||||
$editBranch->desc = '这是一行分支的描述';
|
||||
r($tester->batchEditBranch($editBranch, $productID)) && p('message,status') && e('批量编辑分支成功,SUCCESS');
|
||||
|
||||
$tester->closeBrowser();
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
title=创建分支测试
|
||||
timeout=0
|
||||
cid=12
|
||||
|
||||
-校验分支名称必填
|
||||
-测试结果 @分支名称必填提示信息正确
|
||||
-最终测试状态 @SUCCESS
|
||||
-校验分支正常创建
|
||||
-测试结果 @创建分支成功
|
||||
-最终测试状态 @SUCCESS
|
||||
-校验分支重复
|
||||
-测试结果 @分支已存在提示信息正确
|
||||
-最终测试状态 @SUCCESS
|
||||
*/
|
||||
chdir(__DIR__);
|
||||
include '../lib/createbranch.ui.class.php';
|
||||
|
||||
$product = zenData('product');
|
||||
$product->id->range('11');
|
||||
$product->name->range('多分支产品');
|
||||
$product->status->range('normal');
|
||||
$product->type->range('branch');
|
||||
$product->gen(1);
|
||||
zendata('branch')->loadYaml('branch', false, 2)->gen(0);
|
||||
$tester = new createBranchTester();
|
||||
$tester->login();
|
||||
|
||||
$productID['productID'] = 11;
|
||||
$branch = new stdClass();
|
||||
$branch->name = '';
|
||||
r($tester->createBranch($branch, $productID)) && p('message,status') && e('分支名称必填提示信息正确,SUCCESS');
|
||||
|
||||
$branch->name = '分支test';
|
||||
$branch->desc = '这是一行分支的描述';
|
||||
r($tester->createBranch($branch, $productID)) && p('message,status') && e('创建分支成功,SUCCESS');
|
||||
|
||||
r($tester->createBranch($branch, $productID)) && p('message,status') && e('分支已存在提示信息正确,SUCCESS');
|
||||
$tester->closeBrowser();
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
title=编辑分支测试
|
||||
timeout=0
|
||||
cid=13
|
||||
|
||||
-校验分支名称必填
|
||||
-测试结果 @分支名称必填提示信息正确
|
||||
-最终测试状态 @SUCCESS
|
||||
-校验分支重复
|
||||
-测试结果 @分支已存在提示信息正确
|
||||
-最终测试状态 @SUCCESS
|
||||
-校验分支正常编辑
|
||||
-测试结果 @编辑分支成功
|
||||
-最终测试状态 @SUCCESS
|
||||
|
||||
*/
|
||||
chdir(__DIR__);
|
||||
include '../lib/editbranch.ui.class.php';
|
||||
|
||||
$product = zenData('product');
|
||||
$product->id->range('11');
|
||||
$product->name->range('多分支产品');
|
||||
$product->status->range('normal');
|
||||
$product->type->range('branch');
|
||||
$product->gen(1);
|
||||
|
||||
$branch = zenData('branch');
|
||||
$branch->id->range('1-2');
|
||||
$branch->product->range('11');
|
||||
$branch->name->range('分支01,分支02');
|
||||
$branch->desc->range('分支描述01,分支描述02');
|
||||
$branch->gen(2);
|
||||
|
||||
$tester = new editBranchTester();
|
||||
$tester->login();
|
||||
|
||||
$productID['productID'] = 11;
|
||||
$editBranch = new stdClass();
|
||||
$editBranch->name = '';
|
||||
r($tester->editBranch($editBranch, $productID)) && p('message,status') && e('分支名称必填提示信息正确,SUCCESS');
|
||||
|
||||
$editBranch->name = '分支02';
|
||||
r($tester->editBranch($editBranch, $productID)) && p('message,status') && e('分支已存在提示信息正确,SUCCESS');
|
||||
|
||||
$editBranch->name = '分支test编辑';
|
||||
$editBranch->desc = '这是一行分支的描述';
|
||||
r($tester->editBranch($editBranch, $productID)) && p('message,status') && e('编辑分支成功,SUCCESS');
|
||||
|
||||
$tester->closeBrowser();
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
class managePage extends page
|
||||
{
|
||||
public function __construct($webdriver)
|
||||
{
|
||||
parent::__construct($webdriver);
|
||||
$xpath = array(
|
||||
/*新建分支页*/
|
||||
'branchName' => "//*[@id='zin_branch_create_form']/div[1]/input",
|
||||
'branchDesc' => "//*[@id='zin_branch_create_form']/div[2]/textarea",
|
||||
'save' => "//*[@id='zin_branch_create_form']/div[3]/div/button",
|
||||
/*分支列表*/
|
||||
'allTab' => "//*[@id='featureBar']/menu/li[1]/a",
|
||||
'activeTab' => "//*[@id='featureBar']/menu/li[2]/a",
|
||||
'closedTab' => "//*[@id='featureBar']/menu/li[3]/a",
|
||||
'secName' => "//*[@id='table-branch-manage']/div[2]/div[1]/div/div[4]/div",
|
||||
'secDesc' => "//*[@id='table-branch-manage']/div[2]/div[2]/div/div[8]/div",
|
||||
'secStatus' => "//*[@id='table-branch-manage']/div[2]/div[2]/div/div[5]/div/span",
|
||||
'selectAllBtn' => "//*[@id='table-branch-manage']/div[3]/div[1]/div/label",
|
||||
'batchEditBtn' => "//*[@id='table-branch-manage']/div[3]/nav[1]/button[1]",
|
||||
'editBtn' => "//*[@id='table-branch-manage']/div[2]/div[3]/div/div[2]/div/nav/a[1]",
|
||||
'closeBtn' => "//*[@id='table-branch-manage']/div[2]/div[3]/div/div[2]/div/nav/a[2]",
|
||||
'activateBtn' => "//*[@id='table-branch-manage']/div[2]/div[3]/div/div[2]/div/nav/a[2]",
|
||||
/*编辑分支页*/
|
||||
'editName' => "//*[@id='zin_branch_edit_1_form']/div[1]/input",
|
||||
'editDesc' => "//*[@id='zin_branch_edit_1_form']/div[3]/textarea",
|
||||
'editSave' => "//*[@id='zin_branch_edit_1_form']/div[4]/div/button",
|
||||
);
|
||||
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ featureBar
|
||||
$canCreate = hasPriv('branch', 'create');
|
||||
$canBatchEdit = hasPriv('branch', 'batchEdit');
|
||||
$canMerge = hasPriv('branch', 'mergeBranch');
|
||||
if($canCreate) $createItem = array('icon' => 'plus', 'class' => 'primary branch-create-btn', 'text' => $lang->branch->create, 'url' => $this->createLink('branch', 'create', "productID={$product->id}", '', true), 'data-toggle' => 'modal');
|
||||
if($canCreate) $createItem = array('icon' => 'plus', 'class' => 'primary branch-create-btn', 'text' => $lang->branch->create, 'url' => $this->createLink('branch', 'create', "productID={$product->id}"), 'data-toggle' => 'modal');
|
||||
toolbar
|
||||
(
|
||||
!empty($createItem) ? item(set($createItem)) : null,
|
||||
|
||||
@@ -16,6 +16,13 @@ $(document).off('click', '.batch-btn').on('click', '.batch-btn', function()
|
||||
{
|
||||
postAndLoadPage(url, form);
|
||||
}
|
||||
}).off('click', '#actionBar .export-btn').on('click', '#actionBar export-btn', function()
|
||||
{
|
||||
const dtable = zui.DTable.query($('#table-bug-browse'));
|
||||
const checkedList = dtable ? dtable.$.getChecks() : [];
|
||||
if(!checkedList.length) return;
|
||||
|
||||
$.cookie.set('checkedItem', checkedList, {expires:config.cookieLife, path:config.webRoot});
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
+11
-11
@@ -34,7 +34,7 @@ function changeProduct(event)
|
||||
loadProductBuilds(productID);
|
||||
loadProductPlans(productID);
|
||||
loadProductStories(productID, bug.storyID);
|
||||
if(config.currentMethod == 'edit' && edition == 'max') loadIdentify();
|
||||
if(methodName == 'edit' && edition == 'max') loadIdentify();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ function changeProject(event)
|
||||
loadExecutionLabel(projectID);
|
||||
loadExecutions(productID, projectID);
|
||||
loadAssignedTo(productID, projectID);
|
||||
if(config.currentMethod == 'edit' && edition == 'max') loadIdentify();
|
||||
if(methodName == 'edit' && edition == 'max') loadIdentify();
|
||||
}
|
||||
|
||||
function changeExecution(event)
|
||||
@@ -137,8 +137,8 @@ window.refreshExecutionBuild = function(event)
|
||||
|
||||
function loadProductBranches(productID)
|
||||
{
|
||||
const branchStatus = config.currentMethod == 'create' ? 'active' : 'all';
|
||||
const oldBranch = config.currentMethod == 'edit' ? bug.branch : 0;
|
||||
const branchStatus = methodName == 'create' ? 'active' : 'all';
|
||||
const oldBranch = methodName == 'edit' ? bug.branch : 0;
|
||||
let param = "productID=" + productID + "&oldBranch=" + oldBranch + "¶m=" + branchStatus;
|
||||
if(typeof(tab) != 'undefined' && (tab == 'execution' || tab == 'project')) param += "&projectID=" + bug[tab];
|
||||
$.getJSON($.createLink('branch', 'ajaxGetBranches', param), function(data)
|
||||
@@ -155,7 +155,7 @@ function loadProductBranches(productID)
|
||||
{
|
||||
$('[name="product"]').closest('.input-group').append($('<div id="branchPicker" class="form-group-wrapper picker-box"></div>').picker({name: 'branch', items: data, defaultValue: data[0].value, required: true}));
|
||||
}
|
||||
$('#branchPicker').css('width', config.currentMethod == 'create' ? '120px' : '65px');
|
||||
$('#branchPicker').css('width', methodName == 'create' ? '120px' : '65px');
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -167,7 +167,7 @@ function loadProductBranches(productID)
|
||||
|
||||
function loadProductModules(productID)
|
||||
{
|
||||
if(config.currentMethod == 'edit')
|
||||
if(methodName == 'edit')
|
||||
{
|
||||
const moduleID = $('[name="module"]').val();
|
||||
}
|
||||
@@ -224,7 +224,7 @@ function loadExecutions(productID, projectID = 0)
|
||||
|
||||
function loadExecutionLabel(projectID)
|
||||
{
|
||||
if(config.currentMethod == 'create' && projectID > 0)
|
||||
if(methodName == 'create' && projectID > 0)
|
||||
{
|
||||
const link = $.createLink('bug', 'ajaxGetExecutionLang', 'projectID=' + projectID);
|
||||
$.post(link, function(executionLang)
|
||||
@@ -327,7 +327,7 @@ function loadProjectBuilds(projectID)
|
||||
const productID = $('[name="product"]').val();
|
||||
const oldOpenedBuild = $('[name^="openedBuild"]').val() ? $('[name^="openedBuild"]').val().toString() : 0;
|
||||
|
||||
if(config.currentMethod == 'create')
|
||||
if(methodName == 'create')
|
||||
{
|
||||
const link = $.createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=&branch=' + branch);
|
||||
$.getJSON(link, function(data)
|
||||
@@ -366,7 +366,7 @@ function loadProductBuilds(productID, type = 'normal', buildBox = 'all')
|
||||
let branch = $('[name="branch"]').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
|
||||
if(config.currentMethod == 'create')
|
||||
if(methodName == 'create')
|
||||
{
|
||||
if(buildBox == 'all' || buildBox == 'openedBuild')
|
||||
{
|
||||
@@ -420,7 +420,7 @@ function loadExecutionBuilds(executionID, num)
|
||||
if(typeof(branch) == 'undefined') branch = 'all';
|
||||
if(typeof(productID) == 'undefined') productID = 0;
|
||||
|
||||
if(config.currentMethod == 'create')
|
||||
if(methodName == 'create')
|
||||
{
|
||||
const link = $.createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + "&branch=" + branch + "&needCreate=true");
|
||||
$.getJSON(link, function(data)
|
||||
@@ -666,7 +666,7 @@ function setBranchRelated(event)
|
||||
|
||||
function loadBuildActions()
|
||||
{
|
||||
if(config.currentMethod == 'edit') return;
|
||||
if(methodName == 'edit') return;
|
||||
$('#createRelease, #createBuild').hide();
|
||||
let itemCount = $('[name^=openedBuild]').zui('picker').options.items.length;
|
||||
if(itemCount <= 1)
|
||||
|
||||
@@ -82,6 +82,7 @@ $lang->bug->task = 'Aufgabe';
|
||||
$lang->bug->relatedBug = 'Verknüpfter Bug';
|
||||
$lang->bug->case = 'Fall';
|
||||
$lang->bug->linkMR = 'Related MRs';
|
||||
$lang->bug->linkPR = 'Related PRs';
|
||||
$lang->bug->linkCommit = 'Related Commits';
|
||||
$lang->bug->productplan = $lang->bug->plan;
|
||||
$lang->bug->codeBranch = 'Code branch';
|
||||
|
||||
@@ -82,6 +82,7 @@ $lang->bug->task = 'Task';
|
||||
$lang->bug->relatedBug = 'Related Bugs';
|
||||
$lang->bug->case = 'Cases';
|
||||
$lang->bug->linkMR = 'Related MRs';
|
||||
$lang->bug->linkPR = 'Related PRs';
|
||||
$lang->bug->linkCommit = 'Related Commits';
|
||||
$lang->bug->productplan = $lang->bug->plan;
|
||||
$lang->bug->codeBranch = 'Code branch';
|
||||
|
||||
@@ -82,6 +82,7 @@ $lang->bug->task = 'Tâche';
|
||||
$lang->bug->relatedBug = 'Bugs Liés';
|
||||
$lang->bug->case = 'CasTests';
|
||||
$lang->bug->linkMR = 'Related MRs';
|
||||
$lang->bug->linkPR = 'Related PRs';
|
||||
$lang->bug->linkCommit = 'Related Commits';
|
||||
$lang->bug->productplan = $lang->bug->plan;
|
||||
$lang->bug->codeBranch = 'Code branch';
|
||||
|
||||
@@ -82,6 +82,7 @@ $lang->bug->task = '相关任务';
|
||||
$lang->bug->relatedBug = '相关Bug';
|
||||
$lang->bug->case = '相关用例';
|
||||
$lang->bug->linkMR = '相关合并请求';
|
||||
$lang->bug->linkPR = '相关推送请求';
|
||||
$lang->bug->linkCommit = '相关代码版本';
|
||||
$lang->bug->productplan = $lang->bug->plan;
|
||||
$lang->bug->codeBranch = '代码分支';
|
||||
|
||||
@@ -2158,8 +2158,8 @@ class bugModel extends model
|
||||
{
|
||||
return $this->dao->select('t1.revision,t3.id AS id,t3.title AS title')
|
||||
->from(TABLE_REPOHISTORY)->alias('t1')
|
||||
->leftJoin(TABLE_RELATION)->alias('t2')->on('t2.relation="completedin" AND t2.BType="commit" AND t2.BID=t1.id')
|
||||
->leftJoin(TABLE_BUG)->alias('t3')->on('t2.AType="bug" AND t2.AID=t3.id')
|
||||
->leftJoin(TABLE_RELATION)->alias('t2')->on("t2.relation='completedin' AND t2.BType='commit' AND t2.BID=t1.id")
|
||||
->leftJoin(TABLE_BUG)->alias('t3')->on("t2.AType='bug' AND t2.AID=t3.id")
|
||||
->where('t1.revision')->in($revisions)
|
||||
->andWhere('t1.repo')->eq($repoID)
|
||||
->andWhere('t3.id')->ne('')
|
||||
|
||||
@@ -29,6 +29,7 @@ if(!$product->shadow) $fields->fullModeOrders('module,project,execution');
|
||||
|
||||
jsVar('bug', $bug);
|
||||
jsVar('moduleID', $bug->moduleID);
|
||||
jsVar('methodName', $app->methodName);
|
||||
jsVar('tab', $this->app->tab);
|
||||
jsVar('createRelease', $lang->release->create);
|
||||
jsVar('refresh', $lang->refreshIcon);
|
||||
|
||||
@@ -16,6 +16,7 @@ include($this->app->getModuleRoot() . 'ai/ui/inputinject.html.php');
|
||||
jsVar('bug', $bug);
|
||||
jsVar('confirmChangeProduct', $lang->bug->notice->confirmChangeProduct);
|
||||
jsVar('moduleID', $bug->module);
|
||||
jsVar('methodName', $app->methodName);
|
||||
jsVar('tab', $this->app->tab);
|
||||
jsVar('released', $lang->build->released);
|
||||
jsVar('confirmUnlinkBuild', sprintf($lang->bug->notice->confirmUnlinkBuild, zget($resolvedBuildPairs, $bug->resolvedBuild)));
|
||||
|
||||
@@ -78,7 +78,7 @@ formPanel
|
||||
set::width('1/3'),
|
||||
setID('newBuildExecutionBox'),
|
||||
setClass('hidden'),
|
||||
set::label(!empty($execution) && $execution->type == 'kanban' ? $lang->bug->kanban : $lang->build->execution),
|
||||
set::label(!empty($execution) && $execution->type == 'kanban' ? $lang->bug->kanban : $lang->build->executionAB),
|
||||
set::required(true),
|
||||
picker
|
||||
(
|
||||
|
||||
@@ -582,7 +582,7 @@ $lang->bi->dividerMenu = ',metric,';
|
||||
$lang->bi->menuOrder[5] = 'screen';
|
||||
$lang->bi->menuOrder[10] = 'pivot';
|
||||
$lang->bi->menuOrder[15] = 'chart';
|
||||
$lang->bi->menuOrder[50] = 'metric';
|
||||
$lang->bi->menuOrder[20] = 'metric';
|
||||
|
||||
/* Company menu.*/
|
||||
$lang->company->menu = new stdclass();
|
||||
|
||||
@@ -35,6 +35,7 @@ $lang->dataview->add = 'Add ';
|
||||
$lang->dataview->sqlQuery = 'SQL Query';
|
||||
$lang->dataview->onlyOne = 'Only allow one query';
|
||||
$lang->dataview->empty = 'Please enter a query statement';
|
||||
$lang->dataview->emptyBuilder = 'Please configure the builder correctly';
|
||||
$lang->dataview->allowSelect = 'Only SELECT is allowed';
|
||||
$lang->dataview->noStar = "For performance, 'SELECT *' is not allowed";
|
||||
$lang->dataview->fieldSettings = "Field Settings";
|
||||
@@ -74,10 +75,11 @@ $lang->dataview->varFilter->noticeVarName = 'Filter name cannot be empty';
|
||||
$lang->dataview->varFilter->noticeRequestType = 'Request type cannot be empty';
|
||||
$lang->dataview->varFilter->noticeShowName = 'Show name cannot be empty';
|
||||
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = 'Input';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = 'Date';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = 'Datetime';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = 'Select';
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = 'Input';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = 'Date';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = 'Datetime';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = 'Select';
|
||||
$lang->dataview->varFilter->requestTypeList['multipleselect'] = 'Multiple Select';
|
||||
|
||||
$lang->dataview->varFilter->selectList['product'] = $lang->productCommon . 'List';
|
||||
$lang->dataview->varFilter->selectList['product.status'] = $lang->productCommon . 'Status';
|
||||
|
||||
@@ -35,6 +35,7 @@ $lang->dataview->add = 'Add ';
|
||||
$lang->dataview->sqlQuery = 'SQL Query';
|
||||
$lang->dataview->onlyOne = 'Only allow one query';
|
||||
$lang->dataview->empty = 'Please enter a query statement';
|
||||
$lang->dataview->emptyBuilder = 'Please configure the builder correctly';
|
||||
$lang->dataview->allowSelect = 'Only SELECT is allowed';
|
||||
$lang->dataview->noStar = "For performance, 'SELECT *' is not allowed";
|
||||
$lang->dataview->fieldSettings = "Field Settings";
|
||||
@@ -74,10 +75,11 @@ $lang->dataview->varFilter->noticeVarName = 'Filter name cannot be empty';
|
||||
$lang->dataview->varFilter->noticeRequestType = 'Request type cannot be empty';
|
||||
$lang->dataview->varFilter->noticeShowName = 'Show name cannot be empty';
|
||||
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = 'Input';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = 'Date';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = 'Datetime';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = 'Select';
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = 'Input';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = 'Date';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = 'Datetime';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = 'Select';
|
||||
$lang->dataview->varFilter->requestTypeList['multipleselect'] = 'Multiple Select';
|
||||
|
||||
$lang->dataview->varFilter->selectList['product'] = $lang->productCommon . 'List';
|
||||
$lang->dataview->varFilter->selectList['product.status'] = $lang->productCommon . 'Status';
|
||||
|
||||
@@ -35,6 +35,7 @@ $lang->dataview->add = 'Add ';
|
||||
$lang->dataview->sqlQuery = 'SQL Query';
|
||||
$lang->dataview->onlyOne = 'Only allow one query';
|
||||
$lang->dataview->empty = 'Please enter a query statement';
|
||||
$lang->dataview->emptyBuilder = 'Please configure the builder correctly';
|
||||
$lang->dataview->allowSelect = 'Only SELECT is allowed';
|
||||
$lang->dataview->noStar = "For performance, 'SELECT *' is not allowed";
|
||||
$lang->dataview->fieldSettings = "Field Settings";
|
||||
@@ -74,10 +75,11 @@ $lang->dataview->varFilter->noticeVarName = 'Filter name cannot be empty';
|
||||
$lang->dataview->varFilter->noticeRequestType = 'Request type cannot be empty';
|
||||
$lang->dataview->varFilter->noticeShowName = 'Show name cannot be empty';
|
||||
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = 'Input';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = 'Date';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = 'Datetime';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = 'Select';
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = 'Input';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = 'Date';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = 'Datetime';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = 'Select';
|
||||
$lang->dataview->varFilter->requestTypeList['multipleselect'] = 'Multiple Select';
|
||||
|
||||
$lang->dataview->varFilter->selectList['product'] = $lang->productCommon . 'List';
|
||||
$lang->dataview->varFilter->selectList['product.status'] = $lang->productCommon . 'Status';
|
||||
|
||||
@@ -35,6 +35,7 @@ $lang->dataview->add = '添加';
|
||||
$lang->dataview->sqlQuery = 'SQL语句查询';
|
||||
$lang->dataview->onlyOne = '只能输入一条SQL语句';
|
||||
$lang->dataview->empty = '请输入一条正确的SQL语句';
|
||||
$lang->dataview->emptyBuilder = '请正确配置构建器';
|
||||
$lang->dataview->allowSelect = '只允许SELECT查询';
|
||||
$lang->dataview->noStar = "考虑性能,不允许使用 'SELECT *' 查询";
|
||||
$lang->dataview->fieldSettings = "设置字段标签";
|
||||
@@ -74,10 +75,11 @@ $lang->dataview->varFilter->noticeVarName = '名称不能为空';
|
||||
$lang->dataview->varFilter->noticeRequestType = '筛选器类型不能为空';
|
||||
$lang->dataview->varFilter->noticeShowName = '显示名称不能为空';
|
||||
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = '文本框';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = '日期选择';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = '时间选择';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = '下拉选择';
|
||||
$lang->dataview->varFilter->requestTypeList['input'] = '文本框';
|
||||
$lang->dataview->varFilter->requestTypeList['date'] = '日期选择';
|
||||
$lang->dataview->varFilter->requestTypeList['datetime'] = '时间选择';
|
||||
$lang->dataview->varFilter->requestTypeList['select'] = '下拉选择';
|
||||
$lang->dataview->varFilter->requestTypeList['multipleselect'] = '多选下拉';
|
||||
|
||||
$lang->dataview->varFilter->selectList['product'] = $lang->productCommon . '列表';
|
||||
$lang->dataview->varFilter->selectList['product.status'] = '产品状态';
|
||||
|
||||
@@ -430,8 +430,8 @@ class designModel extends model
|
||||
{
|
||||
return $this->dao->select('t1.revision,t3.id AS id,t3.name AS title')
|
||||
->from(TABLE_REPOHISTORY)->alias('t1')
|
||||
->leftJoin(TABLE_RELATION)->alias('t2')->on('t2.relation="completedin" AND t2.BType="commit" AND t2.BID=t1.id')
|
||||
->leftJoin(TABLE_DESIGN)->alias('t3')->on('t2.AType="design" AND t2.AID=t3.id')
|
||||
->leftJoin(TABLE_RELATION)->alias('t2')->on("t2.relation='completedin' AND t2.BType='commit' AND t2.BID=t1.id")
|
||||
->leftJoin(TABLE_DESIGN)->alias('t3')->on("t2.AType='design' AND t2.AID=t3.id")
|
||||
->where('t1.revision')->in($revisions)
|
||||
->andWhere('t1.repo')->eq($repoID)
|
||||
->andWhere('t3.id')->ne('')
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class assignDesignTester extends tester
|
||||
{
|
||||
/**
|
||||
* Assign a design.
|
||||
* 指派设计。
|
||||
*
|
||||
* @param array $design
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function assignDesign(array $design)
|
||||
{
|
||||
$form = $this->initForm('design', 'browse', array('projectID' => 60), 'appIframe-project');
|
||||
$form->dom->btn($this->lang->design->noAssigned)->click();
|
||||
if(isset($design['assignedTo'])) $form->dom->assignedTo->picker($design['assignedTo']);
|
||||
|
||||
$form->wait(2);
|
||||
$form->dom->assignedToBtn->click();
|
||||
$form->wait(1);
|
||||
|
||||
/* 跳转到设计列表,检查指派给字段信息。 */
|
||||
$browsePage = $this->loadPage('design', 'browse');
|
||||
if($browsePage->dom->assigned->getText() != $design['assignedTo']) return $this->failed('指派给错误');
|
||||
return $this->success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class batchCreateDesignTester extends tester
|
||||
{
|
||||
/**
|
||||
* Batch create a design.
|
||||
* 批量创建设计。
|
||||
*
|
||||
* @param array $design
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function batchCreateDesign(array $design)
|
||||
{
|
||||
$form = $this->initForm('design', 'batchCreate', array('projecID' => 60, 'productID' => 0), 'appIframe-project');
|
||||
if(isset($design['type'])) $form->dom->type->picker($design['type']);
|
||||
if(isset($design['name'])) $form->dom->name_0->setValue($design['name']);
|
||||
|
||||
$form->wait(1);
|
||||
$form->dom->btn($this->lang->save)->click();
|
||||
$form->wait(1);
|
||||
|
||||
/* 跳转到设计列表,检查设计字段信息。*/
|
||||
$browsePage = $this->loadPage('design', 'browse');
|
||||
if($browsePage->dom->designName->getText() != $design['name']) return $this->failed('设计名称错误');
|
||||
if($browsePage->dom->designType->getText() != $design['type']) return $this->failed('设计类型错误');
|
||||
|
||||
return $this->success();
|
||||
}
|
||||
}
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
|
||||
title=指派设计测试
|
||||
timeout=0
|
||||
cid=2
|
||||
|
||||
- 指派设计最终测试状态 @SUCCESS
|
||||
|
||||
*/
|
||||
chdir(__DIR__);
|
||||
include '../lib/assigndesign.ui.class.php';
|
||||
|
||||
zendata('project')->loadYaml('project', false, 2)->gen(10);
|
||||
zendata('design')->loadYaml('design', false, 2)->gen(2);
|
||||
$tester = new assignDesignTester();
|
||||
$tester->login();
|
||||
|
||||
$design = array(
|
||||
array('assignedTo' => 'admin'),
|
||||
);
|
||||
|
||||
r($tester->assignDesign($design['0'])) && p('status') && e('SUCCESS'); //指派设计
|
||||
|
||||
$tester->closeBrowser();
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
|
||||
title=批量创建设计测试
|
||||
timeout=0
|
||||
cid=4
|
||||
|
||||
- 批量创建概要设计类型的设计最终测试状态 @SUCCESS
|
||||
- 批量创建详细设计类型的设计最终测试状态 @SUCCESS
|
||||
|
||||
*/
|
||||
chdir(__DIR__);
|
||||
include '../lib/batchcreatedesign.ui.class.php';
|
||||
|
||||
zendata('project')->loadYaml('project', false, 2)->gen(10);
|
||||
zendata('design')->loadYaml('design', false, 2)->gen(0);
|
||||
$tester = new batchCreateDesignTester();
|
||||
$tester->login();
|
||||
|
||||
$design = array(
|
||||
array('type' => '概要设计', 'name' => '概要设计01'),
|
||||
array('type' => '详细设计', 'name' => '详细设计01'),
|
||||
);
|
||||
|
||||
r($tester->batchCreateDesign($design['0'])) && p('status') && e('SUCCESS'); //批量创建概要设计类型的设计
|
||||
r($tester->batchCreateDesign($design['1'])) && p('status') && e('SUCCESS'); //批量创建详细设计类型的设计
|
||||
|
||||
$tester->closeBrowser();
|
||||
@@ -19,6 +19,7 @@ cid=2
|
||||
chdir(__DIR__);
|
||||
include '../lib/editdesign.ui.class.php';
|
||||
|
||||
zendata('project')->loadYaml('project', false, 2)->gen(10);
|
||||
zendata('design')->loadYaml('design', false, 2)->gen(2);
|
||||
zendata('designspec')->loadYaml('designspec', false, 2)->gen(2);
|
||||
$tester = new editDesignTester();
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
class batchCreatePage extends page
|
||||
{
|
||||
public function __construct($webdriver)
|
||||
{
|
||||
parent::__construct($webdriver);
|
||||
$xpath = array(
|
||||
'type' => "//*[@id='type_0']/div/input",
|
||||
);
|
||||
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,17 @@ class browsePage extends page
|
||||
|
||||
$xpath = array(
|
||||
'designName' => "//*[@id='table-design-browse']/div[2]/div[1]/div/div[2]/div/a",
|
||||
'linkedProduct' => "//*[@id='table-design-browse']/div[2]/div[2]/div/div[1]/div",
|
||||
'linkedProduct' => "//*[@id='mainContent']/div[2]/div[2]/div/div[2]/table/tbody/tr[2]/td",
|
||||
'designType' => "//*[@id='table-design-browse']/div[2]/div[2]/div/div[2]/div/span",
|
||||
'assignedTo' => "//*[@name='assignedTo']",
|
||||
'assignedToBtn' => "//*[@class='form load-indicator form-ajax no-morph form-horz']/div[3]/div/button/span",
|
||||
'assigned' => "//*[@id='table-design-browse']/div[2]/div[2]/div/div[3]/div/a/span",
|
||||
'allMenu' => "//*[@id='mainNavbar']/div/menu/li[1]/a/span",
|
||||
'hldsMenu' => "//*[@id='mainNavbar']/div/menu/li[2]/a/span",
|
||||
'ddsMenu' => "//*[@id='mainNavbar']/div/menu/li[3]/a/span",
|
||||
'dbdsMenu' => "//*[@id='mainNavbar']/div/menu/li[4]/a/span",
|
||||
'adsMenu' => "//*[@id='mainNavbar']/div/menu/li[5]/a/span",
|
||||
'designNum' => "//*[@id='table-design-browse']/div[3]/nav/div[1]",
|
||||
);
|
||||
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class designZen extends control
|
||||
|
||||
/* Show custom design types. */
|
||||
$this->lang->waterfall->menu->design['subMenu'] = new stdclass();
|
||||
$this->lang->waterfall->menu->design['subMenu']->all = array('link' => "{$this->lang->all}|design|browse|projectID=%s&productID={$productID}&browseType=all", 'exclude' => $type == 'all' ? '' : 'design');
|
||||
$this->lang->waterfall->menu->design['subMenu']->all = array('link' => "{$this->lang->all}|design|browse|projectID=%s&productID={$productID}&browseType=all", 'exclude' => $type == 'all' ? '' : 'design', 'alias' => $type == 'all' ? $this->app->rawMethod : '');
|
||||
$count = 1;
|
||||
foreach(array_filter($this->lang->design->{$typeList}) as $key => $value)
|
||||
{
|
||||
|
||||
@@ -1004,10 +1004,13 @@ class doc extends control
|
||||
{
|
||||
list($myObjects, $normalObjects, $closedObjects) = $this->doc->getOrderedObjects($objectType, 'nomerge', $objectID);
|
||||
|
||||
$libData = $this->doc->setMenuByType($objectType, $objectID, 0);
|
||||
|
||||
$this->view->objectType = $objectType;
|
||||
$this->view->objectID = $objectID;
|
||||
$this->view->libID = !empty($libData[1]) ? $libData[1] : 0;
|
||||
$this->view->module = $module;
|
||||
$this->view->method = $method =='view' ? $objectType.'space' : $method;
|
||||
$this->view->method = $method == 'view' ? $objectType.'space' : $method;
|
||||
$this->view->normalObjects = $myObjects + $normalObjects;
|
||||
$this->view->closedObjects = $closedObjects;
|
||||
$this->view->objectsPinYin = common::convert2Pinyin($myObjects + $normalObjects + $closedObjects);
|
||||
|
||||
@@ -45,12 +45,91 @@ class createDocTester extends tester
|
||||
$form->wait(1);
|
||||
$form->dom->releaseBtn->click();
|
||||
|
||||
$this->openUrl('doc', 'mySpace', array('objectType' => 'mine'));
|
||||
$form = $this->loadPage('doc', 'mySpace', array('objectType' => 'mine'));
|
||||
$this->openUrl('doc', 'mySpace', array('objectType' => 'createdby'));
|
||||
$form = $this->loadPage('doc', 'mySpace', array('objectType' => 'createdby'));
|
||||
$form->dom->search(array("文档标题,=,{$docName->dcName}"));
|
||||
$form->wait(1);
|
||||
|
||||
if($form->dom->fstDocName->getText() != $docName->dcName) return $this->failed('文档创建失败');
|
||||
return $this->success('文档创建成功');
|
||||
}
|
||||
|
||||
/*
|
||||
* 创建产品文档。
|
||||
* Create a product doc.
|
||||
*
|
||||
* @param string $productName
|
||||
* @param string $docName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createProductDoc($productName, $docName)
|
||||
{
|
||||
/*创建两个产品*/
|
||||
$form = $this->initForm('product', 'create');
|
||||
$form->dom->name->setValue($productName->fstProduct);
|
||||
$form->dom->btn($this->lang->save)->click();
|
||||
$form->wait(1);
|
||||
$form = $this->initForm('product', 'create');
|
||||
$form->dom->name->setValue($productName->secProduct);
|
||||
$form->dom->btn($this->lang->save)->click();
|
||||
|
||||
/*创建产品下的文档*/
|
||||
$this->openUrl('doc', 'productSpace');
|
||||
$form = $this->loadPage('doc', 'productSpace');
|
||||
$form->dom->createDocBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->showTitle->setValue($docName->dcName);
|
||||
$form->dom->saveBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->product->picker($productName->secProduct);
|
||||
$form->dom->releaseBtn->click();
|
||||
|
||||
if($form->dom->leftListHeader->getText() != $productName->secProduct) return $this->failed('切换产品创建文档失败');
|
||||
return $this->success('切换产品创建文档成功');
|
||||
}
|
||||
|
||||
/*
|
||||
* 创建项目文档。
|
||||
* Create a project doc.
|
||||
*
|
||||
* @param string $projectName
|
||||
* @param string $executionName
|
||||
* @param string $plan
|
||||
* @param string $docName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createProjectDoc($projectName, $executionName, $plan, $docName)
|
||||
{
|
||||
/*创建项目*/
|
||||
$form = $this->initForm('project', 'create', array('modal' => 'scrum'));
|
||||
$form->dom->hasProduct0->click();
|
||||
$form->dom->name->setValue($projectName->fstProject);
|
||||
$form->dom->begin->datePicker($plan->begin);
|
||||
$form->dom->longTime->click();
|
||||
$form->dom->btn($this->lang->save)->click();
|
||||
$form->wait(2);
|
||||
|
||||
/*创建项目下的执行*/
|
||||
$form = $this->initForm('execution', 'create');
|
||||
$form->dom->project->picker($projectName->fstProject);
|
||||
$form->dom->name->setValue($executionName->fstExecution);
|
||||
$form->dom->begin->datePicker($plan->begin);
|
||||
$form->dom->end->datePicker($plan->end);
|
||||
$form->dom->btn($this->lang->save)->click();
|
||||
|
||||
/*创建项目空间下的文档*/
|
||||
$this->openUrl('doc', 'projectSpace');
|
||||
$form = $this->loadPage('doc', 'projectSpace');
|
||||
$form->dom->createDocBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->showTitle->setValue($docName->dcName);
|
||||
$form->dom->saveBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->project->picker($projectName->fstProject);
|
||||
$form->dom->execution->picker($executionName->fstExecution);
|
||||
$form->wait(1);
|
||||
$form->dom->releaseBtn->click();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ class createDocTester extends tester
|
||||
* Edit a doc.
|
||||
*
|
||||
* @param string $editDocName
|
||||
* @param string $docName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -31,8 +32,8 @@ class createDocTester extends tester
|
||||
$form->dom->saveDraftBtn->click();
|
||||
$form->wait(1);
|
||||
|
||||
$this->openUrl('doc', 'mySpace', array('objectType' => 'mine'));
|
||||
$form = $this->loadPage('doc', 'mySpace', array('objectType' => 'mine'));
|
||||
$this->openUrl('doc', 'mySpace', array('objectType' => 'editedby'));
|
||||
$form = $this->loadPage('doc', 'mySpace', array('objectType' => 'editedby'));
|
||||
$form->dom->search(array("文档标题,=,{$editDocName->editName}"));
|
||||
$form->wait(1);
|
||||
|
||||
@@ -44,7 +45,7 @@ class createDocTester extends tester
|
||||
* 移动文档。
|
||||
* Move a doc.
|
||||
*
|
||||
* @param string $editDocName
|
||||
* @param string $libName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -69,14 +70,13 @@ class createDocTester extends tester
|
||||
$form->wait(1);
|
||||
|
||||
if($form->dom->leftListHeader->getText() != $llibName->myDocLib) return $this->failed('文档移动失败');
|
||||
return $this->success('文档移动失败');
|
||||
return $this->success('文档移动成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文档
|
||||
* Delete a doc.
|
||||
*
|
||||
* @param string $editDocName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,8 @@ class createDocTester extends tester
|
||||
* 编辑我的文档库。
|
||||
* Edit a doclib.
|
||||
*
|
||||
* @param string $docLibName
|
||||
* @param string $libName
|
||||
* @param string $editLibName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -37,7 +38,7 @@ class createDocTester extends tester
|
||||
* 删除一个文档库。
|
||||
* Delete a docLib.
|
||||
*
|
||||
* @param string $docLibName
|
||||
* @param string $editLibName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class createDocTester extends tester
|
||||
{
|
||||
/**
|
||||
* 我收藏的文档。
|
||||
* Check my favorite docs.
|
||||
*
|
||||
* @param string $docName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function myFavorites($docName)
|
||||
{
|
||||
/*进入我的空间创建并收藏一个文档*/
|
||||
$this->openUrl('doc', 'mySpace', array('type' => 'mine'));
|
||||
$form = $this->loadPage('doc', 'mySpace', array('type' => 'mine'));
|
||||
$form->dom->createDocBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->showTitle->setValue($docName->dcName);
|
||||
$form->dom->saveBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->releaseBtn->click();
|
||||
|
||||
/*收藏文档*/
|
||||
$this->openUrl('doc', 'mySpace', array('type' => 'mine'));
|
||||
$form = $this->loadPage('doc', 'mySpace', array('type' => 'mine'));
|
||||
$form->dom->fstCollectBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->myFavorites->click();
|
||||
|
||||
if($form->dom->checkFstDoc->getText() != $docName->dcName) return $this->failed('收藏文档失败');
|
||||
return $this->success('收藏文档成功');
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,26 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
|
||||
title=创建文档测试
|
||||
timeout=0
|
||||
cid=0
|
||||
|
||||
- 创建我的空间下草稿文档,创建成功
|
||||
- 测试结果 @创建草稿文档成功
|
||||
- 最终测试状态 @SUCCESS
|
||||
- 创建我的空间下文档,创建成功
|
||||
- 测试结果 @创建文档成功
|
||||
- 最终测试状态 @SUCCESS
|
||||
- 创建产品空间下的文档,创建成功
|
||||
- 测试结果 @创建产品空间下的文档成功
|
||||
- 最终测试结果 @SUCCESS
|
||||
- 创建项目空间下的文档,创建成功
|
||||
- 测试结果 @创建项目空间下的文档成功
|
||||
- 最终测试结果 @SUCCESS
|
||||
|
||||
*/
|
||||
chdir(__DIR__);
|
||||
include '../lib/createdoc.ui.class.php';
|
||||
|
||||
@@ -9,10 +29,26 @@ $tester->login();
|
||||
|
||||
$draftName = new stdClass();
|
||||
$draftName->nullName = '';
|
||||
$draftName->dftName = '我的草稿文档1';
|
||||
$draftName->dftName = '草稿文档1';
|
||||
|
||||
$docName = new stdClass();
|
||||
$docName->dcName = '我的文档1';
|
||||
$docName->dcName = '文档1';
|
||||
|
||||
r($tester->createDraft($draftName)) && p('message,status') && e('创建草稿表单页提示信息正确,SUCCESS');
|
||||
r($tester->createDoc($docName)) && p('message,status') && e('创建文档表单页提示信息正确,SUCCESS');
|
||||
$productName = new stdClass();
|
||||
$productName->fstProduct = '产品1';
|
||||
$productName->secProduct = '产品2';
|
||||
|
||||
$projectName = new stdClass();
|
||||
$projectName->fstProject = '项目1';
|
||||
|
||||
$executionName = new stdClass();
|
||||
$executionName->fstExecution = '执行1';
|
||||
|
||||
$plan = new stdClass();
|
||||
$plan->begin = '2024-09-01';
|
||||
$plan->end = '2024-11-01';
|
||||
|
||||
r($tester->createDraft($draftName)) && p('message,status') && e('创建草稿成功,SUCCESS'); //创建草稿文档成功
|
||||
r($tester->createDoc($docName)) && p('message,status') && e('创建文档成功,SUCCESS'); //创建文档成功
|
||||
r($tester->createProductDoc($productName, $docName)) && p('message,status') && e('创建产品文档成功,SUCCESS'); //创建产品空间下的文档成功
|
||||
r($tester->createProjectDoc($projectName, $executionName, $plan, $docName)) && p('message,status') && e('创建项目文档成功,SUCCESS'); //创建项目空间下的文档成功
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
|
||||
title=收藏文档测试
|
||||
timeout=0
|
||||
cid=0
|
||||
|
||||
- 收藏文档成功
|
||||
- 测试结果 @收藏文档成功
|
||||
- 最终测试状态 @SUCCESS
|
||||
|
||||
*/
|
||||
chdir(__DIR__);
|
||||
include '../lib/lefttree.ui.class.php';
|
||||
|
||||
$tester = new createDocTester();
|
||||
$tester->login();
|
||||
|
||||
$docName = new stdClass();
|
||||
$docName->dcName = '我的文档A';
|
||||
|
||||
r($tester->myFavorites($docName)) && p('message,status') && e('收藏文档成功,SUCCESS'); //收藏文档成功
|
||||
@@ -8,9 +8,9 @@ class myspacePage extends page
|
||||
'createLibBtn' => '/html/body/div[1]/div/div[1]/div[2]/a',
|
||||
'leftListHeader' => '/html/body/div[1]/div/div[2]/div[1]/header/span',
|
||||
'libName' => '//*[@id="zin_doc_createlib_form"]/div[1]/div[1]/input',
|
||||
'fstDocLib' => '/html/body/div[1]/div/div[2]/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/div/div/div/a[1]',
|
||||
'createDocBtn' => '/html/body/div/div/div[1]/div[2]/div',
|
||||
'fstDocName' => '/html/body/div/div/div[2]/div[2]/div/div/div[2]/div[1]/div/div[2]/div/div/div/a[1]',
|
||||
'fstDocName' => '/html/body/div[1]/div/div[2]/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/div/a',
|
||||
'fstDocLabel' => '/html/body/div[1]/div/div[2]/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/div/div[2]/span',
|
||||
'saveDraftBtn' => '/html/body/div[1]/div/div/div[2]/form/div[1]/div[1]/div/div/button',
|
||||
'alertTitle' => '//*[@class="modal modal-async load-indicator modal-alert modal-trans show in"]/div[1]/div[1]/div[2]/div[1]',
|
||||
'saveBtn' => '/html/body/div[1]/div/div/div[2]/form/div[1]/div[1]/div/div/a',
|
||||
@@ -19,12 +19,17 @@ class myspacePage extends page
|
||||
'fstMoreBtn' => '//*[@class="tree-item item is-nested is-nested-show"]/menu[1]/li[2]/div[1]/nav[1]/button[1]',
|
||||
'fstDocLib' => '/html/body/div[1]/div/div[2]/div[1]/div[1]/div/main/menu/li[1]/menu/li[2]/div/div/a',
|
||||
'editLib' => '//*[@class="popover show fade dropdown in"]/menu[1]/menu[1]/li[3]/a[1]',
|
||||
'fstDocLib' => '/html/body/div[1]/div/div[2]/div[1]/div[1]/div/main/menu/li[1]/menu/li[2]/div/div/a',
|
||||
'deleteAccept' => '/html/body/div[3]/div/div/div[3]/nav/button[1]',
|
||||
'fstMoveBtn' => '/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[3]/div/div/div/nav/a[2]/i',
|
||||
'fstDeleteBtn' => '/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[3]/div/div/div/nav/a[3]/i',
|
||||
'formText' => '/html/body/div/div/div[2]/div[2]/div/div/div/div/div',
|
||||
'saveMoveBtn' => '//*[@class="m-doc-myspace"]/div[2]/div[1]/div[1]/div[3]/div[1]/div[1]/form[1]/div[6]/div[1]/button[1]',
|
||||
'checkFstDoc' => '/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[1]/div/div[2]/div/a',
|
||||
'fstCollectBtn' => '/html/body/div[1]/div/div[2]/div[2]/div/div/div[2]/div[1]/div/div[2]/div/div[2]/a/img',
|
||||
'myFavorites' => '/html/body/div[1]/div/div[2]/div[1]/div[1]/div/main/menu/li[3]/div/div/a',
|
||||
'createdBy' => '/html/body/div[1]/div/div[2]/div[1]/div[1]/div/main/menu/li[4]/div/div/a',
|
||||
'myLibMoreBtn' => '/html/body/div[1]/div/div[2]/div[1]/div[1]/div/main/menu/li[1]/menu/li[1]/div/nav/button/i',
|
||||
'addDir' => '/html/body/div[2]/menu/menu/li[1]/a/div/div',
|
||||
);
|
||||
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
class productspacePage extends page
|
||||
{
|
||||
public function __construct($webdriver)
|
||||
{
|
||||
parent::__construct($webdriver);
|
||||
$xpath = array(
|
||||
'createDocBtn' => '/html/body/div[1]/div/div[1]/div[2]/div/a',
|
||||
'saveBtn' => '/html/body/div[1]/div/div/div[2]/form/div[1]/div[1]/div/div/a',
|
||||
'releaseBtn' => '/html/body/div[1]/div/div/div[2]/form/div[2]/div/div/div[3]/div[10]/div/button',
|
||||
'leftListHeader' => '/html/body/div[1]/div/div/div[1]/div[1]/div[1]/button/span',
|
||||
);
|
||||
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class projectspacePage extends page
|
||||
{
|
||||
public function __construct($webdriver)
|
||||
{
|
||||
parent::__construct($webdriver);
|
||||
$xpath = array(
|
||||
'createDocBtn' => '/html/body/div[1]/div/div[1]/div[2]/div/a',
|
||||
'saveBtn' => '/html/body/div[1]/div/div/div[2]/form/div[1]/div[1]/div/div/a',
|
||||
'releaseBtn' => '/html/body/div[1]/div/div/div[2]/form/div[2]/div/div/div[3]/div[10]/div/button',
|
||||
);
|
||||
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
|
||||
}
|
||||
}
|
||||
@@ -53,8 +53,10 @@ $tabs[] = array('name' => 'closed', 'text' => $lang->doc->closed);
|
||||
* 定义最终的 JSON 数据。
|
||||
* Define the final json data.
|
||||
*/
|
||||
$params = $method == 'showfiles' ||$objectType == 'custom' ? "type=$objectType&objectID=%s" : "objectID=%s";
|
||||
$link = $this->createLink($module, $method, $params);
|
||||
$params = "objectID=%s";
|
||||
if($method == 'showfiles' || $objectType == 'custom') $params = "type=$objectType&objectID=%s";
|
||||
if($method == 'create') $params = "objectType=$objectType&objectID=%s&libID=$libID&moduleID=0";
|
||||
$link = $this->createLink($module, $method, $params);
|
||||
|
||||
$json = array();
|
||||
$json['data'] = $data;
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class bugTester extends tester
|
||||
{
|
||||
/**
|
||||
* 检查Tab标签下的数据。
|
||||
* Check the data of the Tab tag.
|
||||
*
|
||||
* @param string $tab allTab|unclosedTab|draftTab|reviewingTab
|
||||
* @param string $expectNum
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function checkTab($tab, $expectNum)
|
||||
{
|
||||
$form = $this->initForm('execution', 'bug', array('execution' => '2'), 'appIframe-execution');
|
||||
$form->dom->$tab->click();
|
||||
$form->wait(1);
|
||||
if($form->dom->num->getText() == $expectNum) return $this->success($tab . '下显示条数正确');
|
||||
return $this->failed($tab . '下显示条数不正确');
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个指派bug。
|
||||
* Assign bug.
|
||||
*
|
||||
* @param string $user
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function assignTo($user)
|
||||
{
|
||||
$form = $this->initForm('execution', 'bug', array('execution' => '2'), 'appIframe-execution');
|
||||
$form->dom->firstAssignedTo->click();
|
||||
$form->dom->assignedTo->picker($user);
|
||||
$form->dom->submitBtn->click();
|
||||
$form->wait(1);
|
||||
|
||||
if($form->dom->firstAssignedTo->getText() == $user) return $this->success('指派bug成功');
|
||||
return $this->failed('指派bug失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量指派bug。
|
||||
* Batch assign bug.
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function batchAssignTo()
|
||||
{
|
||||
$form = $this->initForm('execution', 'bug', array('execution' => '2'), 'appIframe-execution');
|
||||
$form->dom->firstCheckbox->click();
|
||||
$form->dom->batchAssignBtn->click();
|
||||
$form->wait(1);
|
||||
$form->dom->assignToAdmin->click();
|
||||
$form->wait(1);
|
||||
|
||||
if($form->dom->firstAssignedTo->getText() == 'admin') return $this->success('批量指派bug成功');
|
||||
return $this->failed('批量指派bug失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换产品查看buig。
|
||||
* Switch product to view bug.
|
||||
*
|
||||
* @param string $product firstProduct|secondProduct|thirdProduct
|
||||
* @param string $expectNum
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function switchProduct($product, $expectNum)
|
||||
{
|
||||
$form = $this->initForm('execution', 'bug', array('execution' => '2'), 'appIframe-execution');
|
||||
$form->dom->productNav->click();
|
||||
$form->dom->$product->click();
|
||||
$form->wait(1);
|
||||
|
||||
if($form->dom->num->getText() == $expectNum) return $this->success('切换产品查看bug成功');
|
||||
return $this->failed('切换产品查看bug失败');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . '/test/lib/ui.php';
|
||||
class importBugTester extends tester
|
||||
{
|
||||
/**
|
||||
* 导入Bug。
|
||||
* Import bug.
|
||||
*
|
||||
* @param string $executionId
|
||||
* @param string $expectNum
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function importBug($executionId, $expectNum)
|
||||
{
|
||||
$form = $this->initForm('execution', 'task', array('execution' => $executionId), 'appIframe-execution');
|
||||
$form->dom->btn($this->lang->import)->click();
|
||||
$form->dom->btn($this->lang->execution->importBug)->click();
|
||||
|
||||
$importForm = $this->loadPage('execution', 'importBug');
|
||||
$importForm->wait(1);
|
||||
if($importForm->dom->num === false)
|
||||
{
|
||||
if ($expectNum == '0') return $this->success('可导入的Bug数目正确');
|
||||
return $this->failed('可导入的Bug数目不正确');
|
||||
}
|
||||
if($importForm->dom->num->getText() != $expectNum) return $this->failed('可导入的Bug数目不正确');
|
||||
$id = $importForm->dom->firstId->getText();
|
||||
$importForm->dom->firstCheckbox->click();
|
||||
$importForm->dom->saveBtn->click();
|
||||
$importForm->wait(1);
|
||||
$importForm->dom->btn($this->lang->goback)->click();
|
||||
|
||||
$form->dom->search(array("{$this->lang->task->fromBugID},=,{$id}"));
|
||||
if($form->dom->firstName === false) return $this->failed('导入Bug失败');
|
||||
return $this->success('导入Bug成功');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user