* Merge 18.x

This commit is contained in:
zenggang
2023-08-28 10:27:22 +00:00
324 changed files with 17288 additions and 4829 deletions
+1
View File
@@ -33,3 +33,4 @@ CodeSniffer.conf
test/runtime/*
test/www
!/**/.gitkeep
build/*.gz
Vendored
+672 -454
View File
File diff suppressed because it is too large Load Diff
+16 -8
View File
@@ -1,6 +1,6 @@
VERSION = $(shell head -n 1 VERSION)
XUANVERSION = $(shell jq -r .pkg.xuanxuan.gitVersion < dependency.json)
XVERSION = $(shell jq -r .pkg.xuanxuan.ersion < dependency.json)
XUANVERSION = $(shell jq -r .pkg.xuanxuan.gitVersion < ci.json)
XVERSION = $(shell jq -r .pkg.xuanxuan.version < ci.json)
XHPROF_VERSION = 2.3.9
XUANPATH := $(XUANXUAN_SRC_PATH)
@@ -8,6 +8,9 @@ BUILD_PATH := $(if $(ZENTAO_BUILD_PATH),$(ZENTAO_BUILD_PATH),$(shell pwd))
RELEASE_PATH := $(if $(ZENTAO_RELEASE_PATH),$(ZENTAO_RELEASE_PATH),$(shell pwd))
XUAN_WEB_PATH := $(ZENTAO_BUILD_PATH)/web
DOWNGRADE_ENABLED := $(or $(DOWNGRADE_ENABLED),$(shell jq -r .downgrade.enabled < ci.json))
DOWNGRADE_VERSIONS := $(or $(DOWNGRADE_VERSIONS),$(shell jq -r .downgrade.versions < ci.json))
all:
make clean
make ci
@@ -272,12 +275,17 @@ ciCommon:
make cleanAssets
zip -rq -9 ZenTaoPMS.$(VERSION).zip zentaopms
# en
cd zentaopms/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
cd zentaopms/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
cd zentaopms/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
mv zentaopms zentaoalm
zip -r -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
rm -fr zentaoalm
cp -a zentaopms zentaoalm
cd zentaoalm/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
cd zentaoalm/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
cd zentaoalm/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
zip -rq -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
# downgrade
@test "$(DOWNGRADE_ENABLED)" != "true" && echo "skip downgrade" || ./misc/downgrade.sh -p "$(DOWNGRADE_VERSIONS)" -i -r zentaopms -o "$(RELEASE_PATH)" framework/ lib/ module/*
rm -fr zentaopms zentaoalm
# move pms zip to build and release path.
rm -f $(BUILD_PATH)/ZenTao*.zip $(RELEASE_PATH)/ZenTaoPMS.$(VERSION).zip $(RELEASE_PATH)/ZenTaoALM.$(VERSION).int.zip
cp ZenTaoPMS.$(VERSION).zip $(BUILD_PATH)
+1 -1
View File
@@ -1 +1 @@
18.5
18.6
+1 -1
View File
@@ -54,7 +54,7 @@ class ticketsEntry extends entry
*/
public function post()
{
$fields = 'module,product,type,openedBuild,assignedTo,deadline,title,desc,status,notify,uid';
$fields = 'module,product,type,openedBuild,assignedTo,deadline,title,desc,status,notify,uid,pri';
$this->batchSetPost($fields);
$control = $this->loadController('ticket', 'create');
+29
View File
@@ -0,0 +1,29 @@
{
"pkg": {
"xuanxuan": {
"gitVersion": "e08cd0387cbfcf4cbc28b3b3e829683066ee3bc7",
"version": "7.2.1"
},
"zentaoext": {
"gitVersion": "18.x",
"gitRepo": "https://git.zcorp.cc/easycorp/zentaoext.git"
},
"zdoo": {
"gitVersion": "master"
},
"zdooext": {
"gitVersion": "master"
}
},
"downgrade": {
"enabled": true,
"versions": "7.2,7.1,7.0,5.4"
},
"upload": {
"bucket": "download"
},
"notice": {
"users": "qishiyao,hufangzhou",
"groups": "84be4c6e-02e3-4fdc-b081-318c0c1eca02,31a0008b-6e3e-4b7f-9b7b-396a46b1f8f4"
}
}
+2 -1
View File
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
$config->version = '18.6'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '18.7'; // 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.
@@ -161,6 +161,7 @@ $config->wideSize = 1400;
$config->timeout = 30000;
$config->duplicateTime = 30;
$config->maxCount = 500;
$config->batchMaxCount = 20;
$config->moreLinks = array();
/* 渠成平台设置。CNE Api settings. */
+6 -4
View File
@@ -244,6 +244,7 @@ $config->openMethods[] = 'search.buildzinform';
$config->openMethods[] = 'search.buildzinquery';
$config->openMethods[] = 'search.savezinquery';
$config->openMethods[] = 'space.createapplication';
$config->openMethods[] = 'ai.adminindex';
$config->openModules = array();
$config->openModules[] = 'install';
@@ -320,6 +321,7 @@ define('TABLE_API_LIB_RELEASE', '`' . $config->db->prefix . 'api_lib_release`');
define('TABLE_MODULE', '`' . $config->db->prefix . 'module`');
define('TABLE_ACTION', '`' . $config->db->prefix . 'action`');
define('TABLE_ACTIONRECENT', '`' . $config->db->prefix . 'actionrecent`');
define('TABLE_FILE', '`' . $config->db->prefix . 'file`');
define('TABLE_HOLIDAY', '`' . $config->db->prefix . 'holiday`');
define('TABLE_HISTORY', '`' . $config->db->prefix . 'history`');
@@ -376,9 +378,6 @@ define('TABLE_DATASET', '`' . $config->db->prefix . 'dataset`');
define('TABLE_DATAVIEW', '`' . $config->db->prefix . 'dataview`');
define('TABLE_DIMENSION', '`' . $config->db->prefix . 'dimension`');
define('TABLE_SCENE', '`' . $config->db->prefix . 'scene`');
define('VIEW_SCENECASE', '`ztv_scenecase`');
define('CHANGEVALUE', 100000000);
define('TABLE_PRIV', '`' . $config->db->prefix . 'priv`');
define('TABLE_PRIVLANG', '`' . $config->db->prefix . 'privlang`');
@@ -389,6 +388,8 @@ define('TABLE_SPACE', '`' . $config->db->prefix . 'space`');
define('TABLE_INSTANCE', '`' . $config->db->prefix . 'instance`');
define('TABLE_SOLUTION', '`' . $config->db->prefix . 'solution`');
define('TABLE_ARTIFACTREPO', '`' . $config->db->prefix . 'artifactrepo`');
define('TABLE_PROMPT', '`' . $config->db->prefix . 'prompt`');
define('TABLE_PROMPTROLE', '`' . $config->db->prefix . 'promptrole`');
$config->objectTables['product'] = TABLE_PRODUCT;
$config->objectTables['productplan'] = TABLE_PRODUCTPLAN;
@@ -455,8 +456,9 @@ $config->objectTables['instance'] = TABLE_INSTANCE;
$config->objectTables['space'] = TABLE_SPACE;
$config->objectTables['solution'] = TABLE_SOLUTION;
$config->objectTables['artifactrepo'] = TABLE_ARTIFACTREPO;
$config->objectTables['prompt'] = TABLE_PROMPT;
$config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme', 'visions');
$config->newFeatures = array('aiPrompts', 'promptDesign', 'promptExec');
$config->disabledFeatures = '';
$config->closedFeatures = '';
File diff suppressed because it is too large Load Diff
+97
View File
File diff suppressed because one or more lines are too long
+247
View File
@@ -148,3 +148,250 @@ REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `d
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2122, 'priv', 'fr', 'ops-os', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2122, 'priv', 'zh-cn', 'ops-os', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2122, 'priv', 'zh-tw', 'ops-os', '', '');
CREATE TABLE IF NOT EXISTS `zt_prompt` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`desc` text DEFAULT NULL,
`model` mediumint(8) unsigned DEFAULT NULL,
`module` varchar(30) DEFAULT NULL,
`source` text DEFAULT NULL,
`targetForm` varchar(30) DEFAULT NULL,
`purpose` text DEFAULT NULL,
`elaboration` text DEFAULT NULL,
`role` text DEFAULT NULL,
`characterization` text DEFAULT NULL,
`status` enum('draft','active','replaced') NOT NULL DEFAULT 'draft',
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) DEFAULT NULL,
`editedDate` datetime DEFAULT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `zt_promptrole` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`desc` text DEFAULT NULL,
`model` mediumint(8) unsigned DEFAULT NULL,
`role` text DEFAULT NULL,
`characterization` text DEFAULT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
REPLACE INTO
`zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`)
VALUES
(2117, 'ai', 'models', 653, ',open,biz,max,', ',rnd,', '1', 5),
(2118, 'ai', 'editModel', 653, ',open,biz,max,', ',rnd,', '1', 10),
(2119, 'ai', 'testConnection', 653, ',open,biz,max,', ',rnd,', '1', 15),
(2120, 'ai', 'createPrompt', 655, ',biz,max,', ',rnd,', '1', 20),
(2121, 'ai', 'promptEdit', 655, ',biz,max,', ',rnd,', '1', 25),
(2122, 'ai', 'promptDelete', 657, ',biz,max,', ',rnd,', '1', 30),
(2123, 'ai', 'promptAssignRole', 655, ',biz,max,', ',rnd,', '1', 35),
(2124, 'ai', 'promptSelectDataSource', 655, ',biz,max,', ',rnd,', '1', 40),
(2125, 'ai', 'promptSetPurpose', 655, ',biz,max,', ',rnd,', '1', 45),
(2126, 'ai', 'promptSetTargetForm', 655, ',biz,max,', ',rnd,', '1', 50),
(2127, 'ai', 'promptFinalize', 655, ',biz,max,', ',rnd,', '1', 55),
(2128, 'ai', 'promptAudit', 655, ',biz,max,', ',rnd,', '1', 60),
(2129, 'ai', 'promptPublish', 656, ',open,biz,max,', ',rnd,', '1', 65),
(2130, 'ai', 'promptUnpublish', 656, ',open,biz,max,', ',rnd,', '1', 70),
(2131, 'ai', 'prompts', 654, ',open,biz,max,', ',rnd,', '1', 75),
(2132, 'ai', 'promptView', 654, ',open,biz,max,', ',rnd,', '1', 80),
(2133, 'ai', 'promptExecute', 652, ',open,biz,max,', ',rnd,', '1', 85),
(2134, 'ai', 'roleTemplates', 655, ',biz,max,', ',rnd,', '1', 90),
(2135, 'ai', 'promptExecutionReset', 652, ',open,biz,max,', ',rnd,', '1', 95);
REPLACE INTO
`zt_privmanager` (`id`, `parent`, `code`, `type`, `edition`, `vision`, `order`)
VALUES
(651, 457, 'ai', 'module', ',open,biz,max,', ',rnd,', 2020),
(652, 651, '', 'package', ',open,biz,max,', ',rnd,', 2040),
(653, 651, '', 'package', ',open,biz,max,', ',rnd,', 2060),
(654, 651, '', 'package', ',open,biz,max,', ',rnd,', 2080),
(655, 651, '', 'package', ',biz,max,', ',rnd,', 2100),
(656, 651, '', 'package', ',open,biz,max,', ',rnd,', 2120),
(657, 651, '', 'package', ',biz,max,', ',rnd,', 2140);
REPLACE INTO
`zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`)
VALUES
(651, 'manager', 'zh-cn', '', 'AI', ''),
(652, 'manager', 'zh-cn', '', '执行提词', ''),
(653, 'manager', 'zh-cn', '', '语言模型管理', ''),
(654, 'manager', 'zh-cn', '', '浏览提词', ''),
(655, 'manager', 'zh-cn', '', '维护和设计提词', ''),
(656, 'manager', 'zh-cn', '', '提词上下架', ''),
(657, 'manager', 'zh-cn', '', '删除提词', ''),
(651, 'manager', 'zh-tw', '', 'AI', ''),
(652, 'manager', 'zh-tw', '', '執行提詞', ''),
(653, 'manager', 'zh-tw', '', '語言模型管理', ''),
(654, 'manager', 'zh-tw', '', '瀏覽提詞', ''),
(655, 'manager', 'zh-tw', '', '維護和設計提詞', ''),
(656, 'manager', 'zh-tw', '', '提詞上下架', ''),
(657, 'manager', 'zh-tw', '', '刪除提詞', ''),
(651, 'manager', 'en', '', 'AI', ''),
(652, 'manager', 'en', '', 'Execute Prompts', ''),
(653, 'manager', 'en', '', 'Manage Models', ''),
(654, 'manager', 'en', '', 'Browse Prompts', ''),
(655, 'manager', 'en', '', 'Manage and Design Prompts', ''),
(656, 'manager', 'en', '', 'Publish and Unpublish Prompts', ''),
(657, 'manager', 'en', '', 'Delete Prompts', ''),
(651, 'manager', 'de', '', 'AI', ''),
(652, 'manager', 'de', '', 'Execute Prompts', ''),
(653, 'manager', 'de', '', 'Manage Models', ''),
(654, 'manager', 'de', '', 'Browse Prompts', ''),
(655, 'manager', 'de', '', 'Manage and Design Prompts', ''),
(656, 'manager', 'de', '', 'Publish and Unpublish Prompts', ''),
(657, 'manager', 'de', '', 'Delete Prompts', ''),
(651, 'manager', 'fr', '', 'AI', ''),
(652, 'manager', 'fr', '', 'Execute Prompts', ''),
(653, 'manager', 'fr', '', 'Manage Models', ''),
(654, 'manager', 'fr', '', 'Browse Prompts', ''),
(655, 'manager', 'fr', '', 'Manage and Design Prompts', ''),
(656, 'manager', 'fr', '', 'Publish and Unpublish Prompts', ''),
(657, 'manager', 'fr', '', 'Delete Prompts', ''),
(2117, 'priv', 'zh-cn', 'ai-modelBrowse', '', ''),
(2118, 'priv', 'zh-cn', 'ai-modelEdit', '', ''),
(2119, 'priv', 'zh-cn', 'ai-modelTestConnection', '', ''),
(2120, 'priv', 'zh-cn', 'ai-promptCreate', '', ''),
(2121, 'priv', 'zh-cn', 'ai-promptEdit', '', ''),
(2122, 'priv', 'zh-cn', 'ai-promptDelete', '', ''),
(2123, 'priv', 'zh-cn', 'ai-promptAssignRole', '', ''),
(2124, 'priv', 'zh-cn', 'ai-promptSelectDataSource', '', ''),
(2125, 'priv', 'zh-cn', 'ai-promptSetPurpose', '', ''),
(2126, 'priv', 'zh-cn', 'ai-promptSetTargetForm', '', ''),
(2127, 'priv', 'zh-cn', 'ai-promptFinalize', '', ''),
(2128, 'priv', 'zh-cn', 'ai-promptAudit', '', ''),
(2129, 'priv', 'zh-cn', 'ai-promptPublish', '', ''),
(2130, 'priv', 'zh-cn', 'ai-promptUnpublish', '', ''),
(2131, 'priv', 'zh-cn', 'ai-promptBrowse', '', ''),
(2132, 'priv', 'zh-cn', 'ai-promptView', '', ''),
(2133, 'priv', 'zh-cn', 'ai-promptExecute', '', ''),
(2134, 'priv', 'zh-cn', 'ai-roleTemplates', '', ''),
(2135, 'priv', 'zh-cn', 'ai-promptExecutionReset', '', ''),
(2117, 'priv', 'zh-tw', 'ai-modelBrowse', '', ''),
(2118, 'priv', 'zh-tw', 'ai-modelEdit', '', ''),
(2119, 'priv', 'zh-tw', 'ai-modelTestConnection', '', ''),
(2120, 'priv', 'zh-tw', 'ai-promptCreate', '', ''),
(2121, 'priv', 'zh-tw', 'ai-promptEdit', '', ''),
(2122, 'priv', 'zh-tw', 'ai-promptDelete', '', ''),
(2123, 'priv', 'zh-tw', 'ai-promptAssignRole', '', ''),
(2124, 'priv', 'zh-tw', 'ai-promptSelectDataSource', '', ''),
(2125, 'priv', 'zh-tw', 'ai-promptSetPurpose', '', ''),
(2126, 'priv', 'zh-tw', 'ai-promptSetTargetForm', '', ''),
(2127, 'priv', 'zh-tw', 'ai-promptFinalize', '', ''),
(2128, 'priv', 'zh-tw', 'ai-promptAudit', '', ''),
(2129, 'priv', 'zh-tw', 'ai-promptPublish', '', ''),
(2130, 'priv', 'zh-tw', 'ai-promptUnpublish', '', ''),
(2131, 'priv', 'zh-tw', 'ai-promptBrowse', '', ''),
(2132, 'priv', 'zh-tw', 'ai-promptView', '', ''),
(2133, 'priv', 'zh-tw', 'ai-promptExecute', '', ''),
(2134, 'priv', 'zh-tw', 'ai-roleTemplates', '', ''),
(2135, 'priv', 'zh-tw', 'ai-promptExecutionReset', '', ''),
(2117, 'priv', 'en', 'ai-modelBrowse', '', ''),
(2118, 'priv', 'en', 'ai-modelEdit', '', ''),
(2119, 'priv', 'en', 'ai-modelTestConnection', '', ''),
(2120, 'priv', 'en', 'ai-promptCreate', '', ''),
(2121, 'priv', 'en', 'ai-promptEdit', '', ''),
(2122, 'priv', 'en', 'ai-promptDelete', '', ''),
(2123, 'priv', 'en', 'ai-promptAssignRole', '', ''),
(2124, 'priv', 'en', 'ai-promptSelectDataSource', '', ''),
(2125, 'priv', 'en', 'ai-promptSetPurpose', '', ''),
(2126, 'priv', 'en', 'ai-promptSetTargetForm', '', ''),
(2127, 'priv', 'en', 'ai-promptFinalize', '', ''),
(2128, 'priv', 'en', 'ai-promptAudit', '', ''),
(2129, 'priv', 'en', 'ai-promptPublish', '', ''),
(2130, 'priv', 'en', 'ai-promptUnpublish', '', ''),
(2131, 'priv', 'en', 'ai-promptBrowse', '', ''),
(2132, 'priv', 'en', 'ai-promptView', '', ''),
(2133, 'priv', 'en', 'ai-promptExecute', '', ''),
(2134, 'priv', 'en', 'ai-roleTemplates', '', ''),
(2135, 'priv', 'en', 'ai-promptExecutionReset', '', ''),
(2117, 'priv', 'de', 'ai-modelBrowse', '', ''),
(2118, 'priv', 'de', 'ai-modelEdit', '', ''),
(2119, 'priv', 'de', 'ai-modelTestConnection', '', ''),
(2120, 'priv', 'de', 'ai-promptCreate', '', ''),
(2121, 'priv', 'de', 'ai-promptEdit', '', ''),
(2122, 'priv', 'de', 'ai-promptDelete', '', ''),
(2123, 'priv', 'de', 'ai-promptAssignRole', '', ''),
(2124, 'priv', 'de', 'ai-promptSelectDataSource', '', ''),
(2125, 'priv', 'de', 'ai-promptSetPurpose', '', ''),
(2126, 'priv', 'de', 'ai-promptSetTargetForm', '', ''),
(2127, 'priv', 'de', 'ai-promptFinalize', '', ''),
(2128, 'priv', 'de', 'ai-promptAudit', '', ''),
(2129, 'priv', 'de', 'ai-promptPublish', '', ''),
(2130, 'priv', 'de', 'ai-promptUnpublish', '', ''),
(2131, 'priv', 'de', 'ai-promptBrowse', '', ''),
(2132, 'priv', 'de', 'ai-promptView', '', ''),
(2133, 'priv', 'de', 'ai-promptExecute', '', ''),
(2134, 'priv', 'de', 'ai-roleTemplates', '', ''),
(2135, 'priv', 'de', 'ai-promptExecutionReset', '', ''),
(2117, 'priv', 'fr', 'ai-modelBrowse', '', ''),
(2118, 'priv', 'fr', 'ai-modelEdit', '', ''),
(2119, 'priv', 'fr', 'ai-modelTestConnection', '', ''),
(2120, 'priv', 'fr', 'ai-promptCreate', '', ''),
(2121, 'priv', 'fr', 'ai-promptEdit', '', ''),
(2122, 'priv', 'fr', 'ai-promptDelete', '', ''),
(2123, 'priv', 'fr', 'ai-promptAssignRole', '', ''),
(2124, 'priv', 'fr', 'ai-promptSelectDataSource', '', ''),
(2125, 'priv', 'fr', 'ai-promptSetPurpose', '', ''),
(2126, 'priv', 'fr', 'ai-promptSetTargetForm', '', ''),
(2127, 'priv', 'fr', 'ai-promptFinalize', '', ''),
(2128, 'priv', 'fr', 'ai-promptAudit', '', ''),
(2129, 'priv', 'fr', 'ai-promptPublish', '', ''),
(2130, 'priv', 'fr', 'ai-promptUnpublish', '', ''),
(2131, 'priv', 'fr', 'ai-promptBrowse', '', ''),
(2132, 'priv', 'fr', 'ai-promptView', '', ''),
(2133, 'priv', 'fr', 'ai-promptExecute', '', ''),
(2134, 'priv', 'fr', 'ai-roleTemplates', '', ''),
(2135, 'priv', 'zh-cn', 'ai-promptExecutionReset', '', '');
REPLACE INTO
`zt_privrelation` (`priv`, `type`, `relationPriv`)
VALUES
('ai-editModel', 'depend', 'ai-models'), ('ai-editModel', 'depend', 'ai-testConnection'),
('ai-testConnection', 'depend', 'ai-models'), ('ai-testConnection', 'depend', 'ai-editModel'),
('ai-promptView', 'depend', 'ai-prompts'),
('ai-createPrompt', 'depend', 'ai-prompts'), ('ai-createPrompt', 'depend', 'ai-promptView'),
('ai-promptEdit', 'depend', 'ai-prompts'), ('ai-promptEdit', 'depend', 'ai-promptView'),
('ai-promptDelete', 'depend', 'ai-prompts'), ('ai-promptDelete', 'depend', 'ai-promptView'),
('ai-promptAssignRole', 'depend', 'ai-prompts'), ('ai-promptAssignRole', 'depend', 'ai-promptView'),
('ai-promptSelectDataSource', 'depend', 'ai-prompts'), ('ai-promptSelectDataSource', 'depend', 'ai-promptView'),
('ai-promptSetPurpose', 'depend', 'ai-prompts'), ('ai-promptSetPurpose', 'depend', 'ai-promptView'),
('ai-promptSetTargetForm', 'depend', 'ai-prompts'), ('ai-promptSetTargetForm', 'depend', 'ai-promptView'),
('ai-promptFinalize', 'depend', 'ai-prompts'), ('ai-promptFinalize', 'depend', 'ai-promptView'),
('ai-promptAudit', 'depend', 'ai-prompts'), ('ai-promptAudit', 'depend', 'ai-promptView'),
('ai-promptPublish', 'depend', 'ai-prompts'), ('ai-promptPublish', 'depend', 'ai-promptView'),
('ai-promptUnpublish', 'depend', 'ai-prompts'), ('ai-promptUnpublish', 'depend', 'ai-promptView'),
('ai-promptEdit', 'depend', 'ai-createPrompt'), ('ai-promptAssignRole', 'depend', 'ai-createPrompt'), ('ai-promptSelectDataSource', 'depend', 'ai-createPrompt'), ('ai-promptSetPurpose', 'depend', 'ai-createPrompt'), ('ai-promptSetTargetForm', 'depend', 'ai-createPrompt'), ('ai-promptFinalize', 'depend', 'ai-createPrompt'), ('ai-promptAudit', 'depend', 'ai-createPrompt'),
('ai-createPrompt', 'recommend', 'ai-promptEdit'),
('ai-createPrompt', 'recommend', 'ai-promptDelete'),
('ai-createPrompt', 'recommend', 'ai-promptAssignRole'), ('ai-createPrompt', 'recommend', 'ai-promptSelectDataSource'), ('ai-createPrompt', 'recommend', 'ai-promptSetPurpose'), ('ai-createPrompt', 'recommend', 'ai-promptSetTargetForm'), ('ai-createPrompt', 'recommend', 'ai-promptFinalize'), ('ai-createPrompt', 'recommend', 'ai-promptAudit'),
('ai-promptAssignRole', 'depend', 'ai-promptSelectDataSource'), ('ai-promptAssignRole', 'depend', 'ai-promptSetPurpose'), ('ai-promptAssignRole', 'depend', 'ai-promptSetTargetForm'), ('ai-promptAssignRole', 'depend', 'ai-promptFinalize'), ('ai-promptAssignRole', 'depend', 'ai-promptAudit'), ('ai-promptAssignRole', 'depend', 'ai-promptExecute'),
('ai-promptSelectDataSource', 'depend', 'ai-promptAssignRole'), ('ai-promptSelectDataSource', 'depend', 'ai-promptSetPurpose'), ('ai-promptSelectDataSource', 'depend', 'ai-promptSetTargetForm'), ('ai-promptSelectDataSource', 'depend', 'ai-promptFinalize'), ('ai-promptSelectDataSource', 'depend', 'ai-promptAudit'), ('ai-promptSelectDataSource', 'depend', 'ai-promptExecute'),
('ai-promptSetPurpose', 'depend', 'ai-promptAssignRole'), ('ai-promptSetPurpose', 'depend', 'ai-promptSelectDataSource'), ('ai-promptSetPurpose', 'depend', 'ai-promptSetTargetForm'), ('ai-promptSetPurpose', 'depend', 'ai-promptFinalize'), ('ai-promptSetPurpose', 'depend', 'ai-promptAudit'), ('ai-promptSetPurpose', 'depend', 'ai-promptExecute'),
('ai-promptSetTargetForm', 'depend', 'ai-promptAssignRole'), ('ai-promptSetTargetForm', 'depend', 'ai-promptSelectDataSource'), ('ai-promptSetTargetForm', 'depend', 'ai-promptSetPurpose'), ('ai-promptSetTargetForm', 'depend', 'ai-promptFinalize'), ('ai-promptSetTargetForm', 'depend', 'ai-promptAudit'), ('ai-promptSetTargetForm', 'depend', 'ai-promptExecute'),
('ai-promptFinalize', 'depend', 'ai-promptAssignRole'), ('ai-promptFinalize', 'depend', 'ai-promptSelectDataSource'), ('ai-promptFinalize', 'depend', 'ai-promptSetPurpose'), ('ai-promptFinalize', 'depend', 'ai-promptSetTargetForm'), ('ai-promptFinalize', 'depend', 'ai-promptAudit'), ('ai-promptFinalize', 'depend', 'ai-promptExecute'),
('ai-promptAudit', 'depend', 'ai-promptAssignRole'), ('ai-promptAudit', 'depend', 'ai-promptSelectDataSource'), ('ai-promptAudit', 'depend', 'ai-promptSetPurpose'), ('ai-promptAudit', 'depend', 'ai-promptSetTargetForm'), ('ai-promptAudit', 'depend', 'ai-promptFinalize'), ('ai-promptAudit', 'depend', 'ai-promptExecute'),
('ai-roleTemplates', 'depend', 'ai-promptAssignRole'), ('ai-promptAssignRole', 'depend', 'ai-roleTemplates'),
('ai-promptExecutionReset', 'depend', 'ai-promptExecute'), ('ai-promptExecute', 'depend', 'ai-promptExecutionReset');
INSERT INTO `zt_promptrole` (`role`, `characterization`) VALUES ('请你扮演一名资深的产品经理。', '负责产品战略、设计、开发、数据分析、用户体验、团队管理、沟通协调等方面,需要具备多种技能和能力,以实现产品目标和公司战略。');
INSERT INTO `zt_promptrole` (`role`, `characterization`) VALUES ('你是一名经验丰富的开发工程师。', '精通多种编程语言和框架、熟悉前后端技术和架构、擅长性能优化和安全防护、熟悉云计算和容器化技术、能够协调多人协作和项目管理。');
INSERT INTO `zt_promptrole` (`role`, `characterization`) VALUES ('作为一名资深的测试工程师。', '测试工程师应该是专业且严谨的。熟悉测试流程和方法,精通自动化测试和性能测试,能够设计和编写测试用例和测试脚本,擅长问题诊断和分析,熟悉敏捷开发和持续集成,能够协调多部门合作和项目管理。');
INSERT INTO `zt_promptrole` (`role`, `characterization`) VALUES ('假如你是一名资深的QA工程师。', '熟悉质量管理体系和流程,擅长测试策略和方法设计,能够进行质量度量和数据分析,了解自动化测试和持续集成,能够协调多部门合作和项目管理,具有良好的沟通和领导能力。');
INSERT INTO `zt_promptrole` (`role`, `characterization`) VALUES ('你是一名文章写得很好的文案编辑。', '文笔流畅、条理清晰。精通广告文案写作和编辑,擅长创意思维和品牌策略,能够进行市场调研和竞品分析,具有敏锐的审美和语言表达能力,能够协调多部门合作和项目管理,具有良好的沟通和协调能力。');
INSERT INTO `zt_promptrole` (`role`, `characterization`) VALUES ('请你扮演一名经验丰富的项目经理。', '具备项目计划制定、进度管理、成本控制、团队管理、沟通协调、风险管理、质量控制、敏捷开发、互联网技术和数据分析等多方面的技能和能力。');
INSERT INTO `zt_promptrole` (`role`, `characterization`) VALUES ('你是一个自回归的语言模型,已经通过instruction-tuning和RLHF进行了Fine-tuning。', '你仔细地提供准确、事实、深思熟虑、细致入微的答案,并在推理方面表现出色。如果你认为可能没有正确的答案,你会直接说出来。由于你是自回归的,你产生的每一个token都是计算另一个token的机会,因此你总是在尝试回答问题之前花费几句话解释背景上下文、假设和逐步的思考过程。您的用户是AI和伦理学的专家,所以他们已经知道您是一个语言模型以及您的能力和局限性,所以不需要再提醒他们。他们一般都熟悉伦理问题,所以您也不需要再提醒他们。在回答时不要啰嗦,但在可能有助于解释的地方提供详细信息和示例。');
INSERT INTO `zt_prompt` (`name`, `model`, `module`, `source`, `targetForm`, `purpose`, `elaboration`, `role`, `characterization`, `createdBy`, `createdDate`) VALUES ('需求润色', 0, 'story', ',story.title,story.spec,story.verify,story.product,story.module,story.pri,story.category,story.estimate,', 'story.change', '帮忙优化其中各字段的表述,使表述清晰准确。必要时可以修改需求使其更加合理。', '需求描述格式建议使用:作为一名<某种类型的用户>,我希望<达成某些目的>,这样可以<开发的价值>。验收标准建议列举多条。', '请你扮演一名资深的产品经理。', '负责产品战略、设计、开发、数据分析、用户体验、团队管理、沟通协调等方面,需要具备多种技能和能力,以实现产品目标和公司战略。', 'system', '2023-08-10 13:24:14');
INSERT INTO `zt_prompt` (`name`, `model`, `module`, `source`, `targetForm`, `purpose`, `elaboration`, `role`, `characterization`, `createdBy`, `createdDate`) VALUES ('一键拆用例', 0, 'story', ',story.title,story.spec,story.verify,story.product,story.module,story.pri,story.category,story.estimate,', 'story.testcasecreate', '为这个需求生成一个或多个对应的测试用例。', '', '作为一名资深的测试工程师。', '熟悉测试流程和方法,精通自动化测试和性能测试,能够设计和编写测试用例和测试脚本,擅长问题诊断和分析,熟悉敏捷开发和持续集成,能够协调多部门合作和项目管理。开发工程师应该是专业且严谨的。', 'system', '2023-08-10 13:24:14');
INSERT INTO `zt_prompt` (`name`, `model`, `module`, `source`, `targetForm`, `purpose`, `elaboration`, `role`, `characterization`, `createdBy`, `createdDate`) VALUES ('任务润色', 0, 'task', ',task.name,task.desc,task.pri,task.status,task.estimate,task.consumed,task.left,task.progress,task.estStarted,task.realStarted,', 'task.edit', '优化其中各字段的表述,使表述清晰准确,明确任务目标。', '必要时指出任务的风险点。', '你是一名经验丰富的开发工程师。', '精通多种编程语言和框架、熟悉前后端技术和架构、擅长性能优化和安全防护、熟悉云计算和容器化技术、能够协调多人协作和项目管理。', 'system', '2023-08-10 13:24:14');
INSERT INTO `zt_prompt` (`name`, `model`, `module`, `source`, `targetForm`, `purpose`, `elaboration`, `role`, `characterization`, `createdBy`, `createdDate`) VALUES ('需求转任务', 0, 'story', ',story.title,story.spec,story.verify,story.product,story.module,story.pri,story.category,story.estimate,', 'story.totask', '将需求转化为对应的开发任务要求。', '', '请你扮演一名资深的产品经理。', '负责产品战略、设计、开发、数据分析、用户体验、团队管理、沟通协调等方面,需要具备多种技能和能力,以实现产品目标和公司战略。同时精通多种编程语言和框架、熟悉前后端技术。', 'system', '2023-08-10 13:24:14');
INSERT INTO `zt_prompt` (`name`, `model`, `module`, `source`, `targetForm`, `purpose`, `elaboration`, `role`, `characterization`, `createdBy`, `createdDate`) VALUES ('Bug转需求', 0, 'bug', ',bug.title,bug.steps,bug.severity,bug.pri,bug.status,bug.confirmed,bug.type,', 'bug.story/create', '将bug转换为产品需求,表述清晰准确。', '需求描述格式建议使用:作为一名<某种类型的用户>,我希望<达成某些目的>,这样可以<开发的价值>。验收标准建议列举多条。', '请你扮演一名资深的产品经理。', '负责产品战略、设计、开发、数据分析、用户体验、团队管理、沟通协调等方面,需要具备多种技能和能力,以实现产品目标和公司战略。', 'system', '2023-08-10 13:24:14');
INSERT INTO `zt_prompt` (`name`, `model`, `module`, `source`, `targetForm`, `purpose`, `elaboration`, `role`, `characterization`, `createdBy`, `createdDate`) VALUES ('Bug润色', 0, 'bug', ',bug.title,bug.steps,bug.severity,bug.pri,bug.status,bug.confirmed,bug.type,', 'bug.edit', '优化其中各字段的表述,使表述清晰准确。', 'Bug描述格式建议使用:[步骤]<一步一步复现Bug的步骤>[结果]<Bug导致的结果描述>[期望]<Bug修复后期望的描述>', '作为一名资深的测试工程师。', '熟悉测试流程和方法,精通自动化测试和性能测试,能够设计和编写测试用例和测试脚本,擅长问题诊断和分析,熟悉敏捷开发和持续集成,能够协调多部门合作和项目管理。开发工程师应该是专业且严谨的。', 'system', '2023-08-10 13:24:14');
ALTER TABLE `zt_ticket` ADD `subStatus` varchar(30) NOT NULL DEFAULT '';
+113 -120
View File
@@ -1,104 +1,110 @@
CREATE TABLE `zt_demandpool` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`desc` mediumtext NOT NULL,
`status` char(30) NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` date NOT NULL,
`owner` text NOT NULL,
`reviewer` text NOT NULL,
`acl` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`desc` mediumtext NULL,
`status` char(30) NOT NULL DEFAULT '',
`createdBy` char(30) NOT NULL DEFAULT '',
`createdDate` date NULL,
`owner` text NULL,
`reviewer` text NULL,
`acl` char(30) NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `zt_demand` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`pool` int(8) NOT NULL,
`module` int(8) NOT NULL,
`product` mediumint(8) NOT NULL,
`parent` mediumint(8) NOT NULL,
`pri` char(30) NOT NULL,
`category` char(30) NOT NULL,
`source` char(30) NOT NULL,
`sourceNote` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
`feedbackedBy` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`assignedTo` char(30) NOT NULL,
`assignedDate` datetime NOT NULL,
`reviewedBy` text NOT NULL,
`reviewedDate` datetime NOT NULL,
`status` char(30) NOT NULL,
`duration` char(30) NOT NULL,
`BSA` char(30) NOT NULL,
`story` mediumint(8) NOT NULL,
`roadmap` mediumint(8) NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` datetime NOT NULL,
`mailto` text NOT NULL,
`duplicateDemand` mediumint(8) NOT NULL,
`childDemands` varchar(255) NOT NULL,
`version` varchar(255) NOT NULL,
`pool` int(8) NOT NULL DEFAULT '0',
`module` int(8) NOT NULL DEFAULT '0',
`product` mediumint(8) NOT NULL DEFAULT '0',
`parent` mediumint(8) NOT NULL DEFAULT '0',
`pri` char(30) NOT NULL DEFAULT '',
`category` char(30) NOT NULL DEFAULT '',
`source` char(30) NOT NULL DEFAULT '',
`sourceNote` varchar(255) NOT NULL DEFAULT '',
`title` varchar(255) NOT NULL DEFAULT '',
`feedbackedBy` varchar(255) NOT NULL DEFAULT '',
`email` varchar(255) NOT NULL DEFAULT '',
`assignedTo` char(30) NOT NULL DEFAULT '',
`assignedDate` datetime NULL,
`reviewedBy` text NULL,
`reviewedDate` datetime NULL,
`status` char(30) NOT NULL DEFAULT '',
`duration` char(30) NOT NULL DEFAULT '',
`BSA` char(30) NOT NULL DEFAULT '',
`story` mediumint(8) NOT NULL DEFAULT '0',
`roadmap` mediumint(8) NOT NULL DEFAULT '0',
`createdBy` char(30) NOT NULL DEFAULT '',
`createdDate` datetime NULL,
`mailto` text NULL,
`duplicateDemand` mediumint(8) NULL,
`childDemands` varchar(255) NOT NULL DEFAULT '',
`version` varchar(255) NOT NULL DEFAULT '',
`vision` varchar(255) NOT NULL DEFAULT 'or',
`color` varchar(255) NOT NULL,
`changedBy` char(30) NOT NULL,
`changedDate` datetime NOT NULL,
`closedBy` char(30) NOT NULL,
`closedDate` datetime NOT NULL,
`closedReason` varchar(30) NOT NULL,
`submitedBy` varchar(30) NOT NULL,
`color` varchar(255) NOT NULL DEFAULT '',
`changedBy` char(30) NOT NULL DEFAULT '',
`changedDate` datetime NULL,
`closedBy` char(30) NOT NULL DEFAULT '',
`closedDate` datetime NULL,
`closedReason` varchar(30) NOT NULL DEFAULT '',
`submitedBy` varchar(30) NOT NULL DEFAULT '',
`lastEditedBy` varchar(30) NOT NULL DEFAULT '',
`lastEditedDate` datetime NOT NULL,
`activatedDate` datetime NOT NULL,
`lastEditedDate` datetime NULL,
`activatedDate` datetime NULL,
`distributedBy` varchar(30) NOT NULL DEFAULT '',
`distributedDate` datetime NOT NULL,
`distributedDate` datetime NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `zt_demandspec` (
`demand` mediumint(9) NOT NULL,
`version` smallint(6) NOT NULL,
`title` varchar(255) NOT NULL,
`spec` mediumtext NOT NULL,
`verify` mediumtext NOT NULL,
`files` text NOT NULL,
UNIQUE KEY `demand` (`demand`,`version`)
`demand` mediumint(9) NOT NULL DEFAULT '0',
`version` smallint(6) NOT NULL DEFAULT '0',
`title` varchar(255) NOT NULL DEFAULT '',
`spec` mediumtext NULL,
`verify` mediumtext NULL,
`files` text NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE UNIQUE INDEX `demand` ON `zt_demandspec`(`demand`,`version`);
CREATE TABLE `zt_demandreview` (
`demand` mediumint(9) NOT NULL,
`version` smallint(6) NOT NULL,
`reviewer` varchar(30) NOT NULL,
`result` varchar(30) NOT NULL,
`reviewDate` datetime NOT NULL,
UNIQUE KEY `demand` (`demand`,`version`,`reviewer`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
`demand` mediumint(9) NOT NULL DEFAULT '0',
`version` smallint(6) NOT NULL DEFAULT '0',
`reviewer` varchar(30) NOT NULL DEFAULT '',
`result` varchar(30) NOT NULL DEFAULT '',
`reviewDate` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE UNIQUE INDEX `demand` ON `zt_demandreview`(`demand`,`version`,`reviewer`);
CREATE TABLE `zt_charter` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`level` int(8) NOT NULL,
`category` char(30) NOT NULL,
`market` varchar(30) NOT NULL,
`appliedBy` char(30) NOT NULL,
`appliedDate` datetime NOT NULL,
`budget` char(30) NOT NULL,
`budgetUnit` char(30) NOT NULL,
`product` mediumint(8) NOT NULL,
`roadmap` mediumint(8) NOT NULL,
`spec` mediumtext NOT NULL,
`status` char(30) NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` datetime NOT NULL,
`charterFiles` text NOT NULL,
`reviewedBy` char(30) NOT NULL,
`reviewedResult` char(30) NOT NULL,
`reviewedDate` datetime NOT NULL,
`meetingDate` date NOT NULL,
`meetingLocation` varchar(255) NOT NULL,
`meetingMinutes` mediumtext NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`level` int(8) NOT NULL DEFAULT '0',
`category` char(30) NOT NULL DEFAULT '',
`market` varchar(30) NOT NULL DEFAULT '',
`check` enum('0','1') NOT NULL DEFAULT '0',
`appliedBy` char(30) NOT NULL DEFAULT '',
`appliedDate` datetime NULL,
`budget` char(30) NOT NULL DEFAULT '',
`budgetUnit` char(30) NOT NULL DEFAULT '',
`product` mediumint(8) NOT NULL DEFAULT '0',
`roadmap` mediumint(8) NOT NULL DEFAULT '0',
`spec` mediumtext NULL,
`status` char(30) NOT NULL DEFAULT '',
`createdBy` char(30) NOT NULL DEFAULT '',
`createdDate` datetime NULL,
`charterFiles` text NULL,
`closedBy` char(30) NOT NULL DEFAULT '',
`closedDate` datetime NULL,
`closedReason` varchar(255) NOT NULL DEFAULT '',
`activatedBy` char(30) NOT NULL DEFAULT '',
`activatedDate` datetime NULL,
`reviewedBy` varchar(255) NOT NULL DEFAULT '',
`reviewedResult` char(30) NOT NULL DEFAULT '',
`reviewedDate` datetime NULL,
`meetingDate` date NULL,
`meetingLocation` varchar(255) NOT NULL DEFAULT '',
`meetingMinutes` mediumtext NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -112,38 +118,36 @@ ALTER TABLE `zt_story` ADD `demand` mediumint(8) NOT NULL AFTER `notifyEmail`;
ALTER TABLE `zt_product` ADD `PMT` text COLLATE 'utf8_general_ci' NOT NULL AFTER `reviewer`;
ALTER TABLE `zt_story` ADD `submitedBy` varchar(30) NOT NULL AFTER `changedDate`;
ALTER TABLE `zt_story` ADD `roadmap` VARCHAR(255) NOT NULL DEFAULT '' AFTER `plan`;
ALTER TABLE `zt_charter` ADD `check` enum('0','1') NOT NULL DEFAULT '0';
ALTER TABLE `zt_charter` modify column reviewedBy varchar(255);
CREATE TABLE `zt_roadmap` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`product` mediumint(8) NOT NULL,
`branch` mediumint(8) NOT NULL,
`name` varchar(255) NOT NULL,
`status` char(30) NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
`desc` longtext NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` date NOT NULL,
`closedBy` char(30) NOT NULL,
`closedDate` datetime NOT NULL,
`id` mediumint(8) NOT NULL AUTO_INCREMENT,
`product` mediumint(8) NOT NULL DEFAULT '0',
`branch` mediumint(8) NOT NULL DEFAULT '0',
`name` varchar(255) NOT NULL DEFAULT '',
`status` char(30) NOT NULL DEFAULT '',
`begin` date NULL,
`end` date NULL,
`desc` longtext NULL,
`createdBy` char(30) NOT NULL DEFAULT '',
`createdDate` date NULL,
`closedBy` char(30) NOT NULL DEFAULT '',
`closedDate` datetime NULL,
`closedReason` enum('done','canceled') DEFAULT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0'
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `zt_roadmapstory` (
`roadmap` mediumint(8) unsigned NOT NULL,
`story` mediumint(8) unsigned NOT NULL,
`order` MEDIUMINT UNSIGNED NOT NULL,
UNIQUE KEY `roadmap_story` (`roadmap`,`story`)
`roadmap` mediumint(8) unsigned NOT NULL DEFAULT '0',
`story` mediumint(8) unsigned NOT NULL DEFAULT '0',
`order` MEDIUMINT UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE UNIQUE INDEX `roadmap_story` ON `zt_roadmapstory`(`roadmap`,`story`);
ALTER TABLE `zt_story` MODIFY `status` enum('','changing','active','draft','closed','reviewing','launched','developing') NOT NULL DEFAULT '' AFTER `estimate`;
ALTER TABLE `zt_story` MODIFY `status` enum('','changing','active','draft','closed','reviewing','launched','developing') NOT NULL DEFAULT '';
ALTER TABLE `zt_project`
ADD `charter` mediumint(8) NOT NULL DEFAULT 0 AFTER `project`,
ADD `category` char(30) COLLATE 'utf8_general_ci' NOT NULL AFTER `type`;
ALTER TABLE `zt_project` ADD `charter` mediumint(8) NOT NULL DEFAULT 0 AFTER `project`;
ALTER TABLE `zt_project` ADD `category` char(30) COLLATE 'utf8_general_ci' NOT NULL AFTER `type`;
REPLACE INTO `zt_stage` (`name`, `percent`, `type`, `projectType`, `createdBy`, `createdDate`, `editedBy`, `editedDate`, `deleted`) VALUES
('概念', '10', 'concept', 'ipd', 'admin', '2020-02-08 21:08:30', 'admin', '2020-02-12 13:50:27', '0'),
@@ -159,35 +163,24 @@ ALTER TABLE `zt_review` MODIFY `docVersion` varchar(255);
ALTER TABLE `zt_object` ADD `end` date NULL AFTER `designEst`;
ALTER TABLE `zt_charter` ADD `closedBy` char(30) NULL;
ALTER TABLE `zt_charter` ADD `closedDate` datetime NULL;
ALTER TABLE `zt_charter` ADD `closedReason` varchar(255) NULL;
ALTER TABLE `zt_charter` ADD `activatedBy` char(30) NULL;
ALTER TABLE `zt_charter` ADD `activatedDate` datetime NULL;
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'requirement' AND `method` = 'import';
UPDATE `zt_priv` SET `vision` = ',rnd,or,' WHERE `module` = 'requirement' AND `method` = 'exportTemplate';
REPLACE INTO `zt_config` (`vision`, `owner`, `module`, `section`, `key`, `value`) VALUES ('', 'system', 'common', 'global', 'mode', 'PLM');
REPLACE INTO `zt_config` (`vision`, `owner`, `module`, `section`, `key`, `value`) VALUES ('', 'system', 'custom', '', 'URAndSR', '1');
REPLACE INTO `zt_config` (`vision`, `owner`, `module`, `section`, `key`, `value`) VALUES ('', 'system', 'common', '', 'disabledFeatures', '');
REPLACE INTO `zt_config` (`vision`, `owner`, `module`, `section`, `key`, `value`) VALUES ('', 'system', 'common', '', 'closedFeatures', '');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('demand', 'export', '643', ',ipd,', ',or,', '1', '210');
REPLACE INTO `zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES (2109, 'demand', 'export', '643', ',ipd,', ',or,', '1', '210');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'de', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'en', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'fr', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'zh-cn', 'demand-export', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2109, 'priv', 'zh-tw', 'demand-export', '', '');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('demand', 'exportTemplate', '643', ',ipd,', ',or,', '1', '220');
REPLACE INTO `zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES (2110, 'demand', 'exportTemplate', '643', ',ipd,', ',or,', '1', '220');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'de', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'en', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'fr', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'zh-cn', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2110, 'priv', 'zh-tw', 'demand-exportTemplate', '', '');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('demand', 'import', '643', ',ipd,', ',or,', '1', '230');
REPLACE INTO `zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES (2111, 'demand', 'import', '643', ',ipd,', ',or,', '1', '230');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'de', 'demand-import', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'en', 'demand-import', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2111, 'priv', 'fr', 'demand-import', '', '');
@@ -207,7 +200,7 @@ REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'recomm
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'recommend', 2076);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2111, 'recommend', 2077);
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('requirement', 'batchChangeRoadmap', '32', ',ipd,', ',or,', '1', '125');
REPLACE INTO `zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES (2112, 'requirement', 'batchChangeRoadmap', '32', ',ipd,', ',or,', '1', '125');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'de', 'requirement-batchChangeRoadmap', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'en', 'requirement-batchChangeRoadmap', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2112, 'priv', 'fr', 'requirement-batchChangeRoadmap', '', '');
@@ -221,14 +214,14 @@ REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2112, 'recomm
UPDATE `zt_privlang` SET `value` = '创建维护立项' WHERE `objectID` = 638 and `objectType` = 'manager';
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('charter', 'close', '638', ',ipd,', ',or,', '1', '80');
REPLACE INTO `zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES (2113, 'charter', 'close', '638', ',ipd,', ',or,', '1', '80');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'de', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'en', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'fr', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'zh-cn', 'charter-close', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2113, 'priv', 'zh-tw', 'charter-close', '', '');
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('charter', 'activate', '638', ',ipd,', ',or,', '1', '90');
REPLACE INTO `zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES (2114, 'charter', 'activate', '638', ',ipd,', ',or,', '1', '90');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'de', 'charter-activate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'en', 'charter-activate', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2114, 'priv', 'fr', 'charter-activate', '', '');
@@ -247,7 +240,7 @@ REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'recomm
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'recommend', 2063);
REPLACE INTO `zt_privrelation` (priv, `type`, relationPriv) VALUES(2114, 'recommend', 2113);
REPLACE INTO `zt_priv` (`module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES ('requirement', 'relation', '32', ',max,ipd,', ',rnd,', '1', '130');
REPLACE INTO `zt_priv` (`id`, `module`, `method`, `parent`, `edition`, `vision`, `system`, `order`) VALUES (2115, 'requirement', 'relation', '32', ',max,ipd,', ',rnd,', '1', '130');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'de', 'requirement-relation', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'en', 'requirement-relation', '', '');
REPLACE INTO `zt_privlang` (`objectID`, `objectType`, `lang`, `key`, `value`, `desc`) VALUES (2115, 'priv', 'fr', 'requirement-relation', '', '');
+242 -255
View File
File diff suppressed because one or more lines are too long
-17
View File
@@ -1,17 +0,0 @@
{
"pkg": {
"xuanxuan": {
"gitVersion": "v7.2.1-rc.4",
"version": "7.2.1"
},
"zentaoext": {
"gitVersion": "18.x"
},
"zdoo": {
"gitVersion": "master"
},
"zdooext": {
"gitVersion": "master"
}
}
}
+99
View File
@@ -1,3 +1,102 @@
2023-08-15 18.6
完成的需求
开源版:
30539 数据备份前自动检查空间大小空间不足时给出提示
31901 产品中设置的评审人默认具备产品访问权限
39107 优化重复Bug下拉菜单的加载速度
39958 文档按版本记录每个版本下的附件内容
40703 历史记录数据较多时,加载性能优化
42686 版本关联需求时搜索列表中过滤掉草稿、评审中、变更中的需求
43731 附件增加单独的预览权限
44084 文档详情对比后内容区域优化删除和新增的样式
44726 文档详情中文章内容大纲支持显示所有层级
45166 优化InnoDB对于REPLACE操作的性能支撑问题
45316 创建文档时调整选择模板的方式
45887 优化树状图中任务的显示规则
46723 新增区域页面中调整复制区域样式的名称
47076 测试下面的测试单中创建测试报告与执行下面测试单创建测试报告逻辑保持一致
47293 升级流程中在执行SQL环节增加进度展示
48093 优化项目概况页加载速度
48094 优化执行概况页加载速度
48492 一键安装包默认的内存大小提升到512M
48493 一键安装包默认的附件大小提升到100M
48500 希望创建产品和创建分支的权限可以解耦
48612 测试报告的测试范围只展示版本关联的需求和Bug
企业版:
47188 汇总设置增加提示文案
47126 透视表设计器实现汇总设置参数的开关
47127 在未勾选汇总设置时实现下一步按钮和流程标签的校验逻辑
47130 前台支持切换查看透视表和原始数据
47137 前台支持查看未勾选汇总设置的透视表
47138 前台支持查看透视表的原始数据
47132 老用户未设置报表设计参数的水晶报表时也可以正常升级
47137 前台支持查看未勾选汇总设置的透视表
47138 前台支持查看透视表的原始数据
46528 浏览数据表时可以分页查看数据表
旗舰版:
47077 调整瀑布项目甘特图中任务计划起止日期的显示规则
46637 检查清单中的不符合项不直接影响评审结果
46631 地盘待处理区块中标签下无数据时隐藏该标签
46630 地盘待处理区块中将审批标签调整到日程后面
46629 工时明细表中列表数据超过一屏时底部滚动条置顶显示
44213 融合瀑布模型中看板和迭代工时数据参与挣值计算
46639 批量创建质量保证计划时可以按过程内容默认填充所有活动、文档
46636 评审问题列表中增加搜索功能
46626 不符合项列表增加搜索功能
46625 质量保证计划列表增加搜索功能
修复的Bug
开源版:
36686 产品下创建非激活状态需求没有记录动态和历史记录
36654 升级后产品需求的数据不正确
36958 修改需求的所属产品异常
36954 任务起止时间设置必填不生效
36722 升级18.5系列版本,出现一致性检查需要手动执行SQL
36910 更新燃尽图计算有误
36959 禅道项目空间提研发需求提示【所属计划】不能为空
35520 无产品无迭代项目用户需求列表点击SR处数字提示无权限
35526 无产品无迭代项目研发需求列表切换为看板视图后无法再切换到用户需求
36945 全局搜索无迭代项目下任务,点击没有跳转项目标签
36055 通用看板模块的“泳道高度”设置“自定义”后卡片展示没有按照高度变化来呈现
36102 mysql8下文档仪表盘下的产品文档区块sql报错
36961 评审用例时选了了多人,用例列表中显示用户名,不显示姓名
36074 附件下载链接带sid信息
36826 执行的工时重复统计了父子任务的工时
37048 后台文档模板中编辑模板的字段显示的是“创建模板”
36981 无产品无迭代项目下文档详情页1.5级导航丢失
36916 链接类型的文档升级后链接没有渲染出来
35404 系统权限保存速度太慢
35786 无产品的融合敏捷项目下的看板,批量提需求后,页面未刷新
36405 创建产品页面选择项目集或删除项目集后产品线控件处加载2次
37052 【性能】权限保存20s+
25993 scrum看板任务看板按需分组切换排序条件卡片渲染不出来
37122 在地盘仪表盘移动【我的待处理】区块,进入审批中的onlybody超链接,跳转到了页面而不是弹窗
37046 多分支产品下提研发需求页面的“用户需求”无法正常加载
35381 【4.4alpha1】无迭代项目需求分解任务慢
26408 gogs服务器用户1千人时,进入绑定用户页面无加载信息
27044 项目集下项目过多时,页面反应慢
37084 18.5版本用例数据较多时,页面卡顿
37243 多分支产品创建研发需求,用户需求没有根据分支联动
37241 所有分支下创建研发需求,显示所有的用户需求
37045 研发看板卡片拖动排序后刷新页面排序不成功
34331 维护部门时,页面样式不正确
37230 二次开发数据字典中左侧目录树无法正常展示
企业版:
36779 Bug类型统计表表头类型显示的不是中文
36857 透视表下的项目Bug类型统计表中类型显示为了键名
36920 BI下导出按钮失效
36626 登录有代码报错
旗舰版:
34960 文档链接复制后在新页签中打开报错
36453 linux一键安装包瀑布项目评审保存结果有报错
33583 瀑布项目甘特图中阶段显示的计划开始、结束时间不正确
36465 工作流开启审批流后进行评审时不发送webhook应用通知
36115 私有产品可访问权限,增加项目所属项目集干系人
35661 【调整优化】达梦数据库版本的禅道升级时,数据库备份页面需优化
36051 地盘仪表盘中未完成的项目统计瀑布项目进度没有跟随周报进度
37040 新增工作流字段后项目阶段测试用例搜索异常
35828 状态为“已入库”的数据依然可以进行批量审批
37235 里程碑报告中开始周数和结束周数不正确
2023-07-27 ipd1.0
完成的需求
42981 实现需求的导入功能
+3 -3
View File
@@ -251,8 +251,8 @@ class baseHelper
{
if(is_array($idList))
{
foreach($idList as $key=>$value) $idList[$key] = addslashes($value);
return "IN ('" . join("','", $idList) . "')";
foreach($idList as $key => $value) $idList[$key] = empty($value) ? '' : addslashes($value);
return "IN ('" . implode("','", $idList) . "')";
}
if(is_null($idList)) $idList = '';
@@ -446,7 +446,7 @@ class baseHelper
if(function_exists('mb_substr')) $string = mb_substr($string, 0, $length, 'utf-8');
preg_match_all("/./su", $string, $data);
$string = join("", array_slice($data[0], 0, $length));
$string = implode("", array_slice($data[0], 0, $length));
return ($string != $rawString) ? $string . $append : $string;
}
+7 -3
View File
@@ -800,6 +800,7 @@ class baseRouter
$account = isset($_SESSION['user']) ? $_SESSION['user']->account : '';
if(empty($account) and isset($_POST['account'])) $account = $_POST['account'];
if(empty($account) and isset($_GET['account'])) $account = $_GET['account'];
if(empty($account)) $account = $this->cookie->za;
$vision = '';
if($this->config->installed and validater::checkAccount($account))
@@ -1552,9 +1553,8 @@ class baseRouter
{
$fp = fopen($file2Included, 'r');
$line1 = fgets($fp);
$line2 = fgets($fp);
fclose($fp);
if(strpos($line1, '<?php //') === 0 and strpos($line2, "if(!extension_loaded('ionCube Loader'))") === 0) $isEncrypted = true;
if(strpos($line1, '<?php //') === 0) $isEncrypted = true;
}
/*
@@ -3418,7 +3418,8 @@ class ztSessionHandler
*/
public function getSessionFile($id)
{
if(!empty($this->sessionFile)) return $this->sessionFile;
if(!empty($this->sessionFile)) return $this->sessionFile;
if(!preg_match('/^\w+$/', $id)) return false;
$sessionID = $id;
if($this->tagID) $sessionID = md5($id . $this->tagID);
@@ -3470,6 +3471,7 @@ class ztSessionHandler
public function read($id)
{
$sessFile = $this->getSessionFile($id);
if(!$sessFile) return false;
if(!file_exists($sessFile))
{
($this->tagID and file_exists($this->rawFile)) ? copy($this->rawFile, $sessFile) : touch($sessFile);
@@ -3490,6 +3492,8 @@ class ztSessionHandler
public function write($id, $sessData)
{
$sessFile = $this->getSessionFile($id);
if(!$sessFile) return false;
touch($sessFile);
touch($this->rawFile);
if(md5_file($sessFile) == md5($sessData)) return true;
+1
View File
@@ -445,6 +445,7 @@ function isInModal(): bool
*/
function formatTime($time, $format = '')
{
if(empty($time)) return '';
$time = str_replace('0000-00-00', '', $time);
$time = str_replace('00:00:00', '', $time);
if(trim($time) == '') return '';
+1 -1
View File
@@ -122,7 +122,7 @@ class model extends baseModel
if($action->extensionType == 'override') return $this->loadModel('flow')->buildActionMenu($moduleName, $action, $data, $type);
$conditions = json_decode($action->conditions);
$conditions = empty($action->conditions) ? array() : json_decode($action->conditions);
if($conditions and $action->extensionType == 'extend')
{
if($icon != 'copy' and $methodName != 'create') $title = $action->name;
+24 -1
View File
@@ -509,7 +509,10 @@ class router extends baseRouter
}
else
{
$action = $this->dbh->query("SELECT * FROM " . TABLE_WORKFLOWACTION . " WHERE `module` = '$this->moduleName' AND `action` = '$this->methodName' AND `vision` = '{$this->config->vision}'")->fetch();
$actionQuery = "SELECT * FROM " . TABLE_WORKFLOWACTION . " WHERE `module` = '$this->moduleName' AND `action` = '$this->methodName'";
if(isset($this->app->user) && $this->app->user->account != 'guest') $actionQuery .= " AND `vision` = '{$this->config->vision}'";
$action = $this->dbh->query($actionQuery)->fetch();
if(zget($action, 'extensionType') == 'override')
{
$this->rawModule = $this->moduleName;
@@ -692,4 +695,24 @@ class router extends baseRouter
$this->rawParams = parent::mergeParams($defaultParams, $passedParams);
return $this->rawParams;
}
/**
* 加载一个模块:
*
* Load a module.
*
* @access public
* @return bool|object if the module object of die.
*/
public function loadModule()
{
/* 不能直接请求基类的方法 Cannot call methods of base control class. */
if(method_exists('Control', $this->methodName))
{
echo 'Cannot call methods of base control class.';
return false;
}
return parent::loadModule();
}
}
+3 -3
View File
@@ -1925,7 +1925,7 @@ class baseSQL
}
else
{
$condition = ctype_alnum((string)$arg1) ? '`' . $arg1 . '`' : $arg1;
$condition = (is_string($arg1) && ctype_alnum($arg1)) ? '`' . $arg1 . '`' : $arg1;
}
if(!$this->inMark) $this->sql .= ' ' . DAO::WHERE ." $condition ";
@@ -1944,7 +1944,7 @@ class baseSQL
public function andWhere($condition, $addMark = false)
{
if($this->inCondition and !$this->conditionIsTrue) return $this;
if(ctype_alnum($condition)) $condition = '`' . $condition . '`';
if(is_string($condition) && ctype_alnum($condition)) $condition = '`' . $condition . '`';
$mark = $addMark ? '(' : '';
$this->sql .= " AND {$mark} $condition ";
@@ -1962,7 +1962,7 @@ class baseSQL
public function orWhere($condition)
{
if($this->inCondition and !$this->conditionIsTrue) return $this;
if(ctype_alnum($condition)) $condition = '`' . $condition . '`';
if(is_string($condition) && ctype_alnum($condition)) $condition = '`' . $condition . '`';
$this->sql .= " OR $condition ";
return $this;
+3 -3
View File
@@ -1310,12 +1310,12 @@ EOT;
elseif(is_bool($value))
{
$value = $value ? 'true' : 'false';
$js .= "{$prefix}{$key} = $value;";
$js .= "{$prefix}{$key} = $value;";
}
else
{
$value = addslashes($value);
$js .= "{$prefix}{$key} = '{$value}';";
$value = empty($value) ? '' : addslashes($value);
$js .= "{$prefix}{$key} = '{$value}';";
}
$js .= static::end($newline = false);
echo $js;
+47 -7
View File
@@ -256,10 +256,14 @@ class dbh
public function formatDmSQL($sql)
{
$sql = trim($sql);
/* '\\\\n' try to compatible screen json like \u0232\\nBug. */
$sql = str_replace(array('\\\\n', '\r', '\n'), ' ', $sql);
$sql = $this->formatFunction($sql);
if(defined('IN_UPGRADE'))
{
$sql = $this->processDmChangeColumn($sql);
$sql = $this->processDmTableIndex($sql);
}
$actionPos = strpos($sql, ' ');
$action = strtoupper(substr($sql, 0, $actionPos));
$setPos = 0;
@@ -313,7 +317,7 @@ class dbh
}
elseif(stripos($sql, 'CREATE UNIQUE INDEX') === 0 || stripos($sql, 'CREATE INDEX') === 0)
{
preg_match('/ON\ +[0-9a-zA-Z\_\.]+\`([0-9a-zA-Z\_]+)\`/', $sql, $matches);
preg_match('/ON\ +`([0-9a-zA-Z_]+)`/', $sql, $matches);
$tableName = str_replace($this->config->prefix, '', $matches);
$sql = preg_replace('/INDEX\ +\`/', 'INDEX `' . strtolower($tableName[1]) . '_', $sql);
@@ -372,6 +376,32 @@ class dbh
}
}
/**
* Format dm table index.
*
* @param string $sql
* @access public
* @return string
*/
public function processDmTableIndex($sql)
{
if(strpos($sql, 'DROP INDEX') === FALSE) return $sql;
return preg_replace('/DROP INDEX `(\w+)` ON `zt_(\w+)`/', 'DROP INDEX IF EXISTS `$2_$1`', $sql);
}
/**
* Format dm change column.
*
* @param string $sql
* @access public
* @return string
*/
public function processDmChangeColumn($sql)
{
if(strpos($sql, 'CHANGE COLUMN') === FALSE) return $sql;
return preg_replace('/ALTER TABLE `([^`]+)` CHANGE COLUMN `([^`]+)` `([^`]+)` (\w+)/', 'ALTER TABLE `$1` RENAME COLUMN `$2` TO `$3`;', $sql);
}
/**
* Format function.
*
@@ -469,7 +499,16 @@ class dbh
foreach($datetimeMatch[0] as $match) $sql = str_replace($match, $match . '(0)', $sql);
}
if(strpos($sql, "ALTER TABLE") !== false) $sql = $this->convertAlterTableSql($sql);
if(strpos($sql, "ALTER TABLE") === 0)
{
$sql = $this->convertAlterTableSql($sql);
if(stripos($sql, "ADD") !== false)
{
// 使用正则表达式匹配并去除 "AFTER" 关键字及其后面的内容
$pattern = "/\s+AFTER\s+.+$/i";
$sql = preg_replace($pattern, "", $sql);
}
}
}
return $sql;
@@ -486,10 +525,11 @@ class dbh
{
// 解析REPLACE INTO语句,提取出表名、字段和值
$matches = [];
preg_match('/^REPLACE\s+INTO\s+`?([\w_]+)`?\s*\((.*)\)\s+VALUES\s*\((.*?)\)\s*$/i', $sql, $matches);
preg_match('/^REPLACE\s+INTO\s+`?([\w_]+)`?\s*\((.*)\)\s+VALUES\s*\(([^()]+)\)\s*$/i', $sql, $matches);
if(empty($matches)) return $sql;
$table_name = $matches[1];
$columns = array_map('trim', explode(',', $matches[2]));
$values = array_map('trim', explode(', ', $matches[3]));
$columns = array_map('trim', explode(',', $matches[2]));
$values = array_map('trim', explode(', ', $matches[3]));
if($table_name == '' or $columns == '' or $values == '') return $sql;
// 构造SELECT语句,查询数据是否存在
+4 -4
View File
@@ -218,7 +218,7 @@ class mobile
'iPad' => 'iPad|iPad.*Mobile',
// Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
// @see #442
'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
// http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\b',
@@ -756,11 +756,11 @@ class mobile
return self::$uaHttpHeaders;
}
/**
* Set CloudFront headers
* http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
*
*
* @param array $cfHeaders List of HTTP headers
*
* @return boolean If there were CloudFront headers to be set
@@ -1213,7 +1213,7 @@ class mobile
*/
public function match($regex, $userAgent = null)
{
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : ($this->userAgent ? $this->userAgent : '')), $matches);
// If positive match is found, store the results for debug.
if ($match) {
$this->matchingRegex = $regex;
+36
View File
@@ -20,6 +20,28 @@ helper::import(dirname(dirname(__FILE__)) . '/base/pager/pager.class.php');
*/
class pager extends basePager
{
/**
* 分页查询起始偏移量。
* offset
*
* @var float
* @access public
*/
public $offset = 0;
/**
* 设置分页查询起始偏移量。
* Set offset of paging query.
*
* @param int $offset
* @access public
* @return void
*/
public function setOffset($offset)
{
$this->offset = $offset;
}
/**
* 设置模块名。
* Set the $moduleName property.
@@ -85,6 +107,20 @@ class pager extends basePager
if($this->app->isFlow) unset($this->params['module']);
}
/**
* 创建limit语句。
* Create the limit string.
*
* @access public
* @return string
*/
public function limit()
{
$limit = '';
if($this->pageTotal > 1) $limit = ' lImiT ' . ($this->offset + ($this->pageID - 1) * $this->recPerPage) . ", $this->recPerPage";
return $limit;
}
/**
* Show pager.
*
+28 -1
View File
@@ -257,7 +257,7 @@ class zdb
/* Create a value sql. */
$value = array_values($row);
$value = array_map('addslashes', $value);
$value = $this->addslashes($value);
$value = join("','", $value);
$value = "'" . $value . "'";
$sql = "INSERT INTO `$table`($keys) VALUES (" . $value . ");\n";
@@ -367,4 +367,31 @@ class zdb
return $return;
}
}
/**
* Add slashes for string or string list.
*
* @param string|string[] $data
* @return string|string[]
*/
public function addslashes($data)
{
if(is_string($data)) return addslashes($data);
if((function_exists('array_is_list') && array_is_list($data)) || (is_array($data) && array_keys($data) === array_keys(array_keys($data))))
{
$result = array();
foreach($data as $item)
{
if(is_string($item))
$result[] = addslashes($item);
elseif(is_null($item))
$result[] = null;
else
$result[] = $item;
}
return $result;
}
return $data;
}
}
+21
View File
@@ -0,0 +1,21 @@
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Gt
values:
- "7"
containers:
- name: docker
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
+17
View File
@@ -0,0 +1,17 @@
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Lt
values:
- "8"
- weight: 50
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: DoesNotExist
+21
View File
@@ -0,0 +1,21 @@
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Gt
values:
- "7"
containers:
- name: docker
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
+36
View File
@@ -0,0 +1,36 @@
metadata:
labels:
ci-cpu-level: high
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Gt
values:
- "7"
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: ci-cpu-level
operator: In
values:
- high
topologyKey: "kubernetes.io/hostname"
containers:
- name: docker
image: docker:23.0.6-dind-alpine3.17
command: ["sleep"]
args: ["99d"]
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
+319
View File
@@ -0,0 +1,319 @@
#!/bin/bash
set -e
phpVer="7.4"
installRector="false"
codeRootDir=$PWD
composerDir="$(dirname "$(realpath "$0")")"
outputDir="$PWD/build"
helper() {
cat << EOF
Usage: $0 -p version dirs...
Arguments:
-p php版本号,如 7.4
可以指定多个版本,用逗号分隔,如 7.4,7.0,5.4
-i 在 misc 目录执行 composer install, 安装 rector
-r 指定要降级的代码根目录, 默认为当前目录
-o 降级补丁包输出目录
EOF
}
# 处理命令行参数, 获取要降级的目录
[ $# -eq 0 ] && helper
while getopts "ir:p:o:" opt; do
case $opt in
"p")
phpVer=$OPTARG
;;
"r")
codeRootDir=$(realpath "$OPTARG")
;;
"i")
installRector="true"
;;
"o")
outputDir=$OPTARG
;;
*)
helper
exit 1
;;
esac
done
shift $((OPTIND - 1))
if [ "$#" -eq 0 ];then
echo "need at least one file or directory"
exit 2
fi
# 处理降级目录路径
downGradeDirs=()
for d in "$@"
do
targetDir="$codeRootDir/$d"
test -d "$targetDir" || (echo "$d ($targetDir) is not a directory, abort."; exit 2)
downGradeDirs+=("${targetDir}")
done
# 结束命令行参数处理
excludeRegexList=(
module/holiday/ext/
lib/purifier/HTMLPurifier.autoload-legacy.php
lib/sqlparser/vendor/
)
##################################
# 在非容器环境,返回 cpu 核数减一
# 在容器环境,如未对 cpu 做限制,返回宿主机核数减一,否则按实际限制的 cpu 核数
##################################
quotaFile="/sys/fs/cgroup/cpu.max"
getCpuQuota() {
if [ -f $quotaFile ];then
quota=$(cut -d ' ' -f 1 $quotaFile)
period=$(cut -d ' ' -f 2 $quotaFile)
if [ "$quota" = "max" ];then
echo $(($(nproc)-1))
return
else
echo $((quota/period))
return
fi
else
echo $(($(nproc)-1))
return
fi
}
# 检查要降级版本的 php 命令行是否存在,将用于校验语法
existsPHPCli() {
phpVersion="$1"
which php"${phpVersion}" >/dev/null
}
#########################################
# 执行降级命令
# 参数:
# 1. 降级版本, 如 7.4, 7.0
# 2. 关闭缓存 (可选项), nocache
# 3. 并行执行 (可选项), parallel
# * 降级目录列表
# 说明
# 1. 由于降级命令有可能会发生异常,故设置了重试,
# 在函数运行时,缓存目录不变,故重试时会减少部分时间
# 2. 并行执行的个数,根据 cpu 最大核数减一处理,如果是容器环境,按分配的核数
# 并行执行需要安装 parallel 包
##########################################
maxRectorRetries=3
downGradeDir() {
rectorCmd="rector"
export PHP_VERSION=${1/./}
shift
if [ "$1" = "nocache" ];then
rectorCmd="rector-nocache"
shift
fi
withParallel="false"
if [ "$1" = "parallel" ];then
withParallel="true"
shift
fi
downDirs=("$@")
echo "set PHP_VERSION to $PHP_VERSION"
echo "do downgrade on dir ${downDirs[*]}"
lastDir=$PWD
cd "$composerDir" || exit
rectorResult=0
set +e
for ((i=0;i<maxRectorRetries;i++)) {
if [ "$withParallel" = "true" ];then
quotaCpu=$(getCpuQuota)
parallel -j "$quotaCpu" -k composer "${rectorCmd}" ::: "${downDirs[@]}"
else
composer ${rectorCmd} -- "${downDirs[@]}"
fi
rectorResult="$?"
if [ "$rectorResult" -eq 0 ];then
break
fi
}
set -e
if [ "$rectorResult" -ne 0 ];then
echo "Rector failed"
return $rectorResult
fi
cd "$lastDir" || exit
}
############################
# 校验单个 php 文件语法
# 返回值
# 0 没有语法错误
# 1 语法异常,或是执行时异常
############################
syntaxCheck() {
phpVersion="$1"
phpFilePath="$2"
phpCli=$(which php"${phpVersion}")
$phpCli -l "$phpFilePath" | grep -v 'No syntax errors detected' && return 1 || return 0
}
########################################
# 确保php文件语法正确
# 第一次校验失败后,对文件所在目录执行一次降级
# 再做第二次校验,如继续失败,返回错误
########################################
ensureSyntaxPassed() {
phpVersion="$1"
phpFilePath="$2"
beforeMD5=$(md5sum "$phpFilePath" | awk '{print $1}')
if syntaxCheck "$phpVersion" "$phpFilePath";then
echo "Syntax OK, $phpFilePath"
else
downGradeDir "$phpVersion" "nocache" "$(dirname "$phpFilePath")"
afterMD5=$(md5sum "$phpFilePath" | awk '{print $1}')
if ! syntaxCheck "$phpVersion" "$phpFilePath";then
echo "downgrade failed"
echo "md5 compare (before:$beforeMD5) (after:$afterMD5)"
return 1
else
echo "Syntax OK, $phpFilePath"
fi
fi
}
#########################################
# 将变更的文件打包
# 判断条件为文件修改时间晚于脚本开始执行的时间
#########################################
archiveChangedFiles() {
phpVersion="$1"
pointTime=$2
archiveDir=$3
find "$archiveDir" -type f -name '*.php' -newermt "$pointTime" -printf "%P\n" > /tmp/changedFiles
lastDir=$PWD
cd "$archiveDir" || exit 1
mkdir -p build/
test -d "$outputDir" || mkdir -pv "$outputDir"
downPatchFile="${outputDir}/downgrade-php$phpVersion.tar.gz"
tar zcf "$downPatchFile" --files-from=/tmp/changedFiles
echo "Release downgrade patch file: $downPatchFile"
cd "$lastDir"
}
# 正则匹配要排除的文件,跳过校验
matchExclude() {
filePath="$1"
for reg in "${excludeRegexList[@]}"
do
if [[ "$filePath" =~ $reg ]];then
echo "true"
return
fi
done
echo "false"
}
#############################
# 对单个 php 版本降级的主函数
# 参数:
# 1. php 版本
# 2. 起始时间, 用于比较降级后变更的文件
# * 降级目录列表
# 步骤:
# 设置临时缓存目录,执行降级
# 对降级目录里所有 php 文件校验语法,确保通过
# 打包变更文件
########################################
DownGrade() {
phpVersion="$1"
pointTime="$2"
shift 2
downDirs=("$@")
RECTOR_CACHE_DIR=$(mktemp -d)
export RECTOR_CACHE_DIR
startTime="$(date +%s)"
if which parallel >/dev/null ;then
downGradeDir "$phpVersion" parallel "${downDirs[@]}"
else
for d in "${downDirs[@]}"
do
downGradeDir "$phpVersion" "$d"
done
fi
for f in $(find "${downGradeDirs[@]}" -type f -name '*.php')
do
shouldIgnore=$(matchExclude "$f")
if [ "$shouldIgnore" = "true" ];then
echo "$f is excluded"
continue
fi
ensureSyntaxPassed "$phpVersion" "$f"
done
archiveChangedFiles "$phpVersion" "$pointTime" "$codeRootDir"
test -d "$RECTOR_CACHE_DIR" && rm -rf "$RECTOR_CACHE_DIR"
endTime="$(date +%s)"
echo "downgrade to ${phpVersion} cost $((endTime-startTime)) seconds"
echo
}
# 设置脚本启动时间
startPointTime=$(date +'%Y-%m-%d %H:%M:%S')
# 执行 composer 组件安装
if [ "$installRector" = "true" ];then
lastDir=$PWD
cd "$composerDir" || exit 1
composer config -g repo.packagist composer https://mirrors.cloud.tencent.com/composer/
composer install
cd "$lastDir" || exit 1
fi
# 检查 -p 参数, 执行多版本降级或是单版本降级
if [[ "$phpVer" =~ ^.*, ]];then
IFS=',' read -r -a verList <<< "$phpVer"
for v in "${verList[@]}"
do
existsPHPCli "$v" || (echo "php${v} is not found, abort."; exit 3)
done
for v in "${verList[@]}"
do
DownGrade "$v" "$startPointTime" "${downGradeDirs[@]}"
done
else
existsPHPCli "$phpVer" || (echo "php${phpVer} is not found, abort."; exit 3)
DownGrade "$phpVer" "$startPointTime" "${downGradeDirs[@]}"
fi
# syntaxCheck "$phpVer" /code/module/pipeline/model.php
# downGradeDir "$phpVer" "${downGradeDirs[@]}"
# archiveChangedFiles "$t" "$codeRootDir"
+40 -14
View File
@@ -14,14 +14,40 @@ outputLine() {
echo "$1"
}
outputLine "构建日期 **$finishTime**"
renderGitWebUrl() {
if [ -z "$GIT_URL" ];then
return
fi
echo $GIT_URL | sed -r -e 's/^.+@/https:\/\//' -e 's/\.git$//'
}
renderTagUrl() {
GIT_WEB_BASE=$(renderGitWebUrl)
if [ -n "$GIT_WEB_BASE" ];then
echo "[${TAG_NAME}](${GIT_WEB_BASE}/src/tag/${TAG_NAME})"
else
echo ${TAG_NAME}
fi
}
renderCommitUrl() {
GIT_WEB_BASE=$(renderGitWebUrl)
if [ -n "$GIT_WEB_BASE" ];then
echo "[${GIT_COMMIT:0:7}](${GIT_WEB_BASE}/commit/${GIT_COMMIT}) ([提交历史](${GIT_WEB_BASE}/commits/tag/${TAG_NAME}))"
else
echo ${GIT_COMMIT:0:7}
fi
}
outputLine "完成时间 **$finishTime**"
blankLine
outputLine "#### Git 信息"
outputLine "* 触发 Tag: $TAG_NAME"
outputLine "* 触发 Tag: $(renderTagUrl)"
outputLine "* CommitId: ${GIT_COMMIT:0:7}"
outputLine "* CommitId: $(renderCommitUrl)"
outputLine "* 触发人: ${GIT_TAGGER_NAME}"
@@ -32,30 +58,30 @@ blankLine
subGroupPath=`echo $GIT_TAG_BUILD_GROUP | sed 's/\./\//'`
outputLine "#### 下载地址"
outputLine "##### 开源版"
outputFrame "[${PMS_VERSION} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/pmsPack/$subGroupPath/ZenTaoPMS/${PMS_VERSION}/)"
outputFrame "\t\t"
outputLine "[${PMS_VERSION} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/pmsPack/$subGroupPath/ZenTaoALM/${PMS_VERSION}/)"
outputLine "##### 企业版"
outputFrame "[${BIZ_VERSION:3} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/bizPack/$subGroupPath/ZenTaoPMS/${BIZ_VERSION}/)"
outputFrame "\t\t"
outputLine "[${BIZ_VERSION:3} 升级包 (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/bizPack/$subGroupPath/ZenTaoPMS.update/${BIZ_VERSION}/)"
outputLine "[${BIZ_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/bizPack/$subGroupPath/ZenTaoALM/${BIZ_VERSION}/)"
outputFrame "[${BIZ_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/bizPack/$subGroupPath/ZenTaoALM/${BIZ_VERSION}/)"
outputFrame "\t"
outputLine "[${BIZ_VERSION:3} 升级包 (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/bizPack/$subGroupPath/ZenTaoALM.update/${BIZ_VERSION}/)"
outputLine "##### 旗舰版"
outputFrame "[${MAX_VERSION:3} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/maxPack/$subGroupPath/ZenTaoPMS/${MAX_VERSION}/)"
outputFrame "\t\t"
outputLine "[${MAX_VERSION:3} 升级包 (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/maxPack/$subGroupPath/ZenTaoPMS.update/${MAX_VERSION}/)"
outputLine "[${MAX_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/maxPack/$subGroupPath/ZenTaoALM/${MAX_VERSION}/)"
outputFrame "[${MAX_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/maxPack/$subGroupPath/ZenTaoALM/${MAX_VERSION}/)"
outputFrame "\t"
outputLine "[${MAX_VERSION:3} 升级包 (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/maxPack/$subGroupPath/ZenTaoALM.update/${MAX_VERSION}/)"
if [ -n "$IPD_VERSION" ];then
outputLine "##### IPD版"
outputFrame "[${IPD_VERSION:3} (中文)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/ipdPack/$subGroupPath/ZenTaoPMS/${IPD_VERSION}/)"
outputFrame "\t\t"
outputLine "[${IPD_VERSION:3} (English)](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/service/rest/repository/browse/${ARTIFACT_REPOSITORY}/zentao/ipdPack/$subGroupPath/ZenTaoALM/${IPD_VERSION}/)"
fi
outputLine "##### 历史版本"
outputLine "[查看历史版本](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/#browse/browse:easycorp-snapshot)"
outputLine "[查看历史版本](${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/#browse/browse:${ARTIFACT_REPOSITORY})"
+13 -14
View File
@@ -5,8 +5,6 @@ FIELD=$2
frameCount=`echo $TAG| grep -o '_' | wc -l`
build_date=${TAG##*_}
build_id=''
if [ $frameCount -eq 3 ];then
@@ -14,19 +12,20 @@ if [ $frameCount -eq 3 ];then
fi
case $FIELD in
date)
# must 8 numbers
echo $build_date | egrep -E '^[0-9]{8}$'
;;
id)
echo $build_id
;;
group)
if [ -n "$build_id" ];then
echo "$build_date.$build_id"
else
echo "$build_date.release"
fi
case $frameCount in
1)
echo release
;;
*)
build_date=${TAG##*_}
if [ -n "$build_id" ];then
echo "$build_date.$build_id"
else
echo "$build_date.release"
fi
;;
esac
;;
type)
if [ -n "$build_id" ];then
+4 -2
View File
@@ -60,6 +60,7 @@ $config->action->objectNameFields['instance'] = 'name';
$config->action->objectNameFields['space'] = 'name';
$config->action->objectNameFields['solution'] = 'name';
$config->action->objectNameFields['artifactrepo'] = 'name';
$config->action->objectNameFields['prompt'] = 'name';
$config->action->commonImgSize = 870;
@@ -77,7 +78,7 @@ $config->action->majorList['doc'] = array('releaseddoc', 'collected');
$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,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,';
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn';
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn,disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan,editmr,removemr';
$config->action->preferredTypeNum = 10;
@@ -100,4 +101,5 @@ $config->trash->search['params']['objectID'] = array('operator' => 'include',
$config->trash->search['params']['actor'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
$config->trash->search['params']['date'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
$config->action->newPageModule = array('repo', 'mr', 'host', 'account', 'serverroom', 'instance', 'store', 'space', 'deploy', 'domain', 'service', 'gitlab', 'gitea', 'gogs', 'sonarqube', 'jenkins');
$config->action->newPageModule = array('repo', 'mr', 'host', 'account', 'serverroom', 'instance', 'store', 'space', 'deploy', 'domain', 'service', 'gitlab', 'gitea', 'gogs', 'sonarqube', 'jenkins');
$config->action->latestDateList = array('today', 'yesterday', 'thisWeek', 'lastWeek', 'thisMonth');
+11
View File
@@ -461,4 +461,15 @@ class action extends control
return true;
}
/**
* Clear dynamic records older than one month.
*
* @access public
* @return void
*/
public function cleanActions()
{
$this->action->cleanActions();
}
}
+14
View File
@@ -165,6 +165,7 @@ $lang->action->objectTypes['scene'] = 'Scene';
$lang->action->objectTypes['serverroom'] = 'IDC';
$lang->action->objectTypes['account'] = 'Account';
$lang->action->objectTypes['host'] = 'Host';
$lang->action->objectTypes['prompt'] = 'Prompt';
/* Used to describe operation history. */
$lang->action->desc = new stdclass();
@@ -289,6 +290,10 @@ $lang->action->desc->releaseddoc = '$date, 由 <strong>$actor</strong> released
$lang->action->desc->collected = '$date, 由 <strong>$actor</strong> collected <strong>$extra</strong>。' . "\n";
$lang->action->desc->uncollected = '$date, 由 <strong>$actor</strong> uncollected <strong>$extra</strong>。' . "\n";
/* AI prompts related actions. */
$lang->action->desc->published = '$date, published by <strong>$actor</strong>.' . "\n";
$lang->action->desc->unpublished = '$date, unpublished by <strong>$actor</strong>.' . "\n";
/* 用来描述应用的历史操作记录。*/
$lang->action->desc->install = '$date, installed by <strong>$actor</strong>.' . "\n";
$lang->action->desc->uninstall = '$date, uninstalled by <strong>$actor</strong>.' . "\n";
@@ -497,6 +502,9 @@ $lang->action->label->uncollected = 'uncollected';
$lang->action->label->online = 'online';
$lang->action->label->offline = 'offline';
$lang->action->label->linkhost = 'link hosts to';
$lang->action->label->published = 'Published';
$lang->action->label->unpublished = 'Unpublished';
$lang->action->label->prompt = 'Prompt';
/* Dynamic information is grouped by object. */
$lang->action->dynamicAction = new stdclass;
@@ -794,6 +802,11 @@ $lang->action->dynamicAction->repo['edited'] = 'Edit Repo';
$lang->action->dynamicAction->repo['deleted'] = 'Delete Repo';
$lang->action->dynamicAction->repo['undeleted'] = 'Undelete Repo';
$lang->action->dynamicAction->ai['created'] = 'Create prompt';
$lang->action->dynamicAction->ai['edited'] = 'Edited prompt';
$lang->action->dynamicAction->ai['published'] = 'Published prompt';
$lang->action->dynamicAction->ai['unpublished'] = 'Unpublished prompt';
/* Generate the corresponding object link. */
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
$lang->action->label->productplan = 'Plan|productplan|view|productID=%s';
@@ -835,6 +848,7 @@ $lang->action->label->stage = 'Stage|stage|browse|';
$lang->action->label->module = 'Module|tree|browse|productid=%s&type=story&currentModuleID=0&branch=all';
$lang->action->label->ticket = 'Ticket|ticket|view|id=%s';
$lang->action->label->chartgroup = 'Group';
$lang->action->label->prompt = 'Prompt|ai|promptview|id=%s';
/* Object type. */
$lang->action->search = new stdclass();
+14 -2
View File
@@ -169,7 +169,7 @@ $lang->action->objectTypes['deploy'] = 'Deploy';
$lang->action->objectTypes['service'] = 'Service';
$lang->action->objectTypes['domain'] = 'Domain';
$lang->action->objectTypes['artifactrepo'] = 'Artifact Repo';
$lang->action->objectTypes['prompt'] = 'Prompt';
/* Used to describe operation history. */
$lang->action->desc = new stdclass();
@@ -295,6 +295,10 @@ $lang->action->desc->releaseddoc = '$date, 由 <strong>$actor</strong> released
$lang->action->desc->collected = '$date, 由 <strong>$actor</strong> collected <strong>$extra</strong>。' . "\n";
$lang->action->desc->uncollected = '$date, 由 <strong>$actor</strong> uncollected <strong>$extra</strong>。' . "\n";
/* AI prompts related actions. */
$lang->action->desc->published = '$date, published by <strong>$actor</strong>.' . "\n";
$lang->action->desc->unpublished = '$date, unpublished by <strong>$actor</strong>.' . "\n";
/* 用来描述应用的历史操作记录。*/
$lang->action->desc->install = '$date, installed by <strong>$actor</strong>.' . "\n";
$lang->action->desc->uninstall = '$date, uninstalled by <strong>$actor</strong>.' . "\n";
@@ -503,7 +507,9 @@ $lang->action->label->uncollected = 'uncollected';
$lang->action->label->online = 'online';
$lang->action->label->offline = 'offline';
$lang->action->label->linkhost = 'link hosts to';
$lang->action->label->published = 'Published';
$lang->action->label->unpublished = 'Unpublished';
$lang->action->label->prompt = 'Prompt';
/* Dynamic information is grouped by object. */
$lang->action->dynamicAction = new stdclass;
@@ -801,6 +807,11 @@ $lang->action->dynamicAction->repo['edited'] = 'Edit Repo';
$lang->action->dynamicAction->repo['deleted'] = 'Delete Repo';
$lang->action->dynamicAction->repo['undeleted'] = 'Undelete Repo';
$lang->action->dynamicAction->ai['created'] = 'Create prompt';
$lang->action->dynamicAction->ai['edited'] = 'Edited prompt';
$lang->action->dynamicAction->ai['published'] = 'Published prompt';
$lang->action->dynamicAction->ai['unpublished'] = 'Unpublished prompt';
/* Generate the corresponding object link. */
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
$lang->action->label->productplan = 'Plan|productplan|view|productID=%s';
@@ -850,6 +861,7 @@ $lang->action->label->deploy = 'Deploy|deploy|view|id=%s';
$lang->action->label->domian = 'Domain|domian|view|id=%s';
$lang->action->label->service = 'Service|service|view|id=%s';
$lang->action->label->artifactrepo = 'Artifact Repo|artifactrepo|browse|';
$lang->action->label->prompt = 'Prompt|ai|promptview|id=%s';
/* Object type. */
$lang->action->search = new stdclass();
+14
View File
@@ -162,6 +162,7 @@ $lang->action->objectTypes['repo'] = 'Repo';
$lang->action->objectTypes['dataview'] = 'Data View';
$lang->action->objectTypes['privlang'] = 'Priv';
$lang->action->objectTypes['scene'] = 'Scene';
$lang->action->objectTypes['prompt'] = 'Prompt';
/* Used to describe operation history. */
$lang->action->desc = new stdclass();
@@ -311,6 +312,10 @@ $lang->action->desc->autobackup = '$date, backed up of system' . "\
$lang->action->desc->autorestore = '$date, restored by system.' . "\n";
$lang->action->desc->deleteexpiredbackup = '$date, deleted the expired automatic backups by system.' . "\n";
/* AI prompts related actions. */
$lang->action->desc->published = '$date, published by <strong>$actor</strong>.' . "\n";
$lang->action->desc->unpublished = '$date, unpublished by <strong>$actor</strong>.' . "\n";
/* Used to display dynamic information. */
$lang->action->label = new stdclass();
$lang->action->label->install = 'install ';
@@ -494,6 +499,9 @@ $lang->action->label->saveddraft = 'save draft';
$lang->action->label->releaseddoc = 'released';
$lang->action->label->collected = 'collected';
$lang->action->label->uncollected = 'uncollected';
$lang->action->label->published = 'Published';
$lang->action->label->unpublished = 'Unpublished';
$lang->action->label->prompt = 'Prompt';
/* Dynamic information is grouped by object. */
$lang->action->dynamicAction = new stdclass();
@@ -791,6 +799,11 @@ $lang->action->dynamicAction->repo['edited'] = 'Edit Repo';
$lang->action->dynamicAction->repo['deleted'] = 'Delete Repo';
$lang->action->dynamicAction->repo['undeleted'] = 'Undelete Repo';
$lang->action->dynamicAction->ai['created'] = 'Create prompt';
$lang->action->dynamicAction->ai['edited'] = 'Edited prompt';
$lang->action->dynamicAction->ai['published'] = 'Published prompt';
$lang->action->dynamicAction->ai['unpublished'] = 'Unpublished prompt';
/* Generate the corresponding object link. */
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
$lang->action->label->productplan = 'Plan|productplan|view|productID=%s';
@@ -832,6 +845,7 @@ $lang->action->label->stage = 'Stage|stage|browse|';
$lang->action->label->module = 'Module|tree|browse|productid=%s&type=story&currentModuleID=0&branch=all';
$lang->action->label->ticket = 'Ticket|ticket|view|id=%s';
$lang->action->label->chartgroup = 'Group';
$lang->action->label->prompt = 'Prompt|ai|promptview|id=%s';
/* Object type. */
$lang->action->search = new stdclass();
+14
View File
@@ -169,6 +169,7 @@ $lang->action->objectTypes['deploy'] = '发布';
$lang->action->objectTypes['service'] = '服务';
$lang->action->objectTypes['domain'] = '域名';
$lang->action->objectTypes['artifactrepo'] = '制品库';
$lang->action->objectTypes['prompt'] = '提词';
/* 用来描述操作历史记录。*/
$lang->action->desc = new stdclass();
@@ -293,6 +294,10 @@ $lang->action->desc->releaseddoc = '$date, 由 <strong>$actor</strong> 发布 <s
$lang->action->desc->collected = '$date, 由 <strong>$actor</strong> 收藏 <strong>$extra</strong>。' . "\n";
$lang->action->desc->uncollected = '$date, 由 <strong>$actor</strong> 取消收藏 <strong>$extra</strong>。' . "\n";
/* AI 提词历史操作记录。 */
$lang->action->desc->published = '$date, 由 <strong>$actor</strong> 发布。' . "\n";
$lang->action->desc->unpublished = '$date, 由 <strong>$actor</strong> 下架。' . "\n";
/* 用来描述应用的历史操作记录。*/
$lang->action->desc->install = '$date, 由 <strong>$actor</strong> 安装。' . "\n";
$lang->action->desc->uninstall = '$date, 由 <strong>$actor</strong> 删除。' . "\n";
@@ -499,6 +504,9 @@ $lang->action->label->uncollected = '取消收藏了';
$lang->action->label->online = '上架了';
$lang->action->label->offline = '下架了';
$lang->action->label->linkhost = '主机关联到';
$lang->action->label->published = '发布了';
$lang->action->label->unpublished = '下架了';
$lang->action->label->prompt = '提词';
/* 动态信息按照对象分组 */
$lang->action->dynamicAction = new stdclass();
@@ -796,6 +804,11 @@ $lang->action->dynamicAction->repo['edited'] = '编辑代码库';
$lang->action->dynamicAction->repo['deleted'] = '删除代码库';
$lang->action->dynamicAction->repo['undeleted'] = '还原代码库';
$lang->action->dynamicAction->ai['created'] = '创建提词';
$lang->action->dynamicAction->ai['edited'] = '编辑提词';
$lang->action->dynamicAction->ai['published'] = '发布提词';
$lang->action->dynamicAction->ai['unpublished'] = '下架提词';
/* 用来生成相应对象的链接。*/
$lang->action->label->product = $lang->productCommon . '|product|view|productID=%s';
$lang->action->label->productplan = "计划|productplan|view|productID=%s";
@@ -845,6 +858,7 @@ $lang->action->label->deploy = '上线|deploy|view|id=%s';
$lang->action->label->domian = '域名|domian|view|id=%s';
$lang->action->label->service = '服务|service|view|id=%s';
$lang->action->label->artifactrepo = '制品库|artifactrepo|browse|';
$lang->action->label->prompt = '提词|ai|promptview|id=%s';
/* Object type. */
$lang->action->search = new stdclass();
+127 -67
View File
@@ -71,6 +71,18 @@ class actionModel extends model
$this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec();
$actionID = $this->dao->lastInsertID();
$hasRecentTable = true;
if(defined('IN_UPGRADE') and IN_UPGRADE)
{
$fromVersion = $this->loadModel('setting')->getItem('owner=system&module=common&section=global&key=version');
if(is_numeric($fromVersion[0]) and version_compare($fromVersion, '18.6', '<')) $hasRecentTable = false;
if(strpos($fromVersion, 'pro') !== false) $hasRecentTable = false;
if(strpos($fromVersion, 'biz') !== false and version_compare($fromVersion, 'biz8.6', '<')) $hasRecentTable = false;
if(strpos($fromVersion, 'max') !== false and version_compare($fromVersion, 'max4.6', '<')) $hasRecentTable = false;
if(strpos($fromVersion, 'ipd') !== false and version_compare($fromVersion, 'ipd1.0.1', '<')) $hasRecentTable = false;
}
if($hasRecentTable) $this->dao->insert(TABLE_ACTIONRECENT)->data($action)->autoCheck()->exec();
if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $objectType);
/* Call the message notification function. */
@@ -79,6 +91,9 @@ class actionModel extends model
/* Add index for global search. */
$this->saveIndex($objectType, $objectID, $actionType);
$changeFunc = 'after' . ucfirst($objectType);
if(method_exists($this, $changeFunc)) call_user_func_array(array($this, $changeFunc), array($action, $actionID));
return $actionID;
}
@@ -896,6 +911,13 @@ class actionModel extends model
}
$this->dao->insert(TABLE_HISTORY)->data($change)->exec();
}
if(isset($this->session->calllbackActionList[$actionID]))
{
$callbackMethod = $this->session->calllbackActionList[$actionID];
unset($this->session->calllbackActionList[$actionID]);
if(method_exists($this, $callbackMethod)) call_user_func_array(array($this, $callbackMethod), array($actionID));
}
}
/**
@@ -1300,7 +1322,7 @@ class actionModel extends model
* @param string $account
* @param string $period
* @param string $orderBy
* @param object $pager
* @param int $limit
* @param string|int $productID all|int(like 123)|notzero all => include zero, notzero, greater than 0
* @param string|int $projectID same as productID
* @param string|int $executionID same as productID
@@ -1309,8 +1331,10 @@ class actionModel extends model
* @access public
* @return array
*/
public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $pager = null, $productID = 'all', $projectID = 'all', $executionID = 'all', $date = '', $direction = 'next')
public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $limit = 50, $productID = 'all', $projectID = 'all', $executionID = 'all', $date = '', $direction = 'next')
{
$this->cleanActions();
/* Computer the begin and end date of a period. */
$beginAndEnd = $this->computeBeginAndEnd($period);
extract($beginAndEnd);
@@ -1321,34 +1345,33 @@ class actionModel extends model
if(!$this->app->user->admin)
{
$aclViews = isset($this->app->user->rights['acls']['views']) ? $this->app->user->rights['acls']['views'] : array();
if($productID == 'all') $authedProducts = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['product']))) ? $this->app->user->view->products : '0';
if($projectID == 'all') $authedProjects = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['project']))) ? $this->app->user->view->projects : '0';
if($executionID == 'all') $authedExecutions = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['execution']))) ? $this->app->user->view->sprints : '0';
if(empty($authedProducts)) $authedProducts = '0';
if($productID == 'all') $grantedProducts = empty($aclViews) || !empty($aclViews['product']) ? $this->app->user->view->products : '0';
if($projectID == 'all') $grantedProjects = empty($aclViews) || !empty($aclViews['project']) ? $this->app->user->view->projects : '0';
if($executionID == 'all') $grantedExecutions = empty($aclViews) || !empty($aclViews['execution']) ? $this->app->user->view->sprints : '0';
if(empty($grantedProducts)) $grantedProducts = '0';
if($productID == 'all' and $projectID == 'all')
{
$productCondition = '';
foreach(explode(',', $authedProducts) as $product) $productCondition = empty($productCondition) ? "(execution = '0' and project = '0' and (product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
foreach(explode(',', $grantedProducts) as $product) $productCondition = empty($productCondition) ? "(execution = '0' and project = '0' and (product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
if(!empty($productCondition)) $productCondition .= '))';
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($authedProjects) . ')';
$executionCondition = isset($authedExecutions) ? "(execution != 0 and execution " . helper::dbIN($authedExecutions) . ')' : "(execution != 0 and execution = '$executionID')";
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($grantedProjects) . ')';
$executionCondition = isset($grantedExecutions) ? "(execution != 0 and execution " . helper::dbIN($grantedExecutions) . ')' : "(execution != 0 and execution = '$executionID')";
}
elseif($productID == 'all' and is_numeric($projectID))
{
$products = $this->loadModel('product')->getProductPairsByProject($projectID);
$executions = $this->loadModel('execution')->getPairs($projectID) + array(0 => 0);
$executions = $this->loadModel('execution')->fetchPairs($projectID) + array(0 => 0);
$authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions);
$grantedExecutions = isset($grantedExecutions) ? array_intersect(array_keys($executions), explode(',', $grantedExecutions)) : array_keys($executions);
$productCondition = '';
foreach(array_keys($products) as $product) $productCondition = empty($productCondition) ? "(execution = '0' and project = '0' and (product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'";
if(!empty($productCondition)) $productCondition .= '))';
$projectCondition = "(execution = '0' and project = '$projectID')";
$executionCondition = "(execution != '0' and execution " . helper::dbIN($authedExecutions) . ')';
$executionCondition = "(execution != '0' and execution " . helper::dbIN($grantedExecutions) . ')';
}
elseif(is_numeric($productID) and $projectID == 'all')
{
@@ -1356,12 +1379,12 @@ class actionModel extends model
$projects = $this->product->getProjectPairsByProduct($productID);
$executions = $this->product->getExecutionPairsByProduct($productID) + array(0 => 0);
$authedProjects = array_intersect(array_keys($projects), explode(',', $authedProjects));
$authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions);
$grantedProjects = array_intersect(array_keys($projects), explode(',', $grantedProjects));
$grantedExecutions = isset($grantedExecutions) ? array_intersect(array_keys($executions), explode(',', $grantedExecutions)) : array_keys($executions);
$productCondition = "(execution = '0' and project = '0' and product like '%,$productID,%')";
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($authedProjects) . ')';
$executionCondition = "(execution != '0' and execution " . helper::dbIN($authedExecutions) . ')';
$projectCondition = "(execution = '0' and project != '0' and project " . helper::dbIN($grantedProjects) . ')';
$executionCondition = "(execution != '0' and execution " . helper::dbIN($grantedExecutions) . ')';
}
$condition = "((product =',0,' or product = '0' or product=',,') AND project = '0' AND execution = '0')";
@@ -1384,46 +1407,58 @@ class actionModel extends model
if($this->app->getMethodName() == 'dynamic') $beginDate = $year - 1 . '-01-01';
}
$programCondition = empty($this->app->user->view->programs) ? '0' : $this->app->user->view->programs;
if(is_numeric($projectID))
{
$openedDate = $this->dao->select('openedDate')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetch('openedDate');
$beginDate = $openedDate > $beginDate ? $openedDate : $beginDate;
}
$efforts = $this->dao->select('id')->from(TABLE_EFFORT)->where($condition)->fetchPairs();
$efforts = !empty($efforts) ? implode(',', $efforts) : 0;
$condition = "(($condition) OR `objectType` IN ('doc', 'doclib'))";
$noMultipleExecutions = $this->dao->select('id')->from(TABLE_PROJECT)->where('multiple')->eq(0)->andWhere('type')->in('sprint,kanban')->fetchPairs('id', 'id');
$condition = "(`objectType` IN ('doc', 'doclib') OR ($condition)) AND `objectType` NOT IN ('program', 'effort', 'execution')";
if($noMultipleExecutions) $condition .= " OR (`objectID` NOT " . helper::dbIN($noMultipleExecutions) . " AND `objectType` = 'execution')";
$programCondition = empty($this->app->user->view->programs) ? '0' : $this->app->user->view->programs;
$condition .= " OR (`objectID` in ($programCondition) AND `objectType` = 'program')";
$efforts = $this->dao->select('id')->from(TABLE_EFFORT)
->where($condition)
->beginIF($period != 'all')
->beginIF(isset($begin))->andWhere('date')->gt($begin)->fi()
->beginIF(isset($end))->andWhere('date')->lt($end)->fi()
->fi()
->beginIF($beginDate)->andWhere('date')->ge($beginDate)->fi()
->fetchPairs();
$efforts = !empty($efforts) ? implode(',', $efforts) : 0;
$condition .= " OR (`objectID` in ($efforts) AND `objectType` = 'effort')";
$condition = "($condition)";
/* Get actions. */
$actions = $this->dao->select('*')->from(TABLE_ACTION)
$actionTable = in_array($period, $this->config->action->latestDateList) ? TABLE_ACTIONRECENT : TABLE_ACTION;
$actions = $this->dao->select('*')->from($actionTable)
->where('objectType')->notIN($this->config->action->ignoreObjectType4Dynamic)
->beginIF($this->config->vision == 'lite')->andWhere('objectType')->notin('product')->fi()
->beginIF($this->config->systemMode == 'light')->andWhere('objectType')->notin('program')->fi()
->andWhere('vision')->eq($this->config->vision)
->beginIF($period != 'all')->andWhere('date')->gt($begin)->fi()
->beginIF($period != 'all')->andWhere('date')->lt($end)->fi()
->beginIF($period != 'all')
->andWhere('date')->gt($begin)
->andWhere('date')->lt($end)
->fi()
->beginIF($date)->andWhere('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")->fi()
->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
->beginIF($beginDate)->andWhere('date')->ge($beginDate)->fi()
->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
->beginIF(is_numeric($productID))->andWhere('product')->like("%,$productID,%")->fi()
->andWhere('1=1', true)
->beginIF(is_numeric($projectID))->andWhere('project')->eq($projectID)->fi()
->beginIF(!empty($executions))->andWhere('execution')->in(array_keys($executions))->fi()
->beginIF(is_numeric($executionID))->andWhere('execution')->eq($executionID)->fi()
->markRight(1)
/* Types excluded from Lite. */
->beginIF($this->config->vision == 'lite')->andWhere('objectType')->notin('product')->fi()
->beginIF($this->config->systemMode == 'light')->andWhere('objectType')->notin('program')->fi()
->beginIF($productID == 'notzero')->andWhere('product')->gt(0)->andWhere('product')->notlike('%,0,%')->fi()
->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi()
->beginIF($executionID == 'notzero')->andWhere('execution')->gt(0)->fi()
->andWhere($condition)
->beginIF($actionCondition)->andWhere("($actionCondition)")->fi()
/* Filter out client login/logout actions. */
->andWhere('action')->notin('disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan,editmr,removemr')
->orderBy($orderBy)
->page($pager)
->limit($limit)
->fetchAll();
if(!$actions) return array();
@@ -1464,13 +1499,13 @@ class actionModel extends model
* @param array $executions
* @param int $queryID
* @param string $orderBy
* @param object $pager
* @param int $limit
* @param string $date
* @param string $direction
* @access public
* @return array
*/
public function getDynamicBySearch($products, $projects, $executions, $queryID, $orderBy = 'date_desc', $pager = null, $date = '', $direction = 'next')
public function getDynamicBySearch($products, $projects, $executions, $queryID, $orderBy = 'date_desc', $limit = 50, $date = '', $direction = 'next')
{
$query = $queryID ? $this->loadModel('search')->getQuery($queryID) : '';
@@ -1519,7 +1554,7 @@ class actionModel extends model
if($this->config->vision == 'lite') $actionQuery .= " AND objectType != 'product'";
$actionQuery .= " AND vision = '" . $this->config->vision . "'";
$actions = $this->getBySQL($actionQuery, $orderBy, $pager);
$actions = $this->getBySQL($actionQuery, $orderBy, $limit);
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'action');
if(!$actions) return array();
@@ -1531,11 +1566,11 @@ class actionModel extends model
*
* @param string $sql
* @param string $orderBy
* @param object $pager
* @param int $limit
* @access public
* @return array
*/
public function getBySQL($sql, $orderBy, $pager = null)
public function getBySQL($sql, $orderBy, $limit = 50)
{
$actionCondition = $this->getActionCondition();
if(is_array($actionCondition)) return array();
@@ -1544,7 +1579,7 @@ class actionModel extends model
->where($sql)
->beginIF(!empty($actionCondition))->andWhere("($actionCondition)")->fi()
->orderBy($orderBy)
->page($pager)
->limit($limit)
->fetchAll();
}
@@ -2068,22 +2103,16 @@ class actionModel extends model
$period = strtolower($period);
if($period == 'all') return array('begin' => '1970-1-1', 'end' => '2109-1-1');
if($period == 'today') return array('begin' => $today, 'end' => $tomorrow);
if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today);
if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday);
if($period == 'latest3days')return array('begin' => $twoDaysAgo, 'end' => $tomorrow);
if($period == 'all') return array('begin' => '1970-1-1', 'end' => LONG_TIME);
if($period == 'today') return array('begin' => $today, 'end' => $tomorrow);
if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today);
if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday);
if($period == 'latest3days') return array('begin' => $twoDaysAgo, 'end' => $tomorrow);
if($period == 'lastweek') return date::getLastWeek();
if($period == 'thismonth') return date::getThisMonth();
if($period == 'lastmonth') return date::getLastMonth();
/* If the period is by week, add the end time to the end date. */
if($period == 'thisweek' or $period == 'lastweek')
{
$func = "get$period";
extract(date::$func());
return array('begin' => $begin, 'end' => $end);
}
if($period == 'thismonth') return date::getThisMonth();
if($period == 'lastmonth') return date::getLastMonth();
return date::getThisWeek();
}
/**
@@ -2226,21 +2255,21 @@ class actionModel extends model
if($action->objectType == 'case')
{
$case = $this->dao->select('*')->from(TABLE_CASE)->where('id')->eq($action->objectID)->fetch();
if($case->scene)
$caseScene = $this->dao->select('scene')->from(TABLE_CASE)->where('id')->eq($action->objectID)->fetch('scene');
if($caseScene)
{
$scene = $this->dao->select('*')->from(VIEW_SCENECASE)->where('id')->eq($case->scene)->fetch();
$scene = $this->loadModel('testcase')->getSceneByID($caseScene);
if($scene->deleted) return print(js::error($this->lang->action->refusecase));
}
}
if($action->objectType == 'scene')
{
$scene = $this->dao->select('*')->from("zt_scene")->where('id')->eq($action->objectID)->fetch();
$scene = $this->loadModel('testcase')->getSceneByID($action->objectID);
if($scene->parent)
{
$scenerow = $this->dao->select('*')->from(VIEW_SCENECASE)->where('id')->eq($scene->parent)->fetch();
if($scenerow->deleted) return print(js::error($this->lang->action->refusescene));
$parentScene = $this->testcase->getSceneByID($scene->parent);
if($parentScene->deleted) return print(js::error($this->lang->action->refusescene));
}
}
@@ -2368,7 +2397,8 @@ class actionModel extends model
if($dateGroup)
{
$lastDateActions = $this->dao->select('*')->from(TABLE_ACTION)->where($this->session->actionQueryCondition)->andWhere("(LEFT(`date`, 10) = '" . substr($action->originalDate, 0, 10) . "')")->orderBy($this->session->actionOrderBy)->fetchAll('id');
$lastDate = date(DT_DATE1, $timeStamp);
$lastDateActions = $this->dao->select('*')->from(TABLE_ACTION)->where('`date`')->ge($lastDate)->andWhere('`date`')->le("{$lastDate} 23:59:59")->andWhere($this->session->actionQueryCondition)->orderBy($this->session->actionOrderBy)->fetchAll('id');
if(count($dateGroup[$date]) < count($lastDateActions))
{
unset($dateGroup[$date]);
@@ -2412,11 +2442,13 @@ class actionModel extends model
$condition = $this->session->actionQueryCondition;
/* Remove date condition for direction. */
$condition = preg_replace("/AND +date[\<\>]'\d{4}\-\d{2}\-\d{2}'/", '', $condition);
$count = $this->dao->select('count(*) as count')->from(TABLE_ACTION)->where($condition)
->andWhere('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")
->fetch('count');
return $count > 0;
$condition = preg_replace("/AND +[`]?date[`]?[ ]*[\<\>][ |=]*'\d{4}\-\d{2}\-\d{2}'/", '', $condition);
$actions = $this->dao->select('id')->from(TABLE_ACTION)
->where('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")
->andWhere($condition)
->limit(1)
->fetch('id');
return !empty($actions);
}
/**
@@ -2628,4 +2660,32 @@ class actionModel extends model
$this->create($deletedAction->objectType, $deletedAction->objectID, 'undeleted');
}
}
/**
* Clear dynamic records older than one month.
*
* @access public
* @return void
*/
public function cleanActions()
{
$lastMonth = date('Y-m-d', strtotime('-1 month'));
$this->dao->delete()->from(TABLE_ACTIONRECENT)->where('date')->lt($lastMonth)->exec();
return !dao::isError();
}
/**
* Get dynamic count.
*
* @access public
* @return void
*/
public function getDynamicCount()
{
$condition = $this->session->actionQueryCondition;
$count = $this->dao->select('count(1) as count')->from(TABLE_ACTION)
->where($condition)
->fetch('count');
return $count;
}
}
+2
View File
@@ -16,6 +16,7 @@ $config->admin->menuGroup['dev'] = array('dev', 'entry', 'editor');
$config->admin->menuGroup['extension'] = array('extension');
$config->admin->menuGroup['convert'] = array('convert');
$config->admin->menuGroup['platform'] = array('system', 'repo', 'account', 'host', 'serverroom', 'ops', 'tree', 'domain', 'deploy', 'service');
$config->admin->menuGroup['ai'] = array('ai|adminindex', 'ai|prompts', 'ai|promptview', 'ai|conversations', 'ai|models', 'ai|editmodel', 'ai|promptassignrole', 'ai|promptselectdatasource', 'ai|promptsetpurpose', 'ai|promptsettargetform', 'ai|promptfinalize', 'ai|promptedit');
$config->admin->menuModuleGroup['model']['custom|set'] = array('project', 'issue', 'risk', 'opportunity', 'nc');
$config->admin->menuModuleGroup['model']['custom|required'] = array('project', 'build');
@@ -84,6 +85,7 @@ $config->admin->helpURL['extension'] = 'https://www.zentao.net/book/zentaopms/53
$config->admin->helpURL['dev'] = 'https://www.zentao.net/book/zentaopms/537.html';
$config->admin->helpURL['convert'] = 'https://www.zentao.net/book/zentaopms/656.html';
$config->admin->helpURL['platform'] = 'https://www.zentao.net/book/zentaopms/656.html';
$config->admin->helpURL['ai'] = 'https://www.zentao.net/book/zentaopms/';
$config->admin->navsGroup['feature']['my'] = ',todo,block,';
$config->admin->navsGroup['feature']['product'] = ',product,story,productplan,release,';
+7
View File
@@ -183,6 +183,8 @@ $lang->admin->menuSetting['convert']['name'] = 'Data Import';
$lang->admin->menuSetting['convert']['desc'] = 'Data import from third-party systems.';
$lang->admin->menuSetting['platform']['name'] = 'DevOps';
$lang->admin->menuSetting['platform']['desc'] = 'Settings of DevOps elements such as resources and environment.';
$lang->admin->menuSetting['ai']['name'] = 'AI Configurations';
$lang->admin->menuSetting['ai']['desc'] = 'Manage prompts and language models.';
$lang->admin->updateDynamics = 'Dynamics';
$lang->admin->updatePatch = 'Patch';
@@ -206,4 +208,9 @@ $lang->admin->productFeature['max'][] = 'Asset Library';
$lang->admin->productFeature['max'][] = 'QA Plan';
$lang->admin->productFeature['max'][] = 'Opportunity/Risk/Issues Management';
$lang->admin->ai = new stdclass();
$lang->admin->ai->model = 'Language Models';
$lang->admin->ai->conversation = 'Conversations';
$lang->admin->ai->prompt = 'Prompts';
include dirname(__FILE__) . '/menu.php';
+7
View File
@@ -183,6 +183,8 @@ $lang->admin->menuSetting['convert']['name'] = 'Data Import';
$lang->admin->menuSetting['convert']['desc'] = 'Data import from third-party systems.';
$lang->admin->menuSetting['platform']['name'] = 'DevOps';
$lang->admin->menuSetting['platform']['desc'] = 'Settings of DevOps elements such as resources and environment.';
$lang->admin->menuSetting['ai']['name'] = 'AI Configurations';
$lang->admin->menuSetting['ai']['desc'] = 'Manage prompts and language models.';
$lang->admin->updateDynamics = 'Dynamics';
$lang->admin->updatePatch = 'Patch';
@@ -206,4 +208,9 @@ $lang->admin->productFeature['max'][] = 'Asset Library';
$lang->admin->productFeature['max'][] = 'QA Plan';
$lang->admin->productFeature['max'][] = 'Opportunity/Risk/Issues Management';
$lang->admin->ai = new stdclass();
$lang->admin->ai->model = 'Language Models';
$lang->admin->ai->conversation = 'Conversations';
$lang->admin->ai->prompt = 'Prompts';
include dirname(__FILE__) . '/menu.php';
+7
View File
@@ -183,6 +183,8 @@ $lang->admin->menuSetting['convert']['name'] = 'Data Import';
$lang->admin->menuSetting['convert']['desc'] = 'Data import from third-party systems.';
$lang->admin->menuSetting['platform']['name'] = 'DevOps';
$lang->admin->menuSetting['platform']['desc'] = 'Settings of DevOps elements such as resources and environment.';
$lang->admin->menuSetting['ai']['name'] = 'AI Configurations';
$lang->admin->menuSetting['ai']['desc'] = 'Manage prompts and language models.';
$lang->admin->updateDynamics = 'Dynamics';
$lang->admin->updatePatch = 'Patch';
@@ -206,4 +208,9 @@ $lang->admin->productFeature['max'][] = 'Asset Library';
$lang->admin->productFeature['max'][] = 'QA Plan';
$lang->admin->productFeature['max'][] = 'Opportunity/Risk/Issues Management';
$lang->admin->ai = new stdclass();
$lang->admin->ai->model = 'Language Models';
$lang->admin->ai->conversation = 'Conversations';
$lang->admin->ai->prompt = 'Prompts';
include dirname(__FILE__) . '/menu.php';
+21
View File
@@ -48,6 +48,11 @@ $lang->admin->menuList->platform['name'] = $lang->admin->menuSetting['platform'
$lang->admin->menuList->platform['desc'] = $lang->admin->menuSetting['platform']['desc'];
$lang->admin->menuList->platform['order'] = 55;
$lang->admin->menuList->ai['name'] = $lang->admin->menuSetting['ai']['name'];
$lang->admin->menuList->ai['desc'] = $lang->admin->menuSetting['ai']['desc'];
$lang->admin->menuList->ai['link'] = 'ai|adminindex';
$lang->admin->menuList->ai['order'] = 55;
$lang->admin->menuList->system['subMenu']['mode'] = array('link' => "{$lang->custom->mode}|custom|mode|");
$lang->admin->menuList->system['subMenu']['trash'] = array('link' => "{$lang->action->trash}|action|trash|");
$lang->admin->menuList->system['subMenu']['safe'] = array('link' => "{$lang->security}|admin|safe|", 'alias' => 'checkweak,resetpwdsetting', 'links' => array('admin|resetpwdsetting|', 'admin|checkweak|'));
@@ -223,6 +228,22 @@ $lang->admin->menuList->platform['menuOrder']['25'] = 'setrules';
$lang->admin->menuList->platform['dividerMenu'] = ',plat,setrules,';
$lang->admin->menuList->ai['subMenu']['prompts'] = array('link' => "{$lang->admin->ai->prompt}|ai|prompts|", 'alias' => 'promptview,promptassignrole,promptselectdatasource,promptsetpurpose,promptsettargetform,promptfinalize,promptedit');
// $lang->admin->menuList->ai['subMenu']['conversations'] = array('link' => "{$lang->admin->ai->conversation}|ai|conversations|");
$lang->admin->menuList->ai['subMenu']['models'] = array('link' => "{$lang->admin->ai->model}|ai|models|", 'alias' => 'editmodel');
$lang->admin->menuList->ai['menuOrder']['5'] = 'prompts';
// $lang->admin->menuList->ai['menuOrder']['10'] = 'conversations';
$lang->admin->menuList->ai['menuOrder']['15'] = 'models';
$lang->admin->menuList->ai['subMenu']['prompts'] = array('link' => "{$lang->admin->ai->prompt}|ai|prompts|", 'alias' => 'promptview,promptassignrole,promptselectdatasource,promptsetpurpose,promptsettargetform,promptfinalize,promptedit');
// $lang->admin->menuList->ai['subMenu']['conversations'] = array('link' => "{$lang->admin->ai->conversation}|ai|conversations|");
$lang->admin->menuList->ai['subMenu']['models'] = array('link' => "{$lang->admin->ai->model}|ai|models|", 'alias' => 'editmodel');
$lang->admin->menuList->ai['menuOrder']['5'] = 'prompts';
// $lang->admin->menuList->ai['menuOrder']['10'] = 'conversations';
$lang->admin->menuList->ai['menuOrder']['15'] = 'models';
if($config->edition != 'max' and $config->edition != 'ipd')
{
unset($lang->admin->menuList->model['subMenu']['scrum']);
+7
View File
@@ -183,6 +183,8 @@ $lang->admin->menuSetting['convert']['name'] = '数据导入';
$lang->admin->menuSetting['convert']['desc'] = '第三方系统的数据导入。';
$lang->admin->menuSetting['platform']['name'] = 'DevOps设置';
$lang->admin->menuSetting['platform']['desc'] = '资源、环境等DevOps各要素配置。';
$lang->admin->menuSetting['ai']['name'] = 'AI 配置';
$lang->admin->menuSetting['ai']['desc'] = '管理 AI 提词应用、配置语言模型。';
$lang->admin->updateDynamics = '更新动态';
$lang->admin->updatePatch = '补丁更新';
@@ -206,4 +208,9 @@ $lang->admin->productFeature['max'][] = '项目管理可视化,精准掌控项
$lang->admin->productFeature['max'][] = '资产库管理,为项目提供数据支撑';
$lang->admin->productFeature['max'][] = '严格权限控制,方式灵活安全';
$lang->admin->ai = new stdclass();
$lang->admin->ai->model = '语言模型';
$lang->admin->ai->conversation = '会话';
$lang->admin->ai->prompt = '提词';
include dirname(__FILE__) . '/menu.php';
+2 -1
View File
@@ -390,7 +390,8 @@ class adminModel extends model
}
}
}
elseif(!empty($menu['link']) and strpos($menu['link'], '|') !== false)
if(!empty($menu['link']) and strpos($menu['link'], '|') !== false)
{
list($module, $method) = explode('|', $menu['link']);
$menu['link'] = helper::createLink($module, $method);
+264
View File
@@ -0,0 +1,264 @@
<?php
$config->ai->vendorList = array();
$config->ai->vendorList['openai']['requiredFields'] = array('key');
$config->ai->vendorList['azure']['requiredFields'] = array('key', 'resource', 'deployment');
$config->ai->openai = new stdclass();
$config->ai->openai->api = new stdclass();
$config->ai->openai->api->vendor = array('openai', 'azure');
$config->ai->openai->api->openai = new stdclass();
$config->ai->openai->api->openai->version = 'v1'; // OpenAI API version, required.
$config->ai->openai->api->openai->format = 'https://api.openai.com/%s/%s'; // OpenAI API format, args: API version, API name.
$config->ai->openai->api->openai->authFormat = 'Authorization: Bearer %s'; // OpenAI API auth header format.
$config->ai->openai->api->azure = new stdclass();
$config->ai->openai->api->azure->resource = 'openai-at-zentao'; // your Azure OpenAI resource name, required.
$config->ai->openai->api->azure->deployment = 'the-first-gpt'; // your Azure OpenAI deployment name, required.
$config->ai->openai->api->azure->apiVersion = '2023-07-01-preview'; // Azure OpenAI API version, required.
$config->ai->openai->api->azure->format = 'https://%s.openai.azure.com/openai/deployments/%s/%s?api-version=%s'; // Azure API format, args: resource name, deployment name, API name, API version.
$config->ai->openai->api->azure->authFormat = 'api-key: %s'; // Azure API auth header format.
$config->ai->openai->api->methods = array('function' => 'chat/completions', 'chat' => 'chat/completions', 'completion' => 'completions', 'edit' => 'edits');
$config->ai->openai->params = new stdclass();
$config->ai->openai->params->chat = new stdclass();
$config->ai->openai->params->function = new stdclass();
$config->ai->openai->params->completion = new stdclass();
$config->ai->openai->params->edit = new stdclass();
$config->ai->openai->params->chat->required = array('messages');
$config->ai->openai->params->chat->optional = array('max_tokens', 'temperature', 'top_p', 'n', 'stream', 'stop', 'presence_penalty', 'frequency_penalty', 'logit_bias', 'user');
$config->ai->openai->params->function->required = array('messages', 'functions', 'function_call');
$config->ai->openai->params->function->optional = array('max_tokens', 'temperature', 'top_p', 'n', 'stream', 'stop', 'presence_penalty', 'frequency_penalty', 'logit_bias', 'user');
$config->ai->openai->params->completion->required = array('prompt', 'max_tokens');
$config->ai->openai->params->completion->optional = array('suffix', 'temperature', 'top_p', 'n', 'stream', 'logprobs', 'echo', 'stop', 'presence_penalty', 'frequency_penalty', 'best_of', 'logit_bias', 'user');
$config->ai->openai->params->edit->required = array('input', 'instruction');
$config->ai->openai->params->edit->optional = array('temperature', 'top_p', 'n');
$config->ai->openai->model = new stdclass();
$config->ai->openai->model->chat = 'gpt-3.5-turbo';
$config->ai->openai->model->function = 'gpt-3.5-turbo-0613';
$config->ai->openai->model->completion = 'text-davinci-003';
$config->ai->openai->model->edit = 'text-davinci-edit-001';
$config->ai->openai->contentTypeMapping = array('Content-Type: application/json' => array('', 'function', 'chat', 'completion', 'edit'), 'Content-Type: multipart/form-data' => array());
$config->ai->openai->contentType = array();
foreach($config->ai->openai->contentTypeMapping as $contentType => $apis)
{
foreach($apis as $api) $config->ai->openai->contentType[$api] = $contentType;
}
/* Required fields of forms. */
$config->ai->createprompt = new stdclass();
$config->ai->testPrompt = new stdclass();
$config->ai->createprompt->requiredFields = 'name';
$config->ai->testPrompt->requiredFields = 'name,module,source,purpose,targetForm';
/* Data source object props definations, commented out ones are not supported for now. */
$config->ai->dataSource = array();
// $config->ai->dataSource['my']['efforts'] = array('date', 'work', 'account', 'consumed', 'left', 'objectID', 'product', 'project', 'execution');
$config->ai->dataSource['product']['product'] = array('name', 'desc');
// $config->ai->dataSource['product']['modules'] = array('name', 'modules');
$config->ai->dataSource['story']['story'] = array('title', 'spec', 'verify', 'product', 'module', 'pri', 'category', 'estimate');
$config->ai->dataSource['productplan']['productplan'] = array('title', 'desc', 'begin', 'end');
$config->ai->dataSource['productplan']['stories'] = array('title', 'module', 'pri', 'estimate', 'status', 'stage');
$config->ai->dataSource['productplan']['bugs'] = array('title', 'pri', 'status');
$config->ai->dataSource['release']['release'] = array('product', 'name', 'desc', 'date');
$config->ai->dataSource['release']['stories'] = array('title', 'estimate');
$config->ai->dataSource['release']['bugs'] = array('title');
$config->ai->dataSource['project']['project'] = array('name', 'type', 'desc', 'begin', 'end', 'estimate');
$config->ai->dataSource['project']['programplans'] = array('name', 'desc', 'status', 'begin', 'end', 'realBegan', 'realEnd', 'planDuration', 'progress', 'estimate', 'consumed', 'left');
$config->ai->dataSource['project']['executions'] = array('name', 'desc', 'status', 'begin', 'end', 'realBegan', 'realEnd', 'estimate', 'consumed', 'progress');
$config->ai->dataSource['execution']['execution'] = array('name', 'desc', 'estimate');
$config->ai->dataSource['execution']['tasks'] = array('name', 'pri', 'status', 'estimate', 'consumed', 'left', 'progress', 'estStarted', 'realStarted', 'finishedDate', 'closedReason');
$config->ai->dataSource['task']['task'] = array('name', 'desc', 'pri', 'status', 'estimate', 'consumed', 'left', 'progress', 'estStarted', 'realStarted');
$config->ai->dataSource['bug']['bug'] = array('title', 'steps', 'severity','pri', 'status', 'confirmed', 'type');
$config->ai->dataSource['case']['case'] = array('title', 'precondition', 'scene', 'product', 'module', 'pri', 'type', 'lastRunResult', 'status');
$config->ai->dataSource['case']['steps'] = array('desc', 'expect');
$config->ai->dataSource['doc']['doc'] = array('title', 'addedBy', 'addedDate', 'editedBy', 'editedDate', 'content');
/* Available target form definations. Please also update `$lang->ai->targetForm` upon changes! Some are commented out, these need extra work. */
$config->ai->targetForm = array();
// $config->ai->targetForm['product']['tree/managechild'] = (object)array('m' => 'tree', 'f' => 'browse');
// $config->ai->targetForm['product']['doc/create'] = (object)array('m' => 'doc', 'f' => 'create');
$config->ai->targetForm['story']['create'] = (object)array('m' => 'story', 'f' => 'create');
$config->ai->targetForm['story']['batchcreate'] = (object)array('m' => 'story', 'f' => 'batchcreate');
$config->ai->targetForm['story']['change'] = (object)array('m' => 'story', 'f' => 'change');
$config->ai->targetForm['story']['totask'] = (object)array('m' => 'task', 'f' => 'batchcreate');
$config->ai->targetForm['story']['testcasecreate'] = (object)array('m' => 'testcase', 'f' => 'create');
$config->ai->targetForm['story']['subdivide'] = (object)array('m' => 'story', 'f' => 'batchcreate');
$config->ai->targetForm['productplan']['edit'] = (object)array('m' => 'productplan', 'f' => 'edit');
$config->ai->targetForm['productplan']['create'] = (object)array('m' => 'productplan', 'f' => 'create');
// $config->ai->targetForm['projectrelease']['doc/create'] = (object)array('m' => 'doc', 'f' => 'create');
// $config->ai->targetForm['project']['risk/create'] = (object)array('m' => 'risk', 'f' => 'create');
// $config->ai->targetForm['project']['issue/create'] = (object)array('m' => 'issue', 'f' => 'create');
// $config->ai->targetForm['project']['doc/create'] = (object)array('m' => 'doc', 'f' => 'create');
$config->ai->targetForm['project']['programplan/create'] = (object)array('m' => 'programplan', 'f' => 'create');
$config->ai->targetForm['execution']['batchcreatetask'] = (object)array('m' => 'task', 'f' => 'batchcreate');
// $config->ai->targetForm['execution']['createtestreport'] = (object)array('m' => 'execution', 'f' => 'testreport');
// $config->ai->targetForm['execution']['createqa'] = (object)array('m' => 'execution', 'f' => 'createQA');
// $config->ai->targetForm['execution']['createrisk'] = (object)array('m' => 'execution', 'f' => 'createRisk');
// $config->ai->targetForm['execution']['createissue'] = (object)array('m' => 'execution', 'f' => 'createIssue');
$config->ai->targetForm['task']['edit'] = (object)array('m' => 'task', 'f' => 'edit');
$config->ai->targetForm['task']['batchcreate'] = (object)array('m' => 'task', 'f' => 'batchcreate');
$config->ai->targetForm['testcase']['edit'] = (object)array('m' => 'testcase', 'f' => 'edit');
// $config->ai->targetForm['testcase']['createscript'] = (object)array('m' => 'testcase', 'f' => 'createScript');
$config->ai->targetForm['bug']['edit'] = (object)array('m' => 'bug', 'f' => 'edit');
$config->ai->targetForm['bug']['story/create'] = (object)array('m' => 'story', 'f' => 'create');
$config->ai->targetForm['bug']['testcase/create'] = (object)array('m' => 'testcase', 'f' => 'create');
// $config->ai->targetForm['doc']['create'] = (object)array('m' => 'doc', 'f' => 'create');
$config->ai->targetForm['doc']['edit'] = (object)array('m' => 'doc', 'f' => 'edit');
/* Used to check if form injection is available, generated from `$config->ai->targetForm`. */
$config->ai->availableForms = array();
foreach($config->ai->targetForm as $forms)
{
foreach($forms as $form)
{
if(!empty($config->ai->availableForms[$form->m]) && in_array($form->f, $config->ai->availableForms[$form->m])) continue;
$config->ai->availableForms[$form->m][] = $form->f;
}
}
/**
* Target form variables definations, defines format and arguments of target form redirection links,
* useful when method requires additional arguments.
*
* Arg keys are names of objects, usually the same as object name. Arg values indicate if arg is required.
* It will be used to get object ID and sprintf to format.
*/
$config->ai->targetFormVars = array();
$config->ai->targetFormVars['story']['create'] = (object)array('format' => 'product=%d', 'args' => array('product' => 1), 'app' => 'product');
$config->ai->targetFormVars['story']['batchcreate'] = (object)array('format' => 'productID=%d', 'args' => array('product' => 1), 'app' => 'product');
$config->ai->targetFormVars['story']['change'] = (object)array('format' => 'storyID=%d', 'args' => array('story' => 1), 'app' => 'product');
$config->ai->targetFormVars['productplan']['create'] = (object)array('format' => 'productID=%d&branch=%d&parent=%d', 'args' => array('product' => 1, 'branch' => 0, 'productplan' => 0), 'app' => 'product');
$config->ai->targetFormVars['productplan']['edit'] = (object)array('format' => 'planID=%d', 'args' => array('productplan' => 1), 'app' => 'product');
$config->ai->targetFormVars['task']['create'] = (object)array('format' => 'executionID=%d&storyID=%d', 'args' => array('execution' => 1, 'story' => 0), 'app' => 'execution');
$config->ai->targetFormVars['task']['batchcreate'] = (object)array('format' => 'executionID=%d&storyID=%d', 'args' => array('execution' => 1, 'story' => 0), 'app' => 'execution');
$config->ai->targetFormVars['task']['edit'] = (object)array('format' => 'taskID=%d', 'args' => array('task' => 1), 'app' => 'execution');
$config->ai->targetFormVars['bug']['create'] = (object)array('format' => 'productID=%d', 'args' => array('product' => 1), 'app' => 'qa');
$config->ai->targetFormVars['bug']['edit'] = (object)array('format' => 'bugID=%d', 'args' => array('bug' => 1), 'app' => 'qa');
$config->ai->targetFormVars['testcase']['create'] = (object)array('format' => 'productID=%d', 'args' => array('product' => 1), 'app' => 'qa');
$config->ai->targetFormVars['testcase']['edit'] = (object)array('format' => 'caseID=%d', 'args' => array('case' => 1), 'app' => 'qa');
$config->ai->targetFormVars['testreport']['create'] = (object)array('format' => 'productID=%d', 'args' => array('product' => 1), 'app' => 'qa');
$config->ai->targetFormVars['execution']['testreport'] = (object)array('format' => '', 'args' => array(), 'app' => 'execution');
// $config->ai->targetFormVars['tree']['browse'] = (object)array('format' => 'rootID=%d&view=%s', 'args' => array('root', 'view'), 'app' => 'product');
$config->ai->targetFormVars['programplan']['create'] = (object)array('format' => 'projectID=%d', 'args' => array('project' => 1), 'app' => 'project');
$config->ai->targetFormVars['doc']['edit'] = (object)array('format' => 'docID=%d', 'args' => array('doc' => 1), 'app' => 'doc');
/* Menu printing configurations. */
$config->ai->menuPrint = new stdclass();
/**
* Menu location definations, defines acceptable module-methods and on page menu locations, etc.
* Some are identical except for module name, reuse them as much as possible.
*
* @param string $module prompt module name (actual module could differ from prompt module name)
* @param string $targetContainer injection target container selector
* @param string $class class of menu or dropdown button
* @param string $buttonClass specified class of action menu buttons
* @param string $dropdownClass specified class of dropdown menu button
* @param string $objectVarName object variable name of view
* @param string $stylesheet stylesheet to be injected
* @param string $injectMethod injection jQuery method, `append` by default
* @see ./view/promptmenu.html.php
*/
$config->ai->menuPrint->locations = array();
$config->ai->menuPrint->locations['story']['view'] = (object)array(
'module' => 'story',
'targetContainer' => '#mainContent .cell:first-of-type .detail:first-of-type .detail-title',
'class' => 'pull-right',
'stylesheet' => '#mainContent .cell:first-of-type .detail:first-of-type .detail-title>button {margin-left: 10px;} #mainContent .cell:first-of-type .detail:first-of-type .detail-content {margin-top: 12px;}'
);
$config->ai->menuPrint->locations['task']['view'] = clone $config->ai->menuPrint->locations['story']['view'];
$config->ai->menuPrint->locations['task']['view']->module = 'task';
$config->ai->menuPrint->locations['testcase']['view'] = clone $config->ai->menuPrint->locations['story']['view'];
$config->ai->menuPrint->locations['testcase']['view']->module = 'case';
$config->ai->menuPrint->locations['bug']['view'] = clone $config->ai->menuPrint->locations['story']['view'];
$config->ai->menuPrint->locations['bug']['view']->module = 'bug';
$config->ai->menuPrint->locations['projectstory']['view'] = clone $config->ai->menuPrint->locations['story']['view'];
$config->ai->menuPrint->locations['execution']['storyView'] = $config->ai->menuPrint->locations['story']['view'];
$config->ai->menuPrint->locations['execution']['view'] = (object)array(
'module' => 'execution',
'injectMethod' => 'prepend',
'targetContainer' => '#mainContent.main-row > .col-4.side-col .detail:first-child > .detail-title',
'class' => 'pull-right'
);
$config->ai->menuPrint->locations['project']['view'] = clone $config->ai->menuPrint->locations['execution']['view'];
$config->ai->menuPrint->locations['project']['view']->module = 'project';
$config->ai->menuPrint->locations['project']['view'] = clone $config->ai->menuPrint->locations['execution']['view'];
$config->ai->menuPrint->locations['project']['view']->module = 'project';
$config->ai->menuPrint->locations['product']['view'] = (object)array(
'module' => 'product',
'injectMethod' => 'append',
'targetContainer' => '#mainContent.main-row > .col-8.main-col .detail:first-child > .detail-title',
'class' => 'pull-right'
);
$config->ai->menuPrint->locations['productplan']['view'] = (object)array(
'module' => 'productplan',
'targetContainer' => '#mainMenu>.btn-toolbar.pull-right',
'objectVarName' => 'plan'
);
$config->ai->menuPrint->locations['projectplan']['view'] = $config->ai->menuPrint->locations['productplan']['view'];
$config->ai->menuPrint->locations['release']['view'] = clone $config->ai->menuPrint->locations['productplan']['view'];
$config->ai->menuPrint->locations['release']['view']->module = 'release';
$config->ai->menuPrint->locations['release']['view']->objectVarName = null;
$config->ai->menuPrint->locations['projectrelease']['view'] = clone $config->ai->menuPrint->locations['productplan']['view'];
$config->ai->menuPrint->locations['projectrelease']['view']->objectVarName = null;
$config->ai->menuPrint->locations['doc']['view'] = (object)array(
'module' => 'doc',
'injectMethod' => 'prepend',
'targetContainer' => '#mainMenu>.btn-toolbar.pull-right',
);
$config->ai->injectAuditButton = new stdclass();
$config->ai->injectAuditButton->locations = array();
$config->ai->injectAuditButton->locations['task']['edit'] = array(
'toolbar' => (object)array(
'targetContainer' => '#mainContent .main-header',
'injectMethod' => 'append',
'class' => 'pull-right btn-toolbar',
),
'action' => (object)array(
'targetContainer' => '#mainContent .form-actions',
'injectMethod' => 'html',
)
);
$config->ai->injectAuditButton->locations['bug']['create'] = array(
'toolbar' => (object)array(
'targetContainer' => '#mainContent .main-header .btn-toolbar',
'injectMethod' => 'prepend',
),
'action' => (object)array(
'targetContainer' => '#mainContent .form-actions',
'injectMethod' => 'html',
)
);
$config->ai->injectAuditButton->locations['doc']['edit'] = array(
'toolbar' => (object)array(
'targetContainer' => '#mainContent #headerBox .btn-tools',
'injectMethod' => 'prepend',
),
'action' => (object)array(
'targetContainer' => '#mainContent #headerBox .btn-tools',
'injectMethod' => 'html',
'containerStyles' => '{"width": "600px"}'
)
);
$config->ai->injectAuditButton->locations['productplan']['create'] = $config->ai->injectAuditButton->locations['task']['edit'];
$config->ai->injectAuditButton->locations['productplan']['edit'] = $config->ai->injectAuditButton->locations['task']['edit'];
$config->ai->injectAuditButton->locations['programplan']['create'] = $config->ai->injectAuditButton->locations['task']['edit'];
$config->ai->injectAuditButton->locations['bug']['edit'] = $config->ai->injectAuditButton->locations['task']['edit'];
$config->ai->injectAuditButton->locations['story']['change'] = $config->ai->injectAuditButton->locations['task']['edit'];
$config->ai->injectAuditButton->locations['testcase']['edit'] = $config->ai->injectAuditButton->locations['task']['edit'];
$config->ai->injectAuditButton->locations['testreport']['create'] = $config->ai->injectAuditButton->locations['task']['edit'];
$config->ai->injectAuditButton->locations['story']['batchcreate'] = $config->ai->injectAuditButton->locations['bug']['create'];
$config->ai->injectAuditButton->locations['story']['create'] = $config->ai->injectAuditButton->locations['bug']['create'];
$config->ai->injectAuditButton->locations['task']['batchcreate'] = $config->ai->injectAuditButton->locations['bug']['create'];
$config->ai->injectAuditButton->locations['task']['create'] = $config->ai->injectAuditButton->locations['bug']['create'];
$config->ai->injectAuditButton->locations['testcase']['create'] = $config->ai->injectAuditButton->locations['bug']['create'];
+688
View File
@@ -0,0 +1,688 @@
<?php
/**
* The control file of ai module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
class ai extends control
{
public function __construct($module = '', $method = '')
{
parent::__construct($module, $method);
$this->loadModel('user');
}
/**
* Check for user's privs and model configs, redirect to most relevant page.
*
* @access public
* @return void
*/
public function adminIndex()
{
$modelConfig = new stdclass();
$modelConfigData = $this->loadModel('setting')->getItems('owner=system&module=ai');
foreach($modelConfigData as $item) $modelConfig->{$item->key} = $item->value;
$modelConfigured = !empty($modelConfig->key) && !empty($modelConfig->type) && (empty($modelConfig->proxyType) || !empty($modelConfig->proxyAddr));
/* Redirect to model edit if user has priv and model is unconfigured. */
if(commonModel::hasPriv('ai', 'editModel') && !$modelConfigured) return $this->locate($this->createLink('ai', 'editModel'));
/* Redirect to prompts if user has priv. */
if(commonModel::hasPriv('ai', 'prompts')) return $this->locate($this->createLink('ai', 'prompts'));
/* Redirect to models if user has priv. */
if(commonModel::hasPriv('ai', 'models')) return $this->locate($this->createLink('ai', 'models'));
/* User has no priv, deny access. */
return $this->send(array('result' => 'fail', 'message' => $this->lang->error->accessDenied, 'locate' => $this->createLink('admin', 'index')));
}
/**
* List models.
*
* TODO: not fully implemented yet, currently shows the only model config.
*
* @access public
* @return void
*/
public function models()
{
$modelConfig = new stdclass();
$modelConfig->type = '';
$modelConfig->key = '';
$modelConfig->proxyType = '';
$modelConfig->proxyAddr = '';
$modelConfig->description = '';
$modelConfig->status = '';
$storedModelConfig = $this->loadModel('setting')->getItems('owner=system&module=ai');
foreach($storedModelConfig as $item) $modelConfig->{$item->key} = $item->value;
$this->view->modelConfig = $modelConfig;
$this->view->title = $this->lang->ai->models->title;
$this->display();
}
/**
* Edit model configuration, store in system.ai settings.
*
* @access public
* @return void
*/
public function editModel()
{
if(strtolower($this->server->request_method) == 'post')
{
$modelConfig = fixer::input('post')->get();
$currentVendor = empty($modelConfig->vendor) ? key($lang->ai->models->openaiVendorList) : $modelConfig->vendor;
$vendorRequiredFields = $this->config->ai->vendorList[$currentVendor]['requiredFields'];
$errors = array();
if(empty($modelConfig->type)) $errors[] = sprintf($this->lang->ai->validate->noEmpty, $this->lang->ai->models->type);
foreach($vendorRequiredFields as $field)
{
if(empty($modelConfig->$field)) $errors[] = sprintf($this->lang->ai->validate->noEmpty, $this->lang->ai->models->$field);
}
if(!empty($modelConfig->proxyType) && empty($modelConfig->proxyAddr))
{
$errors[] = sprintf($this->lang->ai->validate->noEmpty, $this->lang->ai->models->proxyAddr);
}
if(!empty($errors)) return $this->send(array('result' => 'fail', 'message' => implode(' ', $errors)));
$this->loadModel('setting')->setItems('system.ai', $modelConfig);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'locate' => $this->inlink('models') . '#app=admin'));
}
$modelConfig = new stdclass();
$modelConfig->type = '';
$modelConfig->key = '';
$modelConfig->proxyType = '';
$modelConfig->proxyAddr = '';
$modelConfig->description = '';
$modelConfig->status = '';
$storedModelConfig = $this->loadModel('setting')->getItems('owner=system&module=ai');
foreach($storedModelConfig as $item) $modelConfig->{$item->key} = $item->value;
$this->view->modelConfig = $modelConfig;
$this->view->title = $this->lang->ai->models->title;
$this->display();
}
/**
* Test connection to API endpoint.
*
* @access public
* @return void
*/
public function testConnection()
{
$modelConfig = fixer::input('post')->get();
$currentVendor = empty($modelConfig->vendor) ? key($lang->ai->models->openaiVendorList) : $modelConfig->vendor;
$vendorRequiredFields = $this->config->ai->vendorList[$currentVendor]['requiredFields'];
$errors = array();
if(empty($modelConfig->type)) $errors[] = sprintf($this->lang->ai->validate->noEmpty, $this->lang->ai->models->type);
foreach($vendorRequiredFields as $field)
{
if(empty($modelConfig->$field)) $errors[] = sprintf($this->lang->ai->validate->noEmpty, $this->lang->ai->models->$field);
}
if(!empty($modelConfig->proxyType) && empty($modelConfig->proxyAddr))
{
$errors[] = sprintf($this->lang->ai->validate->noEmpty, $this->lang->ai->models->proxyAddr);
}
if(!empty($errors)) return $this->send(array('result' => 'fail', 'message' => implode(' ', $errors)));
$this->ai->setConfig($modelConfig);
if($currentVendor == 'azure')
{
$messages = array(
(object)array('role' => 'user', 'content' => 'Hello?')
);
$result = $this->ai->converse($messages);
}
else
{
$result = $this->ai->complete('test', 1); // Test completing 'test' with length of 1.
}
if($result === false)
{
return $this->send(array('result' => 'fail', 'message' => empty($this->ai->errors) ? $this->lang->ai->models->testConnectionResult->fail : sprintf($this->lang->ai->models->testConnectionResult->failFormat, implode(', ', $this->ai->errors))));
}
return $this->send(array('result' => 'success', 'message' => $this->lang->ai->models->testConnectionResult->success));
}
/**
* List prompts.
*
* @param string $module
* @param string $status
* @access public
* @return void
*/
public function prompts($module = '', $status = '', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
{
if($_POST)
{
$data = fixer::input('post')->get();
if(isset($data->togglePromptStatus) && isset($data->promptId))
{
$modelConfig = new stdclass();
$storedModelConfig = $this->loadModel('setting')->getItems('owner=system&module=ai');
foreach($storedModelConfig as $item) $modelConfig->{$item->key} = $item->value;
if(empty($modelConfig->key)) return $this->send(array('result' => 'fail', 'message' => $this->lang->ai->models->noModelError, 'locate' => $this->inlink('models') . '#app=admin'));
$this->ai->togglePromptStatus($data->promptId);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success'));
}
}
/* Set pager and order. */
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$order = common::appendOrder($orderBy);
$this->view->prompts = $this->ai->getPrompts($module, $status, $order, $pager);
$this->view->module = $module;
$this->view->status = $status;
$this->view->orderBy = $orderBy;
$this->view->pager = $pager;
$this->view->title = $this->lang->ai->prompts->common;
if($this->config->edition == 'open')
{
$this->view->promptModules = array_map(function($prompt)
{
return $prompt->module;
}, $this->ai->getPrompts());
}
$this->display();
}
/**
* View prompt details.
*
* @param int $id
* @access public
* @return void
*/
public function promptView($id)
{
$prompt = $this->ai->getPromptById($id);
$this->view->prompt = $prompt;
$this->view->preAndNext = $this->loadModel('common')->getPreAndNextObject('prompt', $id);
$this->view->actions = $this->loadModel('action')->getList('prompt', $id);
$this->view->dataPreview = $this->ai->generateDemoDataPrompt($prompt->module, $prompt->source);
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->title = "{$this->lang->ai->prompts->common}#{$prompt->id} $prompt->name";
$this->display();
}
/**
* Create a prompt.
*
* @access public
* @return void
*/
public function createPrompt()
{
if(strtolower($this->server->request_method) == 'post')
{
$prompt = fixer::input('post')->get();
$promptID = $this->ai->createPrompt($prompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'callback' => "gotoPrompt($promptID)"));
}
$this->view->title = $this->lang->ai->prompts->create;
$this->display();
}
/**
* Edit a prompt.
*
* @param int $id
* @access public
* @return void
*/
public function promptEdit($id)
{
$prompt = $this->ai->getPromptByID($id);
if(strtolower($this->server->request_method) == 'post')
{
$data = fixer::input('post')->get();
$prompt->name = $data->name;
$prompt->desc = $data->desc;
$this->ai->updatePrompt($prompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'locate' => $this->inlink('promptView', "id={$prompt->id}") . '#app=admin'));
}
$this->view->prompt = $prompt;
$this->view->title = $this->lang->ai->prompts->edit;
$this->display();
}
/**
* Delete a prompt.
*
* @param int $prompt
* @access public
* @return void
*/
public function promptDelete($prompt)
{
$result = $this->ai->deletePrompt($prompt);
if(dao::isError() || $result === false) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success'));
}
/**
* Edit role of prompt, prompt editing step 2.
*
* @param int $promptID
* @access public
* @return void
*/
public function promptAssignRole($promptID)
{
$prompt = $this->ai->getPromptByID($promptID);
if($_POST)
{
$data = fixer::input('post')->get();
$originalPrompt = clone $prompt;
$prompt->model = 0; // TODO: use actual $data->model;
$prompt->role = $data->role;
$prompt->characterization = $data->characterization;
if(!empty($data->saveTemplate) && $data->saveTemplate == 'save')
{
$this->ai->createRoleTemplate($prompt->role, $prompt->characterization);
}
$this->ai->updatePrompt($prompt, $originalPrompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!empty($data->jumpToNext)) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptSelectDataSource', "promptID=$promptID") . '#app=admin'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptAssignRole', "promptID=$promptID") . '#app=admin'));
}
$this->view->prompt = $prompt;
$this->view->promptID = $promptID;
$this->view->lastActiveStep = $this->ai->getLastActiveStep($prompt);
$this->view->title = "{$this->lang->ai->prompts->common}#{$prompt->id} $prompt->name {$this->lang->colon} " . $this->lang->ai->prompts->assignRole . " {$this->lang->colon} " . $this->lang->ai->prompts->common;
$this->view->roleTemplates = $this->ai->getRoleTemplates();
$this->display();
}
/**
* Set data source of prompt, prompt editing step 3.
*
* @param int $promptID
* @access public
* @return void
*/
public function promptSelectDataSource($promptID)
{
$prompt = $this->ai->getPromptByID($promptID);
if($_POST)
{
$data = fixer::input('post')->get();
$originalPrompt = clone $prompt;
$prompt->module = $data->datagroup;
$prompt->source = ",$data->datasource,";
$this->ai->updatePrompt($prompt, $originalPrompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!empty($data->jumpToNext)) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptSetPurpose', "promptID=$promptID") . '#app=admin'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptSelectDataSource', "promptID=$promptID") . '#app=admin'));
}
$this->view->activeDataSource = empty($prompt->module) ? current(array_keys($this->config->ai->dataSource)) : $prompt->module;
$this->view->dataSource = $this->config->ai->dataSource;
$this->view->prompt = $prompt;
$this->view->promptID = $promptID;
$this->view->lastActiveStep = $this->ai->getLastActiveStep($prompt);
$this->view->title = "{$this->lang->ai->prompts->common}#{$prompt->id} $prompt->name {$this->lang->colon} " . $this->lang->ai->prompts->selectDataSource . " {$this->lang->colon} " . $this->lang->ai->prompts->common;
$this->display();
}
/**
* Edit purpose and purpose elaboration of prompt, prompt editing step 4.
*
* @param int $promptID
* @access public
* @return void
*/
public function promptSetPurpose($promptID)
{
$prompt = $this->ai->getPromptByID($promptID);
if($_POST)
{
$data = fixer::input('post')->get();
$originalPrompt = clone $prompt;
$prompt->purpose = $data->purpose;
$prompt->elaboration = $data->elaboration;
$this->ai->updatePrompt($prompt, $originalPrompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!empty($data->jumpToNext)) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptSetTargetForm', "promptID=$promptID") . '#app=admin'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptSetPurpose', "promptID=$promptID") . '#app=admin'));
}
$this->view->dataPreview = $this->ai->generateDemoDataPrompt($prompt->module, $prompt->source);
$this->view->prompt = $prompt;
$this->view->promptID = $promptID;
$this->view->lastActiveStep = $this->ai->getLastActiveStep($prompt);
$this->view->title = "{$this->lang->ai->prompts->common}#{$prompt->id} $prompt->name {$this->lang->colon} " . $this->lang->ai->prompts->setPurpose . " {$this->lang->colon} " . $this->lang->ai->prompts->common;
$this->display();
}
/**
* Set target form of prompt, prompt editing step 5.
*
* @param int $promptID
* @access public
* @return void
*/
public function promptSetTargetForm($promptID)
{
$prompt = $this->ai->getPromptByID($promptID);
if($_POST)
{
$data = fixer::input('post')->get();
$originalPrompt = clone $prompt;
$prompt->targetForm = $data->targetForm;
$this->ai->updatePrompt($prompt, $originalPrompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!empty($data->goTesting)) // Go to testing object view.
{
$location = $this->ai->getTestingLocation($prompt);
return $this->send(empty($location) ? array('result' => 'fail', 'target' => '#go-test-btn', 'msg' => $this->lang->ai->prompts->goingTestingFail) : array('result' => 'success', 'target' => '#go-test-btn', 'msg' => $this->lang->ai->prompts->goingTesting, 'locate' => $location));
}
if(!empty($data->jumpToNext)) $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptFinalize', "promptID=$promptID") . '#app=admin'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptSetTargetForm', "promptID=$promptID") . '#app=admin'));
}
$this->view->dataPreview = $this->ai->generateDemoDataPrompt($prompt->module, $prompt->source);
$this->view->prompt = $prompt;
$this->view->promptID = $promptID;
$this->view->lastActiveStep = $this->ai->getLastActiveStep($prompt);
$this->view->title = "{$this->lang->ai->prompts->common}#{$prompt->id} $prompt->name {$this->lang->colon} " . $this->lang->ai->prompts->setTargetForm . " {$this->lang->colon} " . $this->lang->ai->prompts->common;
$this->display();
}
/**
* Edit additional information of prompt, final prompt editing step.
*
* @param int $promptID
* @access public
* @return void
*/
public function promptFinalize($promptID)
{
$prompt = $this->ai->getPromptByID($promptID);
if($_POST)
{
$data = fixer::input('post')->get();
$originalPrompt = clone $prompt;
$prompt->name = $data->name;
$prompt->desc = $data->desc;
$this->ai->updatePrompt($prompt, $originalPrompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!empty($data->jumpToNext)) $this->ai->togglePromptStatus($prompt, 'active');
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!empty($data->jumpToNext)) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('prompts') . '#app=admin'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->inlink('promptFinalize', "promptID=$promptID") . '#app=admin'));
}
$this->view->prompt = $prompt;
$this->view->promptID = $promptID;
$this->view->lastActiveStep = $this->ai->getLastActiveStep($prompt);
$this->view->title = "{$this->lang->ai->prompts->common}#{$prompt->id} $prompt->name {$this->lang->colon} " . $this->lang->ai->prompts->finalize . " {$this->lang->colon} " . $this->lang->ai->prompts->common;
$this->display();
}
/**
* Execute prompt on obejct, and redirect to target form page.
*
* @param int $promptId
* @param int $objectId
* @access public
* @return void
*/
public function promptExecute($promptId, $objectId)
{
$modelConfig = new stdclass();
$storedModelConfig = $this->loadModel('setting')->getItems('owner=system&module=ai');
foreach($storedModelConfig as $item) $modelConfig->{$item->key} = $item->value;
if(empty($modelConfig->key)) return $this->send(array('result' => 'fail', 'message' => $this->lang->ai->models->noModelError, 'locate' => $this->inlink('models') . '#app=admin'));
$prompt = $this->ai->getPromptByID($promptId);
if(empty($prompt) || !$this->ai->isExecutable($prompt)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->ai->execute->failFormat, $this->lang->ai->execute->failReasons['noPrompt'])));
$object = $this->ai->getObjectForPromptById($prompt, $objectId);
if(empty($object)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->ai->execute->failFormat, $this->lang->ai->execute->failReasons['noObjectData'])));
list($objectData, $rawObject) = $object;
list($location, $stop) = $this->ai->getTargetFormLocation($prompt, $rawObject);
if(empty($location)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->ai->execute->failFormat, $this->lang->ai->execute->failReasons['noTargetForm'])));
if(!empty($stop)) return header("location: $location", true, 302);
$response = $this->ai->executePrompt($prompt, $object);
if(is_int($response)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->ai->execute->failFormat, $this->lang->ai->execute->executeErrors[$response]) . (empty($this->ai->errors) ? '' : implode(', ', $this->ai->errors))));
if(empty($response)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->ai->execute->failFormat, $this->lang->ai->execute->failReasons['noResponse'])));
$this->ai->setInjectData($prompt->targetForm, $response);
$_SESSION['aiPrompt']['prompt'] = $prompt;
$_SESSION['aiPrompt']['objectId'] = $objectId;
if($prompt->status == 'draft') $_SESSION['auditPrompt']['time'] = time();
$promptViewLink = $this->inlink('promptview', "promptID=$promptId");
echo js::start() . "const currentApp = parent.$.apps.getLastApp().code; parent.$.apps.open('$location'); if(currentApp == 'admin') {location.href = '$promptViewLink';} else if(currentApp != parent.$.apps.getLastApp().code) {parent.$.apps.close(currentApp);}" . js::end();
}
/**
* Reset prompt execution.
*
* @param bool $failed Whether the execution failed, triggers error message.
* @access public
* @return void
*/
public function promptExecutionReset($failed = false)
{
/* Reset session. */
unset($_SESSION['aiPrompt']);
unset($_SESSION['auditPrompt']);
if($failed) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->ai->execute->failFormat, $this->lang->ai->execute->failReasons['noTargetForm']), 'locate' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
return $this->send(array('result' => 'success'));
}
/**
* Audit prompt modal.
*
* @param int $promptId
* @param int $objectId
* @param bool $exit
* @access public
* @return void|int
*/
public function promptAudit($promptId, $objectId, $exit = false)
{
if(!empty($exit))
{
unset($_SESSION['auditPrompt']);
return $this->send(array('result' => 'success', 'locate' => $this->inlink('promptview', "promptID=$promptId") . '#app=admin'));
}
$prompt = $this->ai->getPromptByID($promptId);
if($_POST)
{
$data = fixer::input('post')->get();
$originalPrompt = clone $prompt;
$prompt->role = $data->role;
$prompt->characterization = $data->characterization;
$prompt->purpose = $data->purpose;
$prompt->elaboration = $data->elaboration;
$this->ai->updatePrompt($prompt, $originalPrompt);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(empty($data->backLocation))
{
$response = array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true);
}
else
{
$response = array('result' => 'success', 'message' => $this->lang->saveSuccess, 'callback' => "reloadPrompt($promptId, $objectId)");
}
$this->sendSuccess($response);
}
$objectForPrompt = $this->ai->getObjectForPromptById($prompt, $objectId);
if(empty($objectForPrompt)) return $this->send(array('result' => 'fail', 'message' => $this->lang->ai->execute->fail));
list($objectData, $object) = $objectForPrompt;
$this->view->prompt = $prompt;
$this->view->object = $object;
$this->view->dataPrompt = $this->ai->serializeDataToPrompt($prompt->module, $prompt->source, $objectData);
$this->display();
}
/**
* Publish prompt, set status to active.
*
* @param int $id
* @param bool $backToTestingLocation
* @access public
* @return void
*/
public function promptPublish($id, $backToTestingLocation = false)
{
$modelConfig = new stdclass();
$storedModelConfig = $this->loadModel('setting')->getItems('owner=system&module=ai');
foreach($storedModelConfig as $item) $modelConfig->{$item->key} = $item->value;
if(empty($modelConfig->key)) return $this->send(array('result' => 'fail', 'message' => $this->lang->ai->models->noModelError, 'locate' => $this->inlink('models') . '#app=admin'));
unset($_SESSION['auditPrompt']);
$this->ai->togglePromptStatus($id, 'active');
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if($backToTestingLocation)
{
return $this->send(array('result' => 'success', 'message' => $this->lang->ai->prompts->action->publishSuccess, 'locate' => $this->inlink('promptview', "id=$id") . '#app=admin'));
}
return $this->send(array('result' => 'success'));
}
/**
* Unpublish prompt, set status to draft.
*
* @param int $id
* @access public
* @return void
*/
public function promptUnpublish($id)
{
$this->ai->togglePromptStatus($id, 'draft');
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success'));
}
/**
* Return html element for the role template list.
* This is used in prompt designing step 2.
* Return html will deserialize in the front end js and replace the original role template list.
*
* @access public
* @return void
*/
public function roleTemplates()
{
if($_POST)
{
$data = fixer::input('post')->get();
$method = $data->method;
switch($method)
{
case 'create':
$this->ai->createRoleTemplate($data->role, $data->characterization);
break;
case 'delete':
$this->ai->deleteRoleTemplate($data->id);
break;
case 'edit':
$this->ai->updateRoleTemplate($data->id, $data->role, $data->characterization);
break;
}
}
$this->view->roleTemplates = $this->ai->getRoleTemplates();
$this->display();
}
}
+189
View File
@@ -0,0 +1,189 @@
.design-steps
{
display: flex;
justify-content: space-between;
margin-bottom: 12px;
}
.design-steps .steps
{
box-shadow: inset 0 0 0 rgb(0 0 0 / 10%), 0 0 15px rgb(0 0 0 / 10%);
border-radius: 4px;
isolation: isolate;
display: flex;
}
.step
{
position: relative;
height: 32px;
min-width: 100px;
display: flex;
justify-content: center;
align-items: center;
background-color: #ffffff;
}
.step > a
{
padding: 0 10px;
position: relative;
left: 5px;
cursor: pointer;
}
.step:first-child
{
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.step:last-child
{
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.step:hover
{
background-color: #edeef2 !important;
}
.step > .hover-arrow, .step:hover > .solid-arrow
{
position: absolute;
top: 0;
left: 100%;
width: 0;
height: 0;
z-index: 1;
border-style: solid;
border-width: 16px 0 16px 10px;
border-color: transparent transparent transparent #edeef2 !important;
}
.step > .solid-arrow
{
background: none !important;
width: 0 !important;
height: 0 !important;
}
.step.disabled
{
background-color: #ffffff;
}
.step.disabled > a
{
color: #c4c4c4;
cursor: not-allowed;
pointer-events: none;
}
.step.clickable
{
background-color: #ffffff;
}
.step.clickable > .solid-arrow,
.step.disabled > .solid-arrow
{
position: absolute;
top: 0;
left: 100%;
z-index: 1;
border-style: solid;
border-width: 16px 0 16px 10px;
border-color: transparent transparent transparent #ffffff;
}
.step.clickable > .outline-arrow,
.step.disabled > .outline-arrow
{
background-image: url("static/svg/arrow-step-polyline.svg");
background-size: 8px;
background-position: center;
background-repeat: no-repeat;
position: absolute;
top: 0;
left: 100%;
width: 15px;
height: 32px;
z-index: 1;
}
.step.active
{
background-color: #38b2fe;
}
.step.active > a
{
color: #ffffff;
}
.step:hover.active > a
{
color: #38b2fe;
}
.step.active > .solid-arrow
{
position: absolute;
top: 0;
left: 100%;
z-index: 1;
border-style: solid;
border-width: 16px 0 16px 10px;
border-color: transparent transparent transparent #38b2fe;
}
.step.active > .outline-arrow
{
background-image: url("static/svg/arrow-step-polyline.svg");
background-size: 8px;
background-position: center;
background-repeat: no-repeat;
position: absolute;
top: 0;
left: 100%;
width: 15px;
height: 32px;
z-index: 1;
}
.step.current
{
background-color: #2e7eff;
}
.step.current > a
{
color: #ffffff;
font-weight: bold;
}
.step:hover.current > a
{
color: #2e7eff;
}
.step.current > .solid-arrow
{
position: absolute;
top: 0;
left: 100%;
z-index: 1;
border-style: solid;
border-width: 16px 0 16px 10px;
border-color: transparent transparent transparent #2e7eff;
}
#returnConfirmModal .footer
{
display: flex;
justify-content: space-between;
}
.visibility-hidden{visibility: hidden;}
+8
View File
@@ -0,0 +1,8 @@
.prompt-details .detail-title {
font-weight: normal;
color:#838a9d;
}
.prompt-details .detail-content + .detail-title {
margin-top: 10px;
}
+8
View File
@@ -0,0 +1,8 @@
(function () {
const form = document.querySelector('#mainForm');
if (form) {
form.addEventListener('input', function () {
isPromptDesignDirty = true;
});
}
})();
+58
View File
@@ -0,0 +1,58 @@
(function()
{
let currentPrompt = null;
const actions = document.querySelectorAll('.c-actions');
for(let action of actions)
{
action.addEventListener('click', function()
{
currentPrompt = action.getAttribute('data-prompt-id');
});
}
const goDesignButton = document.getElementById('goDesignButton');
if(goDesignButton)
{
goDesignButton.addEventListener('click', function()
{
if(currentPrompt)
{
location.href = createLink('ai', 'promptassignrole', `prompt=${currentPrompt}`);
}
});
}
const draftPromptButton = document.getElementById('draftPromptButton');
if(draftPromptButton)
{
draftPromptButton.addEventListener('click', function()
{
if(currentPrompt)
{
togglePromptStatus(currentPrompt);
}
});
}
})();
function togglePromptStatus(id)
{
const form = document.createElement("form");
form.method = 'post';
form.action = createLink('ai', 'prompts');
const promptId = document.createElement('input');
promptId.type = 'hidden';
promptId.name = 'promptId';
promptId.value = id;
form.appendChild(promptId);
const publish = document.createElement('input');
publish.type = 'hidden';
publish.name = 'togglePromptStatus';
publish.value = '1';
form.appendChild(publish);
document.body.appendChild(form);
form.submit();
}
+796
View File
@@ -0,0 +1,796 @@
<?php
/**
* The ai module en lang file of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
$lang->ai->common = 'AI';
/* Definitions of table columns, used to sprintf error messages to dao::$errors. */
$lang->prompt = new stdclass();
$lang->prompt->name = 'Name';
$lang->prompt->desc = 'Description';
$lang->prompt->model = 'Model';
$lang->prompt->module = 'Module';
$lang->prompt->source = 'Data Source';
$lang->prompt->targetForm = 'Target Form';
$lang->prompt->purpose = 'Purpose';
$lang->prompt->elaboration = 'Elaboration';
$lang->prompt->role = 'Role';
$lang->prompt->characterization = 'Characterization';
$lang->prompt->status = 'Status';
$lang->prompt->createdBy = 'Created By';
$lang->prompt->createdDate = 'Created Date';
$lang->prompt->editedBy = 'Edited By';
$lang->prompt->editedDate = 'Edited Date';
$lang->prompt->deleted = 'Deleted';
/* Lang for privs, keys are paired with privlang items. */
$lang->ai->modelBrowse = 'Browse Models';
$lang->ai->modelEdit = 'Edit Models';
$lang->ai->modelTestConnection = 'Test Model Connection';
$lang->ai->promptCreate = 'Create Prompt';
$lang->ai->promptEdit = 'Edit Prompt';
$lang->ai->promptDelete = 'Delete Prompt';
$lang->ai->promptAssignRole = 'Assign Prompt Role';
$lang->ai->promptSelectDataSource = 'Select Prompt Data';
$lang->ai->promptSetPurpose = 'Set Prompt Purpose';
$lang->ai->promptSetTargetForm = 'Set Prompt Target Form';
$lang->ai->promptFinalize = 'Finalize Prompt';
$lang->ai->promptAudit = 'Audit Prompt';
$lang->ai->promptPublish = 'Publish Prompt';
$lang->ai->promptUnpublish = 'Unpublish Prompt';
$lang->ai->promptBrowse = 'Browse Prompts';
$lang->ai->promptView = 'View Prompt';
$lang->ai->promptExecute = 'Execute Prompt';
$lang->ai->promptExecutionReset = 'Reset Execute Prompt';
$lang->ai->roleTemplates = 'Manage Role Templates';
$lang->ai->nextStep = 'Next';
$lang->ai->goTesting = 'Go testing';
$lang->ai->validate = new stdclass();
$lang->ai->validate->noEmpty = '%s cannot be empty.';
$lang->ai->validate->dirtyForm = 'The design step of %s has changed. Do you want to save and return it?';
$lang->ai->validate->nameNotUnique = 'A prompt with the same name already exists, please change the name.';
$lang->ai->prompts = new stdclass();
$lang->ai->prompts->common = 'Prompt';
$lang->ai->prompts->emptyList = 'No prompts yet.';
$lang->ai->prompts->create = 'Create Prompt';
$lang->ai->prompts->edit = 'Edit Prompt';
$lang->ai->prompts->id = 'ID';
$lang->ai->prompts->name = 'Name';
$lang->ai->prompts->description = 'Description';
$lang->ai->prompts->createdBy = 'Creator';
$lang->ai->prompts->createdDate = 'Created Date';
$lang->ai->prompts->targetForm = 'Target Form';
$lang->ai->prompts->funcDesc = 'Function Description';
$lang->ai->prompts->deleted = 'Deleted';
$lang->ai->prompts->stage = 'Stage';
$lang->ai->prompts->basicInfo = 'Basic Info';
$lang->ai->prompts->editInfo = 'Edit Info';
$lang->ai->prompts->createdBy = 'Created By';
$lang->ai->prompts->publishedBy = 'Published By';
$lang->ai->prompts->draftedBy = 'Drafted By';
$lang->ai->prompts->lastEditor = 'Last Editor';
$lang->ai->prompts->summary = 'There are %s prompts on this page.';
$lang->ai->prompts->action = new stdclass();
$lang->ai->prompts->action->goDesignConfirm = 'The current prompt is not complete, continue designing?';
$lang->ai->prompts->action->goDesign = 'Go designing';
$lang->ai->prompts->action->draftConfirm = 'Once unpublished, the prompt cannot be used any further. Are you sure you want to proceed?';
$lang->ai->prompts->action->design = 'Design';
$lang->ai->prompts->action->test = 'Test';
$lang->ai->prompts->action->edit = 'Edit';
$lang->ai->prompts->action->publish = 'Publish';
$lang->ai->prompts->action->unpublish = 'Unpublish';
$lang->ai->prompts->action->delete = 'Delete';
$lang->ai->prompts->action->deleteConfirm = 'Deleted prompts will be no longer available. Are you sure you want to proceed?';
$lang->ai->prompts->action->publishSuccess = 'Publish Success';
/* Steps of prompt creation. */
$lang->ai->prompts->assignRole = 'Assign Role';
$lang->ai->prompts->selectDataSource = 'Select Data Fields';
$lang->ai->prompts->setPurpose = 'Set Purpose';
$lang->ai->prompts->setTargetForm = 'Set Target Form';
$lang->ai->prompts->finalize = 'Finalize';
/* Role assigning. */
$lang->ai->prompts->model = 'Model';
$lang->ai->prompts->role = 'Role';
$lang->ai->prompts->characterization = 'Characterization';
$lang->ai->prompts->rolePlaceholder = '"Act as a <role>"';
$lang->ai->prompts->charPlaceholder = 'Detailed characterization of this role';
$lang->ai->prompts->roleTemplate = 'Role Template';
$lang->ai->prompts->roleTemplateTip = 'After a template is referenced, modifying the role or role description does not affect the template.';
$lang->ai->prompts->addRoleTemplate = 'Add Role Template';
$lang->ai->prompts->editRoleTemplate = 'Edit Role Template';
$lang->ai->prompts->editRoleTemplateTip = 'Editing this template will not affect its previous usages in prompts.';
$lang->ai->prompts->roleAddedSuccess = 'Role added successfully.';
$lang->ai->prompts->roleDelConfirm = 'Deleting the role does not affect the role that is already in the prompt. Do you want to delete it?';
$lang->ai->prompts->roleDelSuccess = 'Role deleted successfully.';
$lang->ai->prompts->roleTemplateSave = 'Save Role Template';
$lang->ai->prompts->roleTemplateSaveList = array();
$lang->ai->prompts->roleTemplateSaveList['save'] = 'Save';
$lang->ai->prompts->roleTemplateSaveList['discard'] = 'Discard';
/* Data source selecting. */
$lang->ai->prompts->selectData = 'Select fields';
$lang->ai->prompts->selectDataTip = 'Select an object and its fields will be shown below.';
$lang->ai->prompts->selectedFormat = 'Selecting data from {0}, {1} fields selected.';
$lang->ai->prompts->nonSelected = 'No field selected.';
$lang->ai->prompts->sortTip = 'Sorting fields by priority is suggested.';
$lang->ai->prompts->object = 'Object';
$lang->ai->prompts->field = 'Field';
/* Purpose setting. */
$lang->ai->prompts->purpose = 'Purpose';
$lang->ai->prompts->purposeTip = 'What do I want it to accomplish, in order to achieve what goals?';
$lang->ai->prompts->elaboration = 'Elaboration';
$lang->ai->prompts->elaborationTip = 'I hope its answer draws attention to some additional requests.';
$lang->ai->prompts->inputPreview = 'Prompt Preview';
$lang->ai->prompts->dataPreview = 'Data Prompt Preview';
$lang->ai->prompts->rolePreview = 'Role Prompt Preview';
$lang->ai->prompts->promptPreview = 'Purpose Prompt Preview';
/* Target form selecting. */
$lang->ai->prompts->selectTargetForm = 'Select Target Form';
$lang->ai->prompts->selectTargetFormTip = 'Results returned from LLMs can be directly inputed into forms within ZenTao.';
$lang->ai->prompts->goingTesting = 'Redirecting to testing page';
$lang->ai->prompts->goingTestingFail = 'Unable to go testing, no suitable object found.';
/* Finalize page. */
$lang->ai->moduleDisableTip = 'Module is automatically selected based on selected objects.';
/* Data source definition. */
$lang->ai->dataSource = array();
$lang->ai->dataSource['my']['common'] = 'My';
$lang->ai->dataSource['product']['common'] = 'Product';
$lang->ai->dataSource['story']['common'] = 'Story';
$lang->ai->dataSource['productplan']['common'] = 'Product Plan';
$lang->ai->dataSource['release']['common'] = 'Release';
$lang->ai->dataSource['project']['common'] = 'Project';
$lang->ai->dataSource['execution']['common'] = 'Execution';
$lang->ai->dataSource['task']['common'] = 'Task';
$lang->ai->dataSource['bug']['common'] = 'Bug';
$lang->ai->dataSource['case']['common'] = 'Test Case';
$lang->ai->dataSource['doc']['common'] = 'Document';
$lang->ai->dataSource['my']['efforts']['common'] = 'Efforts';
$lang->ai->dataSource['my']['efforts']['date'] = 'Date';
$lang->ai->dataSource['my']['efforts']['work'] = 'Work';
$lang->ai->dataSource['my']['efforts']['account'] = 'Account';
$lang->ai->dataSource['my']['efforts']['consumed'] = 'Consumed';
$lang->ai->dataSource['my']['efforts']['left'] = 'Left';
$lang->ai->dataSource['my']['efforts']['objectID'] = 'Object';
$lang->ai->dataSource['my']['efforts']['product'] = 'Product';
$lang->ai->dataSource['my']['efforts']['project'] = 'Project';
$lang->ai->dataSource['my']['efforts']['execution'] = 'Execution';
$lang->ai->dataSource['product']['product']['common'] = 'Product';
$lang->ai->dataSource['product']['product']['name'] = 'Product Name';
$lang->ai->dataSource['product']['product']['desc'] = 'Description';
$lang->ai->dataSource['product']['modules']['common'] = 'Module';
$lang->ai->dataSource['product']['modules']['name'] = 'Module Name';
$lang->ai->dataSource['product']['modules']['modules'] = 'Sub Modules';
$lang->ai->dataSource['productplan']['productplan']['common'] = 'Product Plan';
$lang->ai->dataSource['productplan']['productplan']['title'] = 'Title';
$lang->ai->dataSource['productplan']['productplan']['desc'] = 'Description';
$lang->ai->dataSource['productplan']['productplan']['begin'] = 'Begin';
$lang->ai->dataSource['productplan']['productplan']['end'] = 'End';
$lang->ai->dataSource['productplan']['stories']['common'] = 'Stories';
$lang->ai->dataSource['productplan']['stories']['title'] = 'Title';
$lang->ai->dataSource['productplan']['stories']['module'] = 'Module';
$lang->ai->dataSource['productplan']['stories']['pri'] = 'Priority';
$lang->ai->dataSource['productplan']['stories']['estimate'] = 'Estimates';
$lang->ai->dataSource['productplan']['stories']['status'] = 'Status';
$lang->ai->dataSource['productplan']['stories']['stage'] = 'Stage';
$lang->ai->dataSource['productplan']['bugs']['common'] = 'Bugs';
$lang->ai->dataSource['productplan']['bugs']['title'] = 'Title';
$lang->ai->dataSource['productplan']['bugs']['pri'] = 'Priority';
$lang->ai->dataSource['productplan']['bugs']['status'] = 'Status';
$lang->ai->dataSource['release']['release']['common'] = 'Release';
$lang->ai->dataSource['release']['release']['product'] = 'Product';
$lang->ai->dataSource['release']['release']['name'] = 'Name';
$lang->ai->dataSource['release']['release']['desc'] = 'Description';
$lang->ai->dataSource['release']['release']['date'] = 'Release Date';
$lang->ai->dataSource['release']['stories']['common'] = 'Stories';
$lang->ai->dataSource['release']['stories']['title'] = 'Title';
$lang->ai->dataSource['release']['stories']['estimate'] = 'Estimates';
$lang->ai->dataSource['release']['bugs']['common'] = 'Bugs';
$lang->ai->dataSource['release']['bugs']['title'] = 'Title';
$lang->ai->dataSource['project']['project']['common'] = 'Project';
$lang->ai->dataSource['project']['project']['name'] = 'Name';
$lang->ai->dataSource['project']['project']['type'] = 'Type';
$lang->ai->dataSource['project']['project']['desc'] = 'Description';
$lang->ai->dataSource['project']['project']['begin'] = 'Begin';
$lang->ai->dataSource['project']['project']['end'] = 'End';
$lang->ai->dataSource['project']['project']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['programplans']['common'] = 'Program Plan';
$lang->ai->dataSource['project']['programplans']['name'] = 'Name';
$lang->ai->dataSource['project']['programplans']['desc'] = 'Description';
$lang->ai->dataSource['project']['programplans']['status'] = 'Status';
$lang->ai->dataSource['project']['programplans']['begin'] = 'Begin';
$lang->ai->dataSource['project']['programplans']['end'] = 'End';
$lang->ai->dataSource['project']['programplans']['realBegan'] = 'Actual Start';
$lang->ai->dataSource['project']['programplans']['realEnd'] = 'Actual End';
$lang->ai->dataSource['project']['programplans']['planDuration'] = 'Plan Duration';
$lang->ai->dataSource['project']['programplans']['progress'] = 'Progress';
$lang->ai->dataSource['project']['programplans']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['programplans']['consumed'] = 'Consumed';
$lang->ai->dataSource['project']['programplans']['left'] = 'Left';
$lang->ai->dataSource['project']['executions']['common'] = 'Execution';
$lang->ai->dataSource['project']['executions']['name'] = 'Name';
$lang->ai->dataSource['project']['executions']['desc'] = 'Description';
$lang->ai->dataSource['project']['executions']['status'] = 'Status';
$lang->ai->dataSource['project']['executions']['begin'] = 'Begin';
$lang->ai->dataSource['project']['executions']['end'] = 'End';
$lang->ai->dataSource['project']['executions']['realBegan'] = 'Actual Start';
$lang->ai->dataSource['project']['executions']['realEnd'] = 'Actual End';
$lang->ai->dataSource['project']['executions']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['executions']['consumed'] = 'Consumed';
$lang->ai->dataSource['project']['executions']['left'] = 'Left';
$lang->ai->dataSource['project']['executions']['progress'] = 'Progress';
$lang->ai->dataSource['story']['story']['common'] = 'Story';
$lang->ai->dataSource['story']['story']['title'] = 'Title';
$lang->ai->dataSource['story']['story']['spec'] = 'Description';
$lang->ai->dataSource['story']['story']['verify'] = 'Acceptance criteria';
$lang->ai->dataSource['story']['story']['product'] = 'Product';
$lang->ai->dataSource['story']['story']['module'] = 'Module';
$lang->ai->dataSource['story']['story']['pri'] = 'Priority';
$lang->ai->dataSource['story']['story']['category'] = 'Category';
$lang->ai->dataSource['story']['story']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['execution']['common'] = 'Execution';
$lang->ai->dataSource['execution']['execution']['name'] = 'Name';
$lang->ai->dataSource['execution']['execution']['desc'] = 'Description';
$lang->ai->dataSource['execution']['execution']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['tasks']['common'] = 'Task List';
$lang->ai->dataSource['execution']['tasks']['name'] = 'Name';
$lang->ai->dataSource['execution']['tasks']['pri'] = 'Priority';
$lang->ai->dataSource['execution']['tasks']['status'] = 'Status';
$lang->ai->dataSource['execution']['tasks']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['tasks']['consumed'] = 'Consumed hours';
$lang->ai->dataSource['execution']['tasks']['left'] = 'Remaining hours';
$lang->ai->dataSource['execution']['tasks']['progress'] = 'Progress';
$lang->ai->dataSource['execution']['tasks']['estStarted'] = 'Estimated start date';
$lang->ai->dataSource['execution']['tasks']['realStarted'] = 'Actual start date';
$lang->ai->dataSource['execution']['tasks']['finishedDate']= 'Finished date';
$lang->ai->dataSource['execution']['tasks']['closedReason']= 'Closing reason';
$lang->ai->dataSource['task']['task']['common'] = 'Task';
$lang->ai->dataSource['task']['task']['name'] = 'Name';
$lang->ai->dataSource['task']['task']['desc'] = 'Description';
$lang->ai->dataSource['task']['task']['pri'] = 'Priority';
$lang->ai->dataSource['task']['task']['status'] = 'Status';
$lang->ai->dataSource['task']['task']['estimate'] = 'Estimates';
$lang->ai->dataSource['task']['task']['consumed'] = 'Consumed';
$lang->ai->dataSource['task']['task']['left'] = 'Left';
$lang->ai->dataSource['task']['task']['progress'] = 'Progress';
$lang->ai->dataSource['task']['task']['estStarted'] = 'Start Date';
$lang->ai->dataSource['task']['task']['realStarted'] = 'Actual Start';
$lang->ai->dataSource['case']['case']['common'] = 'Test Case';
$lang->ai->dataSource['case']['case']['title'] = 'Title';
$lang->ai->dataSource['case']['case']['precondition'] = 'Prerequisite';
$lang->ai->dataSource['case']['case']['scene'] = 'Scene';
$lang->ai->dataSource['case']['case']['product'] = 'Product';
$lang->ai->dataSource['case']['case']['module'] = 'Module';
$lang->ai->dataSource['case']['case']['pri'] = 'Priority';
$lang->ai->dataSource['case']['case']['type'] = 'Type';
$lang->ai->dataSource['case']['case']['lastRunResult'] = 'Result';
$lang->ai->dataSource['case']['case']['status'] = 'Status';
$lang->ai->dataSource['case']['steps']['common'] = 'Steps';
$lang->ai->dataSource['case']['steps']['desc'] = 'Description';
$lang->ai->dataSource['case']['steps']['expect'] = 'Expectation';
$lang->ai->dataSource['bug']['bug']['common'] = 'Bug';
$lang->ai->dataSource['bug']['bug']['title'] = 'Title';
$lang->ai->dataSource['bug']['bug']['steps'] = 'Repro Steps';
$lang->ai->dataSource['bug']['bug']['severity'] = 'Severity';
$lang->ai->dataSource['bug']['bug']['pri'] = 'Priority';
$lang->ai->dataSource['bug']['bug']['status'] = 'Status';
$lang->ai->dataSource['bug']['bug']['confirmed'] = 'Confirmed';
$lang->ai->dataSource['bug']['bug']['type'] = 'Type';
$lang->ai->dataSource['doc']['doc']['common'] = 'Document';
$lang->ai->dataSource['doc']['doc']['title'] = 'Title';
$lang->ai->dataSource['doc']['doc']['content'] = 'Text';
$lang->ai->dataSource['doc']['doc']['addedBy'] = 'Created By';
$lang->ai->dataSource['doc']['doc']['addedDate'] = 'Created Date';
$lang->ai->dataSource['doc']['doc']['editedBy'] = 'Edited By';
$lang->ai->dataSource['doc']['doc']['editedDate'] = 'Edited Date';
/* Target form definition. See `$config->ai->targetForm`. */
$lang->ai->targetForm = array();
$lang->ai->targetForm['product']['common'] = 'Product';
$lang->ai->targetForm['story']['common'] = 'Story';
$lang->ai->targetForm['productplan']['common'] = 'Plan';
$lang->ai->targetForm['projectrelease']['common'] = 'Release';
$lang->ai->targetForm['project']['common'] = 'Project';
$lang->ai->targetForm['execution']['common'] = 'Execution';
$lang->ai->targetForm['task']['common'] = 'Task';
$lang->ai->targetForm['testcase']['common'] = 'Test Case';
$lang->ai->targetForm['bug']['common'] = 'Bug';
$lang->ai->targetForm['doc']['common'] = 'Document';
$lang->ai->targetForm['product']['tree/managechild'] = 'Manage Modules';
$lang->ai->targetForm['product']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['story']['create'] = 'Create Story';
$lang->ai->targetForm['story']['batchcreate'] = 'Batch Create Story';
$lang->ai->targetForm['story']['change'] = 'Change Story';
$lang->ai->targetForm['story']['totask'] = 'Story to Task';
$lang->ai->targetForm['story']['testcasecreate'] = 'Create Test Case';
$lang->ai->targetForm['story']['subdivide'] = 'Subdivide Story';
$lang->ai->targetForm['productplan']['edit'] = 'Edit Plan';
$lang->ai->targetForm['productplan']['create'] = 'Create Sub-Plan';
$lang->ai->targetForm['projectrelease']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['project']['risk/create'] = 'Create Risk';
$lang->ai->targetForm['project']['issue/create'] = 'Create Issue';
$lang->ai->targetForm['project']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['project']['programplan/create'] = 'Set Program Plan';
$lang->ai->targetForm['execution']['batchcreatetask'] = 'Batch Create Task';
$lang->ai->targetForm['execution']['createtestreport'] = 'Create Test Report';
$lang->ai->targetForm['execution']['createqa'] = 'Create QA';
$lang->ai->targetForm['execution']['createrisk'] = 'Create Risk';
$lang->ai->targetForm['execution']['createissue'] = 'Create Issue';
$lang->ai->targetForm['task']['edit'] = 'Edit Task';
$lang->ai->targetForm['task']['batchcreate'] = 'Batch Create Task';
$lang->ai->targetForm['testcase']['edit'] = 'Edit Test Case';
$lang->ai->targetForm['testcase']['createscript'] = 'Create Script';
$lang->ai->targetForm['bug']['edit'] = 'Edit Bug';
$lang->ai->targetForm['bug']['story/create'] = 'Bug to Story';
$lang->ai->targetForm['bug']['testcase/create'] = 'Bug to Test Case';
$lang->ai->targetForm['doc']['create'] = 'Create Doc';
$lang->ai->targetForm['doc']['edit'] = 'Edit Doc';
$lang->ai->prompts->statuses = array();
$lang->ai->prompts->statuses[''] = 'All';
$lang->ai->prompts->statuses['draft'] = 'Draft';
$lang->ai->prompts->statuses['active'] = 'Active';
$lang->ai->prompts->modules = array();
$lang->ai->prompts->modules[''] = 'All';
// $lang->ai->prompts->modules['my'] = 'My';
$lang->ai->prompts->modules['product'] = 'Product';
$lang->ai->prompts->modules['project'] = 'Project';
$lang->ai->prompts->modules['story'] = 'Story';
$lang->ai->prompts->modules['productplan'] = 'Product Plan';
// $lang->ai->prompts->modules['release'] = 'Release';
$lang->ai->prompts->modules['execution'] = 'Execution';
$lang->ai->prompts->modules['task'] = 'Task';
$lang->ai->prompts->modules['case'] = 'Test Case';
$lang->ai->prompts->modules['bug'] = 'Bug';
$lang->ai->prompts->modules['doc'] = 'Document';
$lang->ai->conversations = new stdclass();
$lang->ai->conversations->common = 'Conversations';
$lang->ai->models = new stdclass();
$lang->ai->models->title = 'Language Model Configuration';
$lang->ai->models->common = 'Language Model';
$lang->ai->models->type = 'Model';
$lang->ai->models->vendor = 'Vendor';
$lang->ai->models->key = 'API Key';
$lang->ai->models->resource = 'Resource';
$lang->ai->models->deployment = 'Deployment';
$lang->ai->models->proxyType = 'Proxy Type';
$lang->ai->models->proxyAddr = 'Proxy Address';
$lang->ai->models->description = 'Description';
$lang->ai->models->testConnection = 'Test Connection';
$lang->ai->models->unconfigured = 'Unconfigured';
$lang->ai->models->edit = 'Edit Parameters';
$lang->ai->models->concealTip = 'Visible when editing';
$lang->ai->models->upgradeBiz = 'For more AI features, all in <a target="_blank" href="https://www.zentao.net/page/enterprise.html" class="text-blue">ZenTao Biz</a>.';
$lang->ai->models->noModelError = 'No language model is configured, please contact the administrator.';
$lang->ai->models->testConnectionResult = new stdclass();
$lang->ai->models->testConnectionResult->success = 'Successfully connected';
$lang->ai->models->testConnectionResult->fail = 'Failed to connect';
$lang->ai->models->testConnectionResult->failFormat = 'Failed to connect: %s';
$lang->ai->models->statusList = array();
$lang->ai->models->statusList['on'] = 'Enable';
$lang->ai->models->statusList['off'] = 'Disable';
$lang->ai->models->typeList = array();
$lang->ai->models->typeList['openai-gpt35'] = 'OpenAI / GPT-3.5';
// $lang->ai->models->typeList['azure-gpt35'] = 'Azure / GPT-3.5';
$lang->ai->models->openaiVendorList = array();
$lang->ai->models->openaiVendorList['openai'] = 'OpenAI';
$lang->ai->models->openaiVendorList['azure'] = 'Azure';
$lang->ai->models->proxyTypes = array();
$lang->ai->models->proxyTypes[''] = 'No Proxy';
$lang->ai->models->proxyTypes['socks5'] = 'SOCKS5';
$lang->ai->models->promptFor = 'Prompt for %s';
$lang->ai->designStepNav = array();
$lang->ai->designStepNav['assignrole'] = 'Specify Role';
$lang->ai->designStepNav['selectdatasource'] = 'Select Object';
$lang->ai->designStepNav['setpurpose'] = 'Confirm Action';
$lang->ai->designStepNav['settargetform'] = 'Process Result';
$lang->ai->designStepNav['finalize'] = 'Ready to Publish';
$lang->ai->dataTypeDesc = '%s is %s type, %s';
$lang->ai->dataType = new stdclass();
$lang->ai->dataType->pri = new stdClass();
$lang->ai->dataType->pri->type = 'numeric';
$lang->ai->dataType->pri->desc = '1 is the highest priority, 4 is the lowest priority.';
$lang->ai->dataType->estimate = new stdClass();
$lang->ai->dataType->estimate->type = 'numeric';
$lang->ai->dataType->estimate->desc = 'Unit is in hours.';
$lang->ai->dataType->consumed = $lang->ai->dataType->estimate;
$lang->ai->dataType->left = $lang->ai->dataType->estimate;
$lang->ai->dataType->progress = new stdClass();
$lang->ai->dataType->progress->type = 'percentage';
$lang->ai->dataType->progress->desc = '0 means not started, 100 means completed.';
$lang->ai->dataType->datetime = new stdClass();
$lang->ai->dataType->datetime->type = 'datetime';
$lang->ai->dataType->datetime->desc = 'Format is: 1970-01-01 00:00:01, or leave it blank.';
$lang->ai->dataType->estStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->realStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->finishedDate = $lang->ai->dataType->datetime;
$lang->ai->demoData = new stdclass();
$lang->ai->demoData->notExist = 'The demo data does not exist for now.';
$lang->ai->demoData->story = array(
'story' => array
(
'title' => 'Develop an online learning platform',
'spec' => 'We need to develop an online learning platform that provides course management, student management, teacher management, and other functions.',
'verify' => '1. All functions can operate properly without any obvious errors or abnormalities.2. The interface is aesthetically pleasing and user-friendly.3. The platform can meet user needs and has a high level of user satisfaction.4. The code has good quality, with clear structure and easy maintenance.',
'module' => 7,
'pri' => 1,
'estimate' => 1,
'product' => 1,
'category' => 'feature',
),
);
$lang->ai->demoData->execution = array
(
'execution' => array(
'name' => 'Online Learning Platform Software Development',
'desc' => 'This plan aims to develop an online learning platform software that provides accessible learning resources, including text, video, and audio, as well as some learning tools such as exams, tests, and discussion forums.',
'estimate' => 7,
),
'tasks' => array(
0 =>
array(
'name' => 'Technology Selection',
'pri' => 1,
'status' => 'done',
'estimate' => 1,
'consumed' => 1,
'left' => 0,
'progress' => 100,
'estStarted' => '2023-07-02 00:00:00',
'realStarted' => '2023-07-02 00:00:00',
'finishedDate' => '2023-07-02 00:00:00',
'closedReason' => 'Completed',
),
1 =>
array(
'name' => 'UI Design',
'pri' => 1,
'status' => 'doing',
'estimate' => 2,
'consumed' => 1,
'left' => 1,
'progress' => 50,
'estStarted' => '2023-07-03 00:00:00',
'realStarted' => '2023-07-03 00:00:00',
'finishedDate' => '',
'closedReason' => '',
),
2 =>
array(
'name' => 'Development',
'pri' => 1,
'status' => 'wait',
'estimate' => 1,
'consumed' => 0,
'left' => 1,
'progress' => 0,
'estStarted' => '',
'realStarted' => '',
'finishedDate' => '',
'closedReason' => '',
),
),
);
/* Forms as JSON Schemas. */
$lang->ai->formSchema = array();
$lang->ai->formSchema['story']['create'] = new stdclass();
$lang->ai->formSchema['story']['create']->title = 'Story';
$lang->ai->formSchema['story']['create']->type = 'object';
$lang->ai->formSchema['story']['create']->properties = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title = new stdclass();
$lang->ai->formSchema['story']['create']->properties->spec = new stdclass();
$lang->ai->formSchema['story']['create']->properties->verify = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title->type = 'string';
$lang->ai->formSchema['story']['create']->properties->title->description = 'Title of story';
$lang->ai->formSchema['story']['create']->properties->spec->type = 'string';
$lang->ai->formSchema['story']['create']->properties->spec->description = 'Description of story';
$lang->ai->formSchema['story']['create']->properties->verify->type = 'string';
$lang->ai->formSchema['story']['create']->properties->verify->description = 'Acceptance criteria of story';
$lang->ai->formSchema['story']['create']->required = array('title', 'spec', 'verify');
$lang->ai->formSchema['story']['change'] = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['story']['batchcreate'] = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->title = 'Stories';
$lang->ai->formSchema['story']['batchcreate']->type = 'object';
$lang->ai->formSchema['story']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories->type = 'array';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->description = 'Stories';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->items = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['productplan']['create'] = new stdclass();
$lang->ai->formSchema['productplan']['create']->title = 'Product Plan';
$lang->ai->formSchema['productplan']['create']->type = 'object';
$lang->ai->formSchema['productplan']['create']->properties = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->end = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->title->description = 'Title of product plan';
$lang->ai->formSchema['productplan']['create']->properties->begin->type = 'date';
$lang->ai->formSchema['productplan']['create']->properties->begin->description = 'Begin date of product plan';
$lang->ai->formSchema['productplan']['create']->properties->end->type = 'date';
$lang->ai->formSchema['productplan']['create']->properties->end->description = 'End date of product plan';
$lang->ai->formSchema['productplan']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->desc->description = 'Description of product plan';
$lang->ai->formSchema['productplan']['create']->required = array('title', 'begin', 'end');
$lang->ai->formSchema['productplan']['edit'] = $lang->ai->formSchema['productplan']['create'];
$lang->ai->formSchema['task']['create'] = new stdclass();
$lang->ai->formSchema['task']['create']->title = 'Task';
$lang->ai->formSchema['task']['create']->type = 'object';
$lang->ai->formSchema['task']['create']->properties = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type = new stdclass();
$lang->ai->formSchema['task']['create']->properties->name = new stdclass();
$lang->ai->formSchema['task']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['task']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['task']['create']->properties->estimate = new stdclass();
$lang->ai->formSchema['task']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['task']['create']->properties->end = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type->type = 'string';
$lang->ai->formSchema['task']['create']->properties->type->description = 'Type of task';
$lang->ai->formSchema['task']['create']->properties->type->enum = array('design', 'devel', 'request', 'test', 'study', 'discuss', 'ui', 'affair', 'misc');
$lang->ai->formSchema['task']['create']->properties->name->type = 'string';
$lang->ai->formSchema['task']['create']->properties->name->description = 'Name of task';
$lang->ai->formSchema['task']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['task']['create']->properties->desc->description = 'Description of task';
$lang->ai->formSchema['task']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['task']['create']->properties->pri->description = 'Priority of task';
$lang->ai->formSchema['task']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['task']['create']->properties->estimate->type = 'number';
$lang->ai->formSchema['task']['create']->properties->estimate->description = 'Estimated hours of task';
$lang->ai->formSchema['task']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['task']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['task']['create']->properties->begin->description = 'Begin date of task';
$lang->ai->formSchema['task']['create']->properties->end->type = 'string';
$lang->ai->formSchema['task']['create']->properties->end->format = 'date';
$lang->ai->formSchema['task']['create']->properties->end->description = 'End date of task';
$lang->ai->formSchema['task']['create']->required = array('type', 'name');
$lang->ai->formSchema['task']['edit'] = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate'] = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->title = 'Tasks';
$lang->ai->formSchema['task']['batchcreate']->type = 'object';
$lang->ai->formSchema['task']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->type = 'array';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->description = 'Tasks';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->estStarted = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin;
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->deadline = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end;
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin);
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end);
$lang->ai->formSchema['bug']['create'] = new stdclass();
$lang->ai->formSchema['bug']['create']->title = 'Bug';
$lang->ai->formSchema['bug']['create']->type = 'object';
$lang->ai->formSchema['bug']['create']->properties = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->severity = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->openedBuild = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->title->description = 'Title of bug';
$lang->ai->formSchema['bug']['create']->properties->steps->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->steps->description = 'Repro steps of bug';
$lang->ai->formSchema['bug']['create']->properties->severity->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->severity->description = 'Severity of bug';
$lang->ai->formSchema['bug']['create']->properties->severity->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->pri->description = 'Priority of bug';
$lang->ai->formSchema['bug']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->openedBuild->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->description = 'Affected builds of bug';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->enum = array('trunk');
$lang->ai->formSchema['bug']['create']->required = array('title', 'steps', 'severity', 'pri', 'openedBuild');
$lang->ai->formSchema['bug']['edit'] = $lang->ai->formSchema['bug']['create'];
$lang->ai->formSchema['testcase']['create'] = new stdclass();
$lang->ai->formSchema['testcase']['create']->title = 'Test Case';
$lang->ai->formSchema['testcase']['create']->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->stage = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->precondition = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->expects = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->type->description = 'Type of test case';
$lang->ai->formSchema['testcase']['create']->properties->type->enum = array('feature', 'performance', 'config', 'install', 'security', 'interface', 'unit', 'other');
$lang->ai->formSchema['testcase']['create']->properties->stage->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->stage->description = 'Stage of test case';
$lang->ai->formSchema['testcase']['create']->properties->stage->enum = array('unittest', 'feature', 'intergrate', 'system', 'smoke', 'bvt');
$lang->ai->formSchema['testcase']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->title->description = 'Title of test case';
$lang->ai->formSchema['testcase']['create']->properties->precondition->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->precondition->description = 'Precondition of test case';
$lang->ai->formSchema['testcase']['create']->properties->steps->type = 'array';
$lang->ai->formSchema['testcase']['create']->properties->steps->description = 'Steps of test case';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->description = 'Step description';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->description = 'Expectation of step';
$lang->ai->formSchema['testcase']['create']->required = array('type', 'title', 'steps');
$lang->ai->formSchema['testcase']['edit'] = $lang->ai->formSchema['testcase']['create'];
$lang->ai->formSchema['testreport']['create'] = new stdclass();
$lang->ai->formSchema['testreport']['create']->title = 'Test Report';
$lang->ai->formSchema['testreport']['create']->type = 'object';
$lang->ai->formSchema['testreport']['create']->properties = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->end = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->report = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->begin->description = 'Begin date of testing';
$lang->ai->formSchema['testreport']['create']->properties->end->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->end->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->end->description = 'End date of testing';
$lang->ai->formSchema['testreport']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->title->description = 'Title of test report';
$lang->ai->formSchema['testreport']['create']->properties->report->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->report->description = 'Report content';
$lang->ai->formSchema['testreport']['create']->required = array('begin', 'end', 'title', 'report');
$lang->ai->formSchema['execution']['testreport'] = $lang->ai->formSchema['testreport']['create'];
$lang->ai->formSchema['doc']['edit'] = new stdclass();
$lang->ai->formSchema['doc']['edit']->title = 'Document';
$lang->ai->formSchema['doc']['edit']->type = 'object';
$lang->ai->formSchema['doc']['edit']->properties = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->content = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->title->description = 'Title of the document';
$lang->ai->formSchema['doc']['edit']->properties->content->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->content->description = 'Content of the document';
$lang->ai->formSchema['doc']['edit']->required = array('title', 'content');
$lang->ai->formSchema['tree']['browse'] = new stdclass();
$lang->ai->formSchema['tree']['browse']->title = 'Modules';
$lang->ai->formSchema['tree']['browse']->type = 'object';
$lang->ai->formSchema['tree']['browse']->properties = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->type = 'array';
$lang->ai->formSchema['tree']['browse']->properties->modules->title = 'Modules';
$lang->ai->formSchema['tree']['browse']->properties->modules->items = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->items->type = 'string';
$lang->ai->formSchema['tree']['browse']->required = array('modules');
$lang->ai->formSchema['programplan']['create'] = new stdclass();
$lang->ai->formSchema['programplan']['create']->title = 'Program Plan';
$lang->ai->formSchema['programplan']['create']->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->type = 'array';
$lang->ai->formSchema['programplan']['create']->properties->stages->title = 'Plans';
$lang->ai->formSchema['programplan']['create']->properties->stages->items = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->description = 'Name of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->description = 'Attribute of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->enum = array('request', 'design', 'dev', 'qa', 'release', 'review', 'other');
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->type = 'boolean';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->description = 'Is milestone?';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->description = 'Begin date of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->description = 'End date of stage';
$lang->ai->formSchema['programplan']['create']->required = array('stages');
$lang->ai->promptMenu = new stdclass();
$lang->ai->promptMenu->dropdownTitle = 'AI';
$lang->ai->dataInject = new stdclass();
$lang->ai->dataInject->success = 'Prompt execution results are filled in.';
$lang->ai->dataInject->fail = 'Failed to fill in prompt execution results.';
$lang->ai->execute = new stdclass();
$lang->ai->execute->loading = 'Prompt executing...';
$lang->ai->execute->auditing = 'Getting ready for auditing...';
$lang->ai->execute->success = 'Prompt executed.';
$lang->ai->execute->fail = 'Prompt execution failed.';
$lang->ai->execute->failFormat = 'Prompt execution failed: %s.';
$lang->ai->execute->failReasons = array();
$lang->ai->execute->failReasons['noPrompt'] = 'unable to get prompt';
$lang->ai->execute->failReasons['noObjectData'] = 'unable to get object data';
$lang->ai->execute->failReasons['noResponse'] = 'no response from external service';
$lang->ai->execute->failReasons['noTargetForm'] = 'unable to get target form or its required fields';
$lang->ai->execute->executeErrors = array();
$lang->ai->execute->executeErrors[-1] = 'unable to get prompt';
$lang->ai->execute->executeErrors[-2] = 'unable to get object data';
$lang->ai->execute->executeErrors[-3] = 'failed to serialize object data';
$lang->ai->execute->executeErrors[-4] = 'unable to get target form schema';
$lang->ai->execute->executeErrors[-5] = 'request failed or API returned error';
$lang->ai->audit = new stdclass();
$lang->ai->audit->designPrompt = 'Prompt Design';
$lang->ai->audit->afterSave = 'After saving,';
$lang->ai->audit->regenerate = 'Regenerate';
$lang->ai->audit->exit = 'Exit Audit';
$lang->ai->audit->backLocationList = array();
$lang->ai->audit->backLocationList[0] = 'back to audit page.';
$lang->ai->audit->backLocationList[1] = 'back to audit page and regenerate.';
+796
View File
@@ -0,0 +1,796 @@
<?php
/**
* The ai module en lang file of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
$lang->ai->common = 'AI';
/* Definitions of table columns, used to sprintf error messages to dao::$errors. */
$lang->prompt = new stdclass();
$lang->prompt->name = 'Name';
$lang->prompt->desc = 'Description';
$lang->prompt->model = 'Model';
$lang->prompt->module = 'Module';
$lang->prompt->source = 'Data Source';
$lang->prompt->targetForm = 'Target Form';
$lang->prompt->purpose = 'Purpose';
$lang->prompt->elaboration = 'Elaboration';
$lang->prompt->role = 'Role';
$lang->prompt->characterization = 'Characterization';
$lang->prompt->status = 'Status';
$lang->prompt->createdBy = 'Created By';
$lang->prompt->createdDate = 'Created Date';
$lang->prompt->editedBy = 'Edited By';
$lang->prompt->editedDate = 'Edited Date';
$lang->prompt->deleted = 'Deleted';
/* Lang for privs, keys are paired with privlang items. */
$lang->ai->modelBrowse = 'Browse Models';
$lang->ai->modelEdit = 'Edit Models';
$lang->ai->modelTestConnection = 'Test Model Connection';
$lang->ai->promptCreate = 'Create Prompt';
$lang->ai->promptEdit = 'Edit Prompt';
$lang->ai->promptDelete = 'Delete Prompt';
$lang->ai->promptAssignRole = 'Assign Prompt Role';
$lang->ai->promptSelectDataSource = 'Select Prompt Data';
$lang->ai->promptSetPurpose = 'Set Prompt Purpose';
$lang->ai->promptSetTargetForm = 'Set Prompt Target Form';
$lang->ai->promptFinalize = 'Finalize Prompt';
$lang->ai->promptAudit = 'Audit Prompt';
$lang->ai->promptPublish = 'Publish Prompt';
$lang->ai->promptUnpublish = 'Unpublish Prompt';
$lang->ai->promptBrowse = 'Browse Prompts';
$lang->ai->promptView = 'View Prompt';
$lang->ai->promptExecute = 'Execute Prompt';
$lang->ai->promptExecutionReset = 'Reset Execute Prompt';
$lang->ai->roleTemplates = 'Manage Role Templates';
$lang->ai->nextStep = 'Next';
$lang->ai->goTesting = 'Go testing';
$lang->ai->validate = new stdclass();
$lang->ai->validate->noEmpty = '%s cannot be empty.';
$lang->ai->validate->dirtyForm = 'The design step of %s has changed. Do you want to save and return it?';
$lang->ai->validate->nameNotUnique = 'A prompt with the same name already exists, please change the name.';
$lang->ai->prompts = new stdclass();
$lang->ai->prompts->common = 'Prompt';
$lang->ai->prompts->emptyList = 'No prompts yet.';
$lang->ai->prompts->create = 'Create Prompt';
$lang->ai->prompts->edit = 'Edit Prompt';
$lang->ai->prompts->id = 'ID';
$lang->ai->prompts->name = 'Name';
$lang->ai->prompts->description = 'Description';
$lang->ai->prompts->createdBy = 'Creator';
$lang->ai->prompts->createdDate = 'Created Date';
$lang->ai->prompts->targetForm = 'Target Form';
$lang->ai->prompts->funcDesc = 'Function Description';
$lang->ai->prompts->deleted = 'Deleted';
$lang->ai->prompts->stage = 'Stage';
$lang->ai->prompts->basicInfo = 'Basic Info';
$lang->ai->prompts->editInfo = 'Edit Info';
$lang->ai->prompts->createdBy = 'Created By';
$lang->ai->prompts->publishedBy = 'Published By';
$lang->ai->prompts->draftedBy = 'Drafted By';
$lang->ai->prompts->lastEditor = 'Last Editor';
$lang->ai->prompts->summary = 'There are %s prompts on this page.';
$lang->ai->prompts->action = new stdclass();
$lang->ai->prompts->action->goDesignConfirm = 'The current prompt is not complete, continue designing?';
$lang->ai->prompts->action->goDesign = 'Go designing';
$lang->ai->prompts->action->draftConfirm = 'Once unpublished, the prompt cannot be used any further. Are you sure you want to proceed?';
$lang->ai->prompts->action->design = 'Design';
$lang->ai->prompts->action->test = 'Test';
$lang->ai->prompts->action->edit = 'Edit';
$lang->ai->prompts->action->publish = 'Publish';
$lang->ai->prompts->action->unpublish = 'Unpublish';
$lang->ai->prompts->action->delete = 'Delete';
$lang->ai->prompts->action->deleteConfirm = 'Deleted prompts will be no longer available. Are you sure you want to proceed?';
$lang->ai->prompts->action->publishSuccess = 'Publish Success';
/* Steps of prompt creation. */
$lang->ai->prompts->assignRole = 'Assign Role';
$lang->ai->prompts->selectDataSource = 'Select Data Fields';
$lang->ai->prompts->setPurpose = 'Set Purpose';
$lang->ai->prompts->setTargetForm = 'Set Target Form';
$lang->ai->prompts->finalize = 'Finalize';
/* Role assigning. */
$lang->ai->prompts->model = 'Model';
$lang->ai->prompts->role = 'Role';
$lang->ai->prompts->characterization = 'Characterization';
$lang->ai->prompts->rolePlaceholder = '"Act as a <role>"';
$lang->ai->prompts->charPlaceholder = 'Detailed characterization of this role';
$lang->ai->prompts->roleTemplate = 'Role Template';
$lang->ai->prompts->roleTemplateTip = 'After a template is referenced, modifying the role or role description does not affect the template.';
$lang->ai->prompts->addRoleTemplate = 'Add Role Template';
$lang->ai->prompts->editRoleTemplate = 'Edit Role Template';
$lang->ai->prompts->editRoleTemplateTip = 'Editing this template will not affect its previous usages in prompts.';
$lang->ai->prompts->roleAddedSuccess = 'Role added successfully.';
$lang->ai->prompts->roleDelConfirm = 'Deleting the role does not affect the role that is already in the prompt. Do you want to delete it?';
$lang->ai->prompts->roleDelSuccess = 'Role deleted successfully.';
$lang->ai->prompts->roleTemplateSave = 'Save Role Template';
$lang->ai->prompts->roleTemplateSaveList = array();
$lang->ai->prompts->roleTemplateSaveList['save'] = 'Save';
$lang->ai->prompts->roleTemplateSaveList['discard'] = 'Discard';
/* Data source selecting. */
$lang->ai->prompts->selectData = 'Select fields';
$lang->ai->prompts->selectDataTip = 'Select an object and its fields will be shown below.';
$lang->ai->prompts->selectedFormat = 'Selecting data from {0}, {1} fields selected.';
$lang->ai->prompts->nonSelected = 'No field selected.';
$lang->ai->prompts->sortTip = 'Sorting fields by priority is suggested.';
$lang->ai->prompts->object = 'Object';
$lang->ai->prompts->field = 'Field';
/* Purpose setting. */
$lang->ai->prompts->purpose = 'Purpose';
$lang->ai->prompts->purposeTip = 'What do I want it to accomplish, in order to achieve what goals?';
$lang->ai->prompts->elaboration = 'Elaboration';
$lang->ai->prompts->elaborationTip = 'I hope its answer draws attention to some additional requests.';
$lang->ai->prompts->inputPreview = 'Prompt Preview';
$lang->ai->prompts->dataPreview = 'Data Prompt Preview';
$lang->ai->prompts->rolePreview = 'Role Prompt Preview';
$lang->ai->prompts->promptPreview = 'Purpose Prompt Preview';
/* Target form selecting. */
$lang->ai->prompts->selectTargetForm = 'Select Target Form';
$lang->ai->prompts->selectTargetFormTip = 'Results returned from LLMs can be directly inputed into forms within ZenTao.';
$lang->ai->prompts->goingTesting = 'Redirecting to testing page';
$lang->ai->prompts->goingTestingFail = 'Unable to go testing, no suitable object found.';
/* Finalize page. */
$lang->ai->moduleDisableTip = 'Module is automatically selected based on selected objects.';
/* Data source definition. */
$lang->ai->dataSource = array();
$lang->ai->dataSource['my']['common'] = 'My';
$lang->ai->dataSource['product']['common'] = 'Product';
$lang->ai->dataSource['story']['common'] = 'Story';
$lang->ai->dataSource['productplan']['common'] = 'Product Plan';
$lang->ai->dataSource['release']['common'] = 'Release';
$lang->ai->dataSource['project']['common'] = 'Project';
$lang->ai->dataSource['execution']['common'] = 'Execution';
$lang->ai->dataSource['task']['common'] = 'Task';
$lang->ai->dataSource['bug']['common'] = 'Bug';
$lang->ai->dataSource['case']['common'] = 'Test Case';
$lang->ai->dataSource['doc']['common'] = 'Document';
$lang->ai->dataSource['my']['efforts']['common'] = 'Efforts';
$lang->ai->dataSource['my']['efforts']['date'] = 'Date';
$lang->ai->dataSource['my']['efforts']['work'] = 'Work';
$lang->ai->dataSource['my']['efforts']['account'] = 'Account';
$lang->ai->dataSource['my']['efforts']['consumed'] = 'Consumed';
$lang->ai->dataSource['my']['efforts']['left'] = 'Left';
$lang->ai->dataSource['my']['efforts']['objectID'] = 'Object';
$lang->ai->dataSource['my']['efforts']['product'] = 'Product';
$lang->ai->dataSource['my']['efforts']['project'] = 'Project';
$lang->ai->dataSource['my']['efforts']['execution'] = 'Execution';
$lang->ai->dataSource['product']['product']['common'] = 'Product';
$lang->ai->dataSource['product']['product']['name'] = 'Product Name';
$lang->ai->dataSource['product']['product']['desc'] = 'Description';
$lang->ai->dataSource['product']['modules']['common'] = 'Module';
$lang->ai->dataSource['product']['modules']['name'] = 'Module Name';
$lang->ai->dataSource['product']['modules']['modules'] = 'Sub Modules';
$lang->ai->dataSource['productplan']['productplan']['common'] = 'Product Plan';
$lang->ai->dataSource['productplan']['productplan']['title'] = 'Title';
$lang->ai->dataSource['productplan']['productplan']['desc'] = 'Description';
$lang->ai->dataSource['productplan']['productplan']['begin'] = 'Begin';
$lang->ai->dataSource['productplan']['productplan']['end'] = 'End';
$lang->ai->dataSource['productplan']['stories']['common'] = 'Stories';
$lang->ai->dataSource['productplan']['stories']['title'] = 'Title';
$lang->ai->dataSource['productplan']['stories']['module'] = 'Module';
$lang->ai->dataSource['productplan']['stories']['pri'] = 'Priority';
$lang->ai->dataSource['productplan']['stories']['estimate'] = 'Estimates';
$lang->ai->dataSource['productplan']['stories']['status'] = 'Status';
$lang->ai->dataSource['productplan']['stories']['stage'] = 'Stage';
$lang->ai->dataSource['productplan']['bugs']['common'] = 'Bugs';
$lang->ai->dataSource['productplan']['bugs']['title'] = 'Title';
$lang->ai->dataSource['productplan']['bugs']['pri'] = 'Priority';
$lang->ai->dataSource['productplan']['bugs']['status'] = 'Status';
$lang->ai->dataSource['release']['release']['common'] = 'Release';
$lang->ai->dataSource['release']['release']['product'] = 'Product';
$lang->ai->dataSource['release']['release']['name'] = 'Name';
$lang->ai->dataSource['release']['release']['desc'] = 'Description';
$lang->ai->dataSource['release']['release']['date'] = 'Release Date';
$lang->ai->dataSource['release']['stories']['common'] = 'Stories';
$lang->ai->dataSource['release']['stories']['title'] = 'Title';
$lang->ai->dataSource['release']['stories']['estimate'] = 'Estimates';
$lang->ai->dataSource['release']['bugs']['common'] = 'Bugs';
$lang->ai->dataSource['release']['bugs']['title'] = 'Title';
$lang->ai->dataSource['project']['project']['common'] = 'Project';
$lang->ai->dataSource['project']['project']['name'] = 'Name';
$lang->ai->dataSource['project']['project']['type'] = 'Type';
$lang->ai->dataSource['project']['project']['desc'] = 'Description';
$lang->ai->dataSource['project']['project']['begin'] = 'Begin';
$lang->ai->dataSource['project']['project']['end'] = 'End';
$lang->ai->dataSource['project']['project']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['programplans']['common'] = 'Program Plan';
$lang->ai->dataSource['project']['programplans']['name'] = 'Name';
$lang->ai->dataSource['project']['programplans']['desc'] = 'Description';
$lang->ai->dataSource['project']['programplans']['status'] = 'Status';
$lang->ai->dataSource['project']['programplans']['begin'] = 'Begin';
$lang->ai->dataSource['project']['programplans']['end'] = 'End';
$lang->ai->dataSource['project']['programplans']['realBegan'] = 'Actual Start';
$lang->ai->dataSource['project']['programplans']['realEnd'] = 'Actual End';
$lang->ai->dataSource['project']['programplans']['planDuration'] = 'Plan Duration';
$lang->ai->dataSource['project']['programplans']['progress'] = 'Progress';
$lang->ai->dataSource['project']['programplans']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['programplans']['consumed'] = 'Consumed';
$lang->ai->dataSource['project']['programplans']['left'] = 'Left';
$lang->ai->dataSource['project']['executions']['common'] = 'Execution';
$lang->ai->dataSource['project']['executions']['name'] = 'Name';
$lang->ai->dataSource['project']['executions']['desc'] = 'Description';
$lang->ai->dataSource['project']['executions']['status'] = 'Status';
$lang->ai->dataSource['project']['executions']['begin'] = 'Begin';
$lang->ai->dataSource['project']['executions']['end'] = 'End';
$lang->ai->dataSource['project']['executions']['realBegan'] = 'Actual Start';
$lang->ai->dataSource['project']['executions']['realEnd'] = 'Actual End';
$lang->ai->dataSource['project']['executions']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['executions']['consumed'] = 'Consumed';
$lang->ai->dataSource['project']['executions']['left'] = 'Left';
$lang->ai->dataSource['project']['executions']['progress'] = 'Progress';
$lang->ai->dataSource['story']['story']['common'] = 'Story';
$lang->ai->dataSource['story']['story']['title'] = 'Title';
$lang->ai->dataSource['story']['story']['spec'] = 'Description';
$lang->ai->dataSource['story']['story']['verify'] = 'Acceptance criteria';
$lang->ai->dataSource['story']['story']['product'] = 'Product';
$lang->ai->dataSource['story']['story']['module'] = 'Module';
$lang->ai->dataSource['story']['story']['pri'] = 'Priority';
$lang->ai->dataSource['story']['story']['category'] = 'Category';
$lang->ai->dataSource['story']['story']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['execution']['common'] = 'Execution';
$lang->ai->dataSource['execution']['execution']['name'] = 'Name';
$lang->ai->dataSource['execution']['execution']['desc'] = 'Description';
$lang->ai->dataSource['execution']['execution']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['tasks']['common'] = 'Task List';
$lang->ai->dataSource['execution']['tasks']['name'] = 'Name';
$lang->ai->dataSource['execution']['tasks']['pri'] = 'Priority';
$lang->ai->dataSource['execution']['tasks']['status'] = 'Status';
$lang->ai->dataSource['execution']['tasks']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['tasks']['consumed'] = 'Consumed hours';
$lang->ai->dataSource['execution']['tasks']['left'] = 'Remaining hours';
$lang->ai->dataSource['execution']['tasks']['progress'] = 'Progress';
$lang->ai->dataSource['execution']['tasks']['estStarted'] = 'Estimated start date';
$lang->ai->dataSource['execution']['tasks']['realStarted'] = 'Actual start date';
$lang->ai->dataSource['execution']['tasks']['finishedDate']= 'Finished date';
$lang->ai->dataSource['execution']['tasks']['closedReason']= 'Closing reason';
$lang->ai->dataSource['task']['task']['common'] = 'Task';
$lang->ai->dataSource['task']['task']['name'] = 'Name';
$lang->ai->dataSource['task']['task']['desc'] = 'Description';
$lang->ai->dataSource['task']['task']['pri'] = 'Priority';
$lang->ai->dataSource['task']['task']['status'] = 'Status';
$lang->ai->dataSource['task']['task']['estimate'] = 'Estimates';
$lang->ai->dataSource['task']['task']['consumed'] = 'Consumed';
$lang->ai->dataSource['task']['task']['left'] = 'Left';
$lang->ai->dataSource['task']['task']['progress'] = 'Progress';
$lang->ai->dataSource['task']['task']['estStarted'] = 'Start Date';
$lang->ai->dataSource['task']['task']['realStarted'] = 'Actual Start';
$lang->ai->dataSource['case']['case']['common'] = 'Test Case';
$lang->ai->dataSource['case']['case']['title'] = 'Title';
$lang->ai->dataSource['case']['case']['precondition'] = 'Prerequisite';
$lang->ai->dataSource['case']['case']['scene'] = 'Scene';
$lang->ai->dataSource['case']['case']['product'] = 'Product';
$lang->ai->dataSource['case']['case']['module'] = 'Module';
$lang->ai->dataSource['case']['case']['pri'] = 'Priority';
$lang->ai->dataSource['case']['case']['type'] = 'Type';
$lang->ai->dataSource['case']['case']['lastRunResult'] = 'Result';
$lang->ai->dataSource['case']['case']['status'] = 'Status';
$lang->ai->dataSource['case']['steps']['common'] = 'Steps';
$lang->ai->dataSource['case']['steps']['desc'] = 'Description';
$lang->ai->dataSource['case']['steps']['expect'] = 'Expectation';
$lang->ai->dataSource['bug']['bug']['common'] = 'Bug';
$lang->ai->dataSource['bug']['bug']['title'] = 'Title';
$lang->ai->dataSource['bug']['bug']['steps'] = 'Repro Steps';
$lang->ai->dataSource['bug']['bug']['severity'] = 'Severity';
$lang->ai->dataSource['bug']['bug']['pri'] = 'Priority';
$lang->ai->dataSource['bug']['bug']['status'] = 'Status';
$lang->ai->dataSource['bug']['bug']['confirmed'] = 'Confirmed';
$lang->ai->dataSource['bug']['bug']['type'] = 'Type';
$lang->ai->dataSource['doc']['doc']['common'] = 'Document';
$lang->ai->dataSource['doc']['doc']['title'] = 'Title';
$lang->ai->dataSource['doc']['doc']['content'] = 'Text';
$lang->ai->dataSource['doc']['doc']['addedBy'] = 'Created By';
$lang->ai->dataSource['doc']['doc']['addedDate'] = 'Created Date';
$lang->ai->dataSource['doc']['doc']['editedBy'] = 'Edited By';
$lang->ai->dataSource['doc']['doc']['editedDate'] = 'Edited Date';
/* Target form definition. See `$config->ai->targetForm`. */
$lang->ai->targetForm = array();
$lang->ai->targetForm['product']['common'] = 'Product';
$lang->ai->targetForm['story']['common'] = 'Story';
$lang->ai->targetForm['productplan']['common'] = 'Plan';
$lang->ai->targetForm['projectrelease']['common'] = 'Release';
$lang->ai->targetForm['project']['common'] = 'Project';
$lang->ai->targetForm['execution']['common'] = 'Execution';
$lang->ai->targetForm['task']['common'] = 'Task';
$lang->ai->targetForm['testcase']['common'] = 'Test Case';
$lang->ai->targetForm['bug']['common'] = 'Bug';
$lang->ai->targetForm['doc']['common'] = 'Document';
$lang->ai->targetForm['product']['tree/managechild'] = 'Manage Modules';
$lang->ai->targetForm['product']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['story']['create'] = 'Create Story';
$lang->ai->targetForm['story']['batchcreate'] = 'Batch Create Story';
$lang->ai->targetForm['story']['change'] = 'Change Story';
$lang->ai->targetForm['story']['totask'] = 'Story to Task';
$lang->ai->targetForm['story']['testcasecreate'] = 'Create Test Case';
$lang->ai->targetForm['story']['subdivide'] = 'Subdivide Story';
$lang->ai->targetForm['productplan']['edit'] = 'Edit Plan';
$lang->ai->targetForm['productplan']['create'] = 'Create Sub-Plan';
$lang->ai->targetForm['projectrelease']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['project']['risk/create'] = 'Create Risk';
$lang->ai->targetForm['project']['issue/create'] = 'Create Issue';
$lang->ai->targetForm['project']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['project']['programplan/create'] = 'Set Program Plan';
$lang->ai->targetForm['execution']['batchcreatetask'] = 'Batch Create Task';
$lang->ai->targetForm['execution']['createtestreport'] = 'Create Test Report';
$lang->ai->targetForm['execution']['createqa'] = 'Create QA';
$lang->ai->targetForm['execution']['createrisk'] = 'Create Risk';
$lang->ai->targetForm['execution']['createissue'] = 'Create Issue';
$lang->ai->targetForm['task']['edit'] = 'Edit Task';
$lang->ai->targetForm['task']['batchcreate'] = 'Batch Create Task';
$lang->ai->targetForm['testcase']['edit'] = 'Edit Test Case';
$lang->ai->targetForm['testcase']['createscript'] = 'Create Script';
$lang->ai->targetForm['bug']['edit'] = 'Edit Bug';
$lang->ai->targetForm['bug']['story/create'] = 'Bug to Story';
$lang->ai->targetForm['bug']['testcase/create'] = 'Bug to Test Case';
$lang->ai->targetForm['doc']['create'] = 'Create Doc';
$lang->ai->targetForm['doc']['edit'] = 'Edit Doc';
$lang->ai->prompts->statuses = array();
$lang->ai->prompts->statuses[''] = 'All';
$lang->ai->prompts->statuses['draft'] = 'Draft';
$lang->ai->prompts->statuses['active'] = 'Active';
$lang->ai->prompts->modules = array();
$lang->ai->prompts->modules[''] = 'All';
// $lang->ai->prompts->modules['my'] = 'My';
$lang->ai->prompts->modules['product'] = 'Product';
$lang->ai->prompts->modules['project'] = 'Project';
$lang->ai->prompts->modules['story'] = 'Story';
$lang->ai->prompts->modules['productplan'] = 'Product Plan';
// $lang->ai->prompts->modules['release'] = 'Release';
$lang->ai->prompts->modules['execution'] = 'Execution';
$lang->ai->prompts->modules['task'] = 'Task';
$lang->ai->prompts->modules['case'] = 'Test Case';
$lang->ai->prompts->modules['bug'] = 'Bug';
$lang->ai->prompts->modules['doc'] = 'Document';
$lang->ai->conversations = new stdclass();
$lang->ai->conversations->common = 'Conversations';
$lang->ai->models = new stdclass();
$lang->ai->models->title = 'Language Model Configuration';
$lang->ai->models->common = 'Language Model';
$lang->ai->models->type = 'Model';
$lang->ai->models->vendor = 'Vendor';
$lang->ai->models->key = 'API Key';
$lang->ai->models->resource = 'Resource';
$lang->ai->models->deployment = 'Deployment';
$lang->ai->models->proxyType = 'Proxy Type';
$lang->ai->models->proxyAddr = 'Proxy Address';
$lang->ai->models->description = 'Description';
$lang->ai->models->testConnection = 'Test Connection';
$lang->ai->models->unconfigured = 'Unconfigured';
$lang->ai->models->edit = 'Edit Parameters';
$lang->ai->models->concealTip = 'Visible when editing';
$lang->ai->models->upgradeBiz = 'For more AI features, all in <a target="_blank" href="https://www.zentao.net/page/enterprise.html" class="text-blue">ZenTao Biz</a>.';
$lang->ai->models->noModelError = 'No language model is configured, please contact the administrator.';
$lang->ai->models->testConnectionResult = new stdclass();
$lang->ai->models->testConnectionResult->success = 'Successfully connected';
$lang->ai->models->testConnectionResult->fail = 'Failed to connect';
$lang->ai->models->testConnectionResult->failFormat = 'Failed to connect: %s';
$lang->ai->models->statusList = array();
$lang->ai->models->statusList['on'] = 'Enable';
$lang->ai->models->statusList['off'] = 'Disable';
$lang->ai->models->typeList = array();
$lang->ai->models->typeList['openai-gpt35'] = 'OpenAI / GPT-3.5';
// $lang->ai->models->typeList['azure-gpt35'] = 'Azure / GPT-3.5';
$lang->ai->models->openaiVendorList = array();
$lang->ai->models->openaiVendorList['openai'] = 'OpenAI';
$lang->ai->models->openaiVendorList['azure'] = 'Azure';
$lang->ai->models->proxyTypes = array();
$lang->ai->models->proxyTypes[''] = 'No Proxy';
$lang->ai->models->proxyTypes['socks5'] = 'SOCKS5';
$lang->ai->models->promptFor = 'Prompt for %s';
$lang->ai->designStepNav = array();
$lang->ai->designStepNav['assignrole'] = 'Specify Role';
$lang->ai->designStepNav['selectdatasource'] = 'Select Object';
$lang->ai->designStepNav['setpurpose'] = 'Confirm Action';
$lang->ai->designStepNav['settargetform'] = 'Process Result';
$lang->ai->designStepNav['finalize'] = 'Ready to Publish';
$lang->ai->dataTypeDesc = '%s is %s type, %s';
$lang->ai->dataType = new stdclass();
$lang->ai->dataType->pri = new stdClass();
$lang->ai->dataType->pri->type = 'numeric';
$lang->ai->dataType->pri->desc = '1 is the highest priority, 4 is the lowest priority.';
$lang->ai->dataType->estimate = new stdClass();
$lang->ai->dataType->estimate->type = 'numeric';
$lang->ai->dataType->estimate->desc = 'Unit is in hours.';
$lang->ai->dataType->consumed = $lang->ai->dataType->estimate;
$lang->ai->dataType->left = $lang->ai->dataType->estimate;
$lang->ai->dataType->progress = new stdClass();
$lang->ai->dataType->progress->type = 'percentage';
$lang->ai->dataType->progress->desc = '0 means not started, 100 means completed.';
$lang->ai->dataType->datetime = new stdClass();
$lang->ai->dataType->datetime->type = 'datetime';
$lang->ai->dataType->datetime->desc = 'Format is: 1970-01-01 00:00:01, or leave it blank.';
$lang->ai->dataType->estStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->realStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->finishedDate = $lang->ai->dataType->datetime;
$lang->ai->demoData = new stdclass();
$lang->ai->demoData->notExist = 'The demo data does not exist for now.';
$lang->ai->demoData->story = array(
'story' => array
(
'title' => 'Develop an online learning platform',
'spec' => 'We need to develop an online learning platform that provides course management, student management, teacher management, and other functions.',
'verify' => '1. All functions can operate properly without any obvious errors or abnormalities.2. The interface is aesthetically pleasing and user-friendly.3. The platform can meet user needs and has a high level of user satisfaction.4. The code has good quality, with clear structure and easy maintenance.',
'module' => 7,
'pri' => 1,
'estimate' => 1,
'product' => 1,
'category' => 'feature',
),
);
$lang->ai->demoData->execution = array
(
'execution' => array(
'name' => 'Online Learning Platform Software Development',
'desc' => 'This plan aims to develop an online learning platform software that provides accessible learning resources, including text, video, and audio, as well as some learning tools such as exams, tests, and discussion forums.',
'estimate' => 7,
),
'tasks' => array(
0 =>
array(
'name' => 'Technology Selection',
'pri' => 1,
'status' => 'done',
'estimate' => 1,
'consumed' => 1,
'left' => 0,
'progress' => 100,
'estStarted' => '2023-07-02 00:00:00',
'realStarted' => '2023-07-02 00:00:00',
'finishedDate' => '2023-07-02 00:00:00',
'closedReason' => 'Completed',
),
1 =>
array(
'name' => 'UI Design',
'pri' => 1,
'status' => 'doing',
'estimate' => 2,
'consumed' => 1,
'left' => 1,
'progress' => 50,
'estStarted' => '2023-07-03 00:00:00',
'realStarted' => '2023-07-03 00:00:00',
'finishedDate' => '',
'closedReason' => '',
),
2 =>
array(
'name' => 'Development',
'pri' => 1,
'status' => 'wait',
'estimate' => 1,
'consumed' => 0,
'left' => 1,
'progress' => 0,
'estStarted' => '',
'realStarted' => '',
'finishedDate' => '',
'closedReason' => '',
),
),
);
/* Forms as JSON Schemas. */
$lang->ai->formSchema = array();
$lang->ai->formSchema['story']['create'] = new stdclass();
$lang->ai->formSchema['story']['create']->title = 'Story';
$lang->ai->formSchema['story']['create']->type = 'object';
$lang->ai->formSchema['story']['create']->properties = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title = new stdclass();
$lang->ai->formSchema['story']['create']->properties->spec = new stdclass();
$lang->ai->formSchema['story']['create']->properties->verify = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title->type = 'string';
$lang->ai->formSchema['story']['create']->properties->title->description = 'Title of story';
$lang->ai->formSchema['story']['create']->properties->spec->type = 'string';
$lang->ai->formSchema['story']['create']->properties->spec->description = 'Description of story';
$lang->ai->formSchema['story']['create']->properties->verify->type = 'string';
$lang->ai->formSchema['story']['create']->properties->verify->description = 'Acceptance criteria of story';
$lang->ai->formSchema['story']['create']->required = array('title', 'spec', 'verify');
$lang->ai->formSchema['story']['change'] = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['story']['batchcreate'] = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->title = 'Stories';
$lang->ai->formSchema['story']['batchcreate']->type = 'object';
$lang->ai->formSchema['story']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories->type = 'array';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->description = 'Stories';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->items = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['productplan']['create'] = new stdclass();
$lang->ai->formSchema['productplan']['create']->title = 'Product Plan';
$lang->ai->formSchema['productplan']['create']->type = 'object';
$lang->ai->formSchema['productplan']['create']->properties = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->end = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->title->description = 'Title of product plan';
$lang->ai->formSchema['productplan']['create']->properties->begin->type = 'date';
$lang->ai->formSchema['productplan']['create']->properties->begin->description = 'Begin date of product plan';
$lang->ai->formSchema['productplan']['create']->properties->end->type = 'date';
$lang->ai->formSchema['productplan']['create']->properties->end->description = 'End date of product plan';
$lang->ai->formSchema['productplan']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->desc->description = 'Description of product plan';
$lang->ai->formSchema['productplan']['create']->required = array('title', 'begin', 'end');
$lang->ai->formSchema['productplan']['edit'] = $lang->ai->formSchema['productplan']['create'];
$lang->ai->formSchema['task']['create'] = new stdclass();
$lang->ai->formSchema['task']['create']->title = 'Task';
$lang->ai->formSchema['task']['create']->type = 'object';
$lang->ai->formSchema['task']['create']->properties = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type = new stdclass();
$lang->ai->formSchema['task']['create']->properties->name = new stdclass();
$lang->ai->formSchema['task']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['task']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['task']['create']->properties->estimate = new stdclass();
$lang->ai->formSchema['task']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['task']['create']->properties->end = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type->type = 'string';
$lang->ai->formSchema['task']['create']->properties->type->description = 'Type of task';
$lang->ai->formSchema['task']['create']->properties->type->enum = array('design', 'devel', 'request', 'test', 'study', 'discuss', 'ui', 'affair', 'misc');
$lang->ai->formSchema['task']['create']->properties->name->type = 'string';
$lang->ai->formSchema['task']['create']->properties->name->description = 'Name of task';
$lang->ai->formSchema['task']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['task']['create']->properties->desc->description = 'Description of task';
$lang->ai->formSchema['task']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['task']['create']->properties->pri->description = 'Priority of task';
$lang->ai->formSchema['task']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['task']['create']->properties->estimate->type = 'number';
$lang->ai->formSchema['task']['create']->properties->estimate->description = 'Estimated hours of task';
$lang->ai->formSchema['task']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['task']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['task']['create']->properties->begin->description = 'Begin date of task';
$lang->ai->formSchema['task']['create']->properties->end->type = 'string';
$lang->ai->formSchema['task']['create']->properties->end->format = 'date';
$lang->ai->formSchema['task']['create']->properties->end->description = 'End date of task';
$lang->ai->formSchema['task']['create']->required = array('type', 'name');
$lang->ai->formSchema['task']['edit'] = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate'] = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->title = 'Tasks';
$lang->ai->formSchema['task']['batchcreate']->type = 'object';
$lang->ai->formSchema['task']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->type = 'array';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->description = 'Tasks';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->estStarted = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin;
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->deadline = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end;
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin);
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end);
$lang->ai->formSchema['bug']['create'] = new stdclass();
$lang->ai->formSchema['bug']['create']->title = 'Bug';
$lang->ai->formSchema['bug']['create']->type = 'object';
$lang->ai->formSchema['bug']['create']->properties = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->severity = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->openedBuild = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->title->description = 'Title of bug';
$lang->ai->formSchema['bug']['create']->properties->steps->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->steps->description = 'Repro steps of bug';
$lang->ai->formSchema['bug']['create']->properties->severity->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->severity->description = 'Severity of bug';
$lang->ai->formSchema['bug']['create']->properties->severity->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->pri->description = 'Priority of bug';
$lang->ai->formSchema['bug']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->openedBuild->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->description = 'Affected builds of bug';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->enum = array('trunk');
$lang->ai->formSchema['bug']['create']->required = array('title', 'steps', 'severity', 'pri', 'openedBuild');
$lang->ai->formSchema['bug']['edit'] = $lang->ai->formSchema['bug']['create'];
$lang->ai->formSchema['testcase']['create'] = new stdclass();
$lang->ai->formSchema['testcase']['create']->title = 'Test Case';
$lang->ai->formSchema['testcase']['create']->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->stage = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->precondition = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->expects = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->type->description = 'Type of test case';
$lang->ai->formSchema['testcase']['create']->properties->type->enum = array('feature', 'performance', 'config', 'install', 'security', 'interface', 'unit', 'other');
$lang->ai->formSchema['testcase']['create']->properties->stage->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->stage->description = 'Stage of test case';
$lang->ai->formSchema['testcase']['create']->properties->stage->enum = array('unittest', 'feature', 'intergrate', 'system', 'smoke', 'bvt');
$lang->ai->formSchema['testcase']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->title->description = 'Title of test case';
$lang->ai->formSchema['testcase']['create']->properties->precondition->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->precondition->description = 'Precondition of test case';
$lang->ai->formSchema['testcase']['create']->properties->steps->type = 'array';
$lang->ai->formSchema['testcase']['create']->properties->steps->description = 'Steps of test case';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->description = 'Step description';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->description = 'Expectation of step';
$lang->ai->formSchema['testcase']['create']->required = array('type', 'title', 'steps');
$lang->ai->formSchema['testcase']['edit'] = $lang->ai->formSchema['testcase']['create'];
$lang->ai->formSchema['testreport']['create'] = new stdclass();
$lang->ai->formSchema['testreport']['create']->title = 'Test Report';
$lang->ai->formSchema['testreport']['create']->type = 'object';
$lang->ai->formSchema['testreport']['create']->properties = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->end = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->report = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->begin->description = 'Begin date of testing';
$lang->ai->formSchema['testreport']['create']->properties->end->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->end->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->end->description = 'End date of testing';
$lang->ai->formSchema['testreport']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->title->description = 'Title of test report';
$lang->ai->formSchema['testreport']['create']->properties->report->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->report->description = 'Report content';
$lang->ai->formSchema['testreport']['create']->required = array('begin', 'end', 'title', 'report');
$lang->ai->formSchema['execution']['testreport'] = $lang->ai->formSchema['testreport']['create'];
$lang->ai->formSchema['doc']['edit'] = new stdclass();
$lang->ai->formSchema['doc']['edit']->title = 'Document';
$lang->ai->formSchema['doc']['edit']->type = 'object';
$lang->ai->formSchema['doc']['edit']->properties = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->content = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->title->description = 'Title of the document';
$lang->ai->formSchema['doc']['edit']->properties->content->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->content->description = 'Content of the document';
$lang->ai->formSchema['doc']['edit']->required = array('title', 'content');
$lang->ai->formSchema['tree']['browse'] = new stdclass();
$lang->ai->formSchema['tree']['browse']->title = 'Modules';
$lang->ai->formSchema['tree']['browse']->type = 'object';
$lang->ai->formSchema['tree']['browse']->properties = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->type = 'array';
$lang->ai->formSchema['tree']['browse']->properties->modules->title = 'Modules';
$lang->ai->formSchema['tree']['browse']->properties->modules->items = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->items->type = 'string';
$lang->ai->formSchema['tree']['browse']->required = array('modules');
$lang->ai->formSchema['programplan']['create'] = new stdclass();
$lang->ai->formSchema['programplan']['create']->title = 'Program Plan';
$lang->ai->formSchema['programplan']['create']->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->type = 'array';
$lang->ai->formSchema['programplan']['create']->properties->stages->title = 'Plans';
$lang->ai->formSchema['programplan']['create']->properties->stages->items = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->description = 'Name of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->description = 'Attribute of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->enum = array('request', 'design', 'dev', 'qa', 'release', 'review', 'other');
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->type = 'boolean';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->description = 'Is milestone?';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->description = 'Begin date of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->description = 'End date of stage';
$lang->ai->formSchema['programplan']['create']->required = array('stages');
$lang->ai->promptMenu = new stdclass();
$lang->ai->promptMenu->dropdownTitle = 'AI';
$lang->ai->dataInject = new stdclass();
$lang->ai->dataInject->success = 'Prompt execution results are filled in.';
$lang->ai->dataInject->fail = 'Failed to fill in prompt execution results.';
$lang->ai->execute = new stdclass();
$lang->ai->execute->loading = 'Prompt executing...';
$lang->ai->execute->auditing = 'Getting ready for auditing...';
$lang->ai->execute->success = 'Prompt executed.';
$lang->ai->execute->fail = 'Prompt execution failed.';
$lang->ai->execute->failFormat = 'Prompt execution failed: %s.';
$lang->ai->execute->failReasons = array();
$lang->ai->execute->failReasons['noPrompt'] = 'unable to get prompt';
$lang->ai->execute->failReasons['noObjectData'] = 'unable to get object data';
$lang->ai->execute->failReasons['noResponse'] = 'no response from external service';
$lang->ai->execute->failReasons['noTargetForm'] = 'unable to get target form or its required fields';
$lang->ai->execute->executeErrors = array();
$lang->ai->execute->executeErrors[-1] = 'unable to get prompt';
$lang->ai->execute->executeErrors[-2] = 'unable to get object data';
$lang->ai->execute->executeErrors[-3] = 'failed to serialize object data';
$lang->ai->execute->executeErrors[-4] = 'unable to get target form schema';
$lang->ai->execute->executeErrors[-5] = 'request failed or API returned error';
$lang->ai->audit = new stdclass();
$lang->ai->audit->designPrompt = 'Prompt Design';
$lang->ai->audit->afterSave = 'After saving,';
$lang->ai->audit->regenerate = 'Regenerate';
$lang->ai->audit->exit = 'Exit Audit';
$lang->ai->audit->backLocationList = array();
$lang->ai->audit->backLocationList[0] = 'back to audit page.';
$lang->ai->audit->backLocationList[1] = 'back to audit page and regenerate.';
+796
View File
@@ -0,0 +1,796 @@
<?php
/**
* The ai module en lang file of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
$lang->ai->common = 'AI';
/* Definitions of table columns, used to sprintf error messages to dao::$errors. */
$lang->prompt = new stdclass();
$lang->prompt->name = 'Name';
$lang->prompt->desc = 'Description';
$lang->prompt->model = 'Model';
$lang->prompt->module = 'Module';
$lang->prompt->source = 'Data Source';
$lang->prompt->targetForm = 'Target Form';
$lang->prompt->purpose = 'Purpose';
$lang->prompt->elaboration = 'Elaboration';
$lang->prompt->role = 'Role';
$lang->prompt->characterization = 'Characterization';
$lang->prompt->status = 'Status';
$lang->prompt->createdBy = 'Created By';
$lang->prompt->createdDate = 'Created Date';
$lang->prompt->editedBy = 'Edited By';
$lang->prompt->editedDate = 'Edited Date';
$lang->prompt->deleted = 'Deleted';
/* Lang for privs, keys are paired with privlang items. */
$lang->ai->modelBrowse = 'Browse Models';
$lang->ai->modelEdit = 'Edit Models';
$lang->ai->modelTestConnection = 'Test Model Connection';
$lang->ai->promptCreate = 'Create Prompt';
$lang->ai->promptEdit = 'Edit Prompt';
$lang->ai->promptDelete = 'Delete Prompt';
$lang->ai->promptAssignRole = 'Assign Prompt Role';
$lang->ai->promptSelectDataSource = 'Select Prompt Data';
$lang->ai->promptSetPurpose = 'Set Prompt Purpose';
$lang->ai->promptSetTargetForm = 'Set Prompt Target Form';
$lang->ai->promptFinalize = 'Finalize Prompt';
$lang->ai->promptAudit = 'Audit Prompt';
$lang->ai->promptPublish = 'Publish Prompt';
$lang->ai->promptUnpublish = 'Unpublish Prompt';
$lang->ai->promptBrowse = 'Browse Prompts';
$lang->ai->promptView = 'View Prompt';
$lang->ai->promptExecute = 'Execute Prompt';
$lang->ai->promptExecutionReset = 'Reset Execute Prompt';
$lang->ai->roleTemplates = 'Manage Role Templates';
$lang->ai->nextStep = 'Next';
$lang->ai->goTesting = 'Go testing';
$lang->ai->validate = new stdclass();
$lang->ai->validate->noEmpty = '%s cannot be empty.';
$lang->ai->validate->dirtyForm = 'The design step of %s has changed. Do you want to save and return it?';
$lang->ai->validate->nameNotUnique = 'A prompt with the same name already exists, please change the name.';
$lang->ai->prompts = new stdclass();
$lang->ai->prompts->common = 'Prompt';
$lang->ai->prompts->emptyList = 'No prompts yet.';
$lang->ai->prompts->create = 'Create Prompt';
$lang->ai->prompts->edit = 'Edit Prompt';
$lang->ai->prompts->id = 'ID';
$lang->ai->prompts->name = 'Name';
$lang->ai->prompts->description = 'Description';
$lang->ai->prompts->createdBy = 'Creator';
$lang->ai->prompts->createdDate = 'Created Date';
$lang->ai->prompts->targetForm = 'Target Form';
$lang->ai->prompts->funcDesc = 'Function Description';
$lang->ai->prompts->deleted = 'Deleted';
$lang->ai->prompts->stage = 'Stage';
$lang->ai->prompts->basicInfo = 'Basic Info';
$lang->ai->prompts->editInfo = 'Edit Info';
$lang->ai->prompts->createdBy = 'Created By';
$lang->ai->prompts->publishedBy = 'Published By';
$lang->ai->prompts->draftedBy = 'Drafted By';
$lang->ai->prompts->lastEditor = 'Last Editor';
$lang->ai->prompts->summary = 'There are %s prompts on this page.';
$lang->ai->prompts->action = new stdclass();
$lang->ai->prompts->action->goDesignConfirm = 'The current prompt is not complete, continue designing?';
$lang->ai->prompts->action->goDesign = 'Go designing';
$lang->ai->prompts->action->draftConfirm = 'Once unpublished, the prompt cannot be used any further. Are you sure you want to proceed?';
$lang->ai->prompts->action->design = 'Design';
$lang->ai->prompts->action->test = 'Test';
$lang->ai->prompts->action->edit = 'Edit';
$lang->ai->prompts->action->publish = 'Publish';
$lang->ai->prompts->action->unpublish = 'Unpublish';
$lang->ai->prompts->action->delete = 'Delete';
$lang->ai->prompts->action->deleteConfirm = 'Deleted prompts will be no longer available. Are you sure you want to proceed?';
$lang->ai->prompts->action->publishSuccess = 'Publish Success';
/* Steps of prompt creation. */
$lang->ai->prompts->assignRole = 'Assign Role';
$lang->ai->prompts->selectDataSource = 'Select Data Fields';
$lang->ai->prompts->setPurpose = 'Set Purpose';
$lang->ai->prompts->setTargetForm = 'Set Target Form';
$lang->ai->prompts->finalize = 'Finalize';
/* Role assigning. */
$lang->ai->prompts->model = 'Model';
$lang->ai->prompts->role = 'Role';
$lang->ai->prompts->characterization = 'Characterization';
$lang->ai->prompts->rolePlaceholder = '"Act as a <role>"';
$lang->ai->prompts->charPlaceholder = 'Detailed characterization of this role';
$lang->ai->prompts->roleTemplate = 'Role Template';
$lang->ai->prompts->roleTemplateTip = 'After a template is referenced, modifying the role or role description does not affect the template.';
$lang->ai->prompts->addRoleTemplate = 'Add Role Template';
$lang->ai->prompts->editRoleTemplate = 'Edit Role Template';
$lang->ai->prompts->editRoleTemplateTip = 'Editing this template will not affect its previous usages in prompts.';
$lang->ai->prompts->roleAddedSuccess = 'Role added successfully.';
$lang->ai->prompts->roleDelConfirm = 'Deleting the role does not affect the role that is already in the prompt. Do you want to delete it?';
$lang->ai->prompts->roleDelSuccess = 'Role deleted successfully.';
$lang->ai->prompts->roleTemplateSave = 'Save Role Template';
$lang->ai->prompts->roleTemplateSaveList = array();
$lang->ai->prompts->roleTemplateSaveList['save'] = 'Save';
$lang->ai->prompts->roleTemplateSaveList['discard'] = 'Discard';
/* Data source selecting. */
$lang->ai->prompts->selectData = 'Select fields';
$lang->ai->prompts->selectDataTip = 'Select an object and its fields will be shown below.';
$lang->ai->prompts->selectedFormat = 'Selecting data from {0}, {1} fields selected.';
$lang->ai->prompts->nonSelected = 'No field selected.';
$lang->ai->prompts->sortTip = 'Sorting fields by priority is suggested.';
$lang->ai->prompts->object = 'Object';
$lang->ai->prompts->field = 'Field';
/* Purpose setting. */
$lang->ai->prompts->purpose = 'Purpose';
$lang->ai->prompts->purposeTip = 'What do I want it to accomplish, in order to achieve what goals?';
$lang->ai->prompts->elaboration = 'Elaboration';
$lang->ai->prompts->elaborationTip = 'I hope its answer draws attention to some additional requests.';
$lang->ai->prompts->inputPreview = 'Prompt Preview';
$lang->ai->prompts->dataPreview = 'Data Prompt Preview';
$lang->ai->prompts->rolePreview = 'Role Prompt Preview';
$lang->ai->prompts->promptPreview = 'Purpose Prompt Preview';
/* Target form selecting. */
$lang->ai->prompts->selectTargetForm = 'Select Target Form';
$lang->ai->prompts->selectTargetFormTip = 'Results returned from LLMs can be directly inputed into forms within ZenTao.';
$lang->ai->prompts->goingTesting = 'Redirecting to testing page';
$lang->ai->prompts->goingTestingFail = 'Unable to go testing, no suitable object found.';
/* Finalize page. */
$lang->ai->moduleDisableTip = 'Module is automatically selected based on selected objects.';
/* Data source definition. */
$lang->ai->dataSource = array();
$lang->ai->dataSource['my']['common'] = 'My';
$lang->ai->dataSource['product']['common'] = 'Product';
$lang->ai->dataSource['story']['common'] = 'Story';
$lang->ai->dataSource['productplan']['common'] = 'Product Plan';
$lang->ai->dataSource['release']['common'] = 'Release';
$lang->ai->dataSource['project']['common'] = 'Project';
$lang->ai->dataSource['execution']['common'] = 'Execution';
$lang->ai->dataSource['task']['common'] = 'Task';
$lang->ai->dataSource['bug']['common'] = 'Bug';
$lang->ai->dataSource['case']['common'] = 'Test Case';
$lang->ai->dataSource['doc']['common'] = 'Document';
$lang->ai->dataSource['my']['efforts']['common'] = 'Efforts';
$lang->ai->dataSource['my']['efforts']['date'] = 'Date';
$lang->ai->dataSource['my']['efforts']['work'] = 'Work';
$lang->ai->dataSource['my']['efforts']['account'] = 'Account';
$lang->ai->dataSource['my']['efforts']['consumed'] = 'Consumed';
$lang->ai->dataSource['my']['efforts']['left'] = 'Left';
$lang->ai->dataSource['my']['efforts']['objectID'] = 'Object';
$lang->ai->dataSource['my']['efforts']['product'] = 'Product';
$lang->ai->dataSource['my']['efforts']['project'] = 'Project';
$lang->ai->dataSource['my']['efforts']['execution'] = 'Execution';
$lang->ai->dataSource['product']['product']['common'] = 'Product';
$lang->ai->dataSource['product']['product']['name'] = 'Product Name';
$lang->ai->dataSource['product']['product']['desc'] = 'Description';
$lang->ai->dataSource['product']['modules']['common'] = 'Module';
$lang->ai->dataSource['product']['modules']['name'] = 'Module Name';
$lang->ai->dataSource['product']['modules']['modules'] = 'Sub Modules';
$lang->ai->dataSource['productplan']['productplan']['common'] = 'Product Plan';
$lang->ai->dataSource['productplan']['productplan']['title'] = 'Title';
$lang->ai->dataSource['productplan']['productplan']['desc'] = 'Description';
$lang->ai->dataSource['productplan']['productplan']['begin'] = 'Begin';
$lang->ai->dataSource['productplan']['productplan']['end'] = 'End';
$lang->ai->dataSource['productplan']['stories']['common'] = 'Stories';
$lang->ai->dataSource['productplan']['stories']['title'] = 'Title';
$lang->ai->dataSource['productplan']['stories']['module'] = 'Module';
$lang->ai->dataSource['productplan']['stories']['pri'] = 'Priority';
$lang->ai->dataSource['productplan']['stories']['estimate'] = 'Estimates';
$lang->ai->dataSource['productplan']['stories']['status'] = 'Status';
$lang->ai->dataSource['productplan']['stories']['stage'] = 'Stage';
$lang->ai->dataSource['productplan']['bugs']['common'] = 'Bugs';
$lang->ai->dataSource['productplan']['bugs']['title'] = 'Title';
$lang->ai->dataSource['productplan']['bugs']['pri'] = 'Priority';
$lang->ai->dataSource['productplan']['bugs']['status'] = 'Status';
$lang->ai->dataSource['release']['release']['common'] = 'Release';
$lang->ai->dataSource['release']['release']['product'] = 'Product';
$lang->ai->dataSource['release']['release']['name'] = 'Name';
$lang->ai->dataSource['release']['release']['desc'] = 'Description';
$lang->ai->dataSource['release']['release']['date'] = 'Release Date';
$lang->ai->dataSource['release']['stories']['common'] = 'Stories';
$lang->ai->dataSource['release']['stories']['title'] = 'Title';
$lang->ai->dataSource['release']['stories']['estimate'] = 'Estimates';
$lang->ai->dataSource['release']['bugs']['common'] = 'Bugs';
$lang->ai->dataSource['release']['bugs']['title'] = 'Title';
$lang->ai->dataSource['project']['project']['common'] = 'Project';
$lang->ai->dataSource['project']['project']['name'] = 'Name';
$lang->ai->dataSource['project']['project']['type'] = 'Type';
$lang->ai->dataSource['project']['project']['desc'] = 'Description';
$lang->ai->dataSource['project']['project']['begin'] = 'Begin';
$lang->ai->dataSource['project']['project']['end'] = 'End';
$lang->ai->dataSource['project']['project']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['programplans']['common'] = 'Program Plan';
$lang->ai->dataSource['project']['programplans']['name'] = 'Name';
$lang->ai->dataSource['project']['programplans']['desc'] = 'Description';
$lang->ai->dataSource['project']['programplans']['status'] = 'Status';
$lang->ai->dataSource['project']['programplans']['begin'] = 'Begin';
$lang->ai->dataSource['project']['programplans']['end'] = 'End';
$lang->ai->dataSource['project']['programplans']['realBegan'] = 'Actual Start';
$lang->ai->dataSource['project']['programplans']['realEnd'] = 'Actual End';
$lang->ai->dataSource['project']['programplans']['planDuration'] = 'Plan Duration';
$lang->ai->dataSource['project']['programplans']['progress'] = 'Progress';
$lang->ai->dataSource['project']['programplans']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['programplans']['consumed'] = 'Consumed';
$lang->ai->dataSource['project']['programplans']['left'] = 'Left';
$lang->ai->dataSource['project']['executions']['common'] = 'Execution';
$lang->ai->dataSource['project']['executions']['name'] = 'Name';
$lang->ai->dataSource['project']['executions']['desc'] = 'Description';
$lang->ai->dataSource['project']['executions']['status'] = 'Status';
$lang->ai->dataSource['project']['executions']['begin'] = 'Begin';
$lang->ai->dataSource['project']['executions']['end'] = 'End';
$lang->ai->dataSource['project']['executions']['realBegan'] = 'Actual Start';
$lang->ai->dataSource['project']['executions']['realEnd'] = 'Actual End';
$lang->ai->dataSource['project']['executions']['estimate'] = 'Estimates';
$lang->ai->dataSource['project']['executions']['consumed'] = 'Consumed';
$lang->ai->dataSource['project']['executions']['left'] = 'Left';
$lang->ai->dataSource['project']['executions']['progress'] = 'Progress';
$lang->ai->dataSource['story']['story']['common'] = 'Story';
$lang->ai->dataSource['story']['story']['title'] = 'Title';
$lang->ai->dataSource['story']['story']['spec'] = 'Description';
$lang->ai->dataSource['story']['story']['verify'] = 'Acceptance criteria';
$lang->ai->dataSource['story']['story']['product'] = 'Product';
$lang->ai->dataSource['story']['story']['module'] = 'Module';
$lang->ai->dataSource['story']['story']['pri'] = 'Priority';
$lang->ai->dataSource['story']['story']['category'] = 'Category';
$lang->ai->dataSource['story']['story']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['execution']['common'] = 'Execution';
$lang->ai->dataSource['execution']['execution']['name'] = 'Name';
$lang->ai->dataSource['execution']['execution']['desc'] = 'Description';
$lang->ai->dataSource['execution']['execution']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['tasks']['common'] = 'Task List';
$lang->ai->dataSource['execution']['tasks']['name'] = 'Name';
$lang->ai->dataSource['execution']['tasks']['pri'] = 'Priority';
$lang->ai->dataSource['execution']['tasks']['status'] = 'Status';
$lang->ai->dataSource['execution']['tasks']['estimate'] = 'Estimated hours';
$lang->ai->dataSource['execution']['tasks']['consumed'] = 'Consumed hours';
$lang->ai->dataSource['execution']['tasks']['left'] = 'Remaining hours';
$lang->ai->dataSource['execution']['tasks']['progress'] = 'Progress';
$lang->ai->dataSource['execution']['tasks']['estStarted'] = 'Estimated start date';
$lang->ai->dataSource['execution']['tasks']['realStarted'] = 'Actual start date';
$lang->ai->dataSource['execution']['tasks']['finishedDate']= 'Finished date';
$lang->ai->dataSource['execution']['tasks']['closedReason']= 'Closing reason';
$lang->ai->dataSource['task']['task']['common'] = 'Task';
$lang->ai->dataSource['task']['task']['name'] = 'Name';
$lang->ai->dataSource['task']['task']['desc'] = 'Description';
$lang->ai->dataSource['task']['task']['pri'] = 'Priority';
$lang->ai->dataSource['task']['task']['status'] = 'Status';
$lang->ai->dataSource['task']['task']['estimate'] = 'Estimates';
$lang->ai->dataSource['task']['task']['consumed'] = 'Consumed';
$lang->ai->dataSource['task']['task']['left'] = 'Left';
$lang->ai->dataSource['task']['task']['progress'] = 'Progress';
$lang->ai->dataSource['task']['task']['estStarted'] = 'Start Date';
$lang->ai->dataSource['task']['task']['realStarted'] = 'Actual Start';
$lang->ai->dataSource['case']['case']['common'] = 'Test Case';
$lang->ai->dataSource['case']['case']['title'] = 'Title';
$lang->ai->dataSource['case']['case']['precondition'] = 'Prerequisite';
$lang->ai->dataSource['case']['case']['scene'] = 'Scene';
$lang->ai->dataSource['case']['case']['product'] = 'Product';
$lang->ai->dataSource['case']['case']['module'] = 'Module';
$lang->ai->dataSource['case']['case']['pri'] = 'Priority';
$lang->ai->dataSource['case']['case']['type'] = 'Type';
$lang->ai->dataSource['case']['case']['lastRunResult'] = 'Result';
$lang->ai->dataSource['case']['case']['status'] = 'Status';
$lang->ai->dataSource['case']['steps']['common'] = 'Steps';
$lang->ai->dataSource['case']['steps']['desc'] = 'Description';
$lang->ai->dataSource['case']['steps']['expect'] = 'Expectation';
$lang->ai->dataSource['bug']['bug']['common'] = 'Bug';
$lang->ai->dataSource['bug']['bug']['title'] = 'Title';
$lang->ai->dataSource['bug']['bug']['steps'] = 'Repro Steps';
$lang->ai->dataSource['bug']['bug']['severity'] = 'Severity';
$lang->ai->dataSource['bug']['bug']['pri'] = 'Priority';
$lang->ai->dataSource['bug']['bug']['status'] = 'Status';
$lang->ai->dataSource['bug']['bug']['confirmed'] = 'Confirmed';
$lang->ai->dataSource['bug']['bug']['type'] = 'Type';
$lang->ai->dataSource['doc']['doc']['common'] = 'Document';
$lang->ai->dataSource['doc']['doc']['title'] = 'Title';
$lang->ai->dataSource['doc']['doc']['content'] = 'Text';
$lang->ai->dataSource['doc']['doc']['addedBy'] = 'Created By';
$lang->ai->dataSource['doc']['doc']['addedDate'] = 'Created Date';
$lang->ai->dataSource['doc']['doc']['editedBy'] = 'Edited By';
$lang->ai->dataSource['doc']['doc']['editedDate'] = 'Edited Date';
/* Target form definition. See `$config->ai->targetForm`. */
$lang->ai->targetForm = array();
$lang->ai->targetForm['product']['common'] = 'Product';
$lang->ai->targetForm['story']['common'] = 'Story';
$lang->ai->targetForm['productplan']['common'] = 'Plan';
$lang->ai->targetForm['projectrelease']['common'] = 'Release';
$lang->ai->targetForm['project']['common'] = 'Project';
$lang->ai->targetForm['execution']['common'] = 'Execution';
$lang->ai->targetForm['task']['common'] = 'Task';
$lang->ai->targetForm['testcase']['common'] = 'Test Case';
$lang->ai->targetForm['bug']['common'] = 'Bug';
$lang->ai->targetForm['doc']['common'] = 'Document';
$lang->ai->targetForm['product']['tree/managechild'] = 'Manage Modules';
$lang->ai->targetForm['product']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['story']['create'] = 'Create Story';
$lang->ai->targetForm['story']['batchcreate'] = 'Batch Create Story';
$lang->ai->targetForm['story']['change'] = 'Change Story';
$lang->ai->targetForm['story']['totask'] = 'Story to Task';
$lang->ai->targetForm['story']['testcasecreate'] = 'Create Test Case';
$lang->ai->targetForm['story']['subdivide'] = 'Subdivide Story';
$lang->ai->targetForm['productplan']['edit'] = 'Edit Plan';
$lang->ai->targetForm['productplan']['create'] = 'Create Sub-Plan';
$lang->ai->targetForm['projectrelease']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['project']['risk/create'] = 'Create Risk';
$lang->ai->targetForm['project']['issue/create'] = 'Create Issue';
$lang->ai->targetForm['project']['doc/create'] = 'Create Doc';
$lang->ai->targetForm['project']['programplan/create'] = 'Set Program Plan';
$lang->ai->targetForm['execution']['batchcreatetask'] = 'Batch Create Task';
$lang->ai->targetForm['execution']['createtestreport'] = 'Create Test Report';
$lang->ai->targetForm['execution']['createqa'] = 'Create QA';
$lang->ai->targetForm['execution']['createrisk'] = 'Create Risk';
$lang->ai->targetForm['execution']['createissue'] = 'Create Issue';
$lang->ai->targetForm['task']['edit'] = 'Edit Task';
$lang->ai->targetForm['task']['batchcreate'] = 'Batch Create Task';
$lang->ai->targetForm['testcase']['edit'] = 'Edit Test Case';
$lang->ai->targetForm['testcase']['createscript'] = 'Create Script';
$lang->ai->targetForm['bug']['edit'] = 'Edit Bug';
$lang->ai->targetForm['bug']['story/create'] = 'Bug to Story';
$lang->ai->targetForm['bug']['testcase/create'] = 'Bug to Test Case';
$lang->ai->targetForm['doc']['create'] = 'Create Doc';
$lang->ai->targetForm['doc']['edit'] = 'Edit Doc';
$lang->ai->prompts->statuses = array();
$lang->ai->prompts->statuses[''] = 'All';
$lang->ai->prompts->statuses['draft'] = 'Draft';
$lang->ai->prompts->statuses['active'] = 'Active';
$lang->ai->prompts->modules = array();
$lang->ai->prompts->modules[''] = 'All';
// $lang->ai->prompts->modules['my'] = 'My';
$lang->ai->prompts->modules['product'] = 'Product';
$lang->ai->prompts->modules['project'] = 'Project';
$lang->ai->prompts->modules['story'] = 'Story';
$lang->ai->prompts->modules['productplan'] = 'Product Plan';
// $lang->ai->prompts->modules['release'] = 'Release';
$lang->ai->prompts->modules['execution'] = 'Execution';
$lang->ai->prompts->modules['task'] = 'Task';
$lang->ai->prompts->modules['case'] = 'Test Case';
$lang->ai->prompts->modules['bug'] = 'Bug';
$lang->ai->prompts->modules['doc'] = 'Document';
$lang->ai->conversations = new stdclass();
$lang->ai->conversations->common = 'Conversations';
$lang->ai->models = new stdclass();
$lang->ai->models->title = 'Language Model Configuration';
$lang->ai->models->common = 'Language Model';
$lang->ai->models->type = 'Model';
$lang->ai->models->vendor = 'Vendor';
$lang->ai->models->key = 'API Key';
$lang->ai->models->resource = 'Resource';
$lang->ai->models->deployment = 'Deployment';
$lang->ai->models->proxyType = 'Proxy Type';
$lang->ai->models->proxyAddr = 'Proxy Address';
$lang->ai->models->description = 'Description';
$lang->ai->models->testConnection = 'Test Connection';
$lang->ai->models->unconfigured = 'Unconfigured';
$lang->ai->models->edit = 'Edit Parameters';
$lang->ai->models->concealTip = 'Visible when editing';
$lang->ai->models->upgradeBiz = 'For more AI features, all in <a target="_blank" href="https://www.zentao.net/page/enterprise.html" class="text-blue">ZenTao Biz</a>.';
$lang->ai->models->noModelError = 'No language model is configured, please contact the administrator.';
$lang->ai->models->testConnectionResult = new stdclass();
$lang->ai->models->testConnectionResult->success = 'Successfully connected';
$lang->ai->models->testConnectionResult->fail = 'Failed to connect';
$lang->ai->models->testConnectionResult->failFormat = 'Failed to connect: %s';
$lang->ai->models->statusList = array();
$lang->ai->models->statusList['on'] = 'Enable';
$lang->ai->models->statusList['off'] = 'Disable';
$lang->ai->models->typeList = array();
$lang->ai->models->typeList['openai-gpt35'] = 'OpenAI / GPT-3.5';
// $lang->ai->models->typeList['azure-gpt35'] = 'Azure / GPT-3.5';
$lang->ai->models->openaiVendorList = array();
$lang->ai->models->openaiVendorList['openai'] = 'OpenAI';
$lang->ai->models->openaiVendorList['azure'] = 'Azure';
$lang->ai->models->proxyTypes = array();
$lang->ai->models->proxyTypes[''] = 'No Proxy';
$lang->ai->models->proxyTypes['socks5'] = 'SOCKS5';
$lang->ai->models->promptFor = 'Prompt for %s';
$lang->ai->designStepNav = array();
$lang->ai->designStepNav['assignrole'] = 'Specify Role';
$lang->ai->designStepNav['selectdatasource'] = 'Select Object';
$lang->ai->designStepNav['setpurpose'] = 'Confirm Action';
$lang->ai->designStepNav['settargetform'] = 'Process Result';
$lang->ai->designStepNav['finalize'] = 'Ready to Publish';
$lang->ai->dataTypeDesc = '%s is %s type, %s';
$lang->ai->dataType = new stdclass();
$lang->ai->dataType->pri = new stdClass();
$lang->ai->dataType->pri->type = 'numeric';
$lang->ai->dataType->pri->desc = '1 is the highest priority, 4 is the lowest priority.';
$lang->ai->dataType->estimate = new stdClass();
$lang->ai->dataType->estimate->type = 'numeric';
$lang->ai->dataType->estimate->desc = 'Unit is in hours.';
$lang->ai->dataType->consumed = $lang->ai->dataType->estimate;
$lang->ai->dataType->left = $lang->ai->dataType->estimate;
$lang->ai->dataType->progress = new stdClass();
$lang->ai->dataType->progress->type = 'percentage';
$lang->ai->dataType->progress->desc = '0 means not started, 100 means completed.';
$lang->ai->dataType->datetime = new stdClass();
$lang->ai->dataType->datetime->type = 'datetime';
$lang->ai->dataType->datetime->desc = 'Format is: 1970-01-01 00:00:01, or leave it blank.';
$lang->ai->dataType->estStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->realStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->finishedDate = $lang->ai->dataType->datetime;
$lang->ai->demoData = new stdclass();
$lang->ai->demoData->notExist = 'The demo data does not exist for now.';
$lang->ai->demoData->story = array(
'story' => array
(
'title' => 'Develop an online learning platform',
'spec' => 'We need to develop an online learning platform that provides course management, student management, teacher management, and other functions.',
'verify' => '1. All functions can operate properly without any obvious errors or abnormalities.2. The interface is aesthetically pleasing and user-friendly.3. The platform can meet user needs and has a high level of user satisfaction.4. The code has good quality, with clear structure and easy maintenance.',
'module' => 7,
'pri' => 1,
'estimate' => 1,
'product' => 1,
'category' => 'feature',
),
);
$lang->ai->demoData->execution = array
(
'execution' => array(
'name' => 'Online Learning Platform Software Development',
'desc' => 'This plan aims to develop an online learning platform software that provides accessible learning resources, including text, video, and audio, as well as some learning tools such as exams, tests, and discussion forums.',
'estimate' => 7,
),
'tasks' => array(
0 =>
array(
'name' => 'Technology Selection',
'pri' => 1,
'status' => 'done',
'estimate' => 1,
'consumed' => 1,
'left' => 0,
'progress' => 100,
'estStarted' => '2023-07-02 00:00:00',
'realStarted' => '2023-07-02 00:00:00',
'finishedDate' => '2023-07-02 00:00:00',
'closedReason' => 'Completed',
),
1 =>
array(
'name' => 'UI Design',
'pri' => 1,
'status' => 'doing',
'estimate' => 2,
'consumed' => 1,
'left' => 1,
'progress' => 50,
'estStarted' => '2023-07-03 00:00:00',
'realStarted' => '2023-07-03 00:00:00',
'finishedDate' => '',
'closedReason' => '',
),
2 =>
array(
'name' => 'Development',
'pri' => 1,
'status' => 'wait',
'estimate' => 1,
'consumed' => 0,
'left' => 1,
'progress' => 0,
'estStarted' => '',
'realStarted' => '',
'finishedDate' => '',
'closedReason' => '',
),
),
);
/* Forms as JSON Schemas. */
$lang->ai->formSchema = array();
$lang->ai->formSchema['story']['create'] = new stdclass();
$lang->ai->formSchema['story']['create']->title = 'Story';
$lang->ai->formSchema['story']['create']->type = 'object';
$lang->ai->formSchema['story']['create']->properties = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title = new stdclass();
$lang->ai->formSchema['story']['create']->properties->spec = new stdclass();
$lang->ai->formSchema['story']['create']->properties->verify = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title->type = 'string';
$lang->ai->formSchema['story']['create']->properties->title->description = 'Title of story';
$lang->ai->formSchema['story']['create']->properties->spec->type = 'string';
$lang->ai->formSchema['story']['create']->properties->spec->description = 'Description of story';
$lang->ai->formSchema['story']['create']->properties->verify->type = 'string';
$lang->ai->formSchema['story']['create']->properties->verify->description = 'Acceptance criteria of story';
$lang->ai->formSchema['story']['create']->required = array('title', 'spec', 'verify');
$lang->ai->formSchema['story']['change'] = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['story']['batchcreate'] = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->title = 'Stories';
$lang->ai->formSchema['story']['batchcreate']->type = 'object';
$lang->ai->formSchema['story']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories->type = 'array';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->description = 'Stories';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->items = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['productplan']['create'] = new stdclass();
$lang->ai->formSchema['productplan']['create']->title = 'Product Plan';
$lang->ai->formSchema['productplan']['create']->type = 'object';
$lang->ai->formSchema['productplan']['create']->properties = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->end = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->title->description = 'Title of product plan';
$lang->ai->formSchema['productplan']['create']->properties->begin->type = 'date';
$lang->ai->formSchema['productplan']['create']->properties->begin->description = 'Begin date of product plan';
$lang->ai->formSchema['productplan']['create']->properties->end->type = 'date';
$lang->ai->formSchema['productplan']['create']->properties->end->description = 'End date of product plan';
$lang->ai->formSchema['productplan']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->desc->description = 'Description of product plan';
$lang->ai->formSchema['productplan']['create']->required = array('title', 'begin', 'end');
$lang->ai->formSchema['productplan']['edit'] = $lang->ai->formSchema['productplan']['create'];
$lang->ai->formSchema['task']['create'] = new stdclass();
$lang->ai->formSchema['task']['create']->title = 'Task';
$lang->ai->formSchema['task']['create']->type = 'object';
$lang->ai->formSchema['task']['create']->properties = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type = new stdclass();
$lang->ai->formSchema['task']['create']->properties->name = new stdclass();
$lang->ai->formSchema['task']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['task']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['task']['create']->properties->estimate = new stdclass();
$lang->ai->formSchema['task']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['task']['create']->properties->end = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type->type = 'string';
$lang->ai->formSchema['task']['create']->properties->type->description = 'Type of task';
$lang->ai->formSchema['task']['create']->properties->type->enum = array('design', 'devel', 'request', 'test', 'study', 'discuss', 'ui', 'affair', 'misc');
$lang->ai->formSchema['task']['create']->properties->name->type = 'string';
$lang->ai->formSchema['task']['create']->properties->name->description = 'Name of task';
$lang->ai->formSchema['task']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['task']['create']->properties->desc->description = 'Description of task';
$lang->ai->formSchema['task']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['task']['create']->properties->pri->description = 'Priority of task';
$lang->ai->formSchema['task']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['task']['create']->properties->estimate->type = 'number';
$lang->ai->formSchema['task']['create']->properties->estimate->description = 'Estimated hours of task';
$lang->ai->formSchema['task']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['task']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['task']['create']->properties->begin->description = 'Begin date of task';
$lang->ai->formSchema['task']['create']->properties->end->type = 'string';
$lang->ai->formSchema['task']['create']->properties->end->format = 'date';
$lang->ai->formSchema['task']['create']->properties->end->description = 'End date of task';
$lang->ai->formSchema['task']['create']->required = array('type', 'name');
$lang->ai->formSchema['task']['edit'] = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate'] = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->title = 'Tasks';
$lang->ai->formSchema['task']['batchcreate']->type = 'object';
$lang->ai->formSchema['task']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->type = 'array';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->description = 'Tasks';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->estStarted = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin;
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->deadline = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end;
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin);
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end);
$lang->ai->formSchema['bug']['create'] = new stdclass();
$lang->ai->formSchema['bug']['create']->title = 'Bug';
$lang->ai->formSchema['bug']['create']->type = 'object';
$lang->ai->formSchema['bug']['create']->properties = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->severity = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->openedBuild = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->title->description = 'Title of bug';
$lang->ai->formSchema['bug']['create']->properties->steps->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->steps->description = 'Repro steps of bug';
$lang->ai->formSchema['bug']['create']->properties->severity->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->severity->description = 'Severity of bug';
$lang->ai->formSchema['bug']['create']->properties->severity->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->pri->description = 'Priority of bug';
$lang->ai->formSchema['bug']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->openedBuild->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->description = 'Affected builds of bug';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->enum = array('trunk');
$lang->ai->formSchema['bug']['create']->required = array('title', 'steps', 'severity', 'pri', 'openedBuild');
$lang->ai->formSchema['bug']['edit'] = $lang->ai->formSchema['bug']['create'];
$lang->ai->formSchema['testcase']['create'] = new stdclass();
$lang->ai->formSchema['testcase']['create']->title = 'Test Case';
$lang->ai->formSchema['testcase']['create']->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->stage = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->precondition = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->expects = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->type->description = 'Type of test case';
$lang->ai->formSchema['testcase']['create']->properties->type->enum = array('feature', 'performance', 'config', 'install', 'security', 'interface', 'unit', 'other');
$lang->ai->formSchema['testcase']['create']->properties->stage->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->stage->description = 'Stage of test case';
$lang->ai->formSchema['testcase']['create']->properties->stage->enum = array('unittest', 'feature', 'intergrate', 'system', 'smoke', 'bvt');
$lang->ai->formSchema['testcase']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->title->description = 'Title of test case';
$lang->ai->formSchema['testcase']['create']->properties->precondition->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->precondition->description = 'Precondition of test case';
$lang->ai->formSchema['testcase']['create']->properties->steps->type = 'array';
$lang->ai->formSchema['testcase']['create']->properties->steps->description = 'Steps of test case';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->description = 'Step description';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->description = 'Expectation of step';
$lang->ai->formSchema['testcase']['create']->required = array('type', 'title', 'steps');
$lang->ai->formSchema['testcase']['edit'] = $lang->ai->formSchema['testcase']['create'];
$lang->ai->formSchema['testreport']['create'] = new stdclass();
$lang->ai->formSchema['testreport']['create']->title = 'Test Report';
$lang->ai->formSchema['testreport']['create']->type = 'object';
$lang->ai->formSchema['testreport']['create']->properties = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->end = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->report = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->begin->description = 'Begin date of testing';
$lang->ai->formSchema['testreport']['create']->properties->end->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->end->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->end->description = 'End date of testing';
$lang->ai->formSchema['testreport']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->title->description = 'Title of test report';
$lang->ai->formSchema['testreport']['create']->properties->report->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->report->description = 'Report content';
$lang->ai->formSchema['testreport']['create']->required = array('begin', 'end', 'title', 'report');
$lang->ai->formSchema['execution']['testreport'] = $lang->ai->formSchema['testreport']['create'];
$lang->ai->formSchema['doc']['edit'] = new stdclass();
$lang->ai->formSchema['doc']['edit']->title = 'Document';
$lang->ai->formSchema['doc']['edit']->type = 'object';
$lang->ai->formSchema['doc']['edit']->properties = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->content = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->title->description = 'Title of the document';
$lang->ai->formSchema['doc']['edit']->properties->content->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->content->description = 'Content of the document';
$lang->ai->formSchema['doc']['edit']->required = array('title', 'content');
$lang->ai->formSchema['tree']['browse'] = new stdclass();
$lang->ai->formSchema['tree']['browse']->title = 'Modules';
$lang->ai->formSchema['tree']['browse']->type = 'object';
$lang->ai->formSchema['tree']['browse']->properties = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->type = 'array';
$lang->ai->formSchema['tree']['browse']->properties->modules->title = 'Modules';
$lang->ai->formSchema['tree']['browse']->properties->modules->items = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->items->type = 'string';
$lang->ai->formSchema['tree']['browse']->required = array('modules');
$lang->ai->formSchema['programplan']['create'] = new stdclass();
$lang->ai->formSchema['programplan']['create']->title = 'Program Plan';
$lang->ai->formSchema['programplan']['create']->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->type = 'array';
$lang->ai->formSchema['programplan']['create']->properties->stages->title = 'Plans';
$lang->ai->formSchema['programplan']['create']->properties->stages->items = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->description = 'Name of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->description = 'Attribute of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->enum = array('request', 'design', 'dev', 'qa', 'release', 'review', 'other');
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->type = 'boolean';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->description = 'Is milestone?';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->description = 'Begin date of stage';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->description = 'End date of stage';
$lang->ai->formSchema['programplan']['create']->required = array('stages');
$lang->ai->promptMenu = new stdclass();
$lang->ai->promptMenu->dropdownTitle = 'AI';
$lang->ai->dataInject = new stdclass();
$lang->ai->dataInject->success = 'Prompt execution results are filled in.';
$lang->ai->dataInject->fail = 'Failed to fill in prompt execution results.';
$lang->ai->execute = new stdclass();
$lang->ai->execute->loading = 'Prompt executing...';
$lang->ai->execute->auditing = 'Getting ready for auditing...';
$lang->ai->execute->success = 'Prompt executed.';
$lang->ai->execute->fail = 'Prompt execution failed.';
$lang->ai->execute->failFormat = 'Prompt execution failed: %s.';
$lang->ai->execute->failReasons = array();
$lang->ai->execute->failReasons['noPrompt'] = 'unable to get prompt';
$lang->ai->execute->failReasons['noObjectData'] = 'unable to get object data';
$lang->ai->execute->failReasons['noResponse'] = 'no response from external service';
$lang->ai->execute->failReasons['noTargetForm'] = 'unable to get target form or its required fields';
$lang->ai->execute->executeErrors = array();
$lang->ai->execute->executeErrors[-1] = 'unable to get prompt';
$lang->ai->execute->executeErrors[-2] = 'unable to get object data';
$lang->ai->execute->executeErrors[-3] = 'failed to serialize object data';
$lang->ai->execute->executeErrors[-4] = 'unable to get target form schema';
$lang->ai->execute->executeErrors[-5] = 'request failed or API returned error';
$lang->ai->audit = new stdclass();
$lang->ai->audit->designPrompt = 'Prompt Design';
$lang->ai->audit->afterSave = 'After saving,';
$lang->ai->audit->regenerate = 'Regenerate';
$lang->ai->audit->exit = 'Exit Audit';
$lang->ai->audit->backLocationList = array();
$lang->ai->audit->backLocationList[0] = 'back to audit page.';
$lang->ai->audit->backLocationList[1] = 'back to audit page and regenerate.';
+795
View File
@@ -0,0 +1,795 @@
<?php
/**
* The ai module zh-cn lang file of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
$lang->ai->common = 'AI';
/* Definitions of table columns, used to sprintf error messages to dao::$errors. */
$lang->prompt = new stdclass();
$lang->prompt->name = '名称';
$lang->prompt->desc = '描述';
$lang->prompt->model = '语言模型';
$lang->prompt->module = '所属分组';
$lang->prompt->source = '对象数据';
$lang->prompt->targetForm = '目标表单';
$lang->prompt->purpose = '操作';
$lang->prompt->elaboration = '补充要求';
$lang->prompt->role = '角色';
$lang->prompt->characterization = '角色描述';
$lang->prompt->status = '阶段';
$lang->prompt->createdBy = '由谁创建';
$lang->prompt->createdDate = '创建时间';
$lang->prompt->editedBy = '最后编辑';
$lang->prompt->editedDate = '编辑时间';
$lang->prompt->deleted = '是否已删除';
/* Lang for privs, keys are paired with privlang items. */
$lang->ai->modelBrowse = '浏览语言模型';
$lang->ai->modelEdit = '编辑语言模型';
$lang->ai->modelTestConnection = '测试连接';
$lang->ai->promptCreate = '创建提词';
$lang->ai->promptEdit = '编辑提词';
$lang->ai->promptDelete = '删除提词';
$lang->ai->promptAssignRole = '指定角色';
$lang->ai->promptSelectDataSource = '选择对象';
$lang->ai->promptSetPurpose = '确认操作';
$lang->ai->promptSetTargetForm = '结果处理';
$lang->ai->promptFinalize = '准备发布';
$lang->ai->promptAudit = '调试提词';
$lang->ai->promptPublish = '发布提词';
$lang->ai->promptUnpublish = '取消发布提词';
$lang->ai->promptBrowse = '浏览提词列表';
$lang->ai->promptView = '查看提词详情';
$lang->ai->promptExecute = '执行提词';
$lang->ai->promptExecutionReset = '重置调试';
$lang->ai->roleTemplates = '管理角色模板';
$lang->ai->nextStep = '下一步';
$lang->ai->goTesting = '去调试';
$lang->ai->validate = new stdclass();
$lang->ai->validate->noEmpty = '%s不能为空。';
$lang->ai->validate->dirtyForm = '%s的参数配置已变动,是否保存并返回?';
$lang->ai->validate->nameNotUnique = '该名称已使用,请尝试其他名称。';
$lang->ai->prompts = new stdclass();
$lang->ai->prompts->common = '提词';
$lang->ai->prompts->emptyList = '暂时没有提词。';
$lang->ai->prompts->create = '创建提词';
$lang->ai->prompts->edit = '编辑提词';
$lang->ai->prompts->id = 'ID';
$lang->ai->prompts->name = '名称';
$lang->ai->prompts->description = '描述';
$lang->ai->prompts->createdBy = '创建者';
$lang->ai->prompts->createdDate = '创建时间';
$lang->ai->prompts->targetForm = '表单';
$lang->ai->prompts->funcDesc = '功能描述';
$lang->ai->prompts->deleted = '已删除';
$lang->ai->prompts->stage = '阶段';
$lang->ai->prompts->basicInfo = '基本信息';
$lang->ai->prompts->editInfo = '创建编辑';
$lang->ai->prompts->createdBy = '由谁创建';
$lang->ai->prompts->publishedBy = '由谁发布';
$lang->ai->prompts->draftedBy = '由谁下架';
$lang->ai->prompts->lastEditor = '最后编辑';
$lang->ai->prompts->summary = '本页共 %s 个提词。';
$lang->ai->prompts->action = new stdclass();
$lang->ai->prompts->action->goDesignConfirm = '当前提词未完成,是否继续设计?';
$lang->ai->prompts->action->goDesign = '去设计';
$lang->ai->prompts->action->draftConfirm = '下架后,提词将不能继续使用,您确定要下架吗?';
$lang->ai->prompts->action->design = '设计';
$lang->ai->prompts->action->test = '调试';
$lang->ai->prompts->action->edit = '编辑';
$lang->ai->prompts->action->publish = '发布';
$lang->ai->prompts->action->unpublish = '下架';
$lang->ai->prompts->action->delete = '删除';
$lang->ai->prompts->action->deleteConfirm = '删除后,提词将不能继续使用,您确定要删除吗?';
$lang->ai->prompts->action->publishSuccess = '发布成功';
/* Steps of prompt creation. */
$lang->ai->prompts->assignRole = '指定角色';
$lang->ai->prompts->selectDataSource = '选择对象';
$lang->ai->prompts->setPurpose = '确认操作';
$lang->ai->prompts->setTargetForm = '结果处理';
$lang->ai->prompts->finalize = '准备发布';
/* Role assigning. */
$lang->ai->prompts->model = '语言模型';
$lang->ai->prompts->role = '角色';
$lang->ai->prompts->characterization = '角色描述';
$lang->ai->prompts->rolePlaceholder = '“你来扮演 <一个什么角色>”';
$lang->ai->prompts->charPlaceholder = '该角色的具体描述信息';
$lang->ai->prompts->roleTemplate = '角色模版';
$lang->ai->prompts->roleTemplateTip = '引用模板后,修改角色、角色描述不会对模板造成影响。';
$lang->ai->prompts->addRoleTemplate = '添加角色模板';
$lang->ai->prompts->editRoleTemplate = '编辑角色模板';
$lang->ai->prompts->editRoleTemplateTip = '本次编辑不会影响已使用该模版的提词';
$lang->ai->prompts->roleAddedSuccess = '角色模版保存成功';
$lang->ai->prompts->roleDelConfirm = '删除不会影响已用角色模版的提词,是否删除?';
$lang->ai->prompts->roleDelSuccess = '角色模板已删除';
$lang->ai->prompts->roleTemplateSave = '存为角色模板';
$lang->ai->prompts->roleTemplateSaveList = array();
$lang->ai->prompts->roleTemplateSaveList['save'] = '保存';
$lang->ai->prompts->roleTemplateSaveList['discard'] = '不保存';
/* Data source selecting. */
$lang->ai->prompts->selectData = '选择字段';
$lang->ai->prompts->selectDataTip = '选择对象后,此处会展示已选对象的字段。';
$lang->ai->prompts->selectedFormat = '已选对象为{0},已选 {1} 条字段';
$lang->ai->prompts->nonSelected = '暂无所选字段。';
$lang->ai->prompts->sortTip = '可根据重要性给数据字段排序。';
$lang->ai->prompts->object = '对象';
$lang->ai->prompts->field = '字段';
/* Purpose setting. */
$lang->ai->prompts->purpose = '操作';
$lang->ai->prompts->purposeTip = '“我希望<它能完成什么事情,以便于达到什么样的目标>”';
$lang->ai->prompts->elaboration = '补充要求';
$lang->ai->prompts->elaborationTip = '“我希望<它的回答请注意一些补充要求>”';
$lang->ai->prompts->inputPreview = '输入预览';
$lang->ai->prompts->dataPreview = '对象数据预览';
$lang->ai->prompts->rolePreview = '角色提词预览';
$lang->ai->prompts->promptPreview = '操作提词预览';
/* Target form selecting. */
$lang->ai->prompts->selectTargetForm = '选择表单';
$lang->ai->prompts->selectTargetFormTip = '选择后,可以将大语言模型返回的结果直接录入到禅道对应的表单中。';
$lang->ai->prompts->goingTesting = '即将跳转至调试页面';
$lang->ai->prompts->goingTestingFail = '无法去调试,找不到合适的对象';
/* Finalize page. */
$lang->ai->moduleDisableTip = '系统根据所选对象自动关联分组';
/* Data source definition. */
$lang->ai->dataSource = array();
$lang->ai->dataSource['my']['common'] = '地盘';
$lang->ai->dataSource['product']['common'] = '产品';
$lang->ai->dataSource['story']['common'] = '需求';
$lang->ai->dataSource['productplan']['common'] = '计划';
$lang->ai->dataSource['release']['common'] = '发布';
$lang->ai->dataSource['project']['common'] = '项目';
$lang->ai->dataSource['execution']['common'] = '执行';
$lang->ai->dataSource['task']['common'] = '任务';
$lang->ai->dataSource['bug']['common'] = 'Bug';
$lang->ai->dataSource['case']['common'] = '用例';
$lang->ai->dataSource['doc']['common'] = '文档';
$lang->ai->dataSource['my']['efforts']['common'] = '日志列表';
$lang->ai->dataSource['my']['efforts']['date'] = '日期';
$lang->ai->dataSource['my']['efforts']['work'] = '工作内容';
$lang->ai->dataSource['my']['efforts']['account'] = '记录人';
$lang->ai->dataSource['my']['efforts']['consumed'] = '耗时';
$lang->ai->dataSource['my']['efforts']['left'] = '剩余';
$lang->ai->dataSource['my']['efforts']['objectID'] = '对象';
$lang->ai->dataSource['my']['efforts']['product'] = '产品';
$lang->ai->dataSource['my']['efforts']['project'] = '项目';
$lang->ai->dataSource['my']['efforts']['execution'] = '执行';
$lang->ai->dataSource['product']['product']['common'] = '产品';
$lang->ai->dataSource['product']['product']['name'] = '产品名称';
$lang->ai->dataSource['product']['product']['desc'] = '产品描述';
$lang->ai->dataSource['product']['modules']['common'] = '产品模块列表';
$lang->ai->dataSource['product']['modules']['name'] = '模块名称';
$lang->ai->dataSource['product']['modules']['modules'] = '子模块';
$lang->ai->dataSource['productplan']['productplan']['common'] = '计划';
$lang->ai->dataSource['productplan']['productplan']['title'] = '计划名称';
$lang->ai->dataSource['productplan']['productplan']['desc'] = '计划描述';
$lang->ai->dataSource['productplan']['productplan']['begin'] = '开始时间';
$lang->ai->dataSource['productplan']['productplan']['end'] = '结束时间';
$lang->ai->dataSource['productplan']['stories']['common'] = '需求列表';
$lang->ai->dataSource['productplan']['stories']['title'] = '需求名称';
$lang->ai->dataSource['productplan']['stories']['module'] = '所属模块';
$lang->ai->dataSource['productplan']['stories']['pri'] = '优先级';
$lang->ai->dataSource['productplan']['stories']['estimate'] = '预计故事点';
$lang->ai->dataSource['productplan']['stories']['status'] = '状态';
$lang->ai->dataSource['productplan']['stories']['stage'] = '阶段';
$lang->ai->dataSource['productplan']['bugs']['common'] = 'Bug列表';
$lang->ai->dataSource['productplan']['bugs']['title'] = 'Bug标题';
$lang->ai->dataSource['productplan']['bugs']['pri'] = '优先级';
$lang->ai->dataSource['productplan']['bugs']['status'] = '状态';
$lang->ai->dataSource['release']['release']['common'] = '发布';
$lang->ai->dataSource['release']['release']['product'] = '所属产品';
$lang->ai->dataSource['release']['release']['name'] = '发布名称';
$lang->ai->dataSource['release']['release']['desc'] = '发布描述';
$lang->ai->dataSource['release']['release']['date'] = '发布日期';
$lang->ai->dataSource['release']['stories']['common'] = '需求列表';
$lang->ai->dataSource['release']['stories']['title'] = '需求名称';
$lang->ai->dataSource['release']['stories']['estimate'] = '预估故事点';
$lang->ai->dataSource['release']['bugs']['common'] = 'Bug列表';
$lang->ai->dataSource['release']['bugs']['title'] = 'Bug标题';
$lang->ai->dataSource['project']['project']['common'] = '项目';
$lang->ai->dataSource['project']['project']['name'] = '项目名称';
$lang->ai->dataSource['project']['project']['type'] = '项目类型';
$lang->ai->dataSource['project']['project']['desc'] = '项目描述';
$lang->ai->dataSource['project']['project']['begin'] = '计划开始';
$lang->ai->dataSource['project']['project']['end'] = '计划结束';
$lang->ai->dataSource['project']['project']['estimate'] = '预计工时';
$lang->ai->dataSource['project']['programplans']['common'] = '阶段列表';
$lang->ai->dataSource['project']['programplans']['name'] = '阶段名称';
$lang->ai->dataSource['project']['programplans']['desc'] = '阶段描述';
$lang->ai->dataSource['project']['programplans']['status'] = '阶段状态';
$lang->ai->dataSource['project']['programplans']['begin'] = '计划开始';
$lang->ai->dataSource['project']['programplans']['end'] = '计划完成';
$lang->ai->dataSource['project']['programplans']['realBegan'] = '实际开始';
$lang->ai->dataSource['project']['programplans']['realEnd'] = '实际完成';
$lang->ai->dataSource['project']['programplans']['planDuration'] = '工期';
$lang->ai->dataSource['project']['programplans']['progress'] = '任务进度';
$lang->ai->dataSource['project']['programplans']['estimate'] = '预计工时';
$lang->ai->dataSource['project']['programplans']['consumed'] = '消耗工时';
$lang->ai->dataSource['project']['programplans']['left'] = '剩余工时';
$lang->ai->dataSource['project']['executions']['common'] = '迭代列表';
$lang->ai->dataSource['project']['executions']['name'] = '执行名称';
$lang->ai->dataSource['project']['executions']['desc'] = '执行描述';
$lang->ai->dataSource['project']['executions']['status'] = '执行状态';
$lang->ai->dataSource['project']['executions']['begin'] = '计划开始';
$lang->ai->dataSource['project']['executions']['end'] = '计划完成';
$lang->ai->dataSource['project']['executions']['realBegan'] = '实际开始';
$lang->ai->dataSource['project']['executions']['realEnd'] = '实际完成';
$lang->ai->dataSource['project']['executions']['estimate'] = '预计工时';
$lang->ai->dataSource['project']['executions']['consumed'] = '消耗工时';
$lang->ai->dataSource['project']['executions']['left'] = '剩余工时';
$lang->ai->dataSource['project']['executions']['progress'] = '进度';
$lang->ai->dataSource['story']['story']['common'] = '需求';
$lang->ai->dataSource['story']['story']['title'] = '需求标题';
$lang->ai->dataSource['story']['story']['spec'] = '需求描述';
$lang->ai->dataSource['story']['story']['verify'] = '验收标准';
$lang->ai->dataSource['story']['story']['product'] = '产品';
$lang->ai->dataSource['story']['story']['module'] = '模块';
$lang->ai->dataSource['story']['story']['pri'] = '优先级';
$lang->ai->dataSource['story']['story']['category'] = '需求类型';
$lang->ai->dataSource['story']['story']['estimate'] = '预计工时';
$lang->ai->dataSource['execution']['execution']['common'] = '执行';
$lang->ai->dataSource['execution']['execution']['name'] = '执行名称';
$lang->ai->dataSource['execution']['execution']['desc'] = '执行描述';
$lang->ai->dataSource['execution']['execution']['estimate'] = '预计工时';
$lang->ai->dataSource['execution']['tasks']['common'] = '任务列表';
$lang->ai->dataSource['execution']['tasks']['name'] = '任务名称';
$lang->ai->dataSource['execution']['tasks']['pri'] = '优先级';
$lang->ai->dataSource['execution']['tasks']['status'] = '状态';
$lang->ai->dataSource['execution']['tasks']['estimate'] = '预计工时';
$lang->ai->dataSource['execution']['tasks']['consumed'] = '已消耗';
$lang->ai->dataSource['execution']['tasks']['left'] = '剩余';
$lang->ai->dataSource['execution']['tasks']['progress'] = '进度';
$lang->ai->dataSource['execution']['tasks']['estStarted'] = '预计开始';
$lang->ai->dataSource['execution']['tasks']['realStarted'] = '实际开始';
$lang->ai->dataSource['execution']['tasks']['finishedDate']= '完成日期';
$lang->ai->dataSource['execution']['tasks']['closedReason']= '关闭原因';
$lang->ai->dataSource['task']['task']['common'] = '任务';
$lang->ai->dataSource['task']['task']['name'] = '任务名称';
$lang->ai->dataSource['task']['task']['desc'] = '任务描述';
$lang->ai->dataSource['task']['task']['pri'] = '优先级';
$lang->ai->dataSource['task']['task']['status'] = '状态';
$lang->ai->dataSource['task']['task']['estimate'] = '预计';
$lang->ai->dataSource['task']['task']['consumed'] = '消耗';
$lang->ai->dataSource['task']['task']['left'] = '剩余';
$lang->ai->dataSource['task']['task']['progress'] = '进度';
$lang->ai->dataSource['task']['task']['estStarted'] = '预计开始';
$lang->ai->dataSource['task']['task']['realStarted'] = '实际开始';
$lang->ai->dataSource['case']['case']['common'] = '用例';
$lang->ai->dataSource['case']['case']['title'] = '标题';
$lang->ai->dataSource['case']['case']['precondition'] = '前置条件';
$lang->ai->dataSource['case']['case']['scene'] = '所属场景';
$lang->ai->dataSource['case']['case']['product'] = '所属产品';
$lang->ai->dataSource['case']['case']['module'] = '所属模块';
$lang->ai->dataSource['case']['case']['pri'] = '优先级';
$lang->ai->dataSource['case']['case']['type'] = '类型';
$lang->ai->dataSource['case']['case']['lastRunResult'] = '结果';
$lang->ai->dataSource['case']['case']['status'] = '状态';
$lang->ai->dataSource['case']['steps']['common'] = '步骤列表';
$lang->ai->dataSource['case']['steps']['desc'] = '步骤描述';
$lang->ai->dataSource['case']['steps']['expect'] = '预期';
$lang->ai->dataSource['bug']['bug']['common'] = 'Bug';
$lang->ai->dataSource['bug']['bug']['title'] = 'Bug标题';
$lang->ai->dataSource['bug']['bug']['steps'] = '重现步骤';
$lang->ai->dataSource['bug']['bug']['severity'] = '级别';
$lang->ai->dataSource['bug']['bug']['pri'] = '优先级';
$lang->ai->dataSource['bug']['bug']['status'] = '状态';
$lang->ai->dataSource['bug']['bug']['confirmed'] = '确认';
$lang->ai->dataSource['bug']['bug']['type'] = 'Bug类型';
$lang->ai->dataSource['doc']['doc']['common'] = '文档';
$lang->ai->dataSource['doc']['doc']['title'] = '文档标题';
$lang->ai->dataSource['doc']['doc']['content'] = '文档正文';
$lang->ai->dataSource['doc']['doc']['addedBy'] = '创建者';
$lang->ai->dataSource['doc']['doc']['addedDate'] = '创建日期';
$lang->ai->dataSource['doc']['doc']['editedBy'] = '修改者';
$lang->ai->dataSource['doc']['doc']['editedDate'] = '修改日期';
/* Target form definition. See `$config->ai->targetForm`. */
$lang->ai->targetForm = array();
$lang->ai->targetForm['product']['common'] = '产品';
$lang->ai->targetForm['story']['common'] = '需求';
$lang->ai->targetForm['productplan']['common'] = '计划';
$lang->ai->targetForm['projectrelease']['common'] = '发布';
$lang->ai->targetForm['project']['common'] = '项目';
$lang->ai->targetForm['execution']['common'] = '执行';
$lang->ai->targetForm['task']['common'] = '任务';
$lang->ai->targetForm['testcase']['common'] = '用例';
$lang->ai->targetForm['bug']['common'] = 'Bug';
$lang->ai->targetForm['doc']['common'] = '文档';
$lang->ai->targetForm['product']['tree/managechild'] = '维护模块';
$lang->ai->targetForm['product']['doc/create'] = '创建文档';
$lang->ai->targetForm['story']['create'] = '提需求';
$lang->ai->targetForm['story']['batchcreate'] = '批量提需求';
$lang->ai->targetForm['story']['change'] = '变更需求';
$lang->ai->targetForm['story']['totask'] = '需求建任务';
$lang->ai->targetForm['story']['testcasecreate'] = '需求建用例';
$lang->ai->targetForm['story']['subdivide'] = '需求细分';
$lang->ai->targetForm['productplan']['edit'] = '编辑计划';
$lang->ai->targetForm['productplan']['create'] = '创建子计划';
$lang->ai->targetForm['projectrelease']['doc/create'] = '创建文档';
$lang->ai->targetForm['project']['risk/create'] = '创建风险';
$lang->ai->targetForm['project']['issue/create'] = '创建问题';
$lang->ai->targetForm['project']['doc/create'] = '创建文档';
$lang->ai->targetForm['project']['programplan/create'] = '设置阶段';
$lang->ai->targetForm['execution']['batchcreatetask'] = '批量创建任务';
$lang->ai->targetForm['execution']['createtestreport'] = '创建测试报告';
$lang->ai->targetForm['execution']['createqa'] = '创建 QA';
$lang->ai->targetForm['execution']['createrisk'] = '创建风险';
$lang->ai->targetForm['execution']['createissue'] = '创建问题';
$lang->ai->targetForm['task']['edit'] = '编辑任务';
$lang->ai->targetForm['task']['batchcreate'] = '批量创建子任务';
$lang->ai->targetForm['testcase']['edit'] = '编辑用例';
$lang->ai->targetForm['testcase']['createscript'] = '创建自动化脚本';
$lang->ai->targetForm['bug']['edit'] = '编辑 Bug';
$lang->ai->targetForm['bug']['story/create'] = 'Bug 转需求';
$lang->ai->targetForm['bug']['testcase/create'] = 'Bug 建用例';
$lang->ai->targetForm['doc']['create'] = '创建文档';
$lang->ai->targetForm['doc']['edit'] = '编辑文档';
$lang->ai->prompts->statuses = array();
$lang->ai->prompts->statuses[''] = '全部';
$lang->ai->prompts->statuses['draft'] = '未发布';
$lang->ai->prompts->statuses['active'] = '已发布';
$lang->ai->prompts->modules = array();
$lang->ai->prompts->modules[''] = '所有分组';
// $lang->ai->prompts->modules['my'] = '地盘';
$lang->ai->prompts->modules['product'] = '产品';
$lang->ai->prompts->modules['project'] = '项目';
$lang->ai->prompts->modules['story'] = '需求';
$lang->ai->prompts->modules['productplan'] = '计划';
$lang->ai->prompts->modules['release'] = '发布';
$lang->ai->prompts->modules['execution'] = '执行';
$lang->ai->prompts->modules['task'] = '任务';
$lang->ai->prompts->modules['case'] = '用例';
$lang->ai->prompts->modules['bug'] = 'Bug';
$lang->ai->prompts->modules['doc'] = '文档';
$lang->ai->conversations = new stdclass();
$lang->ai->conversations->common = '会话';
$lang->ai->models = new stdclass();
$lang->ai->models->title = '语言模型配置';
$lang->ai->models->common = '语言模型';
$lang->ai->models->type = '语言模型';
$lang->ai->models->vendor = '供应商';
$lang->ai->models->key = 'API Key';
$lang->ai->models->resource = 'Resource';
$lang->ai->models->deployment = 'Deployment';
$lang->ai->models->proxyType = '代理类型';
$lang->ai->models->proxyAddr = '代理地址';
$lang->ai->models->description = '描述';
$lang->ai->models->testConnection = '测试连接';
$lang->ai->models->unconfigured = '未配置';
$lang->ai->models->edit = '编辑模型参数';
$lang->ai->models->concealTip = '完整信息在编辑时可见';
$lang->ai->models->upgradeBiz = '更多AI功能,尽在<a target="_blank" href="https://www.zentao.net/page/enterprise.html" class="text-blue">企业版</a>!';
$lang->ai->models->noModelError = '暂无可用的语言模型,请联系管理员配置。';
$lang->ai->models->testConnectionResult = new stdclass();
$lang->ai->models->testConnectionResult->success = '连接成功';
$lang->ai->models->testConnectionResult->fail = '连接失败';
$lang->ai->models->testConnectionResult->failFormat = '连接失败:%s';
$lang->ai->models->statusList = array();
$lang->ai->models->statusList['on'] = '启用';
$lang->ai->models->statusList['off'] = '停用';
$lang->ai->models->typeList = array();
$lang->ai->models->typeList['openai-gpt35'] = 'OpenAI / GPT-3.5';
// $lang->ai->models->typeList['azure-gpt35'] = 'Azure / GPT-3.5';
$lang->ai->models->openaiVendorList = array();
$lang->ai->models->openaiVendorList['openai'] = 'OpenAI';
$lang->ai->models->openaiVendorList['azure'] = 'Azure';
$lang->ai->models->proxyTypes = array();
$lang->ai->models->proxyTypes[''] = '不使用代理';
$lang->ai->models->proxyTypes['socks5'] = 'SOCKS5';
$lang->ai->models->promptFor = '输入给 %s';
$lang->ai->designStepNav = array();
$lang->ai->designStepNav['assignrole'] = '指定角色';
$lang->ai->designStepNav['selectdatasource'] = '选择对象';
$lang->ai->designStepNav['setpurpose'] = '确认操作';
$lang->ai->designStepNav['settargetform'] = '结果处理';
$lang->ai->designStepNav['finalize'] = '准备发布';
$lang->ai->dataTypeDesc = '%s是%s类型,%s';
$lang->ai->dataType = new stdclass();
$lang->ai->dataType->pri = new stdClass();
$lang->ai->dataType->pri->type = '数值';
$lang->ai->dataType->pri->desc = '1 是最高优先级,4 是最低优先级。';
$lang->ai->dataType->estimate = new stdClass();
$lang->ai->dataType->estimate->type = '数值';
$lang->ai->dataType->estimate->desc = '单位为小时。';
$lang->ai->dataType->consumed = $lang->ai->dataType->estimate;
$lang->ai->dataType->left = $lang->ai->dataType->estimate;
$lang->ai->dataType->progress = new stdClass();
$lang->ai->dataType->progress->type = '百分比';
$lang->ai->dataType->progress->desc = '0 是未开始,100是已完成。';
$lang->ai->dataType->datetime = new stdClass();
$lang->ai->dataType->datetime->type = '日期时间';
$lang->ai->dataType->datetime->desc = '格式为:1970-01-01 00:00:01,没有则留空。';
$lang->ai->dataType->estStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->realStarted = $lang->ai->dataType->datetime;
$lang->ai->dataType->finishedDate = $lang->ai->dataType->datetime;
$lang->ai->demoData = new stdclass();
$lang->ai->demoData->notExist = '暂无演示数据。';
$lang->ai->demoData->story = array(
'story' => array
(
'title' => '开发一个在线学习平台',
'spec' => '我们需要开发一个在线学习平台,能够提供课程管理、学生管理、教师管理等功能。',
'verify' => '1. 所有功能均能够正常运行,没有明显的错误和异常。2. 界面美观、易用性好。3. 平台能够满足用户需求,具有较高的用户满意度。4. 代码质量好,结构清晰、易于维护。',
'module' => 7,
'pri' => 1,
'estimate' => 1,
'product' => 1,
'category' => 'feature',
),
);
$lang->ai->demoData->execution = array
(
'execution' => array(
'name' => '在线学习平台软件开发',
'desc' => '本计划旨在开发一款在线学习平台软件,该软件将提供可访问的学习资源,包括文本、视频和音频等,以及一些学习工具如考试、测试和讨论论坛等。',
'estimate' => 7,
),
'tasks' => array(
0 =>
array(
'name' => '技术选型',
'pri' => 1,
'status' => 'done',
'estimate' => 1,
'consumed' => 1,
'left' => 0,
'progress' => 100,
'estStarted' => '2023-07-02 00:00:00',
'realStarted' => '2023-07-02 00:00:00',
'finishedDate' => '2023-07-02 00:00:00',
'closedReason' => '已完成',
),
1 =>
array(
'name' => 'UI设计',
'pri' => 1,
'status' => 'doing',
'estimate' => 2,
'consumed' => 1,
'left' => 1,
'progress' => 50,
'estStarted' => '2023-07-03 00:00:00',
'realStarted' => '2023-07-03 00:00:00',
'finishedDate' => '',
'closedReason' => '',
),
2 =>
array(
'name' => '开发',
'pri' => 1,
'status' => 'wait',
'estimate' => 1,
'consumed' => 0,
'left' => 1,
'progress' => 0,
'estStarted' => '',
'realStarted' => '',
'finishedDate' => '',
'closedReason' => '',
),
),
);
/* Forms as JSON Schemas. */
$lang->ai->formSchema = array();
$lang->ai->formSchema['story']['create'] = new stdclass();
$lang->ai->formSchema['story']['create']->title = '需求';
$lang->ai->formSchema['story']['create']->type = 'object';
$lang->ai->formSchema['story']['create']->properties = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title = new stdclass();
$lang->ai->formSchema['story']['create']->properties->spec = new stdclass();
$lang->ai->formSchema['story']['create']->properties->verify = new stdclass();
$lang->ai->formSchema['story']['create']->properties->title->type = 'string';
$lang->ai->formSchema['story']['create']->properties->title->description = '需求的标题';
$lang->ai->formSchema['story']['create']->properties->spec->type = 'string';
$lang->ai->formSchema['story']['create']->properties->spec->description = '需求的描述';
$lang->ai->formSchema['story']['create']->properties->verify->type = 'string';
$lang->ai->formSchema['story']['create']->properties->verify->description = '需求的验收标准';
$lang->ai->formSchema['story']['create']->required = array('title', 'spec', 'verify');
$lang->ai->formSchema['story']['change'] = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['story']['batchcreate'] = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->title = '批量创建需求';
$lang->ai->formSchema['story']['batchcreate']->type = 'object';
$lang->ai->formSchema['story']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories = new stdclass();
$lang->ai->formSchema['story']['batchcreate']->properties->stories->type = 'array';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->description = '需求列表';
$lang->ai->formSchema['story']['batchcreate']->properties->stories->items = $lang->ai->formSchema['story']['create'];
$lang->ai->formSchema['productplan']['create'] = new stdclass();
$lang->ai->formSchema['productplan']['create']->title = '产品计划';
$lang->ai->formSchema['productplan']['create']->type = 'object';
$lang->ai->formSchema['productplan']['create']->properties = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->end = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['productplan']['create']->properties->title->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->title->description = '产品计划的标题';
$lang->ai->formSchema['productplan']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->begin->description = '产品计划的开始时间';
$lang->ai->formSchema['productplan']['create']->properties->end->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->end->description = '产品计划的结束时间';
$lang->ai->formSchema['productplan']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['productplan']['create']->properties->desc->description = '产品计划的描述';
$lang->ai->formSchema['productplan']['create']->required = array('title', 'begin', 'end');
$lang->ai->formSchema['productplan']['edit'] = $lang->ai->formSchema['productplan']['create'];
$lang->ai->formSchema['task']['create'] = new stdclass();
$lang->ai->formSchema['task']['create']->title = '任务';
$lang->ai->formSchema['task']['create']->type = 'object';
$lang->ai->formSchema['task']['create']->properties = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type = new stdclass();
$lang->ai->formSchema['task']['create']->properties->name = new stdclass();
$lang->ai->formSchema['task']['create']->properties->desc = new stdclass();
$lang->ai->formSchema['task']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['task']['create']->properties->estimate = new stdclass();
$lang->ai->formSchema['task']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['task']['create']->properties->end = new stdclass();
$lang->ai->formSchema['task']['create']->properties->type->type = 'string';
$lang->ai->formSchema['task']['create']->properties->type->description = '任务的类型';
$lang->ai->formSchema['task']['create']->properties->type->enum = array('design', 'devel', 'request', 'test', 'study', 'discuss', 'ui', 'affair', 'misc');
$lang->ai->formSchema['task']['create']->properties->name->type = 'string';
$lang->ai->formSchema['task']['create']->properties->name->description = '任务的名称';
$lang->ai->formSchema['task']['create']->properties->desc->type = 'string';
$lang->ai->formSchema['task']['create']->properties->desc->description = '任务的描述';
$lang->ai->formSchema['task']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['task']['create']->properties->pri->description = '任务的优先级';
$lang->ai->formSchema['task']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['task']['create']->properties->estimate->type = 'number';
$lang->ai->formSchema['task']['create']->properties->estimate->description = '任务的预计工时';
$lang->ai->formSchema['task']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['task']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['task']['create']->properties->begin->description = '任务的预计开始日期';
$lang->ai->formSchema['task']['create']->properties->end->type = 'string';
$lang->ai->formSchema['task']['create']->properties->end->format = 'date';
$lang->ai->formSchema['task']['create']->properties->end->description = '任务的预计结束日期';
$lang->ai->formSchema['task']['create']->required = array('type', 'name');
$lang->ai->formSchema['task']['edit'] = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate'] = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->title = '批量创建任务';
$lang->ai->formSchema['task']['batchcreate']->type = 'object';
$lang->ai->formSchema['task']['batchcreate']->properties = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks = new stdclass();
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->type = 'array';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->description = '任务列表';
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items = $lang->ai->formSchema['task']['create'];
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->estStarted = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin;
$lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->deadline = clone $lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end;
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->begin);
unset($lang->ai->formSchema['task']['batchcreate']->properties->tasks->items->properties->end);
$lang->ai->formSchema['bug']['create'] = new stdclass();
$lang->ai->formSchema['bug']['create']->title = 'Bug';
$lang->ai->formSchema['bug']['create']->type = 'object';
$lang->ai->formSchema['bug']['create']->properties = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->severity = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->pri = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->openedBuild = new stdclass();
$lang->ai->formSchema['bug']['create']->properties->title->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->title->description = 'Bug 的标题';
$lang->ai->formSchema['bug']['create']->properties->steps->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->steps->description = '重现步骤';
$lang->ai->formSchema['bug']['create']->properties->severity->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->severity->description = 'Bug 的严重程度';
$lang->ai->formSchema['bug']['create']->properties->severity->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->pri->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->pri->description = 'Bug 的优先级';
$lang->ai->formSchema['bug']['create']->properties->pri->enum = array('1', '2', '3', '4');
$lang->ai->formSchema['bug']['create']->properties->openedBuild->type = 'string';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->description = 'Bug 影响的版本';
$lang->ai->formSchema['bug']['create']->properties->openedBuild->enum = array('trunk');
$lang->ai->formSchema['bug']['create']->required = array('title', 'steps', 'severity', 'pri', 'openedBuild');
$lang->ai->formSchema['bug']['edit'] = $lang->ai->formSchema['bug']['create'];
$lang->ai->formSchema['testcase']['create'] = new stdclass();
$lang->ai->formSchema['testcase']['create']->title = '用例';
$lang->ai->formSchema['testcase']['create']->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->stage = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->precondition = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects = new stdclass();
$lang->ai->formSchema['testcase']['create']->properties->type->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->type->description = '用例的类型';
$lang->ai->formSchema['testcase']['create']->properties->type->enum = array('feature', 'performance', 'config', 'install', 'security', 'interface', 'unit', 'other');
$lang->ai->formSchema['testcase']['create']->properties->stage->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->stage->description = '用例适用阶段';
$lang->ai->formSchema['testcase']['create']->properties->stage->enum = array('unittest', 'feature', 'intergrate', 'system', 'smoke', 'bvt');
$lang->ai->formSchema['testcase']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->title->description = '用例的标题';
$lang->ai->formSchema['testcase']['create']->properties->precondition->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->precondition->description = '用例的前置条件';
$lang->ai->formSchema['testcase']['create']->properties->steps->type = 'array';
$lang->ai->formSchema['testcase']['create']->properties->steps->description = '用例的步骤列表';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->type = 'object';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->steps->description = '步骤的描述';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->type = 'string';
$lang->ai->formSchema['testcase']['create']->properties->steps->items->properties->expects->description = '步骤的预期结果';
$lang->ai->formSchema['testcase']['create']->required = array('type', 'title', 'steps');
$lang->ai->formSchema['testcase']['edit'] = $lang->ai->formSchema['testcase']['create'];
$lang->ai->formSchema['testreport']['create'] = new stdclass();
$lang->ai->formSchema['testreport']['create']->title = '测试报告';
$lang->ai->formSchema['testreport']['create']->type = 'object';
$lang->ai->formSchema['testreport']['create']->properties = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->end = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->title = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->report = new stdclass();
$lang->ai->formSchema['testreport']['create']->properties->begin->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->begin->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->begin->description = '测试开始时间';
$lang->ai->formSchema['testreport']['create']->properties->end->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->end->format = 'date';
$lang->ai->formSchema['testreport']['create']->properties->end->description = '测试开始时间';
$lang->ai->formSchema['testreport']['create']->properties->title->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->title->description = '测试报告的标题';
$lang->ai->formSchema['testreport']['create']->properties->report->type = 'string';
$lang->ai->formSchema['testreport']['create']->properties->report->description = '测试报告的内容';
$lang->ai->formSchema['testreport']['create']->required = array('begin', 'end', 'title', 'report');
$lang->ai->formSchema['execution']['testreport'] = $lang->ai->formSchema['testreport']['create'];
$lang->ai->formSchema['doc']['edit'] = new stdclass();
$lang->ai->formSchema['doc']['edit']->title = '文档';
$lang->ai->formSchema['doc']['edit']->type = 'object';
$lang->ai->formSchema['doc']['edit']->properties = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->content = new stdclass();
$lang->ai->formSchema['doc']['edit']->properties->title->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->title->description = '文档的标题';
$lang->ai->formSchema['doc']['edit']->properties->content->type = 'string';
$lang->ai->formSchema['doc']['edit']->properties->content->description = '文档的正文';
$lang->ai->formSchema['doc']['edit']->required = array('title', 'content');
$lang->ai->formSchema['tree']['browse'] = new stdclass();
$lang->ai->formSchema['tree']['browse']->title = '模块';
$lang->ai->formSchema['tree']['browse']->type = 'object';
$lang->ai->formSchema['tree']['browse']->properties = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->type = 'array';
$lang->ai->formSchema['tree']['browse']->properties->modules->title = '模块';
$lang->ai->formSchema['tree']['browse']->properties->modules->items = new stdclass();
$lang->ai->formSchema['tree']['browse']->properties->modules->items->type = 'string';
$lang->ai->formSchema['tree']['browse']->required = array('modules');
$lang->ai->formSchema['programplan']['create'] = new stdclass();
$lang->ai->formSchema['programplan']['create']->title = '计划阶段';
$lang->ai->formSchema['programplan']['create']->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->type = 'array';
$lang->ai->formSchema['programplan']['create']->properties->stages->title = '阶段列表';
$lang->ai->formSchema['programplan']['create']->properties->stages->items = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->type = 'object';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end = new stdclass();
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->names->description = '阶段名称';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->description = '阶段类型';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->attributes->enum = array('request', 'design', 'dev', 'qa', 'release', 'review', 'other');
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->type = 'boolean';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->milestone->description = '是否为里程碑';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->begin->description = '阶段开始时间';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->type = 'string';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->format = 'date';
$lang->ai->formSchema['programplan']['create']->properties->stages->items->properties->end->description = '阶段结束时间';
$lang->ai->formSchema['programplan']['create']->required = array('stages');
$lang->ai->promptMenu = new stdclass();
$lang->ai->promptMenu->dropdownTitle = 'AI';
$lang->ai->dataInject = new stdclass();
$lang->ai->dataInject->success = '已将提词执行结果填写到表单中';
$lang->ai->dataInject->fail = '提词执行结果填写失败';
$lang->ai->execute = new stdclass();
$lang->ai->execute->loading = '提词执行中';
$lang->ai->execute->auditing = '即将跳转至调试页面并执行提词';
$lang->ai->execute->success = '提词执行成功';
$lang->ai->execute->fail = '提词执行失败';
$lang->ai->execute->failFormat = '提词执行失败:%s。';
$lang->ai->execute->failReasons = array();
$lang->ai->execute->failReasons['noPrompt'] = '提词不存在';
$lang->ai->execute->failReasons['noObjectData'] = '对象数据获取失败';
$lang->ai->execute->failReasons['noResponse'] = '请求返回值为空';
$lang->ai->execute->failReasons['noTargetForm'] = '目标表单地址获取失败,或表单必要变量获取失败(可能原因为无法找到关联的对象,请检查对象间的关联关系)';
$lang->ai->execute->executeErrors = array();
$lang->ai->execute->executeErrors[-1] = '提词不存在';
$lang->ai->execute->executeErrors[-2] = '对象数据获取失败';
$lang->ai->execute->executeErrors[-3] = '序列化对象数据失败';
$lang->ai->execute->executeErrors[-4] = '表单结构获取失败';
$lang->ai->execute->executeErrors[-5] = 'API 返回值为空或返回了错误';
$lang->ai->audit = new stdclass();
$lang->ai->audit->designPrompt = '提词设计';
$lang->ai->audit->afterSave = '保存后';
$lang->ai->audit->regenerate = '重新生成';
$lang->ai->audit->exit = '退出调试';
$lang->ai->audit->backLocationList = array();
$lang->ai->audit->backLocationList[0] = '返回调试页面';
$lang->ai->audit->backLocationList[1] = '返回调试页面并重新生成';
+1600
View File
File diff suppressed because it is too large Load Diff
+137
View File
@@ -0,0 +1,137 @@
<?php
/**
* The ai editModels view file of ai module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php
$currentVendor = empty($modelConfig->vendor) ? key($lang->ai->models->openaiVendorList) : $modelConfig->vendor;
$requiredFields = $config->ai->vendorList[$currentVendor]['requiredFields'];
js::set('vendorList', $config->ai->vendorList);
?>
<style>
.required:after {right: -12px;}
</style>
<div id='mainContent' class='main-content'>
<form id='mainForm' class='load-indicator main-form form-ajax' method='post'>
<table class='table table-form mw-800px'>
<tr>
<th><?php echo $lang->ai->models->type;?></th>
<td><?php echo html::select('type', $lang->ai->models->typeList, $modelConfig->type, "class='form-control chosen' required");?></td>
</tr>
<tr>
<th><?php echo $lang->ai->models->vendor;?></th>
<td><?php echo html::select('vendor', $lang->ai->models->openaiVendorList, $currentVendor, "class='form-control chosen' required");?></td>
</tr>
<tr class="vendor-row <?php echo in_array('key', $requiredFields) ? '' : ' hidden'; ?>" data-vendor-field="key">
<th><?php echo $lang->ai->models->key;?></th>
<td><?php echo html::input('key', $modelConfig->key, "class='form-control' required");?></td>
</tr>
<tr class="vendor-row <?php echo in_array('resource', $requiredFields) ? '' : ' hidden'; ?>" data-vendor-field="resource">
<th><?php echo $lang->ai->models->resource;?></th>
<td><?php echo html::input('resource', empty($modelConfig->resource) ? '' : $modelConfig->resource, "class='form-control' required");?></td>
</tr>
<tr class="vendor-row <?php echo in_array('deployment', $requiredFields) ? '' : ' hidden'; ?>" data-vendor-field="deployment">
<th><?php echo $lang->ai->models->deployment;?></th>
<td><?php echo html::input('deployment', empty($modelConfig->deployment) ? '' : $modelConfig->deployment, "class='form-control' required");?></td>
</tr>
<tr>
<th><?php echo $lang->ai->models->proxyType;?></th>
<td>
<div class='row'>
<div class='col-md-4'>
<?php echo html::select('proxyType', $lang->ai->models->proxyTypes, $modelConfig->proxyType, "class='form-control chosen' data-disable_search='true' required");?>
</div>
<div class='col-md-8' id='proxyAddrContainer' <?php if(empty($modelConfig->proxyType)) echo 'style="display: none;"'; ?>>
<div class='row'>
<div class='col-md-3 text-right' style='padding-top: 6px;'><strong><?php echo $lang->ai->models->proxyAddr;?></strong></div>
<div class='col-md-9'><div class="required required-wrapper"></div><?php echo html::input('proxyAddr', $modelConfig->proxyAddr, "class='form-control'");?></div>
</div>
</div>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->ai->models->description;?></th>
<td><?php echo html::textarea('description', $modelConfig->description, "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->statusAB;?></th>
<td><?php echo html::radio('status', $lang->ai->models->statusList, empty($modelConfig->status) ? 'on' : $modelConfig->status);?></td>
</tr>
<tr>
<td colspan='2' class='text-center'>
<?php echo html::submitButton();?>
<?php echo html::commonButton($lang->ai->models->testConnection, 'id="testConn"', 'btn btn-secondary btn-wide');?>
<?php echo html::a(inlink('models', ""), $lang->goback, '', 'class="btn btn-wide"');?>
</td>
</tr>
</table>
</form>
</div>
<script>
$(function() {
$('select[name="proxyType"]').change(function()
{
var proxyType = $(this).val();
$('#proxyAddrContainer').toggle(proxyType != '');
});
$('select[name="vendor"]').change(function()
{
var vendor = $(this).val();
var requiredFields = vendorList[vendor]['requiredFields'];
$('.vendor-row').each(function()
{
var name = $(this).data('vendor-field');
$(this).toggleClass('hidden', !requiredFields.includes(name));
});
});
$('#mainForm').on('submit', function()
{
$('#testConn').attr('disabled', 'disabled');
});
$('#mainForm').on('ajaxComplete', function()
{
var timesTried = 0;
var buttonStateSyncInterval = setInterval(function()
{
if(!$('#submit').attr('disabled'))
{
$('#testConn').removeAttr('disabled');
clearInterval(buttonStateSyncInterval);
}
if(timesTried++ > 20) clearInterval(buttonStateSyncInterval);
}, 100);
});
$('#testConn').click(function()
{
$.disableForm('#mainForm');
$.ajax(
{
type: 'POST',
url: createLink('ai', 'testConnection'),
data: $('.main-form').serialize(),
dataType: 'json',
success: function(data)
{
if(data.result == 'success')
{
$.zui.messager.success(data.message);
}
else
{
$.zui.messager.danger(data.message);
}
},
complete: function() {$.enableForm('#mainForm');}
});
});
});
</script>
<?php include '../../common/view/footer.html.php';?>
+255
View File
@@ -0,0 +1,255 @@
<?php
/**
* The ai input inject view file of ai module of ZenTaoPMS.
*
* This view file is used to inject ai generated result into
* input fields. Include this view file in the target forms.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
?>
<?php
$this->app->loadConfig('ai');
$this->app->loadLang('ai');
$module = $this->app->getModuleName();
$method = $this->app->getMethodName();
if(isset($config->ai->availableForms[$module]) && in_array($method, $config->ai->availableForms[$module])):
?>
<?php
if(isset($_SESSION['aiInjectData']) && isset($_SESSION['aiInjectData'][$module]) && isset($_SESSION['aiInjectData'][$module][$method])) $injectData = $_SESSION['aiInjectData'][$module][$method];
if(!empty($injectData)):
?>
<?php
js::set('injectData', $injectData);
unset($_SESSION['aiInjectData'][$module]);
$this->app->loadLang('ai');
?>
<script>
(function()
{
function injectToInputElement(inputName, data, index)
{
if(typeof index !== 'undefined')
{
inputName = inputName + '[' + (index + 1) + ']';
}
const $input = $('[name="' + inputName + '"]');
if(!$input.length) return;
const inputType = $input.prop('nodeName');
switch(inputType) // Contains case fallthroughs, on purpose.
{
case 'TEXTAREA':
/* Textareas might be controlled by KindEditors. */
if(typeof KindEditor !== 'undefined' && KindEditor.instances.length)
{
const editorInstance = KindEditor.instances.find(function(e)
{
return e.srcElement.attr('name') == inputName;
});
if(editorInstance)
{
if(data === null) data = '';
/* Remove placeholder. */
if(data !== '') editorInstance.$placeholder.each(function(_idx, ph) {ph.style.display = 'none';});
/* Set editor content and sync with textarea. */
editorInstance.html(data);
editorInstance.sync();
break;
}
}
default:
/* For normal inputs, just set the value is enough. */
$input.val(data);
break;
}
}
function inject(obj)
{
for(const key in obj)
{
duelWithSpecialInputType(key, obj[key]);
if(Array.isArray(obj[key]))
{
const arr = obj[key];
for(let i = 0; i < arr.length; i++)
{
for(const key in arr[i])
{
injectToInputElement(key, arr[i][key], i);
}
}
}
else if(typeof obj[key] === 'Object')
{
inject(obj[key]);
}
else
{
injectToInputElement(key, obj[key])
}
}
}
function duelWithSpecialInputType(key, value)
{
if(key === 'steps')
{
const steps = document.getElementById('steps');
if(!steps) return;
if(value.length > steps.children.length)
{
const gap = value.length - steps.children.length;
for(let i = 0; i < gap; i++)
{
const addButton = document.querySelector('#steps > tr:last-child > .step-actions button:first-child');
if(!addButton) return;
addButton.click();
}
}
}
}
document.addEventListener("DOMContentLoaded", function()
{
try
{
const data = JSON.parse(injectData);
if(!data) return;
inject(data);
$.zui.messager.success('<?php echo $lang->ai->dataInject->success;?>');
}
catch(e)
{
$.zui.messager.danger('<?php echo $lang->ai->dataInject->fail;?>');
console.error(e);
}
finally
{
/* Set injected in oreder to cancel loading class on object view (see promptmenu.html.php). */
sessionStorage.setItem('ai-prompt-data-injected', true);
}
});
})();
</script>
<?php endif;?>
<?php if(isset($_SESSION['aiPrompt']['prompt']) && $_SESSION['aiPrompt']['objectId']):
$prompt = $_SESSION['aiPrompt']['prompt'];
$objectId = $_SESSION['aiPrompt']['objectId'];
$isAudit = isset($_SESSION['auditPrompt']) && time() - $_SESSION['auditPrompt']['time'] < 10 * 60;
?>
<script>
(function() {
const isAudit = <?php echo $isAudit ? 'true' : 'false';?>;
const promptId = '<?php echo $prompt->id;?>';
<?php if(isset($config->ai->injectAuditButton->locations[$module][$method])) :?>
function injectAuditAction()
{
<?php
$htmlStr = html::commonButton($lang->ai->promptPublish, "id='promptPublish' data-promptId=$prompt->id", 'btn btn-primary btn-wide');
$targetContainer = $config->ai->injectAuditButton->locations[$module][$method]['action']->targetContainer;
$injectMethod = $config->ai->injectAuditButton->locations[$module][$method]['action']->injectMethod;
if($module == 'doc'):
$containerStyles = empty($config->ai->injectAuditButton->locations[$module][$method]['action']->containerStyles) ? '{}' : $config->ai->injectAuditButton->locations[$module][$method]['action']->containerStyles;
$exitAuditButton = html::commonButton($lang->ai->audit->exit, "id='promptAuditExit'", 'btn');
?>
const containerStyles = JSON.parse('<?php echo $containerStyles;?>');
const htmlStr = `<?php echo $htmlStr;?>`;
$('<?php echo $targetContainer;?>')['<?php echo $injectMethod;?>'](htmlStr);
$('<?php echo $targetContainer;?>').css(containerStyles);
$('#mainContent #headerBox td:first-child').html(`<?php echo $exitAuditButton;?>`);
<?php else:
$htmlStr = $htmlStr . html::commonButton($lang->ai->audit->exit, "id='promptAuditExit'", 'btn btn-wide');
?>
const htmlStr = `<?php echo $htmlStr;?>`;
$('<?php echo $targetContainer;?>')['<?php echo $injectMethod;?>'](htmlStr);
<?php endif;?>
}
function injectAuditToolbar()
{
<?php
$htmlStr = html::a(helper::createLink('ai', 'promptexecute', "promptId=$prompt->id&objectId=$objectId"), '<i class="icon icon-refresh muted"></i> ' . $lang->ai->audit->regenerate, '', 'id="promptRegenerate" class="btn btn-link"');
if($isAudit)
{
$htmlStr = $htmlStr . html::a(helper::createLink('ai', 'promptaudit', "promptId=$prompt->id&objectId=$objectId"), $lang->ai->audit->designPrompt, '', 'id="promptAudit" class="btn btn-info iframe"');
}
$targetContainer = $config->ai->injectAuditButton->locations[$module][$method]['toolbar']->targetContainer;
$injectMethod = $config->ai->injectAuditButton->locations[$module][$method]['toolbar']->injectMethod;
if(!empty($config->ai->injectAuditButton->locations[$module][$method]['toolbar']->class)) $htmlStr = '<div class="' . $config->ai->injectAuditButton->locations[$module][$method]['toolbar']->class . '">' . $htmlStr . '</div>';
?>
const targetContainer = `<?php echo $targetContainer;?>`;
const injectMethod = `<?php echo $injectMethod;?>`;
const htmlStr = `<?php echo $htmlStr;?>`;
$(targetContainer)[injectMethod](htmlStr);
}
if(isAudit)
{
injectAuditAction();
}
if(typeof injectData !== 'undefined')
{
injectAuditToolbar();
}
<?php endif;?>
const publishButton = document.getElementById('promptPublish');
if(publishButton)
{
publishButton.addEventListener('click', function(e)
{
e.preventDefault();
const promptId = publishButton.dataset.promptid;
const aTag = document.createElement('a');
aTag.href = createLink('ai', 'promptPublish', 'promptId=' + promptId + '&backToTestingLocation=true') + '#app=admin';
aTag.style.display = 'none';
document.body.appendChild(aTag);
aTag.click();
if($.appCode !== 'admin') $.apps.close($.appCode);
});
}
const auditExitButton = document.getElementById('promptAuditExit');
if(auditExitButton)
{
auditExitButton.addEventListener('click', function(e)
{
e.preventDefault();
const aTag = document.createElement('a');
aTag.href = createLink('ai', 'promptAudit', 'promptId=' + promptId + '&objectId=0' + '&exit=true') + '#app=admin';
aTag.style.display = 'none';
document.body.appendChild(aTag);
aTag.click();
if($.appCode !== 'admin') $.apps.close($.appCode);
});
}
const regenerateButton = document.getElementById('promptRegenerate');
if(regenerateButton)
{
regenerateButton.addEventListener('click', function()
{
$('body').attr('data-loading', '<?php echo $lang->ai->execute->loading;?>');
$('body').addClass('load-indicator loading');
});
}
})();
</script>
<?php endif;?>
<?php endif;?>
+75
View File
@@ -0,0 +1,75 @@
<?php
/**
* The ai models view file of ai module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php
$currentVendor = empty($modelConfig->vendor) ? key($lang->ai->models->openaiVendorList) : $modelConfig->vendor;
$requiredFields = $config->ai->vendorList[$currentVendor]['requiredFields'];
?>
<div id='mainContent' class='main-content'>
<table class='table table-form mw-600px'>
<tr>
<th><?php echo $lang->ai->models->type;?></th>
<td><?php echo zget($lang->ai->models->typeList, $modelConfig->type, $lang->ai->models->unconfigured);?></td>
</tr>
<tr>
<th><?php echo $lang->ai->models->vendor;?></th>
<td><?php echo empty($modelConfig->vendor) ? $lang->ai->models->unconfigured : $lang->ai->models->openaiVendorList[$modelConfig->vendor]?></td>
</tr>
<?php if(in_array('key', $requiredFields)): ?>
<tr>
<th><?php echo $lang->ai->models->key; ?></th>
<td><?php echo empty($modelConfig->key) ? $lang->ai->models->unconfigured : ("<code title='{$lang->ai->models->concealTip}'>" . substr_replace($modelConfig->key, '...', 4, strlen($modelConfig->key) - 8) . '</code>'); ?></td>
</tr>
<?php endif; ?>
<?php if(in_array('resource', $requiredFields)): ?>
<tr>
<th><?php echo $lang->ai->models->resource; ?></th>
<td><?php echo empty($modelConfig->resource) ? $lang->ai->models->unconfigured : $modelConfig->resource; ?></td>
</tr>
<?php endif; ?>
<?php if(in_array('deployment', $requiredFields)): ?>
<tr>
<th><?php echo $lang->ai->models->deployment; ?></th>
<td><?php echo empty($modelConfig->deployment) ? $lang->ai->models->unconfigured : $modelConfig->deployment; ?></td>
</tr>
<?php endif; ?>
<tr>
<th><?php echo $lang->ai->models->proxyType;?></th>
<td><?php echo zget($lang->ai->models->proxyTypes, $modelConfig->proxyType, $lang->ai->models->unconfigured);?></td>
</tr>
<?php if(!empty($modelConfig->proxyType)):?>
<tr>
<th><?php echo $lang->ai->models->proxyAddr;?></th>
<td><?php echo empty($modelConfig->proxyAddr) ? $lang->ai->models->unconfigured : ("<code title='{$lang->ai->models->concealTip}'>" . substr_replace($modelConfig->proxyAddr, '://...', strpos($modelConfig->proxyAddr, ':')) . '</code>');?></td>
</tr>
<?php endif;?>
<tr>
<th><?php echo $lang->ai->models->description;?></th>
<td><?php echo $modelConfig->description;?></td>
</tr>
<tr>
<th><?php echo $lang->statusAB;?></th>
<td><?php echo zget($lang->ai->models->statusList, $modelConfig->status, $lang->ai->models->statusList['off']);?></td>
</tr>
<tr>
<td colspan='2' class='text-center'>
<?php if(commonModel::hasPriv('ai', 'editmodel')) echo html::linkButton($lang->ai->models->edit, inlink('editmodel') . '#app=admin', 'self', '', 'btn btn-primary btn-wide');?>
</td>
</tr>
</table>
</div>
<?php if($config->edition == 'open'):?>
<p style="padding-top: 10px;">
<?php echo $lang->ai->models->upgradeBiz;?>
</p>
<?php endif;?>
<?php include '../../common/view/footer.html.php';?>
+78
View File
@@ -0,0 +1,78 @@
<?php
/**
* The ai prompt menu view file of ai module of ZenTaoPMS.
*
* This view file is used to print the prompt menu, acts just like header php files.
* Prompt menus are generated with php and injected with javascript. A lot of hacking
* went into this, so please don't touch it unless you know what you are doing.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
?>
<?php if(commonModel::hasPriv('ai', 'promptExecute')):?>
<?php
$this->app->loadConfig('ai');
$module = $this->app->getModuleName();
$method = $this->app->getMethodName();
if(isset($config->ai->menuPrint->locations[$module][$method])):
?>
<?php
$menuOptions = $config->ai->menuPrint->locations[$module][$method];
$prompts = $this->loadModel('ai')->getPromptsForUser($menuOptions->module);
$prompts = $this->ai->filterPromptsForExecution($prompts, true);
if(!empty($prompts)):
?>
<?php
$html = '';
$objectVarName = empty($menuOptions->objectVarName) ? $menuOptions->module : $menuOptions->objectVarName;
$currentObjectId = !empty($this->view->$objectVarName) ? $this->view->$objectVarName->id : 0;
if(count($prompts) > 1)
{
$html .= '<div class="prompts dropdown' . ((isset($menuOptions->class) ? ' ' . $menuOptions->class : '') . (isset($menuOptions->dropdownClass) ? ' ' . $menuOptions->dropdownClass : '')) . '"><button class="btn btn-link' . (isset($menuOptions->buttonClass) ? ' ' . $menuOptions->buttonClass : '') . '" type="button" data-toggle="dropdown">' . $lang->ai->promptMenu->dropdownTitle . ' <i class="icon-caret-down"></i></button><ul class="dropdown-menu pull-right">';
foreach($prompts as $prompt) $html .= '<li>' . html::linkButton($prompt->name . ($prompt->status != 'active' ? '<span class="label label-info label-badge" style="margin-left: 4px;">' . $lang->ai->prompts->statuses[$prompt->status] . '</span>' : ''), helper::createLink('ai', 'promptExecute', "promptId=$prompt->id&objectId=$currentObjectId"), 'self', "style='width: 100%;'" . (empty($prompt->unauthorized) ? '' : ' disabled') . (empty($prompt->desc) ? '' : " data-toggle='popover' data-container='body' data-trigger='hover' data-content='$prompt->desc' data-title='$prompt->name' data-placement='left'"), 'btn btn-link text-left') . '</li>';
$html .= '</ul></div>';
}
else
{
$prompt = current($prompts);
$html .= html::linkButton($prompt->name . ($prompt->status != 'active' ? '<span class="label label-info label-badge" style="margin-left: 4px;">' . $lang->ai->prompts->statuses[$prompt->status] . '</span>' : ''), helper::createLink('ai', 'promptExecute', "promptId=$prompt->id&objectId=$currentObjectId"), 'self', (empty($prompt->unauthorized) ? '' : 'disabled') . (empty($prompt->desc) ? '' : " data-toggle='popover' data-container='body' data-trigger='hover' data-content='$prompt->desc' data-title='$prompt->name' data-placement='bottom'"), 'prompt btn btn-link' . ((isset($menuOptions->class) ? ' ' . $menuOptions->class : '') . (isset($menuOptions->buttonClass) ? ' ' . $menuOptions->buttonClass : '')));
}
?>
<?php if(isset($menuOptions->stylesheet)):?>
<style><?php echo $menuOptions->stylesheet;?></style>
<?php endif;?>
<script>
$(function()
{
if(window.location.search.includes('onlybody')) return;
$(`<?php echo $menuOptions->targetContainer;?>`).<?php echo isset($menuOptions->injectMethod) ? $menuOptions->injectMethod : 'append';?>(`<?php echo $html;?>`);
$('[data-toggle="popover"]').popover({template: '<div class="popover"><h3 class="popover-title"></h3><div class="popover-content"></div></div>'});
$('<?php echo count($prompts) > 1 ? '.prompts.dropdown ul.dropdown-menu' : '.prompt';?>').on('click', <?php if(count($prompts) > 1) echo "'button',";?> function(e)
{
$('body').attr('data-loading', e.target.querySelector('.label') ? '<?php echo $lang->ai->execute->auditing;?>' : '<?php echo $lang->ai->execute->loading;?>');
$('body').addClass('load-indicator loading');
/* Checks for session storage to cancel loading status (see inputinject.html.php). */
sessionStorage.removeItem('ai-prompt-data-injected');
const loadCheckInterval = setInterval(function()
{
if(sessionStorage.getItem('ai-prompt-data-injected'))
{
$('body').removeClass('loading');
sessionStorage.removeItem('ai-prompt-data-injected');
clearInterval(loadCheckInterval);
}
}, 200);
});
});
</script>
<?php endif; endif; endif;?>
+203
View File
@@ -0,0 +1,203 @@
<?php
/**
* The ai prompts view file of ai module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php
/**
* Prompt action menu printer, based on prompt status and completion state.
*
* @param object $prompt prompt object
* @return void
*/
$printPromptActionMenu = function($prompt) use($lang)
{
$html = '';
$executable = $this->ai->isExecutable($prompt);
$published = $prompt->status == 'active';
if($this->config->edition != 'open')
{
/* Design button. */
if(common::hasPriv('ai', 'promptassignrole')) $html .= html::a(helper::createLink('ai', 'promptassignrole', "prompt=$prompt->id"), '<i class="icon-design text-primary"></i>', '', "class='btn" . ($published ? ' disabled' : '') . "' title='{$lang->ai->prompts->action->design}'");
/* Test / audit button. */
if(common::hasPriv('ai', 'promptaudit')) $html .= html::a($executable ? $this->ai->getTestingLocation($prompt) : '#', '<i class="icon-menu-backend text-primary"></i>', '', "id='prompt-audit-button-$prompt->id' class='prompt-audit-btn btn" . ($executable && !$published ? '' : ' disabled') . "' title='{$lang->ai->prompts->action->test}'" . ($executable ? '' : " data-toggle='modal' data-target='#designConfirmModal'"));
/* Edit button. */
if(common::hasPriv('ai', 'promptedit')) $html .= html::a(helper::createLink('ai', 'promptedit', "prompt=$prompt->id"), '<i class="icon-edit text-primary"></i>', '', "class='btn' title='{$lang->ai->prompts->action->edit}'");
/* Divider. */
if(common::hasPriv('ai', 'promptpublish') || common::hasPriv('ai', 'promptunpublish')) $html .= '<div class="dividing-line"></div>';
}
/* Publish button. */
if(common::hasPriv('ai', 'promptpublish')) $html .= html::a(!$published && $executable ? "javascript:togglePromptStatus($prompt->id)" : '#', '<i class="icon-publish text-primary"></i>', '', "class='btn" . (!$published && $executable ? '' : ' disabled') . "' title='{$lang->ai->prompts->action->publish}'" . ($executable ? '' : " data-toggle='modal' data-target='#designConfirmModal'"));
/* Unpublish button. */
if(common::hasPriv('ai', 'promptunpublish')) $html .= html::a('#', '<i class="icon-ban text-primary"></i>', '', "class='btn" . (!$published || !$executable ? ' disabled' : '') . "' title='{$lang->ai->prompts->action->unpublish}'" . (!$published ? '' : " data-toggle='modal' data-target='#draftConfirmModal'"));
echo $html;
}
?>
<div id="mainMenu" class="clearfix">
<div id="sidebarHeader">
<div class="title" title="<?php echo $this->lang->ai->prompts->modules[$module];?>">
<?php echo $this->lang->ai->prompts->modules[$module];?>
<?php if($module) echo html::a($this->createLink('ai', 'prompts'), "<i class='icon icon-sm icon-close'></i>", '', "class='text-muted'");?>
</div>
</div>
<div class="btn-toolbar pull-left">
<?php
foreach($this->lang->ai->prompts->statuses as $statusKey => $statusName)
{
echo html::a($this->createLink('ai', 'prompts', "module=$module&status=$statusKey"), "<span class='text'>{$this->lang->ai->prompts->statuses[$statusKey]}" . ($status == $statusKey ? '<span class="label label-light label-badge" style="margin-left: 4px;">' . $pager->recTotal . '</span>' : '') . "</span>", '' ,"id='status-$statusKey' class='btn btn-link" . ($status == $statusKey ? ' btn-active-text' : '') . "'");
}
?>
</div>
<div class="btn-toolbar pull-right">
<?php if($this->config->edition != 'open' && common::hasPriv('ai', 'createprompt')) echo html::a($this->createLink('ai', 'createprompt'), "<i class='icon icon-plus'></i> " . $lang->ai->prompts->create, '', "class='btn btn-primary iframe'");?>
</div>
</div>
<div id="mainContent" class="main-row fade">
<div class="side-col" id="sidebar">
<div class="cell">
<ul id="modules" class="tree" data-ride="tree" data-name="tree-modules">
<?php
$moduleList = $this->config->edition != 'open'
? $this->lang->ai->prompts->modules
: array_filter($this->lang->ai->prompts->modules, function($v, $k) use ($promptModules)
{
return in_array($k, $promptModules);
}, ARRAY_FILTER_USE_BOTH);
?>
<?php foreach($moduleList as $moduleKey => $moduleName): ?>
<li <?php if($module == $moduleKey) echo 'class="active"'; ?>><a
href="<?php echo $this->createLink('ai', 'prompts', "module=$moduleKey"); ?>"><?php echo $moduleName; ?></a>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="main-col">
<?php if(empty($prompts)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->ai->prompts->emptyList;?></span>
<?php if($this->config->edition != 'open' && common::hasPriv('ai', 'createprompt')) echo html::a($this->createLink('ai', 'createprompt'), "<i class='icon icon-plus'></i> " . $lang->ai->prompts->create, '', "class='btn btn-info iframe'");?>
</p>
</div>
<?php else:?>
<div class='main-table'>
<table class='main-table table has-sort-head table-fixed' id='promptList'>
<thead>
<tr>
<?php $vars = "module=$module&status=$status&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";?>
<th class='c-id text-left w-60px'><?php common::printOrderLink('id', $orderBy, $vars, $lang->ai->prompts->id);?></th>
<th class='c-name'><?php common::printOrderLink('name', $orderBy, $vars, $lang->ai->prompts->name);?></th>
<?php if(empty($status)):?>
<th class='c-status w-80px'><?php common::printOrderLink('status', $orderBy, $vars, $lang->ai->prompts->stage);?></th>
<?php endif;?>
<th class='c-createdby w-120px'><?php common::printOrderLink('createdby', $orderBy, $vars, $lang->ai->prompts->createdBy);?></th>
<th class='c-createddate w-180px'><?php common::printOrderLink('createddate', $orderBy, $vars, $lang->ai->prompts->createdDate);?></th>
<th class='c-targetform w-200px'><?php common::printOrderLink('targetform', $orderBy, $vars, $lang->ai->prompts->targetForm);?></th>
<th class='text-center c-actions-5'><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody>
<?php foreach($prompts as $prompt):?>
<tr>
<td class='c-id'><?php echo $prompt->id;?></td>
<td class='c-name'><?php echo html::a(helper::createLink('ai', 'promptview', "id=$prompt->id"), $prompt->name, '_self', "title='$prompt->name'");?></td>
<?php if(empty($status)):?>
<td class='c-status'><?php echo $lang->ai->prompts->statuses[$prompt->status];?></td>
<?php endif;?>
<td class='c-createdby'><?php echo $prompt->createdBy;?></td>
<td class='c-createddate'><?php echo $prompt->createdDate;?></td>
<td class='c-targetform'>
<?php
if($prompt->targetForm)
{
$targetFormPath = explode('.', $prompt->targetForm);
if(count($targetFormPath) == 2) echo $lang->ai->targetForm[$targetFormPath[0]]['common'] . ' / ' . $lang->ai->targetForm[$targetFormPath[0]][$targetFormPath[1]];
}
?>
</td>
<td class='text-center c-actions' data-prompt-id='<?php echo $prompt->id?>'>
<?php $printPromptActionMenu($prompt);?>
</td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<div class="table-statistic"><?php echo sprintf($lang->ai->prompts->summary, count($prompts));?></div>
<?php $pager->show('right', 'pagerjs');?>
</div>
</div>
<?php endif;?>
</div>
</div>
<div class="modal fade" id="designConfirmModal">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-body">
<p><?php echo $lang->ai->prompts->action->goDesignConfirm?></p>
</div>
<div class="modal-footer">
<button id="goDesignButton" type="button" class="btn btn-primary"><?php echo $lang->ai->prompts->action->goDesign?></button>
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo $lang->cancel?></button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="draftConfirmModal">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-body">
<p><?php echo $lang->ai->prompts->action->draftConfirm?></p>
</div>
<div class="modal-footer">
<button id="draftPromptButton" type="button" class="btn btn-primary"><?php echo $lang->confirm?></button>
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo $lang->cancel?></button>
</div>
</div>
</div>
</div>
<script>
$(function()
{
/* Handle clicks from audit button without auditable objects. */
$('.prompt-audit-btn[href=""]').click(function(e)
{
$.zui.messager.danger('<?php echo $lang->ai->prompts->goingTestingFail;?>');
return false;
});
$('.prompt-audit-btn[href!=""][href!="#"]').click(function(e)
{
$('body').attr('data-loading', '<?php echo $lang->ai->execute->loading;?>');
$('body').addClass('load-indicator loading');
/* Checks for session storage to cancel loading status (see inputinject.html.php). */
sessionStorage.removeItem('ai-prompt-data-injected');
const loadCheckInterval = setInterval(function()
{
if(sessionStorage.getItem('ai-prompt-data-injected'))
{
$('body').removeClass('loading');
sessionStorage.removeItem('ai-prompt-data-injected');
clearInterval(loadCheckInterval);
}
}, 200);
});
});
</script>
<?php include '../../common/view/footer.html.php';?>
+207
View File
@@ -0,0 +1,207 @@
<?php
/**
* The ai prompt details view file of ai module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wenrui LI <liwenrui@easycorp.ltd>
* @package ai
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<?php echo html::a(helper::createLink('ai', 'prompts'), '<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', "class='btn btn-secondary'");?>
<div class="divider"></div>
<div class="page-title">
<span class="label label-id"><?php echo $prompt->id;?></span>
<span class="text" title='<?php echo $prompt->name;?>'><?php echo $prompt->name;?></span>
<?php if($prompt->deleted) echo "<span class='label label-danger'>{$lang->ai->prompts->deleted}</span>";?>
</div>
</div>
<div class="btn-toolbar pull-right">
<?php if(common::hasPriv('ai', 'createprompt')) echo html::a(helper::createLink('ai', 'createprompt'), "<i class='icon icon-plus'></i> {$lang->ai->prompts->create}", '', "class='btn btn-primary iframe'");?>
</div>
</div>
<div id="mainContent" class="main-row">
<div class="main-col col-8">
<div class="cell prompt-details">
<div class="detail">
<div class="detail-title"><?php echo $lang->ai->prompts->role;?></div>
<div class="detail-content article-content"><?php echo $prompt->role;?></div>
<div class="detail-title"><?php echo $lang->ai->prompts->characterization;?></div>
<div class="detail-content article-content"><?php echo $prompt->characterization;?></div>
</div>
<div class="detail">
<div class="detail-title"><?php echo $lang->ai->prompts->object;?></div>
<div class="detail-content article-content"><?php echo $prompt->module ? $this->lang->ai->dataSource[$prompt->module]['common'] : ''; ?></div>
<div class="detail-title"><?php echo $lang->ai->prompts->field;?></div>
<div class="detail-content article-content"><?php echo $dataPreview;?></div>
</div>
<div class="detail">
<div class="detail-title"><?php echo $lang->ai->prompts->setPurpose;?></div>
<div class="detail-content article-content"><?php echo $prompt->purpose;?></div>
<div class="detail-title"><?php echo $lang->ai->prompts->elaboration;?></div>
<div class="detail-content article-content"><?php echo $prompt->elaboration;?></div>
</div>
<div class="detail">
<div class="detail-title"><?php echo $lang->ai->prompts->selectTargetForm;?></div>
<div class="detail-content article-content">
<?php
if(empty($prompt->targetForm)) echo '';
else
{
$targetForm = explode('.', $prompt->targetForm);
echo $this->lang->ai->targetForm[$targetForm[0]][$targetForm[1]];
}
?></div>
</div>
</div>
<div class="cell"><?php include '../../common/view/action.html.php';?></div>
<?php if($this->config->edition != 'open'): ?>
<div class='main-actions'>
<div class="btn-toolbar">
<?php echo html::a(helper::createLink('ai', 'prompts'), '<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', "class='btn'"); ?>
<?php if(!$prompt->deleted): ?>
<?php if(($prompt->status == 'draft' && (common::hasPriv('ai', 'promptassignrole') || common::hasPriv('ai', 'promptaudit') || common::hasPriv('ai', 'publish'))) || ($prompt->status != 'draft' && common::hasPriv('ai', 'unpublish'))): ?>
<div class='divider'></div><?php endif; ?>
<?php if(common::hasPriv('ai', 'promptassignrole') && $prompt->status == 'draft') echo html::a(helper::createLink('ai', 'promptassignrole', "prompt=$prompt->id"), '<i class="icon icon-design icon-sm"></i> ' . $lang->ai->prompts->action->design, '', "class='btn'"); ?>
<?php if(common::hasPriv('ai', 'promptaudit') && $prompt->status == 'draft' && $this->ai->isExecutable($prompt)) echo html::a($this->ai->getTestingLocation($prompt), '<i class="icon icon-menu-backend icon-sm"></i> ' . $lang->ai->prompts->action->test, '', "class='btn prompt-audit-btn'"); ?>
<?php if(common::hasPriv('ai', 'promptpublish') && $prompt->status == 'draft' && $this->ai->isExecutable($prompt)) echo html::a(helper::createLink('ai', 'promptpublish', "id={$prompt->id}"), '<i class="icon icon-publish icon-sm"></i> ' . $lang->ai->prompts->action->publish, '', "class='btn'"); ?>
<?php if(common::hasPriv('ai', 'promptunpublish') && $prompt->status == 'active') echo html::a(helper::createLink('ai', 'promptunpublish', "id={$prompt->id}"), '<i class="icon icon-ban icon-sm"></i> ' . $lang->ai->prompts->action->unpublish, '', "class='btn' id='unpublish-btn'"); ?>
<?php if(common::hasPriv('ai', 'promptedit') || common::hasPriv('ai', 'promptdelete')): ?>
<div class='divider'></div><?php endif; ?>
<?php if(common::hasPriv('ai', 'promptedit')) echo html::a(helper::createLink('ai', 'promptedit', "prompt=$prompt->id"), '<i class="icon icon-edit icon-sm"></i>', '', "class='btn' title='{$lang->ai->prompts->action->edit}'"); ?>
<?php if(common::hasPriv('ai', 'promptdelete')) echo html::a(helper::createLink('ai', 'promptdelete', "prompt=$prompt->id"), '<i class="icon icon-trash icon-sm"></i>', '', "class='btn deleter' title='{$lang->ai->prompts->action->delete}'"); ?>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</div>
<div class="side-col col-4">
<div class="cell">
<div class='tabs'>
<ul class='nav nav-tabs'>
<li class='active'><a href='#promptBasicInfo' data-toggle='tab'><?php echo $lang->ai->prompts->basicInfo; ?></a></li>
<li><a href='#promptEditInfo' data-toggle='tab'><?php echo $lang->ai->prompts->editInfo; ?></a></li>
</ul>
</div>
<div class='tab-content'>
<div class='tab-pane active' id='promptBasicInfo'>
<table class="table table-data">
<tbody>
<tr>
<th class="w-90px"><?php echo $lang->prompt->module; ?></th>
<td><?php echo $prompt->module ? $this->lang->ai->dataSource[$prompt->module]['common'] : ''; ?></td>
</tr>
<tr>
<th class="w-90px"><?php echo $lang->prompt->desc; ?></th>
<td><?php echo $prompt->desc; ?></td>
</tr>
<tr>
<th class="w-90px"><?php echo $lang->prompt->status; ?></th>
<td><?php echo $lang->ai->prompts->statuses[$prompt->status]; ?></td>
</tr>
<tr>
<th class="w-90px"><?php echo $lang->prompt->model; ?></th>
<td><?php echo $lang->ai->models->typeList['openai-gpt35']; ?></td>
</tr>
</tbody>
</table>
</div>
<div class='tab-pane' id='promptEditInfo'>
<table class="table table-data">
<tbody>
<tr>
<th class="w-90px"><?php echo $lang->prompt->createdBy; ?></th>
<td><?php echo zget($users, $prompt->createdBy) . $lang->at . $prompt->createdDate;?></td>
</tr>
<?php
/* Search for last publish / unpublish action. */
$lastPublishAction = null;
foreach(array_reverse($actions) as $action)
{
if(in_array($action->action, array('published', 'unpublished'))) $lastPublishAction = $action;
break;
}
?>
<?php if($prompt->status == 'active'):?>
<tr>
<th class="w-90px"><?php echo $lang->ai->prompts->publishedBy; ?></th>
<td><?php echo zget($users, empty($lastPublishAction) ? $prompt->createdBy : $lastPublishAction->actor);?></td>
</tr>
<?php else:?>
<tr>
<th class="w-90px"><?php echo empty($lastPublishAction) ? $lang->ai->prompts->publishedBy : $lang->ai->prompts->draftedBy;?></th>
<td><?php if(!empty($lastPublishAction)) echo zget($users, $lastPublishAction->actor);?></td>
</tr>
<?php endif;?>
<tr>
<th class="w-90px"><?php echo $lang->prompt->editedBy; ?></th>
<td><?php echo $prompt->editedBy ? zget($users, $prompt->editedBy) . $lang->at . $prompt->editedDate : '';?></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="mainActions" class='main-actions'>
<?php common::printPreAndNext($preAndNext, helper::createLink('ai', 'promptview', 'id=%d'));?>
</div>
<script>
$(function()
{
/* TODO: use new modal for these. */
$('.deleter').click(function()
{
if(confirm('<?php echo $lang->ai->prompts->action->deleteConfirm;?>'))
{
$.getJSON($(this).attr('href'), function(resp)
{
if(resp.result != 'success') $.zui.messager.danger(resp.message);
return location.reload();
});
}
return false;
});
$('#unpublish-btn').click(function()
{
if(confirm('<?php echo $lang->ai->prompts->action->draftConfirm;?>'))
{
$.getJSON($(this).attr('href'), function(resp)
{
if(resp.result != 'success') $.zui.messager.danger(resp.message);
return location.reload();
});
}
return false;
});
$('.prompt-audit-btn').click(function()
{
$('body').attr('data-loading', '<?php echo $lang->ai->execute->loading;?>');
$('body').addClass('load-indicator loading');
/* Checks for session storage to cancel loading status (see inputinject.html.php). */
sessionStorage.removeItem('ai-prompt-data-injected');
const loadCheckInterval = setInterval(function()
{
if(sessionStorage.getItem('ai-prompt-data-injected'))
{
$('body').removeClass('loading');
sessionStorage.removeItem('ai-prompt-data-injected');
clearInterval(loadCheckInterval);
}
}, 200);
});
});
</script>
<?php include '../../common/view/footer.html.php';?>
+2 -1
View File
@@ -5,7 +5,8 @@ new Vue({
attr: '',
struct: {
...struct,
attribute: struct.attribute
attribute: struct.attribute,
structType: struct.type
}
}
},
+1 -2
View File
@@ -79,8 +79,7 @@
<td><?php echo $lang->api->boolList[$param['required']];?></td>
<td><?php echo $param['desc'];?></td>
<tr>
<?php endforeach;
;?>
<?php endforeach;?>
</tbody>
</table>
<?php endif;?>
+33 -7
View File
@@ -22,15 +22,19 @@ class backup extends control
parent::__construct($moduleName, $methodName);
$this->backupPath = $this->backup->getBackupPath();
if(!is_dir($this->backupPath))
if($this->app->methodName != 'setting')
{
if(!mkdir($this->backupPath, 0777, true)) $this->view->error = sprintf($this->lang->backup->error->noWritable, dirname($this->backupPath));
if(!is_dir($this->backupPath))
{
if(!mkdir($this->backupPath, 0777, true)) $this->view->error = sprintf($this->lang->backup->error->noWritable, dirname($this->backupPath));
}
else
{
if(!is_writable($this->backupPath)) $this->view->error = sprintf($this->lang->backup->error->noWritable, $this->backupPath);
}
if(!is_writable($this->app->getTmpRoot())) $this->view->error = sprintf($this->lang->backup->error->noWritable, $this->app->getTmpRoot());
}
else
{
if(!is_writable($this->backupPath)) $this->view->error = sprintf($this->lang->backup->error->noWritable, $this->backupPath);
}
if(!is_writable($this->app->getTmpRoot())) $this->view->error = sprintf($this->lang->backup->error->noWritable, $this->app->getTmpRoot());
}
/**
@@ -72,9 +76,31 @@ class backup extends control
$this->view->title = $this->lang->backup->common;
$this->view->position[] = $this->lang->backup->common;
$this->view->backups = $backups;
if(!is_writable($this->backupPath)) $this->view->backupError = sprintf($this->lang->backup->error->plainNoWritable, $this->backupPath);
if(!is_writable($this->app->getTmpRoot())) $this->view->backupError = sprintf($this->lang->backup->error->plainNoWritable, $this->app->getTmpRoot());
$this->display();
}
/**
* Ajax get disk space.
*
* @access public
* @return void
*/
public function ajaxGetkDiskSpace()
{
set_time_limit(0);
session_write_close();
$diskSapce = $this->backup->getkDiskSpace($this->backupPath);
$diskSapce = explode(',', $diskSapce);
$space = new stdclass();
$space->freeSpace = intval($diskSapce[0]);
$space->needSpace = intval($diskSapce[1]);
echo json_encode($space);
}
/**
* Backup.
*
+61 -35
View File
@@ -2,46 +2,41 @@ $(function()
{
$('.backup').click(function()
{
var timeID = null;
$.ajax({
url: $(this).attr('data-link'),
success: function(data)
{
clearInterval(timeID);
$('#waitting .modal-body #message').append(data);
setTimeout(function(){return location.reload();}, 2000);
},
error: function(request, textstatus, error)
{
clearInterval(timeID);
if(textstatus == 'timeout') $('#waitting .modal-body #message').append("<p class='text-danger'>" + backupTimeout + '</p>');
setTimeout(function(){return location.reload();}, 2000);
}
});
$('#waitting .modal-body #backupType').html(backup);
$('#waitting').modal('show');
timeID = setInterval(function()
if(backupError)
{
$.get(createLink('backup', 'ajaxGetProgress'), function(data)
alert(backupError);
return;
}
var that = this;
$(that).toggleClass('loading');
$(that).text(getSpaceLoading);
link = createLink('backup', 'ajaxGetkDiskSpace');
$.get(link, function(data)
{
$(that).toggleClass('loading');
$(that).text(startBackup);
if(data)
{
$('#waitting .modal-content #message').html(data);
});
}, 1000);
})
if(data.needSpace > data.freeSpace)
{
alertTips = alertTips.replace('NEED_SPACE', (data.needSpace / (1024 * 1024 * 1024)).toFixed(2));
$('#spaceConfirm').find('p').text(alertTips);
$('#spaceConfirm').modal('show', 'center');
}
else
{
backupData();
}
}
}, 'json');
});
$('.rmPHPHeader').click(function()
{
$('#waitting .modal-body #backupType').html(rmPHPHeader);
$('#waitting .modal-content #message').hide();
$('#waitting').modal('show');
})
});
$('.restore').click(function()
{
@@ -64,8 +59,39 @@ $(function()
{
return location.reload();
}
})
});
return false;
})
})
});
});
function backupData()
{
var timeID = null;
$.ajax({
url: $('.backup').attr('data-link'),
success: function(data)
{
clearInterval(timeID);
$('#waitting .modal-body #message').append(data);
setTimeout(function(){return location.reload();}, 2000);
},
error: function(request, textstatus, error)
{
clearInterval(timeID);
if(textstatus == 'timeout') $('#waitting .modal-body #message').append("<p class='text-danger'>" + backupTimeout + '</p>');
setTimeout(function(){return location.reload();}, 2000);
}
});
$('#waitting .modal-body #backupType').html(backup);
$('#waitting').modal('show');
timeID = setInterval(function()
{
$.get(createLink('backup', 'ajaxGetProgress'), function(data)
{
$('#waitting .modal-content #message').html(data);
});
}, 1000);
}
+22 -17
View File
@@ -27,26 +27,31 @@ $lang->backup->settingDir = 'Backup Directory';
$lang->backup->settingList['nofile'] = 'Do not back up files or codes.';
$lang->backup->settingList['nosafe'] = 'Do not prevent downloading PHP file header.';
$lang->backup->waitting = '<span id="backupType"></span> In Arbeit. Bitte warten...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Möchten Sie das Backup löschen?';
$lang->backup->confirmRestore = 'Möchten Sie das Backup wiederherstellen?';
$lang->backup->holdDays = 'Behalten der letzen %s Tage der Backups';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Nur Dateien und Datenbanken können wiederhergestellt werden. Code kann manuell wieder hergestellt werden.';
$lang->backup->waitting = '<span id="backupType"></span> In Arbeit. Bitte warten...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Möchten Sie das Backup löschen?';
$lang->backup->confirmRestore = 'Möchten Sie das Backup wiederherstellen?';
$lang->backup->holdDays = 'Behalten der letzen %s Tage der Backups';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Nur Dateien und Datenbanken können wiederhergestellt werden. Code kann manuell wieder hergestellt werden.';
$lang->backup->insufficientDisk = 'Disk space less thanNEED_SPACEG, it may cause insufficient backup space or affect the use, please process it and try again.';
$lang->backup->ongoBackup = 'ongoing backup';
$lang->backup->cancelBackup = 'cancel backup';
$lang->backup->getSpaceLoading = 'Calculate backup space';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Erledigt!';
$lang->backup->success->restore = 'Wiederhergestellt!';
$lang->backup->error = new stdclass();
$lang->backup->error->noCreateDir = 'Directory does not exist and cannot be created';
$lang->backup->error->noWritable = "<code>%s</code> ist nicht beschreibbar! Bitte prüfen Sie die Berechtigungen, ansonsten kann das Backup nicht erstellt werden.";
$lang->backup->error->noDelete = "%s kann nicht gelöscht werden. Bitte passen Sie die Berechtigungen an oder löschen Sie es manuell.";
$lang->backup->error->restoreSQL = "Datenbankwiederherstellung fehlgeschlagen. Error: %s.";
$lang->backup->error->restoreFile = "Dateiwiederherstellung fehlgeschlagen. Error: %s.";
$lang->backup->error->backupFile = "Dateibackup fehlgeschlagen. Error: %s.";
$lang->backup->error->backupCode = "Codebackup fehlgeschlagen. Error: %s.";
$lang->backup->error->timeout = "Backup timeout.";
$lang->backup->error->noCreateDir = 'Directory does not exist and cannot be created';
$lang->backup->error->noWritable = "<code>%s</code> ist nicht beschreibbar! Bitte prüfen Sie die Berechtigungen, ansonsten kann das Backup nicht erstellt werden.";
$lang->backup->error->plainNoWritable = "%s ist nicht beschreibbar! Bitte prüfen Sie die Berechtigungen, ansonsten kann das Backup nicht erstellt werden.";
$lang->backup->error->noDelete = "%s kann nicht gelöscht werden. Bitte passen Sie die Berechtigungen an oder löschen Sie es manuell.";
$lang->backup->error->restoreSQL = "Datenbankwiederherstellung fehlgeschlagen. Error: %s.";
$lang->backup->error->restoreFile = "Dateiwiederherstellung fehlgeschlagen. Error: %s.";
$lang->backup->error->backupFile = "Dateibackup fehlgeschlagen. Error: %s.";
$lang->backup->error->backupCode = "Codebackup fehlgeschlagen. Error: %s.";
$lang->backup->error->timeout = "Backup timeout.";
+21 -16
View File
@@ -27,26 +27,31 @@ $lang->backup->settingDir = 'Backup Directory';
$lang->backup->settingList['nofile'] = 'Do not back up files or codes.';
$lang->backup->settingList['nosafe'] = 'Do not prevent downloading PHP file header.';
$lang->backup->waitting = '<span id="backupType"></span> is ongoing. Please wait...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Do you want to delete the backup?';
$lang->backup->confirmRestore = 'Do you want to restore the backup?';
$lang->backup->holdDays = 'Hold last %s days of backup';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Only files and databases can be restored by clicking Restore. Code can be restored manually.';
$lang->backup->waitting = '<span id="backupType"></span> is ongoing. Please wait...';
$lang->backup->progressSQL = '<p>SQL backup: %s is backed up.</p>';
$lang->backup->progressAttach = '<p>SQL backup is completed.</p><p>Attachment backing up.</p>';
$lang->backup->progressCode = '<p>SQL backup is completed.</p><p>Attachment backup is completed.</p><p>Code backing up.</p>';
$lang->backup->confirmDelete = 'Do you want to delete the backup?';
$lang->backup->confirmRestore = 'Do you want to restore the backup?';
$lang->backup->holdDays = 'Hold last %s days of backup';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Only files and databases can be restored by clicking Restore. Code can be restored manually.';
$lang->backup->insufficientDisk = 'Disk space less thanNEED_SPACEG, it may cause insufficient backup space or affect the use, please process it and try again.';
$lang->backup->ongoBackup = 'ongoing backup';
$lang->backup->cancelBackup = 'cancel backup';
$lang->backup->getSpaceLoading = 'Calculate backup space';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Done!';
$lang->backup->success->restore = 'Restored!';
$lang->backup->error = new stdclass();
$lang->backup->error->noCreateDir = 'Directory does not exist and cannot be created';
$lang->backup->error->noWritable = "<code>%s</code> is not writable! Please check the privilege, or backup will not be done.";
$lang->backup->error->noDelete = "%s cannot be deleted. Please modify the privilege or manually delete it.";
$lang->backup->error->restoreSQL = "Failed to restore the database library. Error %s.";
$lang->backup->error->restoreFile = "Failed to restore the file. Error %s.";
$lang->backup->error->backupFile = "Failed to back up the file. Error %s.";
$lang->backup->error->backupCode = "Failed to back up the code. Error %s.";
$lang->backup->error->noCreateDir = 'Directory does not exist and cannot be created';
$lang->backup->error->noWritable = "<code>%s</code> is not writable! Please check the privilege, or backup will not be done.";
$lang->backup->error->plainNoWritable = "%s is not writable! Please check the privilege, or backup will not be done.";
$lang->backup->error->noDelete = "%s cannot be deleted. Please modify the privilege or manually delete it.";
$lang->backup->error->restoreSQL = "Failed to restore the database library. Error %s.";
$lang->backup->error->restoreFile = "Failed to restore the file. Error %s.";
$lang->backup->error->backupFile = "Failed to back up the file. Error %s.";
$lang->backup->error->backupCode = "Failed to back up the code. Error %s.";
$lang->backup->error->timeout = "Backup timeout.";
+22 -17
View File
@@ -27,26 +27,31 @@ $lang->backup->settingDir = 'Répertoire Backup';
$lang->backup->settingList['nofile'] = 'Ne pas archiver fichiers et codes.';
$lang->backup->settingList['nosafe'] = 'Ne pas prévenir du téléchargement par PHP file header.';
$lang->backup->waitting = '<span id="backupType"></span> est en cours. Patientez s´il vous plait...';
$lang->backup->progressSQL = '<p>SQL backup: %s est sauvegardé.</p>';
$lang->backup->progressAttach = '<p>SQL backup est terminé.</p><p>Les fichiers sont en cours de sauvegarde.</p>';
$lang->backup->progressCode = '<p>SQL backup est terminé.</p><p>Sauvegarde des fichiers terminée.</p><p>Sauvegarde du code en cours.</p>';
$lang->backup->confirmDelete = 'Voulez-vous supprimer la sauvegarde ?';
$lang->backup->confirmRestore = 'Voulez-vous restaurer la sauvegarde ?';
$lang->backup->holdDays = 'conserver les derniers %s jours de backup';
$lang->backup->copiedFail = 'Fichiers en échec de copie : ';
$lang->backup->restoreTip = 'Seulement les fichiers et les bases peuvent être restaurées en cliquant sur Restaurer. Le code doit être restauré manuellement.';
$lang->backup->waitting = '<span id="backupType"></span> est en cours. Patientez s´il vous plait...';
$lang->backup->progressSQL = '<p>SQL backup: %s est sauvegardé.</p>';
$lang->backup->progressAttach = '<p>SQL backup est terminé.</p><p>Les fichiers sont en cours de sauvegarde.</p>';
$lang->backup->progressCode = '<p>SQL backup est terminé.</p><p>Sauvegarde des fichiers terminée.</p><p>Sauvegarde du code en cours.</p>';
$lang->backup->confirmDelete = 'Voulez-vous supprimer la sauvegarde ?';
$lang->backup->confirmRestore = 'Voulez-vous restaurer la sauvegarde ?';
$lang->backup->holdDays = 'conserver les derniers %s jours de backup';
$lang->backup->copiedFail = 'Fichiers en échec de copie : ';
$lang->backup->restoreTip = 'Seulement les fichiers et les bases peuvent être restaurées en cliquant sur Restaurer. Le code doit être restauré manuellement.';
$lang->backup->insufficientDisk = 'Disk space less thanNEED_SPACEG, it may cause insufficient backup space or affect the use, please process it and try again.';
$lang->backup->ongoBackup = 'ongoing backup';
$lang->backup->cancelBackup = 'cancel backup';
$lang->backup->getSpaceLoading = 'Calculate backup space';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Terminé avec succès !';
$lang->backup->success->restore = 'Restauré avec succès !';
$lang->backup->error = new stdclass();
$lang->backup->error->noCreateDir = "Le répertoire n'existe pas et ne peut pas être créer. C'est problématique.";
$lang->backup->error->noWritable = "<code>%s</code> n'est pas autorisé à l'écriture ! Vérifier les privilèges sinon le backup ne pourra pas se faire.";
$lang->backup->error->noDelete = "%s ne peut pas être supprimé. Modifiez les privilèges ou supprimez-le avec vos petites mains.";
$lang->backup->error->restoreSQL = "Echec pour restaurer la database library. Error %s.";
$lang->backup->error->restoreFile = "Echec pour restaurer le fichier. Erreur %s.";
$lang->backup->error->backupFile = "Echec pour sauvegarder le fichier. Erreur %s.";
$lang->backup->error->backupCode = "Echec pour sauvegarder le code. Erreur %s.";
$lang->backup->error->timeout = "Backup timeout.";
$lang->backup->error->noCreateDir = "Le répertoire n'existe pas et ne peut pas être créer. C'est problématique.";
$lang->backup->error->noWritable = "<code>%s</code> n'est pas autorisé à l'écriture ! Vérifier les privilèges sinon le backup ne pourra pas se faire.";
$lang->backup->error->plainNoWritable = "%s n'est pas autorisé à l'écriture ! Vérifier les privilèges sinon le backup ne pourra pas se faire.";
$lang->backup->error->noDelete = "%s ne peut pas être supprimé. Modifiez les privilèges ou supprimez-le avec vos petites mains.";
$lang->backup->error->restoreSQL = "Echec pour restaurer la database library. Error %s.";
$lang->backup->error->restoreFile = "Echec pour restaurer le fichier. Erreur %s.";
$lang->backup->error->backupFile = "Echec pour sauvegarder le fichier. Erreur %s.";
$lang->backup->error->backupCode = "Echec pour sauvegarder le code. Erreur %s.";
$lang->backup->error->timeout = "Backup timeout.";
+21 -16
View File
@@ -24,25 +24,30 @@ $lang->backup->settingDir = 'Thư mục sao lưu';
$lang->backup->settingList['nofile'] = 'Không sao lưu tập tin hoặc mã nguồn.';
$lang->backup->settingList['nosafe'] = 'Không ngăn tải xuống tập tin PHP.';
$lang->backup->waitting = '<span id="backupType"></span> đang diễn ra. Vui lòng đợi...';
$lang->backup->progressSQL = '<p>Sao lưu SQL: %s được sao lưu.</p>';
$lang->backup->progressAttach = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm: %s được sao lưu.</p>';
$lang->backup->progressCode = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm đã hoàn thành.</p><p>Sao lưu mã nguồn: %s được sao lưu.</p>';
$lang->backup->confirmDelete = 'Bạn có muốn xóa sao lưu này?';
$lang->backup->confirmRestore = 'Bạn có muốn khôi phục sao lưu này?';
$lang->backup->holdDays = 'Giữ ít nhất %s ngày sao lưu';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Chỉ tập tin và CSDL có thể được khôi phục bằng cách Click Khôi phục. Mã nguồn có thể khôi phục thủ công.';
$lang->backup->waitting = '<span id="backupType"></span> đang diễn ra. Vui lòng đợi...';
$lang->backup->progressSQL = '<p>Sao lưu SQL: %s được sao lưu.</p>';
$lang->backup->progressAttach = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm: %s được sao lưu.</p>';
$lang->backup->progressCode = '<p>Sao lưu SQL đã hoàn thành.</p><p>Sao lưu đính kèm đã hoàn thành.</p><p>Sao lưu mã nguồn: %s được sao lưu.</p>';
$lang->backup->confirmDelete = 'Bạn có muốn xóa sao lưu này?';
$lang->backup->confirmRestore = 'Bạn có muốn khôi phục sao lưu này?';
$lang->backup->holdDays = 'Giữ ít nhất %s ngày sao lưu';
$lang->backup->copiedFail = 'Copy failed files: ';
$lang->backup->restoreTip = 'Chỉ tập tin và CSDL có thể được khôi phục bằng cách Click Khôi phục. Mã nguồn có thể khôi phục thủ công.';
$lang->backup->insufficientDisk = 'Không gian đĩa nhỏ hơnNEED_SPACEG, Nó có thể gây ra không đủ dung lượng sao lưu hoặc ảnh hưởng đến việc sử dụng, vui lòng xử lý và thử lại.';
$lang->backup->ongoBackup = 'tiếp tục sao lưu';
$lang->backup->cancelBackup = 'hủy sao lưu';
$lang->backup->getSpaceLoading = 'Tính toán không gian dự phòng';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = 'Sao lưu hoàn thành!';
$lang->backup->success->restore = 'Khôi phục hoàn thành!';
$lang->backup->error = new stdclass();
$lang->backup->error->noCreateDir = 'Thư mục không tồn tại và không thể tạo';
$lang->backup->error->noWritable = "<code>%s</code> không thể ghi! Vui lòng kiểm tra quyền, nếu không sao lưu sẽ không thể hoàn thành.";
$lang->backup->error->noDelete = "%s không thể xóa. Vui lòng điều chỉnh quyền hoặc xóa nó thủ công.";
$lang->backup->error->restoreSQL = "Lỗi khôi phục thư viện CSDL. Lỗi %s.";
$lang->backup->error->restoreFile = "Lỗi khôi phục tập tin. Lỗi %s.";
$lang->backup->error->backupFile = "Lỗi sao lưu tập tin. Lỗi %s.";
$lang->backup->error->backupCode = "Lỗi sao lưu mã nguồn. Lỗi %s.";
$lang->backup->error->noCreateDir = 'Thư mục không tồn tại và không thể tạo';
$lang->backup->error->noWritable = "<code>%s</code> không thể ghi! Vui lòng kiểm tra quyền, nếu không sao lưu sẽ không thể hoàn thành.";
$lang->backup->error->plainNoWritable = "%s không thể ghi! Vui lòng kiểm tra quyền, nếu không sao lưu sẽ không thể hoàn thành.";
$lang->backup->error->noDelete = "%s không thể xóa. Vui lòng điều chỉnh quyền hoặc xóa nó thủ công.";
$lang->backup->error->restoreSQL = "Lỗi khôi phục thư viện CSDL. Lỗi %s.";
$lang->backup->error->restoreFile = "Lỗi khôi phục tập tin. Lỗi %s.";
$lang->backup->error->backupFile = "Lỗi sao lưu tập tin. Lỗi %s.";
$lang->backup->error->backupCode = "Lỗi sao lưu mã nguồn. Lỗi %s.";
+22 -17
View File
@@ -27,26 +27,31 @@ $lang->backup->settingDir = '备份目录';
$lang->backup->settingList['nofile'] = '不备份附件和代码';
$lang->backup->settingList['nosafe'] = '不需要防下载PHP文件头';
$lang->backup->waitting = '<span id="backupType"></span>正在进行中,请稍候...';
$lang->backup->progressSQL = '<p>SQL备份中,已备份%s</p>';
$lang->backup->progressAttach = '<p>SQL备份完成</p><p>附件备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->progressCode = '<p>SQL备份完成</p><p>附件备份完成</p><p>代码备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->confirmDelete = '是否删除备份?';
$lang->backup->confirmRestore = '是否还原该备份?';
$lang->backup->holdDays = '备份保留最近 %s 天';
$lang->backup->copiedFail = '复制失败的文件:';
$lang->backup->restoreTip = '还原功能只还原附件和数据库,如果需要还原代码,可以手动还原。';
$lang->backup->waitting = '<span id="backupType"></span>正在进行中,请稍候...';
$lang->backup->progressSQL = '<p>SQL备份中,已备份%s</p>';
$lang->backup->progressAttach = '<p>SQL备份完成</p><p>附件备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->progressCode = '<p>SQL备份完成</p><p>附件备份完成</p><p>代码备份中,共有%s个文件,已经备份%s个</p>';
$lang->backup->confirmDelete = '是否删除备份?';
$lang->backup->confirmRestore = '是否还原该备份?';
$lang->backup->holdDays = '备份保留最近 %s 天';
$lang->backup->copiedFail = '复制失败的文件:';
$lang->backup->restoreTip = '还原功能只还原附件和数据库,如果需要还原代码,可以手动还原。';
$lang->backup->insufficientDisk = '磁盘空间小于NEED_SPACEG,可能会导致备份空间不足或影响使用,请处理后再试。';
$lang->backup->ongoBackup = '继续备份';
$lang->backup->cancelBackup = '取消备份';
$lang->backup->getSpaceLoading = '正在计算备份空间';
$lang->backup->success = new stdclass();
$lang->backup->success->backup = '备份成功!';
$lang->backup->success->restore = '还原成功!';
$lang->backup->error = new stdclass();
$lang->backup->error->noCreateDir = '备份目录不存在,也无法创建该目录';
$lang->backup->error->noWritable = "<code>%s</code> 不可写!请检查该目录权限,否则无法备份。";
$lang->backup->error->noDelete = "文件 %s 无法删除,修改权限或手工删除。";
$lang->backup->error->restoreSQL = "数据库还原失败,错误:%s";
$lang->backup->error->restoreFile = "附件还原失败,错误:%s";
$lang->backup->error->backupFile = "附件备份失败,错误:%s";
$lang->backup->error->backupCode = "代码备份失败,错误:%s";
$lang->backup->error->timeout = "备份超时";
$lang->backup->error->noCreateDir = '备份目录不存在,也无法创建该目录';
$lang->backup->error->noWritable = "<code>%s</code> 不可写!请检查该目录权限,否则无法备份。";
$lang->backup->error->plainNoWritable = "%s 不可写!请检查该目录权限,否则无法备份。";
$lang->backup->error->noDelete = "文件 %s 无法删除,修改权限或手工删除。";
$lang->backup->error->restoreSQL = "数据库还原失败,错误:%s";
$lang->backup->error->restoreFile = "附件还原失败,错误:%s";
$lang->backup->error->backupFile = "附件备份失败,错误:%s";
$lang->backup->error->backupCode = "代码备份失败,错误:%s";
$lang->backup->error->timeout = "备份超时";
+56
View File
@@ -431,4 +431,60 @@ class backupModel extends model
if(file_put_contents($summaryFile, json_encode($summary))) return true;
return false;
}
/**
* Get disk space.
*
* @param int $backupPath
* @access public
* @return int
*/
public function getkDiskSpace($backupPath)
{
$nofile = strpos($this->config->backup->setting, 'nofile') !== false;
$diskFreeSpace = disk_free_space($backupPath);
$backFileSize = 0;
$zfile = $this->app->loadClass('zfile');
if(!$nofile)
{
$appRoot = $this->app->getAppRoot();
$appRootSize = $this->getZentaoSize($appRoot);
$backFileSize = $appRootSize - $zfile->getDirSize($appRoot . 'tmp') - $zfile->getDirSize($appRoot . 'www/course');
}
$backSqlSize = $this->dao->select('sum(data_length+index_length) as size')
->from('information_schema.tables')
->where('TABLE_SCHEMA')->eq($this->config->db->name)
->groupBy('TABLE_SCHEMA')
->fetch('size');
return $diskFreeSpace . ',' . ($backFileSize + $backSqlSize);
}
/**
* Get zentao size.
*
* @param string $appRoot
* @access public
* @return int
*/
public function getZentaoSize($appRoot)
{
$totalSize = 0;
$tmpDir = realPath($appRoot . 'tmp/');
$dataDir = realPath($appRoot . 'www/data/');
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($appRoot, RecursiveDirectoryIterator::SKIP_DOTS));
foreach($iterator as $file)
{
$filePath = $file->getRealPath();
if(strpos($filePath, $tmpDir) !== 0 and strpos($filePath, $dataDir) !== 0)
{
$totalSize += $file->getSize();
}
}
return $totalSize;
}
}
+17 -1
View File
@@ -31,7 +31,7 @@
if(common::hasPriv('backup', 'backup'))
{
$backupLink = helper::createLink('backup', 'backup', 'reload=yes');
echo html::commonButton("<i class='icon icon-copy'> </i>" . $lang->backup->backup, "data-link='{$backupLink}'", 'btn btn-primary backup');
echo html::commonButton("<i class='icon icon-copy'> </i>" . $lang->backup->backup, "data-link='{$backupLink}'", 'btn btn-primary backup load-indicator');
}
?>
</div>
@@ -116,9 +116,25 @@
</div>
</div>
</div>
<div class="modal fade" id="spaceConfirm" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-body">
<p></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo $lang->backup->cancelBackup;?></button>
</div>
</div>
</div>
</div>
<?php js::set('backup', $lang->backup->common);?>
<?php js::set('startBackup', $lang->backup->backup);?>
<?php js::set('getSpaceLoading', $lang->backup->getSpaceLoading);?>
<?php js::set('rmPHPHeader', $lang->backup->rmPHPHeader);?>
<?php js::set('confirmRestore', $lang->backup->confirmRestore);?>
<?php js::set('restore', $lang->backup->restore);?>
<?php js::set('backupTimeout', $lang->backup->error->timeout);?>
<?php js::set('alertTips', $lang->backup->insufficientDisk);?>
<?php js::set('backupError', empty($backupError) ? '' : $backupError);?>
<?php include '../../common/view/footer.html.php';?>
+51 -34
View File
@@ -244,6 +244,7 @@ class block extends control
public function dashboard($module, $type = '', $projectID = 0)
{
if($this->loadModel('user')->isLogon()) $this->session->set('blockModule', $module);
session_write_close();
$blocks = $this->block->getBlockList($module, $type);
$vision = $this->config->vision;
@@ -360,11 +361,7 @@ class block extends control
*/
public function dynamic()
{
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$pager = new pager(0, 30, 1);
$this->view->actions = $this->loadModel('action')->getDynamic('all', 'today', 'id_desc', $pager);
$this->view->actions = $this->loadModel('action')->getDynamic('all', 'today', 'id_desc', 30);
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter|all', '', 0, array_unique(array_column($this->view->actions, 'actor')));
$this->display();
@@ -417,6 +414,7 @@ class block extends control
*/
public function contribute()
{
session_write_close();
$cacheKey = $this->config->cacheKeys->block->contribute;
if(helper::isCacheEnabled() && $this->cache->has($cacheKey))
{
@@ -441,6 +439,7 @@ class block extends control
*/
public function printBlock($id, $module = 'my')
{
session_write_close(); // Avoid session blocking.
$block = $this->block->getByID($id);
if(empty($block)) return false;
@@ -500,6 +499,7 @@ class block extends control
*/
public function main($module = '', $id = 0)
{
session_write_close(); // Avoid session blocking.
if(!$this->selfCall)
{
$lang = str_replace('_', '-', $this->get->lang);
@@ -559,6 +559,7 @@ class block extends control
elseif($mode == 'getblockdata')
{
$code = strtolower($this->get->blockid);
$this->loadModel('program')->refreshStats();
$params = $this->get->param;
$params = json_decode(base64_decode($params));
@@ -658,6 +659,7 @@ class block extends control
$this->session->set('taskList', $uri, 'execution');
$this->session->set('storyList', $uri, 'product');
$this->session->set('testtaskList', $uri, 'qa');
session_write_close();
$tasks = $this->loadModel('task')->getUserSuspendedTasks($this->app->user->account);
foreach($todos as $key => $todo)
@@ -682,6 +684,7 @@ class block extends control
public function printTaskBlock()
{
$this->session->set('taskList', $this->createLink('my', 'index'), 'execution');
session_write_close();
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$account = $this->app->user->account;
@@ -700,6 +703,7 @@ class block extends control
public function printBugBlock()
{
$this->session->set('bugList', $this->createLink('my', 'index'), 'qa');
session_write_close();
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$projectID = $this->lang->navGroup->qa == 'project' ? $this->session->project : 0;
@@ -716,6 +720,7 @@ class block extends control
public function printCaseBlock()
{
$this->session->set('caseList', $this->createLink('my', 'index'), 'qa');
session_write_close();
$this->app->loadLang('testcase');
$this->app->loadLang('testtask');
@@ -764,6 +769,7 @@ class block extends control
$this->session->set('productList', $uri, 'product');
$this->session->set('testtaskList', $uri, 'qa');
$this->session->set('buildList', $uri, 'execution');
session_write_close();
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$this->view->projects = $this->loadModel('project')->getPairsByProgram();
@@ -791,6 +797,7 @@ class block extends control
public function printStoryBlock()
{
$this->session->set('storyList', $this->createLink('my', 'index'), 'product');
session_write_close();
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$this->app->loadClass('pager', $static = true);
@@ -813,6 +820,7 @@ class block extends control
$uri = $this->createLink('my', 'index');
$this->session->set('productList', $uri, 'product');
$this->session->set('productPlanList', $uri, 'product');
session_write_close();
$this->app->loadLang('productplan');
$this->view->plans = $this->dao->select('t1.*,t2.name as productName')->from(TABLE_PRODUCTPLAN)->alias('t1')
@@ -836,6 +844,7 @@ class block extends control
$uri = $this->createLink('my', 'index');
$this->session->set('releaseList', $uri, 'product');
$this->session->set('buildList', $uri, 'execution');
session_write_close();
$this->app->loadLang('release');
$this->view->releases = $this->dao->select('t1.*,t2.name as productName,t3.name as buildName')->from(TABLE_RELEASE)->alias('t1')
@@ -859,6 +868,7 @@ class block extends control
public function printBuildBlock()
{
$this->session->set('buildList', $this->createLink('my', 'index'), 'execution');
session_write_close();
$this->app->loadLang('build');
$builds = $this->dao->select('t1.*, t2.name AS productName, t2.shadow, t3.name AS projectName')->from(TABLE_BUILD)->alias('t1')
@@ -992,25 +1002,20 @@ class block extends control
{
$today = helper::today();
$monday = date('Ymd', strtotime($this->weekly->getThisMonday($today)));
$tasks = $this->dao->select("project,
sum(consumed) as totalConsumed,
sum(if(status != 'cancel' and status != 'closed', `left`, 0)) as totalLeft")
->from(TABLE_TASK)
->where('project')->in(array_keys($projects))
->andWhere('deleted')->eq(0)
->andWhere('parent')->lt(1)
->groupBy('project')
->fetchAll('project');
$this->app->loadClass('pager', $static = true);
$projectExecutions = $this->dao->select('*')->from(TABLE_EXECUTION)
->where('project')->in(array_keys($projects))
->andWhere('deleted')->eq('0')
->andWhere('type')->in('sprint,stage,kanban')
->groupBy('project')
->orderBy('id_desc')
->fetchAll('project');
foreach($projects as $projectID => $project)
{
if(in_array($project->model, array('scrum', 'kanban', 'agileplus')))
{
$pager = pager::init(0, 1, 1);
$project->progress = $project->allStories == 0 ? 0 : round($project->doneStories / $project->allStories, 3) * 100;
$project->executions = $this->execution->getStatData($projectID, 'all', 0, 0, false, '', 'id_desc', $pager);
$project->execution = zget($projectExecutions, $projectID, array());
}
elseif(in_array($project->model, array('waterfall', 'waterfallplus', 'ipd')))
{
@@ -1026,10 +1031,10 @@ class block extends control
$project->sv = $this->weekly->getSV($project->ev, $project->pv);
$project->cv = $this->weekly->getCV($project->ev, $project->ac);
$progress = isset($tasks[$projectID]) ? (($tasks[$projectID]->totalConsumed + $tasks[$projectID]->totalLeft)) ? round($tasks[$projectID]->totalConsumed / ($tasks[$projectID]->totalConsumed + $tasks[$projectID]->totalLeft), 3) * 100 : 0 : 0;
$left = (float)$this->weekly->getLeft($project->id, $today);
$project->progress = ($project->ac + $left) ? floor($project->ac / ($project->ac + $left) * 1000) / 1000 * 100 : 0;
$project->progress = $project->progress > 100 ? 100 : $project->progress;
$project->current = $current;
$project->progress = $progress;
}
}
@@ -1295,7 +1300,7 @@ class block extends control
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
$left = (float)$this->weekly->getLeft($this->session->project, $today);
$progress = (!empty($this->view->ac) or !empty($left)) ? floor($this->view->ac / ($this->view->ac + $left) * 1000) / 1000 * 100 : 0;
$progress = ($this->view->ac + $left) ? floor($this->view->ac / ($this->view->ac + $left) * 1000) / 1000 * 100 : 0;
$this->view->progress = $progress > 100 ? 100 : $progress;
$this->view->current = $current;
}
@@ -1351,6 +1356,7 @@ class block extends control
{
$uri = $this->app->tab == 'my' ? $this->createLink('my', 'index') : $this->server->http_referer;
$this->session->set('issueList', $uri, 'project');
session_write_close();
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->issues = $this->loadModel('issue')->getBlockIssues($this->session->project, $this->params->type, $this->viewType == 'json' ? 0 : (int)$this->params->count, $this->params->orderBy);
@@ -1366,6 +1372,7 @@ class block extends control
{
$uri = $this->app->tab == 'my' ? $this->createLink('my', 'index') : $this->server->http_referer;
$this->session->set('riskList', $uri, 'project');
session_write_close();
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->risks = $this->loadModel('risk')->getBlockRisks($this->session->project, $this->params->type, $this->viewType == 'json' ? 0 : (int)$this->params->count, $this->params->orderBy);
}
@@ -1503,6 +1510,7 @@ class block extends control
{
$uri = $this->app->tab == 'my' ? $this->createLink('my', 'index') : $this->server->http_referer;
$this->session->set('issueList', $uri, 'project');
session_write_close();
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->issues = $this->loadModel('issue')->getBlockIssues($this->session->project, $this->params->type, $this->viewType == 'json' ? 0 : (int)$this->params->count, $this->params->orderBy);
@@ -1518,6 +1526,7 @@ class block extends control
{
$uri = $this->app->tab == 'my' ? $this->createLink('my', 'index') : $this->server->http_referer;
$this->session->set('riskList', $uri, 'project');
session_write_close();
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->risks = $this->loadModel('risk')->getBlockRisks($this->session->project, $this->params->type, $this->viewType == 'json' ? 0 : (int)$this->params->count, $this->params->orderBy);
}
@@ -1562,11 +1571,7 @@ class block extends control
{
$projectID = $this->session->project;
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$pager = new pager(0, 30, 1);
$this->view->actions = $this->loadModel('action')->getDynamic('all', 'all', 'id_desc', $pager, 'all', $projectID);
$this->view->actions = $this->loadModel('action')->getDynamic('all', 'all', 'id_desc', 30, 'all', $projectID);
$this->view->users = $this->loadModel('user')->getPairs('noletter', '', 0, array_unique(array_column($this->view->actions, 'actor')));
}
@@ -1583,6 +1588,7 @@ class block extends control
$uri = $this->app->tab == 'my' ? $this->createLink('my', 'index') : $this->server->http_referer;
$this->session->set('releaseList', $uri, 'product');
$this->session->set('productPlanList', $uri, 'product');
session_write_close();
$products = $this->loadModel('product')->getPairs('', $this->session->project);
if(!is_numeric($productID)) $productID = key($products);
@@ -1613,6 +1619,7 @@ class block extends control
$this->session->set('productList', $uri, 'product');
$this->session->set('projectList', $uri, 'project');
$this->session->set('buildList', $uri, 'execution');
session_write_close();
$this->app->loadLang('testtask');
$count = zget($this->params, 'count', 10);
@@ -1998,6 +2005,7 @@ class block extends control
->fetchAll();
$count['meeting'] = count($meetings);
$objectList += array('meeting' => 'meetings');
$this->view->meetings = $meetings;
$this->view->depts = $this->loadModel('dept')->getOptionMenu();
$this->view->users = $this->loadModel('user')->getPairs('all,noletter');
@@ -2009,7 +2017,12 @@ class block extends control
$reviews = $this->loadModel('my')->getReviewingList('all', 'time_desc', $pager);
if($reviews)
{
$hasViewPriv['review'] = true;
$todoPriv = $hasViewPriv['todo'];
unset($hasViewPriv['todo']);
$hasViewPriv = array_merge(array('todo' => $todoPriv, 'review' => true), $hasViewPriv);
$objectList += array('review' => 'reviews');
$count['review'] = count($reviews);
$this->view->reviews = $reviews;
if($this->config->edition == 'max' or $this->config->edition == 'ipd')
@@ -2019,6 +2032,12 @@ class block extends control
}
}
foreach($objectList as $objectType => $object)
{
if($objectType == 'todo') continue;
if(empty($this->view->$object)) $hasViewPriv[$objectType] = false;
}
$this->view->selfCall = $this->selfCall;
$this->view->hasViewPriv = $hasViewPriv;
$this->view->count = $count;
@@ -2089,11 +2108,7 @@ class block extends control
*/
public function printDocDynamicBlock()
{
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$pager = new pager(0, 30, 1);
$this->view->actions = $this->loadModel('doc')->getDynamic($pager);
$this->view->actions = $this->loadModel('doc')->getDynamic(30);
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter|all', '', 0, array_unique(array_column($this->view->actions, 'actor')));
}
@@ -2187,6 +2202,7 @@ class block extends control
{
$this->loadModel('doc');
$this->session->set('docList', $this->createLink('doc', 'index'), 'doc');
session_write_close();
/* Set project status and count. */
$count = isset($this->params->count) ? (int)$this->params->count : 15;
@@ -2194,7 +2210,7 @@ class block extends control
$involveds = $this->product->getOrderedProducts('involved');
$productIdList = array_merge(array_keys($products), array_keys($involveds));
$stmt = $this->dao->select('id,product,lib,title,type,addedBy,addedDate,editedDate,status,acl,groups,users,deleted')->from(TABLE_DOC)->alias('t1')
$stmt = $this->dao->select('id,product,lib,title,type,addedBy,addedDate,editedDate,`status`,acl,`groups`,`users`,deleted')->from(TABLE_DOC)->alias('t1')
->where('deleted')->eq(0)
->andWhere('product')->in($productIdList)
->orderBy('product,status,editedDate_desc')
@@ -2234,6 +2250,7 @@ class block extends control
$this->loadModel('doc');
$this->app->loadLang('project');
$this->session->set('docList', $this->createLink('doc', 'index'), 'doc');
session_write_close();
/* Set project status and count. */
$count = isset($this->params->count) ? (int)$this->params->count : 15;
+5 -5
View File
@@ -220,7 +220,7 @@ class blockModel extends model
$delayBugs = array();
foreach($bugs as $bug)
{
if($bug->status == 'active' && $bug->deadline && $bug->deadline < $today) $delayBugs[$bug->id] = true;
if($bug->status == 'active' && !helper::isZeroDate($bug->deadline) && $bug->deadline < $today) $delayBugs[$bug->id] = true;
$totalBugs[$bug->id] = true;
}
$data['bugs'] = count($totalBugs);
@@ -822,6 +822,10 @@ class blockModel extends model
$params->todoCount['default'] = 20;
$params->todoCount['control'] = 'input';
$params->reviewCount['name'] = $this->lang->block->reviewCount;
$params->reviewCount['default'] = 20;
$params->reviewCount['control'] = 'input';
$params->taskCount['name'] = $this->lang->block->taskCount;
$params->taskCount['default'] = 20;
$params->taskCount['control'] = 'input';
@@ -862,10 +866,6 @@ class blockModel extends model
$params->storyCount['default'] = 20;
$params->storyCount['control'] = 'input';
$params->reviewCount['name'] = $this->lang->block->reviewCount;
$params->reviewCount['default'] = 20;
$params->reviewCount['control'] = 'input';
return json_encode($params);
}
@@ -21,6 +21,7 @@
<?php $i = 0;?>
<?php $maxItem = common::checkNotCN() ? 6 : 8;?>
<?php foreach($hasViewPriv as $type => $bool):?>
<?php if(!$bool) continue;?>
<?php if($i <= $maxItem):?>
<li<?php if($isFirstTab) {echo ' class="active"';}?>>
<a data-tab href='#assigntomeTab-<?php echo $type;?>' onClick="changeLabel('<?php echo $type;?>')">
@@ -49,6 +50,7 @@
<div class="tab-content">
<?php $isFirstTab = true; ?>
<?php foreach($hasViewPriv as $type => $bool):?>
<?php if(!$bool) continue;?>
<div class="tab-pane<?php if($isFirstTab) {echo ' active'; $isFirstTab = false;}?>" id="assigntomeTab-<?php echo $type?>">
<?php include "{$type}block.html.php";?>
</div>
@@ -197,15 +197,15 @@ $(function()
</div>
</div>
</div>
<?php if(!empty($project->executions) and $project->multiple):?>
<?php if(!empty($project->execution) and $project->multiple):?>
<div class="table-row project-info">
<div class="col-2 text-right"><h4><?php echo $lang->block->last;?></h4></div>
<div class="table-row lastIteration">
<div class='col-5 text-center executionName'><?php echo html::a($this->createLink('execution', 'task', "executionID={$project->executions[0]->id}"), $project->executions[0]->name, '', "title='{$project->executions[0]->name}'");?></div>
<div class='col-5 text-center executionName'><?php echo html::a($this->createLink('execution', 'task', "executionID={$project->execution->id}"), $project->execution->name, '', "title='{$project->name}'");?></div>
<div class='col-7'>
<div class='progress progress-text-left'>
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="<?php echo $project->executions[0]->hours->progress;?>" aria-valuemin="0" aria-valuemax="100" style="width: <?php echo $project->executions[0]->hours->progress;?>%">
<span class='progress-text'><?php echo !empty($project->executions[0]->hours->progress) ? $project->executions[0]->hours->progress . '%' : '0%';?></span>
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="<?php echo $project->execution->progress;?>" aria-valuemin="0" aria-valuemax="100" style="width: <?php echo $project->execution->progress;?>%">
<span class='progress-text'><?php echo !empty($project->execution->progress) ? $project->execution->progress . '%' : '0%';?></span>
</div>
</div>
</div>
+1 -2
View File
@@ -56,8 +56,7 @@
}
else
{
$class = "class='iframe' data-width='90%'";
if(strpos(",{$config->my->oaObjectType},", ",{$type},") !== false) $class = "data-toggle='modal'";
$class = "class='iframe' data-width='90%' data-toggle='modal'";
$titleHtml = html::a($this->createLink($type, 'view', "objectID=$review->id", 'html', true), $review->title, '', $class);
}
echo $titleHtml;
+42 -7
View File
@@ -172,7 +172,7 @@ class bug extends control
}
else
{
$executions = $this->loadModel('execution')->getPairs($this->projectID, 'all', 'empty|withdelete|hideMultiple');
$executions = $this->loadModel('execution')->fetchPairs($this->projectID, 'all', 'empty|withdelete|hideMultiple');
if($this->config->cache->enable) $this->cache->set($cacheKey, $executions);
}
@@ -234,7 +234,6 @@ class bug extends control
$this->view->position[] = $this->lang->bug->common;
$this->view->productID = $productID;
$this->view->product = $product;
$this->view->projectProducts = $this->product->getProducts($this->projectID);
$this->view->productName = $productName;
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch);
$this->view->releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch);
@@ -1417,6 +1416,11 @@ class bug extends control
$this->view->customFields = $customFields;
$this->view->showFields = $this->config->bug->custom->batchEditFields;
/* Set users. */
$users = $this->loadModel('user')->getPairs();
$limitUsers = $users;
if(count($users) > $this->config->batchMaxCount) $limitUsers = array_slice($users, 0 , $this->config->batchMaxCount);
$branchIdList = array();
$projectIdList = array();
$executionIdList = array();
@@ -1441,7 +1445,38 @@ class bug extends control
}
}
$bug->assignedToList = array();
if($this->app->tab == 'project' or $this->app->tab == 'execution')
{
if($bug->execution)
{
$bug->assignedToList = $executionMembers[$bug->execution];
}
elseif($bug->project)
{
$bug->assignedToList = $projectMembers[$bug->project];
}
else
{
$bug->assignedToList = $productMembers[$bug->product][$bug->branch];
if(empty($bug->assignedToList))
{
$bug->assignedToList = $limitUsers;
if(count($users) > $this->config->batchMaxCount) $this->config->moreLinks["assignedTos[$bug->id]"] = helper::createLink('user', 'ajaxGetMore');
unset($bug->assignedToList['closed']);
}
}
}
else
{
$bug->assignedToList = $limitUsers;
if(count($users) > $this->config->batchMaxCount) $this->config->moreLinks["assignedTos[$bug->id]"] = helper::createLink('user', 'ajaxGetMore');
unset($bug->assignedToList['closed']);
}
$bug->assignedToList = array('' => '', 'ditto' => $this->lang->bug->ditto) + array($bug->assignedTo => zget($users, $bug->assignedTo)) + $bug->assignedToList;
$this->config->moreLinks["duplicateBugs[{$bug->id}]"] = inlink('ajaxGetProductBugs', "productID={$bug->product}&bugID={$bug->id}&type=json");
if(count($users) > $this->config->batchMaxCount) $this->config->moreLinks["resolvedBys[$bug->id]"] = helper::createLink('user', 'ajaxGetMore');
}
/* Get assigned to member. */
@@ -1504,10 +1539,6 @@ class bug extends control
$this->view->executionMembers = $executionMembers;
}
/* Set users. */
$users = $this->user->getPairs('devfirst');
$users = array('' => '', 'ditto' => $this->lang->bug->ditto) + $users;
/* Assign. */
$this->view->productID = $productID;
$this->view->branchProduct = $branchProduct;
@@ -1519,6 +1550,7 @@ class bug extends control
$this->view->bugs = $bugs;
$this->view->branch = $branch;
$this->view->users = $users;
$this->view->limitUsers = $limitUsers;
$this->view->modules = $modules;
$this->view->branchTagOption = $branchTagOption;
$this->view->productBugList = $productBugList;
@@ -1934,6 +1966,8 @@ class bug extends control
$this->bug->checkBugExecutionPriv($bug);
$this->qa->setMenu($this->products, $productID, $bug->branch);
$this->config->moreLinks['duplicateBug'] = inlink('ajaxGetProductBugs', "productID={$productID}&bugID={$bugID}&type=json");
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
$this->view->bug = $bug;
$this->view->users = $users;
@@ -2591,13 +2625,14 @@ class bug extends control
*
* @param int $productID
* @param int $bugID
* @param string $type
* @access public
* @return string
*/
public function ajaxGetProductBugs($productID, $bugID, $type = 'html')
{
$search = $this->get->search;
$limit = $this->get->limit;
$limit = $this->get->limit ? $this->get->limit : $this->config->maxCount;
$product = $this->loadModel('product')->getById($productID);
$bug = $this->bug->getById($bugID);
$branch = $product->type == 'branch' ? ($bug->branch > 0 ? $bug->branch . ',0' : '0') : '';
+8 -8
View File
@@ -24,7 +24,7 @@ $(document).on('click', '.chosen-with-drop', function(){oldValue = $(this).prev(
/* Set ditto value. */
$(document).on('change', 'select', function()
{
if($(this).val() == 'ditto')
if($(this).data('zui.picker').getValue() == 'ditto')
{
var index = $(this).closest('td').index();
var row = $(this).closest('tr').index();
@@ -38,34 +38,34 @@ $(document).on('change', 'select', function()
}
var value = '';
var label = '';
for(i = row - 1; i >= 0; i--)
{
value = tbody.children('tr').eq(i).find('td').eq(index).find('select').val();
value = tbody.children('tr').eq(i).find('td').eq(index).find('select').data('zui.picker').getValue();
label = tbody.children('tr').eq(i).find('td').eq(index).find('select').data('zui.picker').getListItem(value).text;
if(value != 'ditto') break;
}
isPlans = $(this).attr('name').indexOf('plans') != -1;
$(this).data('zui.picker').updateOptionList([{text: label, value}]);
if(isPlans)
{
var valueStr = ',' + $(this).find('option').map(function(){return $(this).val();}).get().join(',') + ',';
if(valueStr.indexOf(',' + value + ',') != -1)
{
$(this).val(value);
$(this).data('zui.picker').setValue(value);
}
else
{
alert(dittoNotice);
$(this).val(oldValue);
$(this).data('zui.picker').setValue(oldValue);
}
}
else
{
$(this).val(value);
$(this).data('zui.picker').setValue(value);
}
$(this).trigger("chosen:updated");
$(this).trigger("change");
}
})
-12
View File
@@ -2,18 +2,6 @@ function setDuplicate(resolution)
{
if(resolution == 'duplicate')
{
$.ajaxSettings.async = false;
$.get(createLink('bug', 'ajaxGetProductBugs', 'projectID=' + productID + '&bugID=' + bugID),function(data)
{
$('#duplicateBug').replaceWith(data);
$('#pk_duplicateBug-search').parent().parent().remove();
$('#duplicateBug').picker(
{
disableEmptySearch : true,
dropWidth : 'auto'
});
});
$.ajaxSettings.async = true;
$('#duplicateBugBox').show();
}
else
+12 -11
View File
@@ -561,7 +561,7 @@ class bugModel extends model
$bug = $this->loadModel('file')->replaceImgURL($bug, 'steps');
if($setImgSize) $bug->steps = $this->file->setImgSize($bug->steps);
foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr(is_null($value) ? '' : $value, 0, 4)) $bug->$key = '';
foreach($bug as $key => $value) if(strpos($key, 'Date') !== false && $value && !(int)substr(is_null($value) ? '' : $value, 0, 4)) $bug->$key = '';
if($bug->duplicateBug) $bug->duplicateBugTitle = $this->dao->findById($bug->duplicateBug)->from(TABLE_BUG)->fields('title')->fetch('title');
if($bug->case) $bug->caseTitle = $this->dao->findById($bug->case)->from(TABLE_CASE)->fields('title')->fetch('title');
@@ -2052,21 +2052,21 @@ class bugModel extends model
*/
public function getProductBugPairs($productID, $branch = '', $search = '', $limit = 0)
{
$bugs = array('' => '');
$data = $this->dao->select('id, title')->from(TABLE_BUG)
$bugs = $this->dao->select("id, CONCAT(id, ':', title) AS title")->from(TABLE_BUG)
->where('product')->eq((int)$productID)
->beginIF(!$this->app->user->admin)->andWhere('execution')->in('0,' . $this->app->user->view->sprints)->fi()
->beginIF($branch !== '')->andWhere('branch')->in($branch)->fi()
->beginIF(strlen(trim($search)))->andWhere('title')->like('%' . $search . '%')->fi()
->beginIF(strlen(trim($search)))
->andWhere('id', true)->like('%' . $search . '%')
->orWhere('title')->like('%' . $search . '%')
->markRight(1)
->fi()
->andWhere('deleted')->eq(0)
->orderBy('id desc')
->beginIF($limit)->limit($limit)->fi()
->fetchAll();
foreach($data as $bug)
{
$bugs[$bug->id] = $bug->id . ':' . $bug->title;
}
return $bugs;
->fetchPairs();
return array('' => '') + $bugs;
}
/**
@@ -2861,7 +2861,8 @@ class bugModel extends model
->beginIF($projectID)->andWhere('project')->eq($projectID)->fi()
->andWhere('deleted')->eq(0)
->beginIF(!$this->app->user->admin)->andWhere('project')->in('0,' . $this->app->user->view->projects)->fi()
->orderBy($orderBy)->page($pager)
->orderBy($orderBy)
->page($pager)
->fetchAll();
}
+2 -30
View File
@@ -101,40 +101,12 @@
<?php endif;?>
<td><?php echo html::select("modules[$bugID]", isset($modules[$bug->product][$bug->branch]) ? $modules[$bug->product][$bug->branch] : array(0 => '/'), $bug->module, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td class='<?php echo zget($visibleFields, 'productplan', ' hidden')?>' style='overflow:visible'><?php echo html::select("plans[$bugID]", $plans, $bug->plan, "class='form-control picker-select' data-drop-width='auto'");?></td>
<?php
$assignedToList = array();
if($app->tab == 'project' or $app->tab == 'execution')
{
if($bug->execution)
{
$assignedToList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $executionMembers[$bug->execution];
}
elseif($bug->project)
{
$assignedToList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $projectMembers[$bug->project];
}
else
{
$assignedToList = $productMembers[$bug->product][$bug->branch];
if(empty($assignedToList))
{
$assignedToList = $users;
unset($assignedToList['closed']);
}
}
}
else
{
$assignedToList = $users;
unset($assignedToList['closed']);
}
?>
<td class='<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>' style='overflow:visible'><?php echo $bug->status == 'closed' ? html::input("assignedTos[$bugID]", ucfirst($bug->assignedTo), 'class=form-control disabled') : html::select("assignedTos[$bugID]", $assignedToList, $bug->assignedTo, "class='form-control picker-select' data-drop-width='135px'");?></td>
<td class='<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>' style='overflow:visible'><?php echo $bug->status == 'closed' ? html::input("assignedTos[$bugID]", ucfirst($bug->assignedTo), 'class=form-control disabled') : html::select("assignedTos[$bugID]", $bug->assignedToList, $bug->assignedTo, "class='form-control picker-select' data-drop-width='135px'");?></td>
<td class='<?php echo zget($visibleFields, 'deadline', ' hidden')?>' style='overflow:visible'><?php echo html::input("deadlines[$bugID]", helper::isZeroDate($bug->deadline) ? '' : $bug->deadline, "class='form-control form-date'");?></td>
<td <?php echo zget($visibleFields, 'os', "class='hidden'")?>><?php echo html::select("os[$bugID][]", $lang->bug->osList, $bug->os, 'class="form-control chosen" multiple');?></td>
<td <?php echo zget($visibleFields, 'browser', "class='hidden'")?>><?php echo html::select("browsers[$bugID][]", $lang->bug->browserList, $bug->browser, 'class="form-control chosen" multiple');?></td>
<td <?php echo zget($visibleFields, 'keywords', "class='hidden'")?>><?php echo html::input("keywords[$bugID]", $bug->keywords, 'class=form-control');?></td>
<td class='<?php echo zget($visibleFields, 'resolvedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("resolvedBys[$bugID]", $users, $bug->resolvedBy, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td class='<?php echo zget($visibleFields, 'resolvedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("resolvedBys[$bugID]", array('' => '', 'ditto' => $this->lang->bug->ditto) + array($bug->resolvedBy => zget($users, $bug->resolvedBy)) + $limitUsers, $bug->resolvedBy, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td <?php echo zget($visibleFields, 'resolution', "class='hidden'")?>>
<table class='table-borderless table no-margin table-form'>
<tr>
+1
View File
@@ -378,4 +378,5 @@ $('#osBox').next('.table-col').remove();
$('#typeBox').closest('tr').append('<td>' + browser + '</td>');
</script>
<?php endif;?>
<?php include '../../ai/view/inputinject.html.php';?>
<?php include '../../common/view/footer.html.php';?>
+1
View File
@@ -329,4 +329,5 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
</div>
</form>
</div>
<?php include '../../ai/view/inputinject.html.php';?>
<?php include '../../common/view/footer.html.php';?>
+1
View File
@@ -12,6 +12,7 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php include '../../ai/view/promptmenu.html.php';?>
<?php js::set('sysurl', common::getSysUrl());?>
<?php js::set('confrimToStory', $lang->bug->confirmToStory);?>
<?php js::set('tab', $app->tab);?>
+2 -2
View File
@@ -677,11 +677,11 @@ class build extends control
$executionID = $build->execution ? $build->execution : $build->project;
if($browseType == 'bySearch')
{
$allStories = $this->story->getBySearch($build->product, $build->branch, $queryID, 'id', $executionID, 'story', $build->allStories, $pager);
$allStories = $this->story->getBySearch($build->product, $build->branch, $queryID, 'id', $executionID, 'story', $build->allStories, 'draft,reviewing,changing', $pager);
}
else
{
$allStories = $this->story->getExecutionStories($executionID, $build->product, 0, 't1.`order`_desc', 'byBranch', $build->branch, 'story', $build->allStories, $pager);
$allStories = $this->story->getExecutionStories($executionID, $build->product, 0, 't1.`order`_desc', 'byBranch', $build->branch, 'story', $build->allStories, 'draft,reviewing,changing', $pager);
}
$this->view->allStories = $allStories;
+1 -1
View File
@@ -270,7 +270,7 @@ class buildModel extends model
->leftJoin(TABLE_RELEASE)->alias('t3')->on("FIND_IN_SET(t1.id,t3.build)")
->leftJoin(TABLE_PRODUCT)->alias('t4')->on('t1.product = t4.id')
->where('1=1')
->beginIf(!empty($shaows))->andWhere('t1.id')->notIN($shadows)->fi()
->beginIf(!empty($shadows))->andWhere('t1.id')->notIN($shadows)->fi()
->beginIF(strpos($params, 'hasdeleted') === false)->andWhere('t1.deleted')->eq(0)->fi()
->beginIF(strpos($params, 'hasproject') !== false)->andWhere('t1.project')->ne(0)->fi()
->beginIF(strpos($params, 'singled') !== false)->andWhere('t1.execution')->ne(0)->fi()
+7 -2
View File
@@ -433,10 +433,15 @@ $lang->exportTypeList['all'] = 'Alle';
$lang->exportTypeList['selected'] = 'Ausgewählte';
$lang->visionList = array();
$lang->visionList['or'] = 'OR & MM Interface';
$lang->visionList['rnd'] = 'IPD Interface';
$lang->visionList['rnd'] = 'Full Feature Interface';
$lang->visionList['lite'] = 'Operation Management Interface';
if($config->edition == 'ipd')
{
$lang->visionList['or'] = 'OR & MM Interface';
$lang->visionList['rnd'] = 'IPD Interface';
}
$lang->createObjects['todo'] = 'Todo';
$lang->createObjects['effort'] = 'Effort';
$lang->createObjects['bug'] = 'Bug';
+8 -2
View File
@@ -25,6 +25,7 @@ $lang->ellipsis = '…';
$lang->percent = '%';
$lang->dash = '-';
$lang->and = 'and';
$lang->separater = ',';
$lang->zentaoPMS = 'ZenTao';
$lang->pmsName = 'ALM';
@@ -435,10 +436,15 @@ $lang->exportTypeList['all'] = 'All Data';
$lang->exportTypeList['selected'] = 'Selected Data';
$lang->visionList = array();
$lang->visionList['or'] = 'OR & MM Interface';
$lang->visionList['rnd'] = 'IPD Interface';
$lang->visionList['rnd'] = 'Full Feature Interface';
$lang->visionList['lite'] = 'Operation Management Interface';
if($config->edition == 'ipd')
{
$lang->visionList['or'] = 'OR & MM Interface';
$lang->visionList['rnd'] = 'IPD Interface';
}
$lang->createObjects['todo'] = 'Todo';
$lang->createObjects['effort'] = 'Effort';
$lang->createObjects['bug'] = 'Bug';
+7 -2
View File
@@ -433,10 +433,15 @@ $lang->exportTypeList['all'] = 'Toutes les Données';
$lang->exportTypeList['selected'] = 'Données sélectionnées';
$lang->visionList = array();
$lang->visionList['or'] = 'OR & MM Interface';
$lang->visionList['rnd'] = 'IPD Interface';
$lang->visionList['rnd'] = 'Full Feature Interface';
$lang->visionList['lite'] = 'Operation Management Interface';
if($config->edition == 'ipd')
{
$lang->visionList['or'] = 'OR & MM Interface';
$lang->visionList['rnd'] = 'IPD Interface';
}
$lang->createObjects['todo'] = 'Todo';
$lang->createObjects['effort'] = 'Effort';
$lang->createObjects['bug'] = 'Bug';
+8 -2
View File
@@ -25,6 +25,7 @@ $lang->ellipsis = '…';
$lang->percent = '%';
$lang->dash = '-';
$lang->and = '和';
$lang->separater = '、';
$lang->zentaoPMS = '禅道';
$lang->pmsName = '开源版';
@@ -433,10 +434,15 @@ $lang->exportTypeList['all'] = '全部记录';
$lang->exportTypeList['selected'] = '选中记录';
$lang->visionList = array();
$lang->visionList['or'] = '需求与市场管理界面';
$lang->visionList['rnd'] = 'IPD研发管理界面';
$lang->visionList['rnd'] = '综合研发界面';
$lang->visionList['lite'] = '运营管理界面';
if($config->edition == 'ipd')
{
$lang->visionList['or'] = '需求与市场管理界面';
$lang->visionList['rnd'] = 'IPD研发管理界面';
}
$lang->createObjects['todo'] = '待办';
$lang->createObjects['effort'] = '日志';
$lang->createObjects['bug'] = 'Bug';
+6 -1
View File
@@ -996,6 +996,9 @@ class commonModel extends model
$app->loadLang('my');
/* Ensure user has latest rights set. */
$app->user->rights = $app->control->loadModel('user')->authorize($app->user->account);
$menuOrder = $lang->mainNav->menuOrder;
ksort($menuOrder);
@@ -1719,6 +1722,7 @@ EOF;
/* Add data-app attribute. */
if(strpos($misc, 'data-app') === false) $misc .= ' data-app="' . $app->tab . '"';
if($onlyBody && strpos($misc, 'data-toggle') === false) $misc .= ' data-toggle="modal"';
/* Judge the $method of $module clickable or not, default is clickable. */
$clickable = true;
@@ -2570,7 +2574,8 @@ EOF;
* The following pages can be allowed to open in non-iframe, so ignore these pages.
*/
$module = $this->app->getModuleName();
$whitelist = '|index|tutorial|install|upgrade|sso|cron|misc|user-login|user-deny|user-logout|user-reset|user-forgetpassword|user-resetpassword|my-changepassword|my-preference|file-read|file-download|file-uploadimages|report-annualdata|misc-captcha|execution-printkanban||traincourse-playvideo|';
$method = $this->app->getMethodName();
$whitelist = '|index|tutorial|install|upgrade|sso|cron|misc|user-login|user-deny|user-logout|user-reset|user-forgetpassword|user-resetpassword|my-changepassword|my-preference|file-read|file-download|file-preview|file-uploadimages|file-ajaxwopifiles|report-annualdata|misc-captcha|execution-printkanban|traincourse-ajaxuploadlargefile|traincourse-playvideo|screen-view|zanode-create|screen-ajaxgetchart|';
if(strpos($whitelist, "|{$module}|") !== false || strpos($whitelist, "|{$module}-{$method}|") !== false) return true;
/**
+2 -2
View File
@@ -36,7 +36,7 @@ $(function()
{
$dropmenu.append("<li><a href='<?php echo $this->createLink('datatable', 'ajaxCustom', 'id=' . $this->moduleName . '&method=' . $this->methodName)?>' data-toggle='modal' data-type='ajax'><?php echo $lang->datatable->custom?></a></li>");
}
if(!(currentModule == 'execution' && currentMethod == 'all')) $dropmenu.append("<li><a href='javascript:saveDatatableConfig(\"mode\", \"<?php echo $mode == 'table' ? 'datatable' : 'table';?>\", true);' id='switchToDatatable'><?php echo $mode == 'table' ? $lang->datatable->switchToDatatable : $lang->datatable->switchToTable;?></a></li>");
if(!(currentModule == 'execution' && (currentMethod == 'all' || currentMethod == 'task'))) $dropmenu.append("<li><a href='javascript:saveDatatableConfig(\"mode\", \"<?php echo $mode == 'table' ? 'datatable' : 'table';?>\", true);' id='switchToDatatable'><?php echo $mode == 'table' ? $lang->datatable->switchToDatatable : $lang->datatable->switchToTable;?></a></li>");
$dropdown.append($dropmenu)
.appendTo($btnToolbar)
.on('shown.zui.dropdown', function(){$btnToolbar.closest('.table-header').css('z-index', 11);})
@@ -112,7 +112,7 @@ $(function()
<td><?php echo html::radio('showAllModule', $lang->datatable->showAllModuleList, isset($config->execution->task->allModule) ? $config->execution->task->allModule : 0);?></td>
</tr>
<?php endif;?>
<?php if($showBranch):?>
<?php if(isset($showBranch) and $showBranch):?>
<tr>
<td><?php echo $lang->datatable->showBranch;?></td>
<td><?php echo html::radio('showBranch', $lang->datatable->showBranchList, isset($config->$currentModule->$currentMethod->showBranch) ? $config->$currentModule->$currentMethod->showBranch : 1);?></td>
+21
View File
@@ -0,0 +1,21 @@
<?php
js::import($jsRoot . 'dtable/min.js');
css::import($jsRoot . 'dtable/min.css');
?>
<style>
.dtable {box-shadow: 0 1px 1px rgba(0,0,0,.05), 0 2px 6px 0 rgba(0,0,0,.045)}
.dtable-header {border-bottom: 1px solid #f4f5f7;}
.dtable-header .dtable-cell {font-weight: bold;}
</style>
<script>
function convertCols(cols)
{
cols.forEach(function(col)
{
if(col.fixed == 'no') col.fixed = false;
});
return cols;
}
zui.DTable.defineFn();
</script>
+7 -8
View File
@@ -201,10 +201,6 @@ class company extends control
$this->session->set('meetingList', $uri, 'project');
$this->session->set('meetingroomList', $uri, 'admin');
/* Set the pager. */
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage = 50, $pageID = 1);
/* Append id for secend sort. */
if($direction == 'next') $orderBy = 'date_desc';
if($direction == 'pre') $orderBy = 'date_asc';
@@ -253,11 +249,11 @@ class company extends control
if(!$productID) $productID = 'all';
if(!$projectID) $projectID = 'all';
if(!$executionID) $executionID = 'all';
$actions = $this->action->getDynamic($account, $browseType, $orderBy, $pager, $productID, $projectID, $executionID, $date, $direction);
$actions = $this->action->getDynamic($account, $browseType, $orderBy, 50, $productID, $projectID, $executionID, $date, $direction);
}
else
{
$actions = $this->action->getDynamicBySearch($products, $projects, $executions, $queryID, $orderBy, $pager, $date, $direction);
$actions = $this->action->getDynamicBySearch($products, $projects, $executions, $queryID, $orderBy, 50, $date, $direction);
}
/* Build search form. */
@@ -285,6 +281,10 @@ class company extends control
$this->config->company->dynamic->search['params']['actor']['values'] = $accountPairs;
$this->loadModel('search')->setSearchParams($this->config->company->dynamic->search);
$dateGroups = $this->action->buildDateGroup($actions, $direction, $browseType, $orderBy);
if(empty($recTotal)) $recTotal = count($dateGroups) < 2 ? count($actions) : $this->action->getDynamicCount();
/* Assign. */
$this->view->recTotal = $recTotal;
$this->view->browseType = $browseType;
@@ -295,10 +295,9 @@ class company extends control
$this->view->executionID = $executionID;
$this->view->queryID = $queryID;
$this->view->orderBy = $orderBy;
$this->view->pager = $pager;
$this->view->userID = $userID;
$this->view->param = $param;
$this->view->dateGroups = $this->action->buildDateGroup($actions, $direction, $browseType, $orderBy);
$this->view->dateGroups = $dateGroups;
$this->view->direction = $direction;
$this->display();
}
+3 -4
View File
@@ -21,8 +21,7 @@
if($period == $browseType)
{
$active = 'btn-active-text';
$pager->recTotal = $recTotal ? $recTotal : $pager->recTotal;
$label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";
$label .= " <span class='label label-light label-badge'>{$recTotal}</span>";
}
echo html::a(inlink('dynamic', "browseType=$period&param=&recTotal=0&date=&direction=next&userID=$userID&productID=$productID&projectID=$projectID&executionID=$executionID&orderBy=$orderBy"), $label, '', "class='btn btn-link $active' id='{$period}'")
?>
@@ -116,8 +115,8 @@ $firstDate = date('Y-m-d', strtotime($firstAction->originalDate) + 24 * 3600);
$lastDate = substr($action->originalDate, 0, 10);
$hasPre = $this->action->hasPreOrNext($firstDate, 'pre');
$hasNext = $this->action->hasPreOrNext($lastDate, 'next');
$preLink = $hasPre ? inlink('dynamic', "browseType=$browseType&param=$param&recTotal={$pager->recTotal}&date=" . strtotime($firstDate) . "&direction=pre&userID=$userID&productID=$productID&projectID=$projectID&executionID=$executionID&orderBy=$orderBy") : 'javascript:;';
$nextLink = $hasNext ? inlink('dynamic', "browseType=$browseType&param=$param&recTotal={$pager->recTotal}&date=" . strtotime($lastDate) . "&direction=next&userID=$userID&productID=$productID&projectID=$projectID&executionID=$executionID&orderBy=$orderBy") : 'javascript:;';
$preLink = $hasPre ? inlink('dynamic', "browseType=$browseType&param=$param&recTotal={$recTotal}&date=" . strtotime($firstDate) . "&direction=pre&userID=$userID&productID=$productID&projectID=$projectID&executionID=$executionID&orderBy=$orderBy") : 'javascript:;';
$nextLink = $hasNext ? inlink('dynamic', "browseType=$browseType&param=$param&recTotal={$recTotal}&date=" . strtotime($lastDate) . "&direction=next&userID=$userID&productID=$productID&projectID=$projectID&executionID=$executionID&orderBy=$orderBy") : 'javascript:;';
?>
<?php if($hasPre or $hasNext):?>
<div id="mainActions" class='main-actions'>
+21 -11
View File
@@ -150,13 +150,13 @@ class cron extends control
/* make cron status to running. */
$configID = $this->cron->getConfigID();
$configID = $this->cron->markCronStatus('running', $configID);
$this->dao->update(TABLE_CRON)->set('lastTime')->eq(date(DT_DATETIME1))->where('id')->eq(1)->exec();
/* Get and parse crons. */
$crons = $this->cron->getCrons('nostop');
$parsedCrons = $this->cron->parseCron($crons);
/* Update last time. */
$this->cron->changeStatus(key($parsedCrons), 'normal', true);
$this->cron->logCron("The cron process created.\n");
$this->loadModel('common');
$startedTime = time();
while(true)
@@ -166,10 +166,18 @@ class cron extends control
/* When cron is null then die. */
if(empty($crons)) break;
if(empty($parsedCrons)) break;
if(!$this->cron->getTurnon()) break;
if(!$this->cron->getTurnon())
{
$this->cron->logCron("The cron process turned off.\n");
break;
}
/* Die old process when restart. */
if(file_exists($restartTag) and !$restart) return unlink($restartTag);
if(file_exists($restartTag) and !$restart)
{
$this->cron->logCron("The cron process restarted.\n");
return unlink($restartTag);
}
$restart = false;
/* Run crons. */
@@ -205,6 +213,11 @@ class cron extends control
$return = '';
if($cron['command'])
{
/* Save log of executing cron. */
$time = $now->format('Y-m-d H:i:s');
$log = "\n$time task " . $id . " executing,\ncommand: $cron[command]\n";
$this->cron->logCron($log);
if(isset($crons[$id]) and $crons[$id]->type == 'zentao')
{
parse_str($cron['command'], $params);
@@ -220,12 +233,11 @@ class cron extends control
if($output) $output = join("\n", $output);
}
/* Save log. */
$log = '';
$time = $now->format('G:i:s');
$output = "\n" . $output;
/* Save log of executed cron. */
$time = $now->format('Y-m-d H:i:s');
$output = $output;
$log = "$time task " . $id . " executed,\ncommand: $cron[command].\nreturn : $return.\noutput : $output\n";
$log = "\n$time task " . $id . " executed,\ncommand: $cron[command]\nreturn : $return\noutput : $output\n";
$this->cron->logCron($log);
unset($log);
}
@@ -248,8 +260,6 @@ class cron extends control
$sleepTime = 60 - ((time() - strtotime($now->format('Y-m-d H:i:s'))) % 60);
sleep($sleepTime);
/* Break while. */
if('cli' !== PHP_SAPI && connection_status() != CONNECTION_NORMAL) break;
if(((time() - $startedTime) / 3600 / 24) >= $this->config->cron->maxRunDays) break;
}

Some files were not shown because too many files have changed in this diff Show More