v1.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. /**
  3. * The thinkStepBase widget class file of zin 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 Zemei Wang<wangzemei@easycorp.ltd>
  8. * @package zin
  9. * @link http://www.zentao.net
  10. */
  11. namespace zin;
  12. /**
  13. * 思引师基础节点内容。
  14. * thinmory basic node content.
  15. */
  16. class thinkStepBase extends wg
  17. {
  18. /**
  19. * @var mixed[]
  20. */
  21. protected static $defineProps = array(
  22. 'title?: string', // 标题
  23. 'desc?: string', // 描述
  24. 'isRun?: bool=false', // 是否是分析活动
  25. 'step?: object', // 整个步骤的对象
  26. 'mode?: string="detail"', // detail|create|edit
  27. 'type?: string="node"', // node|transition/question
  28. 'quoteQuestions?: array'. // 引用的问题
  29. 'quotedQuestions?: attay', // 被引用的问题
  30. 'isResult?: bool=false', // 是否是结果页
  31. 'wizard?: object', // 模型数据
  32. );
  33. public static function getPageCSS()
  34. {
  35. return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
  36. }
  37. protected function buildDetail()
  38. {
  39. global $lang, $app;
  40. $app->loadLang('thinkrun');
  41. $app->loadLang('thinkstep');
  42. list($step, $mode, $wizard) = $this->prop(array('step', 'mode', 'wizard'));
  43. if($mode != 'detail') return array();
  44. $options = $step->options;
  45. if($step->type == 'question')
  46. {
  47. $questionType = $options->questionType;
  48. $tips = $lang->thinkstep->$questionType;
  49. $setOption = empty($options->setOption) || $options->setOption == 0;
  50. if(!empty($options->required) && $questionType == 'checkbox' && $setOption)
  51. {
  52. $tips = $lang->thinkrun->requiredTitle[$questionType];
  53. $tips = str_replace(array('%min%', '%max%'), array($options->minCount, $options->maxCount), $tips);
  54. }
  55. if(!empty($options->required) && $questionType == 'tableInput')
  56. {
  57. if($wizard->model == 'bcg' && empty($options->requiredRows)) $options->requiredRows = 3;
  58. if($options->supportAdd) $tips = sprintf($lang->thinkrun->tableInputTitle->notSupportAdd, count($options->fields), $options->requiredRows);
  59. if(!$options->supportAdd) $tips = sprintf($lang->thinkrun->tableInputTitle->supportAdd, $options->requiredRows);
  60. }
  61. }
  62. $requiredSymbal = !empty($options->required) ? span(setClass('text-danger mr-0.5 h-5'), '*') : null;
  63. $questionTips = !empty($tips) ? span(setClass('text-gray mx-1'), '(' . $tips . ')') : null;
  64. $errorText = isset($options->questionType) && !empty($lang->thinkrun->error->requiredType[$options->questionType]) ? span
  65. (
  66. setClass('run-error-msg h-5 inline-block text-canvas text-md px-2 ml-0.5 rounded-md hidden'),
  67. setStyle('background', 'var(--color-danger-600)'),
  68. $lang->thinkrun->error->requiredType[$options->questionType]
  69. ) : null;
  70. return array
  71. (
  72. div
  73. (
  74. setClass('flex items-start justify-between mb-2 step-title'),
  75. $step->type == 'question' ? div
  76. (
  77. setClass('h-full text-fore text-lg'),
  78. $requiredSymbal,
  79. isset($step->index) ? $step->index . '. ' : '',
  80. $step->title,
  81. $questionTips,
  82. $errorText
  83. ) : div
  84. (
  85. setClass('text-2xl'),
  86. $step->title
  87. )
  88. ),
  89. div
  90. (
  91. setClass('run-desc mb-3.5'),
  92. setStyle(array('margin-top' => '-28px')),
  93. section
  94. (
  95. setClass('break-words'),
  96. set::content(!empty($step->desc) ? htmlspecialchars_decode($step->desc) : ''),
  97. set::useHtml(true)
  98. )
  99. )
  100. );
  101. }
  102. protected function buildDetailTip()
  103. {
  104. global $lang, $app, $config;
  105. $app->loadLang('thinkstep');
  106. $app->loadLang('thinkrun');
  107. list($quoteQuestions, $quotedQuestions, $step, $isRun, $wizard) = $this->prop(array('quoteQuestions', 'quotedQuestions', 'step', 'isRun', 'wizard'));
  108. $preViewModel = in_array($wizard->model, $config->thinkwizard->hiddenMenuModel);
  109. if(!empty($step->options->fields)) $step->options->fields = is_string($step->options->fields) ? explode(', ', $step->options->fields) : array_values((array)$step->options->fields);
  110. $questionType = !empty($step) && $step->type == 'question' ? $step->options->questionType : '';
  111. $isCheckBox = !empty($step) && $step->type == 'question' && in_array($questionType, $config->thinkstep->quoteQuestionType);
  112. $isQuoteItem = $isCheckBox && !empty($step->options->setOption) && $step->options->setOption == 1;
  113. $quoteTitleList = !empty($step->options->quoteTitle) ? explode(", ", $step->options->quoteTitle) : array();
  114. $detailTip = array();
  115. $quotedItems = array();
  116. $sourceQuestion = array();
  117. $sourceItems = array();
  118. $wizard->config = !empty($wizard->config) ? $wizard->config : array();
  119. $wizard->config = is_string($wizard->config) ? json_decode($wizard->config, true) : $wizard->config;
  120. $configureObjects = !empty($wizard->config['configureObjects']) ? json_decode($wizard->config['configureObjects'], true) : array();
  121. $isAssignedObject = !empty($configureObjects['isAssignedObject']) ? $configureObjects['isAssignedObject'] : 0;
  122. $showBuiltTip = isset($step->options->canConfigureRatio) && $step->options->canConfigureRatio == 0;
  123. if(!empty($quotedQuestions))
  124. {
  125. foreach($quotedQuestions as $item)
  126. {
  127. $quotedItems[] = a
  128. (
  129. setClass('block text-primary-500 leading-relaxed'),
  130. set::href(createLink('thinkstep', 'view', "marketID=0&&wizardID=$item->wizard&&stepID=$item->id&&from=detail")),
  131. setData('toggle', 'modal'),
  132. setData('dismiss', 'modal'),
  133. setData('size', 'sm'),
  134. $item->index . '. ' . $item->title
  135. );
  136. }
  137. }
  138. if($isQuoteItem && !empty($quoteQuestions))
  139. {
  140. foreach($quoteQuestions as $item)
  141. {
  142. if(!$isRun && in_array($item->id, $quoteTitleList)) $sourceQuestion[] = $item;
  143. if($isRun && in_array($item->origin, $quoteTitleList)) $sourceQuestion[] = $item;
  144. }
  145. }
  146. if(!empty($sourceQuestion))
  147. {
  148. foreach ($sourceQuestion as $sourceQuestionItem)
  149. {
  150. $sourceItems[] = a
  151. (
  152. setClass('block text-primary-500 leading-relaxed'),
  153. set::href(createLink('thinkstep', 'view', "marketID=0&&wizardID=$sourceQuestionItem->wizard&&stepID=$sourceQuestionItem->id&&from=detail")),
  154. setData('toggle', 'modal'),
  155. setData('dismiss', 'modal'),
  156. setData('size', 'sm'),
  157. $sourceQuestionItem->index . '. ' . $sourceQuestionItem->title
  158. );
  159. }
  160. }
  161. $runSourceTip = !empty($sourceQuestion) && !$preViewModel;
  162. if($isRun && (!empty($quotedQuestions) || $runSourceTip))
  163. {
  164. $tipType = $lang->thinkstep->label->option;
  165. $sourceQuestionTip = array();
  166. if($runSourceTip)
  167. {
  168. foreach ($sourceQuestion as $sourceQuestionItem)
  169. {
  170. $sourceQuestionType = is_string($sourceQuestionItem->options) ? json_decode($sourceQuestionItem->options)->questionType : $sourceQuestionItem->options->questionType;
  171. if($sourceQuestionType == 'multicolumn') $tipType = sprintf($lang->thinkstep->entry, $step->options->selectColumn);
  172. $sourceQuestionTip[] = div
  173. (
  174. setClass('ml-4 pl-0.5'),
  175. sprintf($lang->thinkstep->tips->checkbox, $lang->thinkstep->tips->options[$questionType], ($sourceQuestionItem->index . '. ' . $sourceQuestionItem->title)),
  176. $tipType
  177. );
  178. }
  179. }
  180. $showRunTips = ((!empty($quotedQuestions) && empty($isAssignedObject)) || !empty($runSourceTip));
  181. $detailTip[] = $showRunTips ? div
  182. (
  183. setClass('bg-primary-50 text-gray p-2 mt-3 leading-normal'),
  184. (!empty($quotedQuestions) && empty($isAssignedObject)) ? div
  185. (
  186. setClass('flex items-center'),
  187. icon(setClass('font text-warning mr-1'), 'about'),
  188. $lang->thinkrun->tips->quotedTip
  189. ) : null,
  190. !empty($runSourceTip) ? $sourceQuestionTip : null
  191. ) : null;
  192. }
  193. if(!$isRun)
  194. {
  195. /* 以下类型引用其他没有答案的问题,底部需提示信息。The following types of questions refer to other unanswered questions, and prompt information is required at the bottom. */
  196. $quoteTipsType = array('multicolumn', 'score', 'tableInput');
  197. if(!empty($sourceQuestion) && !empty($questionType) && in_array($questionType, $quoteTipsType))
  198. {
  199. $quoteTips = empty($step->options->fields) ? div(setClass('text-sm text-gray-400 leading-loose mt-2'), $lang->thinkstep->tips->{$questionType}) : null;
  200. }
  201. $detailTip[] = array
  202. (
  203. !empty($sourceQuestion) ? array(
  204. div
  205. (
  206. setClass('bg-primary-50 leading-normal p-2 mt-3'),
  207. div(sprintf($lang->thinkstep->tips->sourceofOptions, $lang->thinkstep->tips->options[$questionType])),
  208. $sourceItems
  209. ),
  210. !empty($quoteTips) ? $quoteTips : null
  211. ) : null,
  212. (!empty($quotedQuestions) && !$preViewModel) ? div
  213. (
  214. setClass('bg-primary-50 leading-normal p-2 mt-3'),
  215. div(sprintf($lang->thinkstep->tips->optionsAreReferenced, $questionType == 'multicolumn' ? $lang->thinkstep->inputItem : $lang->thinkstep->label->option)),
  216. $quotedItems
  217. ) : null
  218. );
  219. }
  220. if($preViewModel)
  221. {
  222. if((!empty($quotedQuestions) && !empty($isAssignedObject)) || $showBuiltTip) $detailTip[] = $this->buildTipsNode($lang->thinkwizard->previewSteps->quotedTips);
  223. if(isset($step->options->isPreset) && $step->options->isPreset == 1) $detailTip[] = $this->buildTipsNode($lang->thinkwizard->previewSteps->presetDataTips);
  224. }
  225. return $detailTip;
  226. }
  227. /**
  228. * @param string $message
  229. */
  230. protected function buildTipsNode($message)
  231. {
  232. return div
  233. (
  234. setClass('flex text-gray-400 mt-2 items-center text-sm ml-2'),
  235. icon(setClass('text-important mr-2'), 'about'),
  236. span(setClass('leading-6'), $message)
  237. );
  238. }
  239. protected function buildFormItem()
  240. {
  241. global $lang, $app;
  242. $app->loadLang('thinkstep');
  243. list($step, $title, $desc, $type, $mode) = $this->prop(array('step', 'title', 'desc', 'type', 'mode'));
  244. if($mode == 'create') $title = $lang->thinkstep->untitled . $lang->thinkstep->$type;
  245. if($step)
  246. {
  247. $title = $step->title;
  248. $desc = htmlspecialchars_decode($step->desc);
  249. }
  250. return array(
  251. formGroup
  252. (
  253. set::width('full'),
  254. set::label($lang->thinkstep->label->title),
  255. set::labelClass('required'),
  256. input
  257. (
  258. setClass('is-required'),
  259. set::value($title ?? ''),
  260. set::name('title'),
  261. set::placeholder($lang->thinkstep->placeholder->inputContent)
  262. )
  263. ),
  264. formGroup
  265. (
  266. set::width('full'),
  267. set::label($lang->thinkstep->label->desc),
  268. editor
  269. (
  270. setClass('desc'),
  271. set::name('desc'),
  272. set::placeholder($lang->thinkstep->placeholder->pleaseInput),
  273. html($desc ?? ''),
  274. set::rows(3)
  275. )
  276. )
  277. );
  278. }
  279. protected function buildForm()
  280. {
  281. global $lang;
  282. $actions = array(array(
  283. 'text' => $lang->save,
  284. 'btnType' => 'submit',
  285. 'class' => 'primary h-7 ring-0 submit-btn px-4',
  286. 'style' => array('min-width' => '0')
  287. ));
  288. return formPanel
  289. (
  290. setClass('think-step-panel py-4 px-0'),
  291. set::formClass('form-watched gap-3'),
  292. set::bodyClass('think-step-form'),
  293. set::actions($actions),
  294. formHidden('type', $this->prop('type')),
  295. $this->buildFormItem()
  296. );
  297. }
  298. /**
  299. * @return \zin\wg|\zin\node|mixed[]
  300. */
  301. protected function build()
  302. {
  303. list($isResult, $step, $isRun) = $this->prop(array('isResult', 'step', 'isRun'));
  304. $questionType = '';
  305. if($isResult && isset($step->options->questionType)) $questionType = $step->options->questionType;
  306. $content = $isRun ? div
  307. (
  308. setClass('w-full col bg-white items-center pt-4 pb-10 px-8 mb-4'),
  309. div
  310. (
  311. setStyle(array('max-width' => '878px')),
  312. setClass('w-full'),
  313. $this->buildDetail(),
  314. $this->buildDetailTip()
  315. )
  316. ) : div
  317. (
  318. $questionType == 'tableInput' ? setStyle(array('min-width' => '220px')) : null,
  319. $this->buildDetail(),
  320. $this->buildDetailTip()
  321. );
  322. return $this->prop('mode') == 'detail' ? $content : $this->buildForm();
  323. }
  324. }