DBColumn.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 (Helper::hasAnyString($this->field, ['phone', 'tel'])) {
  104. $rule[] = "{ pattern: /^1[3456789]\\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }";
  105. } else {
  106. if ($min > 0 && $max > 0) {
  107. $rule[] = "{ min: {$min}, max: {$max}, message: '长度在{$min}到{$max}个字符', trigger: 'blur' }";
  108. } elseif ($min > 0) {
  109. $rule[] = "{ min: {$min}, message: '长度最少{$min}个字符', trigger: 'blur' }";
  110. } elseif ($max > 0) {
  111. $rule[] = "{ max: {$max}, message: '长度最多{$max}个字符', trigger: 'blur' }";
  112. }
  113. }
  114. }
  115. } elseif ($type == 'number') {
  116. $html = $this->getInputHtml('number');
  117. } elseif ($type == '0|1') {
  118. $rule = '';
  119. $html = $this->getSelectHtml();
  120. }
  121. $ruleHtml = '';
  122. if ($rule) {
  123. $rule = implode(',', $rule);
  124. $ruleHtml = $this->field . ": [{$rule}],";
  125. }
  126. return [$html, $ruleHtml];
  127. }
  128. /**
  129. * 获取字段的表单html和验证规则
  130. * TODO: 这里可能要vue,react, layui, ... 代码
  131. * @return array
  132. */
  133. public function getDetailHtml() :string
  134. {
  135. $html = "{{ info.{$this->field} }}";
  136. $type = $this->getTsType();
  137. $textType = 'string';
  138. if ($type == 'string') {
  139. // 图片处理
  140. if (Helper::hasAnyString($this->field, ['img', 'image'])) {
  141. // 单张图片
  142. } elseif (Helper::hasAnyString($this->field, ['images', 'imgs'])) {
  143. // 多张图片
  144. } elseif (Helper::hasAnyString($this->field, ['_id'])) {
  145. // select
  146. } elseif (Helper::hasAnyString($this->field, ['ids'])) {
  147. // 多选框
  148. } else {
  149. // input
  150. $max = $this->getMaxLength();
  151. if ($max > 64 || Helper::hasAnyString($this->field, ['text'])) {
  152. $textType = 'textarea';
  153. }
  154. }
  155. } elseif ($type == '0|1') {
  156. $data = $this->getCommentArr();
  157. $html = "{{ info.{$this->field} ? '{$data[1]}' : '$data[0]'}}";
  158. }
  159. $elHtml = $textType != 'textarea' ? ':xs="24" :lg="8" :sm="12"' : ':span=24';
  160. return <<<Detail
  161. <el-col {$elHtml}>
  162. <label>{$this->comment}:</label> <span>{$html}</span>
  163. </el-col>
  164. Detail;
  165. }
  166. /**
  167. * 生成input
  168. * @param string $type
  169. * @param int $maxLength
  170. * @return string
  171. */
  172. public function getInputHtml(string $type, int $maxLength = 0): string
  173. {
  174. $maxLengthHtml = '';
  175. if ($type != 'number' && $maxLength > 0) {
  176. $maxLengthHtml = "maxlength='{$maxLength}'";
  177. }
  178. $elHtml = $type != 'textarea' ? ':xs="24" :lg="8" :sm="12"' : ':span=24';
  179. return <<<input
  180. <el-col {$elHtml}>
  181. <ElFormItem label="{$this->comment}" prop="{$this->field}">
  182. <ElInput v-model="formData.{$this->field}" $maxLengthHtml type="{$type}"/>
  183. </ElFormItem>
  184. </el-col>
  185. input;
  186. }
  187. /**
  188. * 生成select
  189. * @return string
  190. */
  191. public function getSelectHtml(): string
  192. {
  193. $selectData = $this->getCommentArr();
  194. if (!$selectData) {
  195. return '';
  196. }
  197. $data = '';
  198. foreach ($selectData as $key => $item) {
  199. if (is_numeric($key)) {
  200. $data.= "{label: '{$item}', value: {$key}}, ";
  201. } else {
  202. $data.= "{label: '{$item}', value: '{$key}'},";
  203. }
  204. }
  205. return <<<select
  206. <el-col :xs="24" :lg="8" :sm="12">
  207. <ElFormItem label="{$this->comment}" prop="{$this->field}">
  208. <el-select v-model="formData.{$this->field}" placeholder="请选择" :empty-values="[0]" :value-on-clear="0">
  209. <el-option v-for="item in [{$data}]" :key="item.value" :value="item.value" :label="item.label"/>
  210. </el-select>
  211. </ElFormItem>
  212. </el-col>
  213. select;
  214. }
  215. /**
  216. * 获取字段的最大长度
  217. * @return int
  218. */
  219. public function getMaxLength():int
  220. {
  221. preg_match('/(\d+)/', $this->type, $match);
  222. return $match[0] ?? 0;
  223. }
  224. /**
  225. * 获取字段的最小长度
  226. * @return int
  227. */
  228. public function getMinLength():int
  229. {
  230. return 0;
  231. }
  232. /**
  233. * 判断字段是否是数字字段
  234. * @return bool
  235. */
  236. public function isNumberFiled(): bool
  237. {
  238. $type = $this->getTsType();
  239. return $type == 'number' || str_contains($type, '|');
  240. }
  241. /**
  242. * 获取字段的注释数组
  243. * @return array
  244. */
  245. public function getCommentArr():array
  246. {
  247. if (!$this->isNumberFiled()) {
  248. return [];
  249. }
  250. $arr = [];
  251. preg_match_all('/(\d+\-\S+)/', $this->wholeComment, $match);
  252. if ($match) {
  253. foreach ($match[0] as $matchItem) {
  254. list($key, $value) = explode('-', $matchItem);
  255. $arr[$key] = $value;
  256. }
  257. }
  258. return $arr;
  259. }
  260. public function getTableAttr(): array
  261. {
  262. $JsTableArr = ['prop' => $this->field, 'label' => $this->comment];
  263. // 长字段列表需要添加showOverflowTooltip
  264. if ($this->getMaxLength() > 64 || Helper::hasAnyString($this->field, ['text'])) {
  265. $JsTableArr['showOverflowTooltip'] = 'true';
  266. }
  267. if (str_contains($this->field, 'ids')) {
  268. $JsTableArr = [];
  269. } elseif (Helper::hasAnyString($this->field, ['is', 'can', 'has', 'status'])) {
  270. $commentArr = $this->getCommentArr();
  271. if (count($commentArr) == 2) {
  272. $JsTableArr['formatter'] = <<<HTML
  273. (row) => { {$this->line}
  274. return h(ElTag, { type: row.{$this->field} ? 'success' : 'danger' }, () => row.{$this->field} ? '{$commentArr[1]}' : '{$commentArr[0]}') {$this->line}
  275. }
  276. HTML;
  277. } else {
  278. $JsTableArr['formatter'] = <<<HTML
  279. (row) => {{$this->line}
  280. return h(ElTag, { type: row.{$this->field} ? 'success' : 'danger' }, () => row.{$this->field} ? '是' : '否'){$this->line}
  281. }
  282. HTML;
  283. }
  284. }
  285. return $JsTableArr;
  286. }
  287. }