DBColumn.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <?php
  2. class DBColumn {
  3. public string $field;
  4. public string $type;
  5. public ?string $collation;
  6. public ?string $key;
  7. public ?string $default;
  8. public ?string $extra;
  9. public ?string $privileges;
  10. public string $comment;
  11. public ?string $wholeComment;
  12. public string $allowNull;
  13. public string $line = '<br/>';
  14. public function __construct(array $info) {
  15. $this->field = $info['Field'];
  16. $this->type = $info['Type'];
  17. $this->collation = $info['Collation'];
  18. $this->key = $info['Key'];
  19. $this->default = $info['Default'];
  20. $this->extra = $info['Extra'];
  21. $this->privileges = $info['Privileges'];
  22. $this->wholeComment = $info['Comment'];
  23. $this->comment = $info['Comment'] ? explode(' ', $info['Comment'])[0] : '';
  24. $this->allowNull = empty($info['Null']) || $info['Null'] == 'YES';
  25. }
  26. /**
  27. * 获取字段的ts类型
  28. * @return string
  29. */
  30. public function getTsType() :string
  31. {
  32. $type = 'string';
  33. if (str_contains($this->field, 'ids')) {
  34. $type = 'number[]';
  35. } elseif (Helper::hasAnyString($this->type, ['int', 'decimal', 'double', 'float'])) {
  36. if (Helper::hasAnyString($this->field, ['is_', 'can_', 'has_', 'status', '_status', 'type'])) {
  37. $type = '0|1';
  38. } else {
  39. $type = 'number';
  40. }
  41. }
  42. return $type;
  43. }
  44. /**
  45. * 获取字段的ts定义
  46. * @return string
  47. */
  48. public function getTsDefine() :string
  49. {
  50. $type = $this->getTsType();
  51. $temp = $this->field . ": {$type}";
  52. $comment = $this->comment ? " // {$this->comment}" : '';
  53. return $temp . " {$comment}";
  54. }
  55. /**
  56. * 获取字段的默认值
  57. * @return string
  58. */
  59. public function getDefaultValue() :string
  60. {
  61. $type = $this->getTsType();
  62. if (in_array($type, ['number', '0|1'])) {
  63. $default = $this->default ? : 0;
  64. return $this->field . ": {$default},";
  65. } else {
  66. $default = $this->default ? : '';
  67. return $this->field . ": '{$default}',";
  68. }
  69. }
  70. /**
  71. * 获取字段的表单html和验证规则
  72. * TODO: 这里可能要vue,react, layui, ... 代码
  73. * @return array
  74. */
  75. public function getFormHtmlAndRule() :array
  76. {
  77. $html = '';
  78. $rule = [];
  79. if (!$this->allowNull) {
  80. $rule[] = "{ required: true, message: '请输入{$this->comment}', trigger: 'blur' }";
  81. }
  82. $type = $this->getTsType();
  83. if ($type == 'string') {
  84. // 图片处理
  85. if (Helper::hasAnyString($this->field, ['img', 'image'])) {
  86. // 单张图片
  87. } elseif (Helper::hasAnyString($this->field, ['images', 'imgs'])) {
  88. // 多张图片
  89. } elseif (Helper::hasAnyString($this->field, ['_id'])) {
  90. // select
  91. } elseif (Helper::hasAnyString($this->field, ['ids'])) {
  92. // 多选框
  93. } else {
  94. // input
  95. $inputType = 'text';
  96. $max = $this->getMaxLength();
  97. $min = $this->getMinLength();
  98. if ($max > 64) {
  99. $inputType = 'textarea';
  100. }
  101. $html = $this->getInputHtml($inputType, $max);
  102. // rule
  103. if ($min > 0 && $max > 0) {
  104. $rule[] = "{ min: {$min}, max: {$max}, message: '长度在{$min}到{$max}个字符', trigger: 'blur' }";
  105. } elseif ($min > 0) {
  106. $rule[] = "{ min: {$min}, message: '长度最少{$min}个字符', trigger: 'blur' }";
  107. } elseif ($max > 0) {
  108. $rule[] = "{ max: {$max}, message: '长度最多{$max}个字符', trigger: 'blur' }";
  109. }
  110. }
  111. } elseif ($type == 'number') {
  112. $html = $this->getInputHtml('number');
  113. } elseif ($type == '0|1') {
  114. $rule = '';
  115. $html = $this->getSelectHtml();
  116. }
  117. $ruleHtml = '';
  118. if ($rule) {
  119. $rule = implode(',', $rule);
  120. $ruleHtml = $this->field . ": [{$rule}],";
  121. }
  122. return [$html, $ruleHtml];
  123. }
  124. /**
  125. * 获取字段的表单html和验证规则
  126. * TODO: 这里可能要vue,react, layui, ... 代码
  127. * @return array
  128. */
  129. public function getDetailHtml() :string
  130. {
  131. $html = "{{ info.{$this->field} }}";
  132. $type = $this->getTsType();
  133. $textType = 'string';
  134. if ($type == 'string') {
  135. // 图片处理
  136. if (Helper::hasAnyString($this->field, ['img', 'image'])) {
  137. // 单张图片
  138. } elseif (Helper::hasAnyString($this->field, ['images', 'imgs'])) {
  139. // 多张图片
  140. } elseif (Helper::hasAnyString($this->field, ['_id'])) {
  141. // select
  142. } elseif (Helper::hasAnyString($this->field, ['ids'])) {
  143. // 多选框
  144. } else {
  145. // input
  146. $max = $this->getMaxLength();
  147. if ($max > 64 || Helper::hasAnyString($this->field, ['text'])) {
  148. $textType = 'textarea';
  149. }
  150. }
  151. } elseif ($type == '0|1') {
  152. $data = $this->getCommentArr();
  153. $html = "{{ info.{$this->field} ? '{$data[1]}' : '$data[0]'}}";
  154. }
  155. $elHtml = $textType != 'textarea' ? ':xs="24" :lg="8" :sm="12"' : ':span=24';
  156. return <<<Detail
  157. <el-col {$elHtml}>
  158. <label>{$this->comment}:</label> <span>{$html}</span>
  159. </el-col>
  160. Detail;
  161. }
  162. /**
  163. * 生成input
  164. * @param string $type
  165. * @param int $maxLength
  166. * @return string
  167. */
  168. public function getInputHtml(string $type, int $maxLength = 0): string
  169. {
  170. $maxLengthHtml = '';
  171. if ($type != 'number' && $maxLength > 0) {
  172. $maxLengthHtml = "maxlength='{$maxLength}'";
  173. }
  174. $elHtml = $type != 'textarea' ? ':xs="24" :lg="8" :sm="12"' : ':span=24';
  175. return <<<input
  176. <el-col {$elHtml}>
  177. <ElFormItem label="{$this->comment}" prop="{$this->field}">
  178. <ElInput v-model="formData.{$this->field}" $maxLengthHtml type="{$type}"/>
  179. </ElFormItem> ≤,≤≥≤ rmItem>
  180. </el-col>
  181. input;
  182. }
  183. /**
  184. * 生成select
  185. * @return string
  186. */
  187. public function getSelectHtml(): string
  188. {
  189. $selectData = $this->getCommentArr();
  190. if (!$selectData) {
  191. return '';
  192. }
  193. $data = '';
  194. foreach ($selectData as $key => $item) {
  195. if (is_numeric($key)) {
  196. $data.= "{label: '{$item}', value: {$key}}, ";
  197. } else {
  198. $data.= "{label: '{$item}', value: '{$key}'},";
  199. }
  200. }
  201. return <<<select
  202. <el-col :xs="24" :lg="8" :sm="12">
  203. <ElFormItem label="{$this->comment}" prop="{$this->field}">
  204. <el-select v-model="formData.{$this->field}" placeholder="请选择">
  205. <el-option v-for="item in [{$data}]" :key="item.value" :value="item.value" :label="item.label"/>
  206. </el-select>
  207. </ElFormItem>
  208. </el-col>
  209. select;
  210. }
  211. /**
  212. * 获取字段的最大长度
  213. * @return int
  214. */
  215. public function getMaxLength():int
  216. {
  217. preg_match('/(\d+)/', $this->type, $match);
  218. return $match[0] ?? 0;
  219. }
  220. /**
  221. * 获取字段的最小长度
  222. * @return int
  223. */
  224. public function getMinLength():int
  225. {
  226. return 0;
  227. }
  228. /**
  229. * 判断字段是否是数字字段
  230. * @return bool
  231. */
  232. public function isNumberFiled(): bool
  233. {
  234. $type = $this->getTsType();
  235. return $type == 'number' || str_contains($type, '|');
  236. }
  237. /**
  238. * 获取字段的注释数组
  239. * @return array
  240. */
  241. public function getCommentArr():array
  242. {
  243. if (!$this->isNumberFiled()) {
  244. return [];
  245. }
  246. $arr = [];
  247. preg_match_all('/(\d+\-\S+)/', $this->wholeComment, $match);
  248. if ($match) {
  249. foreach ($match[0] as $matchItem) {
  250. list($key, $value) = explode('-', $matchItem);
  251. $arr[$key] = $value;
  252. }
  253. }
  254. return $arr;
  255. }
  256. public function getTableAttr(): array
  257. {
  258. $JsTableArr = ['prop' => $this->field, 'label' => $this->comment];
  259. // 长字段列表需要添加showOverflowTooltip
  260. if ($this->getMaxLength() > 64 || Helper::hasAnyString($this->field, ['text'])) {
  261. $JsTableArr['showOverflowTooltip'] = true;
  262. }
  263. if (str_contains($this->field, 'ids')) {
  264. $JsTableArr = [];
  265. } elseif (Helper::hasAnyString($this->field, ['is', 'can', 'has', 'status'])) {
  266. $commentArr = $this->getCommentArr();
  267. if (count($commentArr) == 2) {
  268. $JsTableArr['formatter'] = <<<HTML
  269. (row) => { {$this->line}
  270. return h(ElTag, { type: row.{$this->field} ? 'success' : 'danger' }, () => row.{$this->field} ? '{$commentArr[1]}' : '{$commentArr[0]}') {$this->line}
  271. }
  272. HTML;
  273. } else {
  274. $JsTableArr['formatter'] = <<<HTML
  275. (row) => {{$this->line}
  276. return h(ElTag, { type: row.{$this->field} ? 'success' : 'danger' }, () => row.{$this->field} ? '是' : '否'){$this->line}
  277. }
  278. HTML;
  279. }
  280. }
  281. return $JsTableArr;
  282. }
  283. }