ModelManage.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. <?php
  2. namespace app\admin\controller\base\models;
  3. /**
  4. * @title : 模型管理控制器
  5. * @desc :
  6. * @Author : Rock
  7. * @Date : 2023-04-11 20:14:01
  8. */
  9. use app\admin\controller\Base;
  10. use app\common\model\base\models\ModelManage as ModelManageModel;
  11. use app\common\model\base\models\ModelFields;
  12. use app\common\model\base\models\ModelServer;
  13. use app\common\model\base\models\ControllerServer;
  14. use app\common\model\base\models\ValidateServer;
  15. use app\common\model\base\models\VueIndexServer;
  16. use app\common\model\base\models\VueEditServer;
  17. use app\common\model\base\models\VueServer;
  18. use think\facade\Db;
  19. class ModelManage extends Base
  20. {
  21. protected $model = null;
  22. protected $fieldModel = null;
  23. protected $noNeedLogin = ['getTableList','getTableFields'];
  24. public function initialize()
  25. {
  26. parent::initialize();
  27. $this->model = new ModelManageModel;
  28. $this->fieldsModel = new ModelFields;
  29. }
  30. /**
  31. * @title: 创建统一查询条件
  32. * @desc: 描述
  33. * @return {*}
  34. * @author: Rock
  35. * @method: POST
  36. * @Date: 2023-04-12 10:54:48
  37. */
  38. private function createWhere()
  39. {
  40. $data = array_intersect_key($this->request->only(['status', 'keyword']), array_flip(['status', 'keyword']));
  41. return array_filter([
  42. !empty($data['status']) ? ['status', '=', $data['status']] : null,
  43. !empty($data['keyword']) ? ['name|title', 'LIKE', "%{$data['keyword']}%"] : null
  44. ]);
  45. }
  46. /**
  47. * @title: 获取模型列表
  48. * @desc: 描述
  49. * @param {int} {pageNo} {0} {页码}
  50. * @param {int} {pageSize} {10} {每页数量}
  51. * @param {int} {status} {} {模型状态,1=启用,2=停用}
  52. * @param {string} {keyword} {10} {搜索关键词,可搜索模型名称,数据表名}
  53. * @return {*}
  54. * @author: Rock
  55. * @method: POST
  56. * @Date: 2023-04-12 10:58:30
  57. */
  58. public function getList(int $pageNo = 0,int $pageSize = 10)
  59. {
  60. $where = $this->createWhere();
  61. if(!empty($pageNo)){
  62. $res = $this->model->where($where)->paginate(['page'=>$pageNo,'list_rows'=>$pageSize]);
  63. return pageRes(1,"获取成功",$res->total(),$res->items());
  64. }else{
  65. $list = $this->model->where($where)->select();
  66. return res(1,"获取成功",$list);
  67. }
  68. }
  69. /**
  70. * @title: 新增/修改模型
  71. * @desc: 描述
  72. * @return {*}
  73. * @author: Rock
  74. * @method: POST
  75. * @Date: 2023-04-12 10:59:29
  76. */
  77. public function doEdit()
  78. {
  79. $data = $this->request->param();
  80. $name = $data['name'];
  81. $title = $data['title'];
  82. $isExists = ModelManageModel::checkTable($name);
  83. if(strpos($name,'system_')===0){
  84. return res(2,"表名不能以system_开头");
  85. }
  86. try{
  87. Db::startTrans();
  88. if(empty($data['id'])){
  89. if($isExists){
  90. return res(2,"表名已存在");
  91. }
  92. $this->model->replace()->save($data);
  93. $id = $this->model->id;
  94. ModelManageModel::createTable($id);//创建表
  95. }else{
  96. $oldname = $this->model->where('id',$data['id'])->value('name');
  97. $this->model->replace()->save($data);
  98. $id = $this->model->id;
  99. if($name!=$oldname){
  100. if($isExists){
  101. Db::rollback();
  102. return res(2,"新表名已存在");
  103. }else{
  104. $this->fieldsModel->where('model_name',$oldname)->update(['model_name'=>$name,'model_title'=>$title]);
  105. }
  106. }
  107. ModelManageModel::updateTable($id,$oldname);//修改表
  108. }
  109. Db::commit();
  110. return res(1,"编辑成功");
  111. }catch(\Exception $e){
  112. Db::rollback();
  113. return res(2,"编辑失败",$e->getMessage(),$e->getTrace());
  114. }
  115. }
  116. /**
  117. * @title: 删除模型
  118. * @desc: 描述
  119. * @param {int} {id} {} {模型ID}
  120. * @param {array} {deleteList} {} {待删除的内容}
  121. * @return {*}
  122. * @author: Rock
  123. * @method: POST
  124. * @Date: 2023-04-12 10:59:44
  125. */
  126. public function doDelete(int $id=0,array $deleteList = [])
  127. {
  128. if(!$id){
  129. return res(2,"参数错误");
  130. }
  131. if(empty($deleteList)){
  132. return res(2,"请选择待删除内容");
  133. }
  134. try{
  135. Db::startTrans();
  136. // 数据表
  137. if(in_array('table',$deleteList)){
  138. ModelManageModel::deleteTable($id);
  139. }
  140. //菜单及菜单请求
  141. if(in_array('menu',$deleteList)){
  142. VueServer::deleteMenu($id);
  143. }
  144. // Model文件
  145. if(in_array('model',$deleteList)){
  146. ModelServer::deleteFile($id);
  147. }
  148. // controller文件
  149. if(in_array('controller',$deleteList)){
  150. ControllerServer::deleteFile($id);
  151. }
  152. // validate文件
  153. if(in_array('validate',$deleteList)){
  154. ValidateServer::deleteFile($id);
  155. }
  156. // vue列表页
  157. if(in_array('vue',$deleteList)){
  158. VueIndexServer::deleteIndex($id);
  159. }
  160. // vue编辑/新增页
  161. if(in_array('edit',$deleteList)){
  162. VueEditServer::deleteEdit($id);
  163. }
  164. // api接口文件
  165. if(in_array('api',$deleteList)){
  166. VueServer::deleteAPI($id);
  167. }
  168. // 选择器组件
  169. if(in_array('selector',$deleteList)){
  170. VueServer::deleteSelector($id);
  171. }
  172. // 模型及模型字段
  173. if(in_array('modelinfo',$deleteList)){
  174. $info = ModelManageModel::find($id);
  175. ModelFields::destroy(function($query)use($info){
  176. $query->where('model_name',$info->name);
  177. });
  178. $info->delete();
  179. }
  180. Db::commit();
  181. return res(1,"删除成功");
  182. }catch(\Exception $e){
  183. Db::rollback();
  184. return res(2,"删除失败",$e->getMessage(),$e->getTrace());
  185. }
  186. }
  187. /**
  188. * @title: 获取模型管理可选项
  189. * @desc: 描述
  190. * @return {*}
  191. * @author: Rock
  192. * @method: POST
  193. * @Date: 2023-04-12 10:59:54
  194. */
  195. public function getOptions()
  196. {
  197. $data = [
  198. 'statusList' => ModelManageModel::statusList(),
  199. 'engineList' => ModelManageModel::engineList(),
  200. ];
  201. return res(1,"获取成功",$data);
  202. }
  203. /**
  204. * @title: 启用禁用模型
  205. * @desc: 描述
  206. * @param {int} {id} {} {模型ID}
  207. * @return {*}
  208. * @author: Rock
  209. * @method: POST
  210. * @Date: 2023-04-12 11:23:47
  211. */
  212. public function changeStatus(int $id=0)
  213. {
  214. $info = ModelManageModel::find($id);
  215. if(!$info){
  216. return res(2,"记录不存在");
  217. }
  218. $info->status = abs(3 * $info->status - 5);
  219. $info->save();
  220. return res(1,"操作成功");
  221. }
  222. /**
  223. * @title: 生成相关代码
  224. * @desc: 含Model,Controller,View
  225. * @param {int} {id} {} {模型ID}
  226. * @param {array} {createList} {} {需要生成代码的模块,可选:model,controller,validate,vue,api,edit,menu}
  227. * @return {*}
  228. * @author: Rock
  229. * @method: POST
  230. * @Date: 2023-04-18 10:27:00
  231. */
  232. public function createCode(int $id = 0,array $createList=[])
  233. {
  234. try{
  235. // 模型文件
  236. if(in_array('model',$createList)){
  237. ModelServer::createModelFile($id);
  238. }
  239. // 控制器文件
  240. if(in_array('controller',$createList)){
  241. ControllerServer::createControllerFile($id,$this->userinfo['name'],$createList);
  242. }
  243. // 验证器文件
  244. if(in_array('validate',$createList)){
  245. ValidateServer::createValidateFile($id);
  246. }
  247. // Vue列表文件
  248. if(in_array('vue',$createList)){
  249. VueIndexServer::createIndexFile($id);
  250. }
  251. // API接口文件
  252. if(in_array('api',$createList)){
  253. VueServer::createApiJS($id);
  254. }
  255. //编辑弹窗文件
  256. if(in_array('edit',$createList)){
  257. VueEditServer::createEditFile($id);
  258. }
  259. // 菜单及菜单请求
  260. if(in_array('menu',$createList)){
  261. $res = VueServer::createMenu($id);
  262. if(!$res){
  263. return res(2,"生成失败",$res);
  264. }
  265. }
  266. // 生成选择器
  267. if(in_array('selector',$createList)){
  268. $res = VueServer::createSelector($id);
  269. if(!$res){
  270. return res(2,"生成失败",$res);
  271. }
  272. }
  273. return res(1,"文件生成成功");
  274. }catch(\Exception $e){
  275. $msg = $e->getMessage();
  276. if(false!==strpos($msg,'mkdir(): Permission denied')){
  277. return res(2,"创建文件夹时没有权限");
  278. }
  279. return res(2,"生成失败",$e->getMessage(),$e->getTrace());
  280. }
  281. }
  282. /**
  283. * @title: 复制模型
  284. * @desc: 描述
  285. * @param {int} {id} {} {模型ID}
  286. * @return {*}
  287. * @author: Rock
  288. * @method: POST
  289. * @Date: 2023-04-25 11:29:21
  290. */
  291. public function doCopy(int $id)
  292. {
  293. $info = $this->model->find($id);
  294. if(!$info){
  295. return res(2,"未找到模型");
  296. }
  297. $model_name = $info->name;
  298. $newModelName = $model_name.'_copy';
  299. $fieldList = ModelFields::where('model_name',$model_name)->select()->toArray();
  300. $modelData = $info->toArray();
  301. unset($modelData['id']);
  302. $modelData['name'] = $newModelName;
  303. $modelData['title'] .= '副本';
  304. $fieldData = [];
  305. foreach($fieldList as $item){
  306. unset($item['field_id']);
  307. $item['model_name'] = $newModelName;
  308. $item['model_title'] = $modelData['title'].'副本';
  309. $fieldData[] = $item;
  310. }
  311. try{
  312. Db::startTrans();
  313. $this->model->replace()->save($modelData);
  314. (new ModelFields)->replace()->saveAll($fieldData);
  315. ModelManageModel::copyTable($id);//复制表
  316. Db::commit();
  317. return res(1,"复制成功,请生成代码");
  318. }catch(\Exception $e){
  319. Db::rollback();
  320. return res(2,"复制失败",$e->getMessage(),$e->getTrace());
  321. }
  322. }
  323. /**
  324. * @title: 获取未生成模型的数据表列表
  325. * @desc: 获取未生成模型的数据表列表,不包含system_开头的表及已生成模型的表
  326. * @return {*}
  327. * @author: Rock
  328. * @method: POST
  329. * @Date: 2023-07-24 09:54:22
  330. */
  331. public function getTableList()
  332. {
  333. $sql = "SHOW TABLE STATUS";
  334. $res = Db::query($sql);
  335. $list = [];
  336. $hasList = $this->model->column('name');
  337. foreach($res as $item){
  338. $table = $item['Name'];
  339. // 排除系统表及已生成模型的表
  340. if(strpos($table,'system_')!==0 && !in_array($table,$hasList)){
  341. $list[] = $item;
  342. }
  343. }
  344. return res(1,'获取成功',$list);
  345. }
  346. /**
  347. * @title: 获取数据表字段
  348. * @desc: 描述
  349. * @param {string} {table} {} {数据表名}
  350. * @return {*}
  351. * @author: Rock
  352. * @method: POST
  353. * @Date: 2023-07-24 10:50:29
  354. */
  355. public function getTableFields(string $table='')
  356. {
  357. if(empty($table)){
  358. return res(2,"请选择数据表");
  359. }
  360. // 获取表注释
  361. $sql = "SELECT TABLE_COMMENT FROM information_schema.TABLES WHERE table_name = '$table'";
  362. $res = Db::query($sql);
  363. $tableTitle = $res?$res[0]['TABLE_COMMENT']:'';
  364. // 获取表字段
  365. $sql = "SHOW FULL COLUMNS FROM `$table`";
  366. $res = Db::query($sql);
  367. $list = [];
  368. foreach($res as $index=>$item){
  369. // 处理成模型字段需要的数据
  370. $field = $item['Field'];
  371. // 排除创建、更新、删除时间及主键
  372. if(in_array($field,['create_at','update_at','delete_at']) || 'PRI'==$item['Key']){
  373. continue;
  374. }
  375. $fl = strpos($item['Type'],'(');
  376. $el = strpos($item['Type'],')');
  377. $db_type = $fl!==false?substr($item['Type'],0,$fl):$item['Type'];
  378. $len = $fl!==false&&$el!==false?intval(substr($item['Type'],$fl+1,$el-$fl-1)):0;
  379. $list[] = [
  380. 'model_name'=>$table,//模型名称
  381. 'model_title'=>$tableTitle,//模型标题
  382. 'title'=>$item['Comment'],//字段标题
  383. 'field'=>$item['Field'],//字段名称
  384. 'field_type'=>'string',//字段类型,默认都是string,页面上修改
  385. 'db_type'=>$db_type,//数据类型
  386. 'len'=>$len,//数据长度
  387. 'show_in_table'=>1,//是否显示到表格中,默认显示
  388. 'search_type'=>'keyword',//搜索类型,默认关键字搜索
  389. 'status'=>1,//字段状态,默认可用
  390. 'weigh'=>$index+1,//字段排序,默认为序号
  391. 'rule'=>"require|chsAlphaNum|length:2,255",//验证规则,默认必填
  392. 'content'=>[],//可选项,默认为空
  393. 'content_txt'=>'',//可选项,默认为空
  394. 'default_value'=>$item['Default'],//默认值
  395. 'extra_rule'=>[],//组件属性
  396. 'extra_rule_txt'=>"placeholder|请输入文本\nclearable|false",//组件属性文本
  397. 'is_relation'=>2,//是否关联,默认不关联
  398. 'relation_model'=>'',//关联模型
  399. 'relation_field'=>'',//关联字段
  400. 'relation_show'=>'',//关联显示字段
  401. 'relation_dic_group'=>'',//关联字典分组
  402. 'fieldList'=>[],//可供选择的关联字段
  403. ];
  404. }
  405. return res(1,"获取成功",$list,$res);
  406. }
  407. /**
  408. * @title: 保存从数据表导入的模型
  409. * @desc: 描述
  410. * @return {*}
  411. * @author: Rock
  412. * @method: POST
  413. * @Date: 2023-07-25 15:40:29
  414. */
  415. public function saveFromDb()
  416. {
  417. $data = $this->request->param();
  418. try{
  419. $this->model->startTrans();
  420. $modelInfo = $data['modelInfo'];
  421. $modelFields = $data['fieldList'];
  422. $this->model->replace()->save($modelInfo);
  423. (new ModelFields)->replace()->saveAll($modelFields);
  424. $this->model->commit();
  425. return res(1,"保存成功,请前往模型列表生成代码",$data);
  426. }catch(\Exception $e){
  427. $this->model->rollback();
  428. return res(2,"保存失败:".$e->getMessage(),$e->getTrace());
  429. }
  430. }
  431. public function __call($name,$arguments)
  432. {
  433. return res(2,"方法{$name}不存在");
  434. }
  435. }