export.html.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <?php
  2. /**
  3. * The UI file of file module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  6. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author chen.tao <chentao@easycorp.ltd>
  8. * @package file
  9. * @link https://www.zentao.net
  10. */
  11. namespace zin;
  12. $this->loadModel('file');
  13. /* Unset useless export type. */
  14. if(isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], 'calendar') !== false) unset($lang->exportTypeList['selected']);
  15. /* Generate custom export fields. */
  16. if(!isset($hideExportRange)) $hideExportRange = isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], 'kanban') !== false;
  17. $customExportRowList = array();
  18. $isCustomExport = (!empty($customExport) and !empty($allExportFields));
  19. $showBizGuide = $config->edition == 'open' && empty($config->{$this->moduleName}->closeBizGuide) ? true : false;
  20. $bizGuideLink = common::checkNotCN() ? 'https://www.zentao.pm/page/zentao-pricing.html' : 'https://www.zentao.net/page/enterprise.html';
  21. $bizName = $showBizGuide ? "<a href='{$bizGuideLink}' target='_blank' class='text-primary'>{$lang->bizName}</a>" : '';
  22. $defaultExportFields = '';
  23. if($isCustomExport)
  24. {
  25. if(is_string($allExportFields)) $allExportFields = explode(',', $allExportFields);
  26. $hasDefaultField = isset($selectedFields);
  27. $selectedFields = $hasDefaultField ? explode(',', $selectedFields) : array();
  28. $moduleName = $this->moduleName;
  29. $moduleLang = $moduleName == 'caselib' ? $lang->testcase : $lang->$moduleName;
  30. $exportFieldPairs = array();
  31. foreach($allExportFields as $key => $field)
  32. {
  33. $field = trim($field);
  34. $fieldName = isset($lang->$field) && is_string($lang->$field) ? $lang->$field : $field;
  35. $exportFieldPairs[$field] = isset($moduleLang->$field) && is_string($moduleLang->$field) ? $moduleLang->$field : $fieldName;
  36. if(!$hasDefaultField) $selectedFields[] = $field;
  37. }
  38. $defaultExportFields = implode(',', $selectedFields);
  39. $templates = $this->file->getExportTemplate($app->moduleName);
  40. $templateList = array();
  41. $templatePairs[] = $this->lang->file->defaultTPL;
  42. foreach($templates as $template)
  43. {
  44. $templatePairs[$template->id] = ($template->public ? "[{$this->lang->public}] " : '') . $template->title;
  45. $templateList[] = span(setID("template{$template->id}"), setClass('hidden'), set('data-public', $template->public), set('data-title', $template->title), $template->content);
  46. }
  47. /* Choose template. */
  48. $customExportRowList[] = formRow
  49. (
  50. setID('tplBox'),
  51. formGroup
  52. (
  53. set::label($lang->file->tplTitleAB),
  54. inputGroup
  55. (
  56. picker(set::name('template'), set::items($templatePairs), on::change('setTemplate(e.target)'), set::required(true)),
  57. span
  58. (
  59. setClass('input-group-addon'),
  60. checkbox(setID('showCustomFieldsBox'), set::checked(false), on::change('setExportTPL'), $lang->file->setExportTPL)
  61. )
  62. ),
  63. $templateList ? $templateList : null
  64. )
  65. );
  66. /* Panel for customize template. */
  67. $customExportRowList[] = div
  68. (
  69. setClass('customFieldsBox border p-4'),
  70. formRow
  71. (
  72. formGroup
  73. (
  74. set::label($lang->file->exportFields),
  75. control
  76. (
  77. set::type('picker'),
  78. set::name('exportFields[]'),
  79. set::items($exportFieldPairs),
  80. set::value($selectedFields),
  81. set::multiple(true),
  82. set::required(true)
  83. )
  84. )
  85. ),
  86. formRow
  87. (
  88. formGroup
  89. (
  90. set::label($lang->file->tplTitle),
  91. set::className('mt-4'),
  92. inputGroup
  93. (
  94. input(set::name('title'), set::value($lang->file->defaultTPL)),
  95. hasPriv('file', 'setPublic') ? div
  96. (
  97. setClass('input-group-addon'),
  98. checkbox(set::name('public'), set::value(1), $lang->public)
  99. ) : null,
  100. btn(setClass('btn-link'), on::click('window.saveTemplate'), icon('save')),
  101. btn(setClass('btn-link'), on::click('window.deleteTemplate'), icon('trash'))
  102. )
  103. )
  104. )
  105. );
  106. }
  107. if($app->rawModule == 'epic') $lang->exportTypeList['all'] = $lang->ERCommon . ' - ' . $lang->exportTypeList['all'];
  108. if($app->rawModule == 'requirement') $lang->exportTypeList['all'] = $lang->URCommon . ' - ' . $lang->exportTypeList['all'];
  109. $isNotZh = strpos($app->getClientLang(), 'zh-') === false;
  110. formPanel
  111. (
  112. setID('exportPanel'),
  113. pageCSS('.form-horz .form-label.required:after{content:""}'), // Remove required tag.
  114. pageCSS('.modal-content{padding-top: 0.5rem; padding-left: 0.75rem; padding-right: 0.75rem; padding-bottom: 1.25rem;}'),
  115. $isNotZh ? pageCSS('#exportPanel .form-label{width: 86px}') : null,
  116. $isNotZh ? pageCSS('#exportPanel .form-group{padding-left: 86px}') : null,
  117. $isNotZh ? pageCSS('#exportPanel .customFieldsBox .form-label{width: 100px}') : null,
  118. $isNotZh ? pageCSS('#exportPanel .customFieldsBox .form-group{padding-left: 100px}') : null,
  119. setCssVar('--form-horz-label-width', '4rem'),
  120. set::target('_self'),
  121. set::actions(array()),
  122. on::submit('setDownloading'),
  123. formGroup
  124. (
  125. set::width('full'),
  126. set::label($lang->file->fileName),
  127. set::name('fileName'),
  128. set::value(isset($fileName) ? $fileName : $lang->file->untitled),
  129. on::change('onChangeFileName'),
  130. set::required(true)
  131. ),
  132. formGroup
  133. (
  134. set::label($lang->file->extension),
  135. set::name('fileType'),
  136. set::items($lang->exportFileTypeList),
  137. on::change('onChangeFileType'),
  138. set::required(true)
  139. ),
  140. formGroup
  141. (
  142. set::label($lang->file->encoding),
  143. set::control('picker'),
  144. set::name('encode'),
  145. set::items($config->charsets[$this->cookie->lang]),
  146. set::value($this->config->zin->lang == 'zh-cn' ? 'gbk' : 'utf-8'),
  147. set::required(true)
  148. ),
  149. /* Fields for KanBan. */
  150. formRow
  151. (
  152. $hideExportRange ? setClass('hidden') : null,
  153. setClass('exportRange'),
  154. formGroup
  155. (
  156. set::label($lang->file->exportRange),
  157. set::control('picker'),
  158. set::name('exportType'),
  159. set::items($lang->exportTypeList),
  160. set::required(true)
  161. )
  162. ),
  163. formRow
  164. (
  165. setClass('hidden'),
  166. formGroup
  167. (
  168. set::control('checkList'),
  169. set::name('part'),
  170. set::items(array(1 => $lang->file->batchExport)),
  171. set::value('')
  172. ),
  173. input
  174. (
  175. set::type('hidden'),
  176. set::name('limit'),
  177. set::value('')
  178. )
  179. ),
  180. /* Custom export. */
  181. $customExportRowList,
  182. formRow
  183. (
  184. setClass('justify-center'),
  185. div
  186. (
  187. setClass('form-actions col text-center'),
  188. div
  189. (
  190. btn
  191. (
  192. on::click()->do("$(target).parent().addClass('disabled');$(target).parent().attr('disabled');$(target).closest('.form-actions').append('<span class=\"text-gray\">{$lang->file->waitDownloadTip}</span>');"),
  193. set::btnType('submit'),
  194. set::type('primary'),
  195. $lang->export
  196. )
  197. )
  198. )
  199. ),
  200. $showBizGuide ? formRow
  201. (
  202. setClass('justify-center bizGuideBox'),
  203. div
  204. (
  205. span
  206. (
  207. setClass('text-gray'),
  208. html(sprintf($lang->file->bizGuide, $bizName))
  209. ),
  210. a
  211. (
  212. setID('closeBizGuideButton'),
  213. setClass('btn btn-default ghost text-gray'),
  214. set::href('#'),
  215. icon(
  216. 'close',
  217. setStyle('font-size', '12px')
  218. ),
  219. on::click('closeBizGuide')
  220. )
  221. )
  222. ) : null
  223. );
  224. set::title($lang->file->exportData);
  225. h::js
  226. (
  227. <<<JAVASCRIPT
  228. window.setDownloading = function(event)
  229. {
  230. $('[name=encode]').removeAttr('disabled');
  231. /* Doesn't support Opera, omit it. */
  232. if(navigator.userAgent.toLowerCase().indexOf("opera") > -1) return true;
  233. $.cookie.set('downloading', 0, {expires:config.cookieLife, path:config.webRoot});
  234. var time = setInterval(function()
  235. {
  236. if($.cookie.get('downloading') == 1)
  237. {
  238. const modal = zui.Modal.query(event.target);
  239. if(modal) modal.hide();
  240. if(!modal) parent.$.closeModal();
  241. $.cookie.set('downloading', null, {expires:config.cookieLife, path:config.webRoot});
  242. clearInterval(time);
  243. }
  244. }, 300);
  245. return true;
  246. }
  247. /* If file type is CSV, then user can select encode type. */
  248. window.onChangeFileType = function(event)
  249. {
  250. if($(event.target).attr('name') != 'fileType') return;
  251. var fileType = $(event.target).val();
  252. var encodePicker = $('[name="encode"]').zui('picker');
  253. if(fileType === 'csv')
  254. {
  255. encodePicker.render({disabled: false});
  256. return;
  257. }
  258. encodePicker.$.setValue('utf-8');
  259. encodePicker.render({disabled: true});
  260. $('#tplBox').toggleClass('hidden', fileType == 'word');
  261. $('.customFieldsBox').toggleClass('hidden', fileType == 'word' || !$('#showCustomFieldsBox').prop('checked'));
  262. }
  263. window.onChangeFileName = function(event)
  264. {
  265. var objFileName = $(event.target);
  266. if(objFileName.val() == '')
  267. {
  268. objFileName.val('{$lang->file->untitled}');
  269. return;
  270. }
  271. }
  272. window.waitDom('[name=fileType]', function(){ $('[name=fileType]').trigger('change');})
  273. window.saveTemplate = function()
  274. {
  275. var customFieldsBox = $('.customFieldsBox');
  276. var publicBox = customFieldsBox.find('input[name="public"]');
  277. var title = customFieldsBox.find('[name="title"]').val();
  278. var content = customFieldsBox.find('[name^="exportFields"]').val();
  279. var isPublic = (publicBox.length > 0 && publicBox.prop('checked')) ? 1 : 0;
  280. if(!title || !content) return;
  281. const saveTemplateLink = $.createLink('file', 'ajaxSaveTemplate', 'module={$this->moduleName}');
  282. $.post(saveTemplateLink, {title:title, content:content.join(','), public:isPublic}, function(data)
  283. {
  284. if(data.indexOf('alert') == -1)
  285. {
  286. $('#tplBox').html(data);
  287. customFieldsBox.find('[name=title]').val(title);
  288. }
  289. else
  290. {
  291. data = JSON.parse(data);
  292. zui.Modal.alert(data.alert);
  293. }
  294. });
  295. };
  296. window.deleteTemplate = function()
  297. {
  298. var template = $('#tplBox [name="template"]');
  299. var templateID = template.val();
  300. if(templateID == 0) return;
  301. const deleteLink = $.createLink('file', 'ajaxDeleteTemplate', 'templateID=' + templateID);
  302. $.get(deleteLink, function()
  303. {
  304. var templatePicker = template.zui('picker');
  305. var newItems = templatePicker.options.items.filter(item => item.value != templateID);
  306. templatePicker.render({items: newItems});
  307. templatePicker.$.setValue(newItems.length > 0 ? newItems[0].value : '');
  308. });
  309. };
  310. window.setTemplate = function(obj)
  311. {
  312. var templateID = $(obj).val();
  313. var template = $('#template' + templateID);
  314. var exportFields = template.length > 0 ? template.html() : '{$defaultExportFields}';
  315. exportFields = exportFields.split(',');
  316. const customFieldsBox = $('.customFieldsBox');
  317. customFieldsBox.find('[name^="exportFields"]').zui('picker').$.setValue(exportFields);
  318. customFieldsBox.find('input[name="public"]').prop('checked', template.data('public'));
  319. customFieldsBox.find('[name="title"]').val(templateID != '0' ? template.data('title') : '{$lang->file->defaultTPL}');
  320. };
  321. window.setExportTPL = function()
  322. {
  323. $('.customFieldsBox').toggleClass('hidden', !$('#showCustomFieldsBox').prop('checked'));
  324. };
  325. setExportTPL();
  326. /* Auto select selected item for exportRange. */
  327. if($('.dtable .dtable-header .has-checkbox').length > 0)
  328. {
  329. const dtable = zui.DTable.query($('.dtable .dtable-header .has-checkbox').closest('.dtable')[0]);
  330. let checkedList = dtable ? dtable.$.getChecks() : [];
  331. if(checkedList.length)
  332. {
  333. if(window.config.currentModule == 'testcase') checkedList.forEach(function(item, index){ checkedList[index] = item.replace('case_', '');});
  334. if(window.config.currentModule == 'product') checkedList.forEach(function(item, index){if(item.indexOf('-')) checkedList[index] = item.substr(item.indexOf('-') + 1);});
  335. if(window.config.currentModule == 'testtask' && window.config.currentMethod == 'cases')
  336. {
  337. let caseIDList = [];
  338. checkedList.forEach(function(item, index) {
  339. let testrun = dtable.options.data.find(obj => obj.id == item);
  340. let caseID = testrun ? testrun.case : null;
  341. if(caseID) caseIDList.push(caseID);
  342. });
  343. checkedList = caseIDList;
  344. }
  345. waitDom('#exportPanel [name=exportType]', function(){ $('#exportPanel [name=exportType]').zui('picker').$.setValue('selected');});
  346. $.cookie.set('checkedItem', checkedList.join(','), {expires:config.cookieLife, path:config.webRoot});
  347. }
  348. else
  349. {
  350. $.cookie.set('checkedItem', '', {expires:config.cookieLife, path:config.webRoot});
  351. }
  352. }
  353. /**
  354. * 关闭升级到企业版提示。
  355. * Close the biz guide.
  356. *
  357. * @access public
  358. * @return void
  359. */
  360. window.closeBizGuide = function()
  361. {
  362. let closeBizGuideLink = $.createLink('file', 'ajaxcloseBizGuide', 'module={$this->moduleName}');
  363. $.get(closeBizGuideLink);
  364. $('.bizGuideBox').remove();
  365. }
  366. JAVASCRIPT
  367. );
  368. render();