CommonController.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. <?php
  2. class CommonController extends Controller
  3. {
  4. public function actionSendCode()
  5. {
  6. $phone = Helper::getPostString('phone', '');
  7. if (!Helper::isPhone($phone)) {
  8. Helper::error('手机号码格式错误');
  9. }
  10. // 验证码发送限制
  11. Helper::dealCommonResult(Helper::limitSmsSend(10, $phone, 5), false);
  12. if (!DB::getScalerWithCriteria('useradmin', DbCriteria::simpleCompare(['phone' => $phone])->setSelect('id'))) {
  13. Helper::error('该手机号用户不存在');
  14. }
  15. $code = (string)random_int(100000,999999);
  16. RedisInstance::getInstance()->set('user_code:'.$phone, $code, 600);
  17. // 发送短信
  18. Helper::dealCommonResult(SMS::getInstance()->send($phone, '2094847', [$code]));
  19. }
  20. public function actionJson()
  21. {
  22. $newData = [];
  23. $data = file_get_contents(PROJECT_PATH . '/runtime/city.json');
  24. foreach (json_decode($data, true) as $province) {
  25. $newData[] = ['label' => $province['province'], 'value' => $province['province'], 'children' => array_map(function($city) {
  26. return ['label' => $city['city'], 'value' => $city['city'], 'children' => array_map(function($area) {
  27. return ['label' => $area['area'], 'value' => $area['area']];
  28. }, $city['areas'])];
  29. }, $province['citys'])];
  30. }
  31. echo json_encode($newData, JSON_UNESCAPED_UNICODE);
  32. }
  33. public function actionEdit()
  34. {
  35. $table = Helper::getGetString('t1');
  36. if (!$table) {
  37. Helper::error('参数错误');
  38. }
  39. $table = DB::formTableName($table);
  40. $sql = "show full columns from {$table}";
  41. $taleInfo = \Yii::app()->db->createCommand($sql)->queryAll();
  42. if (!$taleInfo) {
  43. Helper::error('该表不存在');
  44. }
  45. $excludeField = ['create_date', 'update_date', 'is_delete', 'id', 'city', 'area', 'province'];
  46. $this->getEditHtml($taleInfo, $excludeField);
  47. }
  48. public function getEditHtml(array $tableFieldArr, array $excludeField = []): void
  49. {
  50. $data = [];
  51. $notNullField = [];
  52. $allowEmptyField = [];
  53. echo '$data = [<br/>';
  54. foreach ($tableFieldArr as $column) {
  55. if (in_array($column['Field'], $excludeField)) {
  56. continue;
  57. }
  58. $name = $column['Field'];
  59. $tmpl = "'{$name}' => Helper::{{method}}('{$name}'),<br/>";
  60. if (Helper::hasAnyString($column['Type'], ['decimal', 'double', 'float'])) {
  61. $method = 'getPostFloat';
  62. } elseif (Helper::hasAnyString($column['Type'], ['int'])) {
  63. $method = 'getPostInt';
  64. } elseif (Helper::hasAnyString($column['Type'], ['datetime'])) {
  65. $method = 'getPostDatetime';
  66. } elseif (Helper::hasAnyString($column['Type'], ['date'])) {
  67. $method = 'getPostDate';
  68. } else {
  69. $method = 'getPostString';
  70. }
  71. echo str_replace('{{method}}', $method, $tmpl);
  72. if ($column['Null'] == 'NO') {
  73. $notNullField[] = $name;
  74. }
  75. if ($column['Default'] != null || $method == 'getPostInt') {
  76. $allowEmptyField[] = $name;
  77. }
  78. }
  79. echo '];<br/><br/>';
  80. echo '$notNullField = ' . json_encode($notNullField) . ';<br/>';
  81. echo '$allowEmptyField = ' . json_encode($allowEmptyField) . ';<br/>';
  82. }
  83. public function actionsqlToTs()
  84. {
  85. $table = Helper::getGetString('t1');
  86. if (!$table) {
  87. Helper::error('参数错误');
  88. }
  89. $table = strtolower($table);
  90. $table1 = DB::formTableName($table);
  91. $sql = "show full columns from {$table1}";
  92. $taleInfo = \Yii::app()->db->createCommand($sql)->queryAll();
  93. if (!$taleInfo) {
  94. Helper::error('该表不存在');
  95. }
  96. $excludeField = ['create_date', 'update_date', 'is_delete'];
  97. echo $this->getTsInterFace($table, $taleInfo, $excludeField);
  98. // echo $this->getTableHtml($taleInfo, $excludeField);
  99. $editTmpl = file_get_contents(PROJECT_PATH . '/protected/runtime/edit.tmpl');
  100. $fromExcludeField = ['create_date', 'update_date', 'is_delete', 'id', 'city', 'area', 'province'];
  101. echo $this->getTsInterFace($table, $taleInfo, $fromExcludeField);
  102. $formDefault = $this->getFormDefault($taleInfo, $fromExcludeField);
  103. list($template, $rule) = $this->getFormAndRule($table, $taleInfo, $fromExcludeField);
  104. $editTmpl = str_replace(
  105. ['{{template}}', '{{table}}', '{{formDefault}}', '{{formRule}}', '{{ucTable}}'],
  106. [$template, $table, $formDefault, $rule, ucfirst($table)],
  107. $editTmpl
  108. );
  109. $filePath = PROJECT_PATH . "/web/src/views/{$table}/edit.vue";
  110. file_put_contents($filePath, $editTmpl);
  111. // 格式化代码
  112. echo "<h4>命令后执行下面代码</h4>";
  113. echo "<p style='color: red;'>npx prettier --write $filePath</p>";
  114. }
  115. /**
  116. * 生成ts接口
  117. * @param string $table
  118. * @param array $tableFieldArr
  119. * @param array $excludeField 排除的字段
  120. * @return string
  121. */
  122. private function getTsInterFace(string $table, array $tableFieldArr, array $excludeField = []): string
  123. {
  124. $content = '';
  125. foreach ($tableFieldArr as $column) {
  126. if (in_array($column['Field'], $excludeField)) {
  127. continue;
  128. }
  129. $type = $this->getTypeByColumn($column);
  130. $temp = $column['Field'] . ": {$type}";
  131. $comment = $column['Comment'] ? " // {$column['Comment']}" : '';
  132. $content.= $temp . " {$comment}, <br/>";
  133. }
  134. $template = <<<typescript
  135. interface {$table} {<br/>
  136. $content}<br/><br/>
  137. typescript;
  138. return $template;
  139. }
  140. private function getTypeByColumn(array $column) :string
  141. {
  142. $type = 'string';
  143. if (str_contains($column['Field'], 'ids')) {
  144. $type = 'number[]';
  145. } elseif (Helper::hasAnyString($column['Type'], ['int', 'decimal', 'double', 'float'])) {
  146. if (Helper::hasAnyString($column['Field'], ['is_', 'can_', 'has_', 'status', '_status', 'type'])) {
  147. $type = '0|1';
  148. } else {
  149. $type = 'number';
  150. }
  151. }
  152. return $type;
  153. }
  154. /**
  155. * 生成form默认值
  156. * @param array $tableFieldArr
  157. * @param array $excludeField 排除的字段
  158. * @return string
  159. */
  160. private function getFormDefault(array $tableFieldArr, array $excludeField = []): string
  161. {
  162. $content = '';
  163. foreach ($tableFieldArr as $column) {
  164. if (in_array($column['Field'], $excludeField)) {
  165. continue;
  166. }
  167. $type = $this->getTypeByColumn($column);
  168. if (in_array($type, ['number', '0|1'])) {
  169. $default = $column['Default'] ? : 0;
  170. $content.= $column['Field'] . ": {$default},";
  171. } else {
  172. $default = $column['Default'] ? : '';
  173. $content.= $column['Field'] . ": '{$default}',";
  174. }
  175. }
  176. return $content;
  177. }
  178. /**
  179. * 生成form验证规则 前后端需要保持一致
  180. * @param string $table
  181. * @param array $tableFieldArr
  182. * @param array $excludeField 排除的字段
  183. * @return string
  184. */
  185. private function getFormAndRule(string $table, array $tableFieldArr, array $excludeField = []): array
  186. {
  187. $html = '';
  188. $ruleHtml = '';
  189. foreach ($tableFieldArr as $column) {
  190. if (in_array($column['Field'], $excludeField)) {
  191. continue;
  192. }
  193. $comment = explode(' ', $column['Comment'])[0];
  194. $rule = [];
  195. if ($column['Null'] == 'NO') {
  196. $rule[] = "{ required: true, message: '请输入{$comment}', trigger: 'blur' }";
  197. }
  198. $type = $this->getTypeByColumn($column);
  199. if ($type == 'string') {
  200. // 图片处理
  201. if (Helper::hasAnyString($column['Field'], ['img', 'image'])) {
  202. // 单张图片
  203. } elseif (Helper::hasAnyString($column['Field'], ['images', 'imgs'])) {
  204. // 多张图片
  205. } elseif (Helper::hasAnyString($column['Field'], ['_id'])) {
  206. // select
  207. } elseif (Helper::hasAnyString($column['Field'], ['ids'])) {
  208. // 多选框
  209. } else {
  210. // input框
  211. $inputType = 'text';
  212. $max = $this->getMaxLength($column);
  213. if ($max) {
  214. $min = Helper::hasAnyString($column['Field'], ['']) ? 0 : 0;
  215. if ($min) {
  216. $rule[] = "{ min: {$min}, max: {$max}, message: '长度在{$min}到{$max}个字符', trigger: 'blur' }";
  217. } else {
  218. $rule[] = "{ max: {$max}, message: '长度最多{$max}个字符', trigger: 'blur' }";
  219. }
  220. if ($max > 64) {
  221. $inputType = 'textarea';
  222. }
  223. }
  224. $html.= $this->getInputHtml($comment, $column['Field'], $inputType, $max);
  225. }
  226. } elseif ($type == 'number') {
  227. $html.= $this->getInputHtml($comment, $column['Field'], 'number');
  228. } elseif ($type == '0|1') {
  229. $rule = '';
  230. $html.= $this->getSelectHtml($comment, $column['Field'], $this->getSelectData($column, $type));
  231. }
  232. if ($rule) {
  233. $rule = implode(',', $rule);
  234. $ruleHtml.= $column['Field'] . ": [{$rule}],";
  235. }
  236. }
  237. $content = <<<typescript
  238. <template>
  239. <ElForm ref="formRef" :model="formData" :rules="rules" label-width="auto">
  240. <el-row :gutter="20">
  241. {$html}
  242. <el-col :span="24">
  243. <ElFormItem label=" " prop="">
  244. <ElButton type="primary" @click="handleSubmit">提交</ElButton>
  245. </ElFormItem>
  246. </el-col>
  247. </el-row>
  248. </ElForm>
  249. </template>
  250. typescript;
  251. return [$content, $ruleHtml];
  252. }
  253. public function getInputHtml(string $name, string $field, string $type, int $maxLength = 0): string
  254. {
  255. $maxLengthHtml = '';
  256. if ($type != 'number' && $maxLength > 0) {
  257. $maxLengthHtml = "maxlength='{$maxLength}'";
  258. }
  259. $elHtml = $type != 'textarea' ? ':xs="24" :lg="8" :sm="12"' : ':span=24';
  260. return <<<input
  261. <el-col {$elHtml}>
  262. <ElFormItem label="{$name}" prop="{$field}">
  263. <ElInput v-model="formData.{$field}" $maxLengthHtml type="{$type}"/>
  264. </ElFormItem>
  265. </el-col>
  266. input;
  267. }
  268. public function getSelectHtml(string $name, string $field, array $selectData, bool $multi = false): string
  269. {
  270. if (!$selectData) {
  271. return [];
  272. }
  273. $data = '';
  274. foreach ($selectData as $key => $item) {
  275. if (is_numeric($key)) {
  276. $data.= "{label: '{$item}', value: {$key}}, ";
  277. } else {
  278. $data.= "{label: '{$item}', value: '{$key}'},";
  279. }
  280. }
  281. return <<<select
  282. <el-col :xs="24" :lg="8" :sm="12">
  283. <ElFormItem label="{$name}" prop="{$field}">
  284. <el-select v-model="formData.{$field}" placeholder="请选择">
  285. <el-option v-for="item in [{$data}]" :key="item.value" :value="item.value" :label="item.label"/>
  286. </el-select>
  287. </ElFormItem>
  288. </el-col>
  289. select;
  290. }
  291. /**
  292. * 生成table字段配置
  293. * @param array $tableFieldArr
  294. * @param array $excludeField 排除的字段
  295. * @return string
  296. */
  297. private function getTableHtml(array $tableFieldArr, $excludeField = []): string
  298. {
  299. $tableContent = '';
  300. foreach ($tableFieldArr as $column) {
  301. if (in_array($column['Field'], $excludeField)) {
  302. continue;
  303. }
  304. $commentArr = explode(' ', $column['Comment']);
  305. $JsTableArr = ['prop' => $column['Field'], 'label' => $commentArr[0]];
  306. // 长字段列表需要添加showOverflowTooltip
  307. if ($this->getMaxLength($column) || $this->isTextField($column)) {
  308. $JsTableArr['showOverflowTooltip'] = true;
  309. }
  310. if (str_contains($column['Field'], 'ids')) {
  311. $JsTableArr = []; // TODO:这种一般是tag集合
  312. } elseif (Helper::hasAnyString($column['Field'], ['is', 'can', 'has', 'status'])) {
  313. if (count($commentArr) == 3) {
  314. $arr1 = explode('-', $commentArr[1]);
  315. $arr2 = explode('-', $commentArr[2]);
  316. $tempArr[intval($arr1[0])] = $arr1[1];
  317. $tempArr[intval($arr2[0])] = $arr2[1];
  318. } else {
  319. $tempArr = [0 => '否', 1 => '是'];
  320. }
  321. $JsTableArr['formatter'] = <<<HTML
  322. (row) => {<br/>
  323. return h(ElTag, { type: row.{$column['Field']} ? 'success' : 'danger' }, () => row.{$column['Field']} ? '{$tempArr[1]}' : '{$tempArr[0]}')<br/>
  324. }
  325. HTML;
  326. }
  327. $tableContent.= $this->getHtmlWithJsTableArr($JsTableArr);
  328. }
  329. $template = <<<typescript
  330. {<br/>
  331. $tableContent}<br/><br/>
  332. typescript;
  333. return $template;
  334. }
  335. private function getMaxLength(array $column):int
  336. {
  337. preg_match('/(\d+)/', $column['Type'], $match);
  338. return $match[0] ?? 0;
  339. }
  340. private function isNumberFiled(?string $type = null)
  341. {
  342. return $type == 'number' || str_contains($type, '|');
  343. }
  344. private function isTextField(array $column):int
  345. {
  346. return Helper::hasAnyString($column['Type'], ['text']);
  347. }
  348. public function getSelectData(array $column, ?string $type = null):array
  349. {
  350. if (!$type) {
  351. $type = $this->getTypeByColumn($column);
  352. }
  353. if (!$this->isNumberFiled($type)) {
  354. return [];
  355. }
  356. $arr = [];
  357. preg_match_all('/(\d+\-\S+)/', $column['Comment'], $match);
  358. if ($match) {
  359. foreach ($match[0] as $matchItem) {
  360. list($key, $value) = explode('-', $matchItem);
  361. $arr[$key] = $value;
  362. }
  363. }
  364. return $arr;
  365. }
  366. private function getHtmlWithJsTableArr(array $arr): string
  367. {
  368. if (!$arr) {
  369. return '';
  370. }
  371. $str = '{';
  372. foreach ($arr as $k => $v) {
  373. $str.= " {$k}:{$v},";
  374. }
  375. return trim($str, ',') . ' },<br/>';
  376. }
  377. public function actionSetPassword()
  378. {
  379. $phone = Helper::getPostString('phone');
  380. $code = Helper::getPostString('code');
  381. $password = Helper::getPostString('password');
  382. if (!Helper::isPhone($phone)) {
  383. Helper::error('手机号码格式错误');
  384. }
  385. if (!$code || !$password) {
  386. Helper::error('参数错误');
  387. }
  388. if (RedisInstance::getInstance()->get('user_code:'.$phone) != $code) {
  389. Helper::error('验证码错误');
  390. }
  391. $id = DB::getScalerWithCriteria('useradmin', DbCriteria::simpleCompare(['phone' => $phone])->setSelect('id'));
  392. if (!$id) {
  393. Helper::error('该手机号用户不存在');
  394. }
  395. DB::updateById('useradmin', ['password' => md5($password)], $id);
  396. Helper::ok();
  397. }
  398. /**
  399. * ajax提交图片temp临时存放
  400. */
  401. public function actionUploadtemp(){
  402. $type = strtolower($_FILES['surface']['type']);
  403. $size = $_FILES['surface']['size'];
  404. $maxsize = isset($_POST['imgmaxsize'])?$_POST['imgmaxsize']:'512000';
  405. $imagetype = isset($_POST['type'])?$_POST['type']:'all';
  406. if(stristr($type, 'png') || stristr($type, 'jpeg') || stristr($type, 'jpg')) {
  407. if($size > $maxsize){
  408. echo 'size';//图片容量超过200K
  409. }else{
  410. if(stristr($type, 'png')) {
  411. $extention = '.png';
  412. }else{
  413. $extention = '.jpg';
  414. }
  415. $temp_words = LewaimaiString::create_noncestr(32);//随机图片名
  416. $temp_url= 'public/temp/images/admin_'.Yii::app()->user->_id . '/';
  417. if(!is_dir($temp_url)){
  418. mkdir($temp_url,0755,true);
  419. }
  420. $temp_name = $temp_url.$temp_words.$extention;
  421. $time = LewaimaiString:: GetOutTradeNo();
  422. if(copy($_FILES['surface']['tmp_name'], $temp_name)){
  423. chmod($temp_name,0755);
  424. $cdn_url = getUpyunUploadPath();
  425. $fileName = $temp_words . $extention;
  426. $surfaceimg = $cdn_url.$fileName;
  427. LewaimaiImageUpload('./'.$temp_name,$surfaceimg);
  428. echo $surfaceimg;
  429. //清除本地文件
  430. LewaimaiUtility::clearTempimages();
  431. }else{
  432. echo 'error';//出错
  433. }
  434. }
  435. }else{
  436. echo 'suffix';//格式不对
  437. }
  438. exit;
  439. }
  440. public function actionCropImg()
  441. {
  442. $type = strtolower($_FILES['surface']['type']);
  443. $size = $_FILES['surface']['size'];
  444. $maxsize = isset($_POST['imgmaxsize'])?$_POST['imgmaxsize']:'512000';
  445. $imagetype = isset($_POST['type'])?$_POST['type']:'all';
  446. if(stristr($type, 'png') || stristr($type, 'jpeg') || stristr($type, 'jpg')) {
  447. if($size > $maxsize){
  448. echo 'size';//图片容量超过200K
  449. }else{
  450. if(stristr($type, 'png')) {
  451. $extention = '.png';
  452. }else{
  453. $extention = '.jpg';
  454. }
  455. $temp_words = LewaimaiString::create_noncestr(32);//随机图片名
  456. $temp_url= 'public/temp/images/admin_'.Yii::app()->user->_id . '/';
  457. if(!is_dir($temp_url)){
  458. mkdir($temp_url,0755,true);
  459. }
  460. $temp_name = $temp_url.$temp_words.$extention;
  461. $time = LewaimaiString:: GetOutTradeNo();
  462. $file = $_FILES['surface']['tmp_name'];
  463. if(isset($_POST['avatar_src']) && isset($_POST['avatar_data'])) {
  464. require_once 'CropImage.php';
  465. $crop = new CropImage($_POST['avatar_src'], $_POST['avatar_data'], $_FILES['surface']);
  466. $file = $crop->getResult();
  467. }
  468. if(copy($file, $temp_name)){
  469. chmod($temp_name,0755);
  470. $cdn_url = getUpyunUploadPath();
  471. $fileName = $temp_words . $extention;
  472. $surfaceimg = $cdn_url.$fileName;
  473. LewaimaiImageUpload('./'.$temp_name,$surfaceimg);
  474. echo $surfaceimg;
  475. //清除本地文件
  476. LewaimaiUtility::clearTempimages();
  477. }else{
  478. echo 'error';//出错
  479. }
  480. }
  481. }else{
  482. echo 'suffix';//格式不对
  483. }
  484. exit;
  485. }
  486. }