SystemCrud.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\adminapi\controller\v1\setting;
  12. use app\adminapi\controller\AuthController;
  13. use app\Request;
  14. use app\services\system\log\SystemFileServices;
  15. use app\services\system\SystemCrudDataService;
  16. use app\services\system\SystemCrudListServices;
  17. use app\services\system\SystemCrudServices;
  18. use app\services\system\SystemMenusServices;
  19. use app\services\system\SystemRouteServices;
  20. use crmeb\services\CacheService;
  21. use crmeb\services\crud\enum\FormTypeEnum;
  22. use crmeb\services\crud\Make;
  23. use crmeb\services\crud\Service;
  24. use crmeb\services\FileService;
  25. use think\facade\App;
  26. use think\facade\Db;
  27. use think\facade\Env;
  28. use think\helper\Str;
  29. use think\Response;
  30. /**
  31. * Class SystemCrud
  32. * @author 等风来
  33. * @email 136327134@qq.com
  34. * @date 2023/4/6
  35. * @package app\adminapi\controller\v1\setting
  36. */
  37. class SystemCrud extends AuthController
  38. {
  39. /**
  40. * SystemCrud constructor.
  41. * @param App $app
  42. * @param SystemCrudServices $services
  43. */
  44. public function __construct(App $app, SystemCrudServices $services)
  45. {
  46. parent::__construct($app);
  47. $this->services = $services;
  48. }
  49. /**
  50. * @return Response
  51. * @author 等风来
  52. * @email 136327134@qq.com
  53. * @date 2023/4/11
  54. */
  55. public function index()
  56. {
  57. return app('json')->success($this->services->getList());
  58. }
  59. /**
  60. * 验证路径
  61. * @param $data
  62. * @return bool
  63. * @author wuhaotian
  64. * @email 442384644@qq.com
  65. * @date 2024/2/19
  66. */
  67. public function crudVerifyPath($data)
  68. {
  69. if (strpos($data['controller'], 'app' . DS . 'adminapi' . DS . 'controller' . DS . 'crud' . DS) !== 0) return false;
  70. if (strpos($data['validate'], 'app' . DS . 'adminapi' . DS . 'validate' . DS . 'crud' . DS) !== 0) return false;
  71. if (strpos($data['service'], 'app' . DS . 'services' . DS . 'crud' . DS) !== 0) return false;
  72. if (strpos($data['dao'], 'app' . DS . 'dao' . DS . 'crud' . DS) !== 0) return false;
  73. if (strpos($data['model'], 'app' . DS . 'model' . DS . 'crud' . DS) !== 0) return false;
  74. if (strpos($data['route'], 'app' . DS . 'adminapi' . DS . 'route' . DS . 'crud' . DS) !== 0) return false;
  75. if (strpos($data['router'], 'router' . DS . 'modules' . DS . 'crud' . DS) !== 0) return false;
  76. if (strpos($data['api'], 'api' . DS . 'crud' . DS) !== 0) return false;
  77. if (strpos($data['pages'], 'pages' . DS . 'crud' . DS) !== 0) return false;
  78. return true;
  79. }
  80. /**
  81. * @return Response
  82. * @author 等风来
  83. * @email 136327134@qq.com
  84. * @date 2023/4/11
  85. */
  86. public function save(SystemCrudDataService $service, $id = 0)
  87. {
  88. $data = $this->request->postMore([
  89. ['pid', 0],//上级菜单id
  90. ['menuName', ''],//菜单名
  91. ['tableName', ''],//表名
  92. ['modelName', ''],//模块名称
  93. ['tableComment', ''],//表备注
  94. ['tableField', []],//表字段
  95. ['tableIndex', []],//索引
  96. ['filePath', []],//生成文件位置
  97. ['isTable', 0],//是否生成表
  98. ['deleteField', []],//删除的表字段
  99. ]);
  100. if (!preg_match('/^[\x{4e00}-\x{9fa5}a-zA-Z]+$/u', $data['menuName'])) return app('json')->fail('菜单名称只能是中文或者英文');
  101. if (!preg_match('/^[\x{4e00}-\x{9fa5}a-zA-Z]+$/u', $data['modelName'])) return app('json')->fail('模块名称只能是中文或者英文');
  102. if (!preg_match('/^[a-zA-Z_]+$/u', $data['tableName'])) return app('json')->fail('表名称只能是英文和下划线组成');
  103. if (!$this->crudVerifyPath($data['filePath'])) return app('json')->fail('生成的文件位置有误,请检查后重新生成');
  104. $fromField = $searchField = $hasOneField = $columnField = $tableIndex = [];
  105. $dictionaryids = array_column($data['tableField'], 'dictionary_id');
  106. $dictionaryList = [];
  107. foreach ($dictionaryids as $dictionaryid) {
  108. $dictionaryList[$dictionaryid] = $service->selectList(['cid' => $dictionaryid], 'name as label,value')->toArray();
  109. }
  110. // if ($dictionaryids) {
  111. // $dictionaryList = $service->getColumn([['id', 'in', $dictionaryids]], 'value', 'id');
  112. // foreach ($dictionaryList as &$value) {
  113. // $value = is_string($value) ? json_decode($value, true) : $value;
  114. // }
  115. // } else {
  116. // $dictionaryList = [];
  117. // }
  118. foreach ($data['tableField'] as $item) {
  119. //判断字段长度
  120. if (in_array($item['field_type'], [FormTypeEnum::DATE_TIME, 'timestamp', 'time', 'date', 'year']) && $item['limit'] > 6) {
  121. return app('json')->fail('字段' . $item['field'] . '长度不能大于6');
  122. }
  123. if ($item['field_type'] == 'enum' && !is_array($item['limit'])) {
  124. return app('json')->fail('数据类型为枚举时,长度为数组类型');
  125. }
  126. //收集列表展示数据
  127. if ($item['is_table'] && !in_array($item['field_type'], ['primaryKey', 'addSoftDelete'])) {
  128. if (isset($item['primaryKey']) && !$item['primaryKey']) {
  129. $columnField[] = [
  130. 'field' => $item['field'],
  131. 'name' => $item['table_name'] ?: $item['comment'],
  132. 'type' => $item['from_type'],
  133. ];
  134. }
  135. }
  136. $name = $item['table_name'] ?: $item['comment'];
  137. $option = $item['options'] ?? (isset($item['dictionary_id']) ? ($dictionaryList[$item['dictionary_id']] ?? []) : []);
  138. //收集表单展示数据
  139. if ($item['from_type']) {
  140. if (!$name) {
  141. return app('json')->fail('列表名称不能为空', [], ['field' => $item['field']]);
  142. }
  143. if (!$option && in_array($item['from_type'], [FormTypeEnum::RADIO, FormTypeEnum::SELECT])) {
  144. return app('json')->fail('表单类型为radio或select时,options字段不能为空');
  145. }
  146. $fromField[] = [
  147. 'field' => $item['field'],
  148. 'type' => $item['from_type'],
  149. 'name' => $name,
  150. 'required' => $item['required'],
  151. 'option' => $option
  152. ];
  153. }
  154. //搜索
  155. if (!empty($item['search'])) {
  156. $searchField[] = [
  157. 'field' => $item['field'],
  158. 'type' => $item['from_type'],
  159. 'name' => $name,
  160. 'search' => $item['search'],
  161. 'options' => $option
  162. ];
  163. }
  164. //关联
  165. if (!empty($item['hasOne'])) {
  166. $hasOneField[] = [
  167. 'field' => $item['field'],
  168. 'hasOne' => $item['hasOne'] ?? '',
  169. 'name' => $name,
  170. ];
  171. }
  172. //索引
  173. if (!empty($item['index'])) {
  174. $tableIndex[] = $item['field'];
  175. }
  176. }
  177. if (!$fromField) {
  178. return app('json')->fail('表单类型至少选择一项');
  179. }
  180. if (!$columnField) {
  181. return app('json')->fail('列表展示数据生成失败');
  182. }
  183. $data['fromField'] = $fromField;
  184. $data['tableIndex'] = $tableIndex;
  185. $data['columnField'] = $columnField;
  186. $data['searchField'] = $searchField;
  187. $data['hasOneField'] = $hasOneField;
  188. if (!$data['tableName']) {
  189. return app('json')->fail('表名不能为空');
  190. }
  191. $this->services->createCrud($id, $data);
  192. return app('json')->success('功能创建成功');
  193. }
  194. /**
  195. * 获取创建文件的目录存放位置
  196. * @return Response
  197. * @author 等风来
  198. * @email 136327134@qq.com
  199. * @date 2023/4/11
  200. */
  201. public function getFilePath()
  202. {
  203. [$tableName] = $this->request->postMore([
  204. ['tableName', ''],
  205. ], true);
  206. if (!$tableName) {
  207. return app('json')->fail('表名不能为空');
  208. }
  209. if (in_array($tableName, SystemCrudServices::NOT_CRUD_TABANAME)) {
  210. return app('json')->fail('系统数据表,无法生成');
  211. }
  212. $routeName = 'crud/' . Str::snake($tableName);
  213. $key = 'id';
  214. $tableField = [];
  215. $field = $this->services->getColumnNamesList($tableName);
  216. foreach ($field as $item) {
  217. if ($item['primaryKey']) {
  218. $key = $item['name'];
  219. }
  220. $tableField[] = [
  221. 'field' => $item['name'],
  222. 'field_type' => $item['type'],
  223. 'primaryKey' => (bool)$item['primaryKey'],
  224. 'default' => $item['default'],
  225. 'limit' => $item['limit'],
  226. 'comment' => $item['comment'],
  227. 'required' => false,
  228. 'is_table' => false,
  229. 'table_name' => '',
  230. 'from_type' => '',
  231. ];
  232. }
  233. $make = $this->services->makeFile($tableName, $routeName, false, [
  234. 'menuName' => '',
  235. 'key' => $key,
  236. 'fromField' => [],
  237. 'columnField' => [],
  238. ]);
  239. $makePath = [];
  240. foreach ($make as $k => $item) {
  241. $makePath[$k] = $item['path'];
  242. }
  243. return app('json')->success(compact('makePath', 'tableField'));
  244. }
  245. /**
  246. * @param $id
  247. * @return Response
  248. * @author 等风来
  249. * @email 136327134@qq.com
  250. * @date 2023/4/12
  251. */
  252. public function read($id)
  253. {
  254. if (!$id) {
  255. return app('json')->fail('接口不存在');
  256. }
  257. $info = $this->services->get($id);
  258. if (!$info) {
  259. return app('json')->fail('数据不存在');
  260. }
  261. $routeName = 'crud/' . Str::snake($info->table_name);
  262. $column = $this->services->getColumnNamesList($info->table_name);
  263. $key = 'id';
  264. foreach ($column as $value) {
  265. if ($value['primaryKey']) {
  266. $key = $value['name'];
  267. break;
  268. }
  269. }
  270. $softDelete = false;
  271. foreach ((array)$info->field['tableField'] as $item) {
  272. if (isset($item['field_type']) && $item['field_type'] === 'addSoftDelete') {
  273. $softDelete = true;
  274. break;
  275. }
  276. }
  277. $make = $this->services->makeFile($info->table_name, $routeName, false, [
  278. 'menuName' => $info->name,
  279. 'modelName' => $info->model_name,
  280. 'tableField' => $info->field['tableField'] ?? [],
  281. 'key' => $key,
  282. 'softDelete' => $softDelete,
  283. 'fromField' => $info->field['fromField'] ?? [],
  284. 'columnField' => $info->field['columnField'] ?? [],
  285. 'searchField' => $info->field['searchField'] ?? [],
  286. 'hasOneField' => $info->field['hasOneField'] ?? [],
  287. ]);
  288. $data = [];
  289. foreach ($make as $key => $item) {
  290. if (in_array($key, ['pages', 'router', 'api'])) {
  291. $path = Make::adminTemplatePath() . $item['path'];
  292. } else {
  293. $path = app()->getRootPath() . $item['path'];
  294. }
  295. $item['name'] = $item['path'];
  296. try {
  297. $item['content'] = file_get_contents($path, LOCK_EX);
  298. $data[$key] = $item;
  299. } catch (\Throwable $e) {
  300. }
  301. }
  302. //调整排序
  303. $makeData = [];
  304. $names = [
  305. 'controller' => '控制器',
  306. 'validate' => '验证器',
  307. 'service' => '逻辑层',
  308. 'dao' => '数据库操作',
  309. 'model' => '模型层',
  310. 'route' => '后端路由',
  311. 'router' => '前端路由',
  312. 'api' => '前端接口',
  313. 'pages' => '前端页面'
  314. ];
  315. foreach ($names as $name => $value) {
  316. if (isset($data[$name])) {
  317. $data[$name]['file_name'] = $value;
  318. $makeData[] = $data[$name];
  319. }
  320. }
  321. $data = $makeData;
  322. $info = $info->toArray();
  323. //记录没有修改之前的数据
  324. foreach ((array)$info['field']['tableField'] as $key => $item) {
  325. $item['default_field'] = $item['field'];
  326. $item['default_limit'] = $item['limit'];
  327. $item['default_field_type'] = $item['field_type'];
  328. $item['default_comment'] = $item['comment'];
  329. $item['default_default'] = $item['default'];
  330. $item['default_default_type'] = $item['default_type'] ?? '1';
  331. $item['default_type'] = $item['default_type'] ?? '1';
  332. $item['is_table'] = !!$item['is_table'];
  333. $item['required'] = !!$item['required'];
  334. $item['index'] = isset($item['index']) && !!$item['index'];
  335. $item['primaryKey'] = isset($item['primaryKey']) ? (int)$item['primaryKey'] : 0;
  336. if (!isset($item['dictionary_id'])) {
  337. $item['dictionary_id'] = 0;
  338. }
  339. $info['field']['tableField'][$key] = $item;
  340. }
  341. //对比数据库,是否有新增字段
  342. $newColumn = [];
  343. $fieldAll = array_column($info['field']['tableField'], 'field');
  344. foreach ($column as $value) {
  345. if (!in_array($value['name'], $fieldAll)) {
  346. $newColumn[] = [
  347. 'field' => $value['name'],
  348. 'field_type' => $value['type'],
  349. 'primaryKey' => $value['primaryKey'] ? 1 : 0,
  350. 'default' => $value['default'],
  351. 'limit' => $value['limit'],
  352. 'comment' => $value['comment'],
  353. 'required' => '',
  354. 'is_table' => '',
  355. 'table_name' => '',
  356. 'from_type' => '',
  357. 'default_field' => $value['name'],
  358. 'default_limit' => $value['limit'],
  359. 'default_field_type' => $value['type'],
  360. 'default_comment' => $value['comment'],
  361. 'default_default' => $value['default'],
  362. ];
  363. }
  364. }
  365. if ($newColumn) {
  366. $info['field']['tableField'] = array_merge($newColumn, $info['field']['tableField']);
  367. }
  368. $keyInfo = $deleteInfo = $createInfo = $updateInfo = [];
  369. $tableField = [];
  370. foreach ($info['field']['tableField'] as $item) {
  371. if ($item['primaryKey']) {
  372. $keyInfo = $item;
  373. continue;
  374. }
  375. if ($item['field_type'] == 'timestamp' && $item['field'] === 'delete_time') {
  376. $deleteInfo = $item;
  377. continue;
  378. }
  379. if ($item['field_type'] == 'timestamp' && $item['field'] === 'create_time') {
  380. $createInfo = $item;
  381. continue;
  382. }
  383. if ($item['field_type'] == 'timestamp' && $item['field'] === 'update_time') {
  384. $updateInfo = $item;
  385. continue;
  386. }
  387. $tableField[] = $item;
  388. }
  389. if ($keyInfo) {
  390. array_unshift($tableField, $keyInfo);
  391. }
  392. if ($createInfo) {
  393. array_push($tableField, $createInfo);
  394. }
  395. if ($updateInfo) {
  396. array_push($tableField, $updateInfo);
  397. }
  398. if ($deleteInfo) {
  399. array_push($tableField, $deleteInfo);
  400. }
  401. $info['field']['tableField'] = $tableField;
  402. $info['field']['pid'] = (int)$info['field']['pid'];
  403. return app('json')->success(['file' => $data, 'crudInfo' => $info]);
  404. }
  405. /**
  406. * @param Request $request
  407. * @param SystemFileServices $service
  408. * @param $id
  409. * @return Response
  410. * @author 等风来
  411. * @email 136327134@qq.com
  412. * @date 2023/4/24
  413. */
  414. public function savefile(Request $request, SystemFileServices $service, $id)
  415. {
  416. $comment = $request->param('comment');
  417. $filepath = $request->param('filepath');
  418. $pwd = $request->param('pwd');
  419. if ($pwd == '') {
  420. return app('json')->fail('请输入文件管理密码');
  421. }
  422. if (config('filesystem.password') != $pwd) {
  423. return app('json')->fail('文件管理密码错误');
  424. }
  425. if (empty($filepath) || !$id) {
  426. return app('json')->fail('平台错误:发生异常,请稍后重试');
  427. }
  428. $crudInfo = $this->services->get($id, ['make_path']);
  429. if (!$crudInfo) {
  430. return app('json')->fail('修改的CRUD文件不存在');
  431. }
  432. $makeFilepath = '';
  433. foreach ($crudInfo->make_path as $key => $item) {
  434. $path = $item;
  435. if (in_array($key, ['pages', 'router', 'api'])) {
  436. $item = Make::adminTemplatePath() . $item;
  437. } else {
  438. $item = app()->getRootPath() . $item;
  439. }
  440. if ($filepath == $path) {
  441. $makeFilepath = $item;
  442. break;
  443. }
  444. }
  445. if (!$makeFilepath || !in_array($filepath, $crudInfo->make_path)) {
  446. return app('json')->fail('您没有权限修改此文件');
  447. }
  448. $res = $service->savefile($makeFilepath, $comment);
  449. if ($res) {
  450. return app('json')->success('保存成功');
  451. } else {
  452. return app('json')->fail('保存失败');
  453. }
  454. }
  455. /**
  456. * 获取tree菜单
  457. * @return Response
  458. * @author 等风来
  459. * @email 136327134@qq.com
  460. * @date 2023/4/11
  461. */
  462. public function getMenus()
  463. {
  464. return app('json')->success(app()->make(SystemMenusServices::class)
  465. ->getList(['auth_type' => 1, 'is_show' => 1], ['auth_type', 'pid', 'id', 'menu_name as label', 'id as value']));
  466. }
  467. /**
  468. * 获取可以进行关联的表名
  469. * @return Response
  470. * @author 等风来
  471. * @email 136327134@qq.com
  472. * @date 2023/8/2
  473. */
  474. public function getAssociationTable()
  475. {
  476. return app('json')->success($this->services->getTableAll());
  477. }
  478. /**
  479. * 获取表的详细信息
  480. * @param string $tableName
  481. * @return Response
  482. * @author 等风来
  483. * @email 136327134@qq.com
  484. * @date 2023/8/2
  485. */
  486. public function getAssociationTableInfo(string $tableName)
  487. {
  488. if (!$tableName) {
  489. return app('json')->fail('缺少表名');
  490. }
  491. if (in_array($tableName, SystemCrudServices::NOT_CRUD_TABANAME)) {
  492. return app('json')->fail('不允许查看当前表明细');
  493. }
  494. $tableInfo = $this->services->getColumnNamesList($tableName);
  495. $data = [];
  496. foreach ($tableInfo as $key => $item) {
  497. $data[] = [
  498. 'label' => $item['comment'] ?: $key,
  499. 'value' => $key,
  500. 'leaf' => true
  501. ];
  502. }
  503. return app('json')->success($data);
  504. }
  505. /**
  506. * 获取创建表数据类型
  507. * @return Response
  508. * @author 等风来
  509. * @email 136327134@qq.com
  510. * @date 2023/4/11
  511. */
  512. public function columnType()
  513. {
  514. return app('json')->success($this->services->getTabelRule());
  515. }
  516. /**
  517. * @param SystemMenusServices $services
  518. * @param $id
  519. * @return Response
  520. * @author 等风来
  521. * @email 136327134@qq.com
  522. * @date 2023/4/11
  523. */
  524. public function delete(SystemMenusServices $services, $id)
  525. {
  526. if (!$id) {
  527. return app('json')->fail('接口不存在');
  528. }
  529. $info = $this->services->get($id);
  530. if (!$info) {
  531. return app('json')->fail('数据不存在');
  532. }
  533. $menusServices = app()->make(SystemMenusServices::class);
  534. if ($info->menu_ids) {
  535. $menusServices->deleteMenus($info->menu_ids);
  536. }
  537. if ($info->menu_id) {
  538. $menusServices->deleteMenus([$info->menu_id]);
  539. }
  540. $routeServices = app()->make(SystemRouteServices::class);
  541. if ($info->route_ids) {
  542. $routeServices->deleteRoutes($info->route_ids);
  543. }
  544. Db::query("DROP TABLE `" . Env::get('database.prefix', 'eb_') . $info->table_name . "`");
  545. if ($info->make_path) {
  546. $errorFile = [];
  547. foreach ($info->make_path as $key => $item) {
  548. if (in_array($key, ['pages', 'router', 'api'])) {
  549. $item = Make::adminTemplatePath() . $item;
  550. } else {
  551. $item = app()->getRootPath() . $item;
  552. }
  553. try {
  554. unlink($item);
  555. } catch (\Throwable $e) {
  556. $errorFile[] = $item;
  557. }
  558. }
  559. if ($errorFile) {
  560. return app('json')->success('删除文件失败,失败原因{:message}', [], [
  561. 'message' => '文件:' . implode("\n", $errorFile) . ';无法被删除!'
  562. ]);
  563. }
  564. }
  565. $info->delete();
  566. return app('json')->success('删除成功');
  567. }
  568. /**
  569. * 下载文件
  570. * @param $id
  571. * @return Response
  572. * @author 等风来
  573. * @email 136327134@qq.com
  574. * @date 2023/4/15
  575. */
  576. public function download($id)
  577. {
  578. if (!$id) {
  579. return app('json')->fail('接口不存在');
  580. }
  581. $info = $this->services->get($id);
  582. if (!$info) {
  583. return app('json')->fail('数据不存在');
  584. }
  585. $zipPath = app()->getRootPath() . 'backup' . DS . Str::camel($info->table_name);
  586. $zipName = app()->getRootPath() . 'backup' . DS . Str::camel($info->table_name) . '.zip';
  587. if (is_file($zipName)) {
  588. unlink($zipName);
  589. }
  590. $makePath = $info->make_path ?? [];
  591. foreach ($makePath as $key => $item) {
  592. if (in_array($key, ['pages', 'router', 'api'])) {
  593. $item = $zipPath . str_replace(dirname(app()->getRootPath()), '', Make::adminTemplatePath()) . $item;
  594. } else {
  595. $item = $zipPath . DS . 'crmeb' . DS . $item;
  596. }
  597. $makePath[$key] = $item;
  598. }
  599. $routeName = 'crud/' . Str::snake($info->table_name);
  600. $column = $this->services->getColumnNamesList($info->table_name);
  601. $key = 'id';
  602. foreach ($column as $value) {
  603. if ($value['primaryKey']) {
  604. $key = $value['name'];
  605. break;
  606. }
  607. }
  608. $softDelete = false;
  609. foreach ((array)$info->field['tableField'] as $item) {
  610. if (isset($item['field_type']) && $item['field_type'] === 'addSoftDelete') {
  611. $softDelete = true;
  612. break;
  613. }
  614. }
  615. $this->services->makeFile($info->table_name, $routeName, true, [
  616. 'menuName' => $info->name,
  617. 'tableFields' => $info->field['tableField'] ?? [],
  618. 'key' => $key,
  619. 'softDelete' => $softDelete,
  620. 'fromField' => $info->field['fromField'] ?? [],
  621. 'columnField' => $info->field['columnField'] ?? [],
  622. 'searchField' => $info->field['searchField'] ?? [],
  623. 'hasOneField' => $info->field['hasOneField'] ?? [],
  624. ], $makePath, $zipPath);
  625. if (!extension_loaded('zip')) {
  626. return app('json')->fail('zip扩展未安装');
  627. }
  628. $fileService = new FileService();
  629. $fileService->addZip($zipPath, $zipName, app()->getRootPath() . 'backup');
  630. $key = md5($zipName);
  631. CacheService::set($key, [
  632. 'path' => $zipName,
  633. 'fileName' => Str::camel($info->table_name) . '.zip',
  634. ], 300);
  635. return app('json')->success(['download_url' => sys_config('site_url') . '/adminapi/download/' . $key]);
  636. }
  637. /**
  638. * 获取权限路由
  639. * @param $tableName
  640. * @return Response
  641. * @author 等风来
  642. * @email 136327134@qq.com
  643. * @date 2023/4/20
  644. */
  645. public function getRouteList($tableName)
  646. {
  647. $info = $this->services->get(['table_name' => $tableName]);
  648. if (!$info) {
  649. return app('json')->fail('crud详情查询失败');
  650. }
  651. $routeList = app()->make(SystemMenusServices::class)->getColumn([
  652. ['id', 'in', $info->menu_ids],
  653. ['auth_type', '=', 2]
  654. ], 'methods,api_url');
  655. $newRoute = [];
  656. foreach ($routeList as $item) {
  657. if ($item['methods'] == 'GET') {
  658. if (strstr($item['api_url'], 'create')) {
  659. $newRoute['create'] = $item['api_url'];
  660. } else if (strstr($item['api_url'], 'edit')) {
  661. $newRoute['edit'] = $item['api_url'];
  662. } else if (strstr($item['api_url'], 'status')) {
  663. $newRoute['status'] = $item['api_url'];
  664. } else {
  665. if (strstr($item['api_url'], '<id>')) {
  666. $newRoute['read'] = $item['api_url'];
  667. } else {
  668. $newRoute['index'] = $item['api_url'];
  669. }
  670. }
  671. } else if ($item['methods'] == 'DELETE') {
  672. $newRoute['delete'] = $item['api_url'];
  673. } else if ($item['methods'] == 'PUT' && strstr($item['api_url'], 'status')) {
  674. $newRoute['status'] = $item['api_url'];
  675. }
  676. }
  677. $column = $this->services->getColumnNamesList($info->table_name);
  678. $key = 'id';
  679. foreach ($column as $value) {
  680. if ($value['primaryKey']) {
  681. $key = $value['name'];
  682. break;
  683. }
  684. }
  685. $columns = [
  686. [
  687. 'title' => 'ID',
  688. 'key' => $key,
  689. 'from_type' => '',
  690. ]
  691. ];
  692. $readFields = [
  693. 'name' => $info->field['modelName'] ?: $info->field['menuName'],
  694. 'all' => [],
  695. ];
  696. foreach ((array)$info->field['tableField'] as $item) {
  697. if (isset($item['primaryKey']) && $item['primaryKey']) {
  698. continue;
  699. }
  700. $prefix = app()->make(Service::class)->getAttrPrefix();
  701. $readFields['all'][] = [
  702. 'field' => in_array($item['from_type'], [FormTypeEnum::FRAME_IMAGES,
  703. FormTypeEnum::DATE_TIME_RANGE,
  704. FormTypeEnum::RADIO,
  705. FormTypeEnum::SELECT,
  706. FormTypeEnum::CHECKBOX]) ? $item['field'] . $prefix : $item['field'],
  707. 'comment' => $item['comment'],
  708. 'from_type' => $item['from_type'],
  709. ];
  710. if (isset($item['is_table']) && $item['is_table']) {
  711. $label = '';
  712. if (in_array($item['from_type'], [FormTypeEnum::SWITCH, FormTypeEnum::DATE_TIME_RANGE, FormTypeEnum::FRAME_IMAGE_ONE, FormTypeEnum::FRAME_IMAGES])) {
  713. $keyName = 'slot';
  714. if ($item['from_type'] == FormTypeEnum::FRAME_IMAGES) {
  715. $label = $prefix;
  716. } else if ($item['from_type'] == FormTypeEnum::DATE_TIME_RANGE) {
  717. $label = $prefix;
  718. }
  719. } elseif (in_array($item['from_type'], [FormTypeEnum::RADIO, FormTypeEnum::SELECT, FormTypeEnum::CHECKBOX])) {
  720. $label = $prefix;
  721. $keyName = 'key';
  722. } else {
  723. $keyName = 'key';
  724. }
  725. $columns[] = [
  726. 'title' => $item['table_name'] ?: $item['comment'],
  727. $keyName => $item['field'] . $label,
  728. 'from_type' => $item['from_type'],
  729. ];
  730. }
  731. }
  732. $searchField = $info->field['searchField'] ?? [];
  733. $search = [];
  734. foreach ((array)$searchField as $item) {
  735. if (!$item['type']) {
  736. $item['type'] = FormTypeEnum::INPUT;
  737. }
  738. if ($item['search'] == 'BETWEEN') {
  739. $item['type'] = 'date-picker';
  740. } else {
  741. if (in_array($item['type'], [FormTypeEnum::CHECKBOX, FormTypeEnum::RADIO, FormTypeEnum::SELECT])) {
  742. $item['type'] = FormTypeEnum::SELECT;
  743. } else {
  744. $item['type'] = FormTypeEnum::INPUT;
  745. }
  746. }
  747. $search[] = [
  748. 'field' => $item['field'],
  749. 'type' => $item['type'],
  750. 'name' => $item['name'],
  751. 'option' => $item['options'] ?? [],
  752. ];
  753. }
  754. $route = $newRoute;
  755. return app('json')->success(compact('key', 'route', 'columns', 'readFields', 'search'));
  756. }
  757. /**
  758. * 修改或者保存字典数据
  759. * @param SystemCrudDataService $service
  760. * @param int $id
  761. * @return Response
  762. * @author 等风来
  763. * @email 136327134@qq.com
  764. * @date 2023/8/1
  765. */
  766. public function saveDataDictionary(SystemCrudDataService $service, $id = 0)
  767. {
  768. $data = $this->request->postMore([
  769. ['name', ''],
  770. ['value', []],
  771. ]);
  772. if (!$data['name']) {
  773. return app('json')->fail('数据字段名不能为空');
  774. }
  775. if (!$data['value']) {
  776. return app('json')->fail('数据字段内容不能为空');
  777. }
  778. $data['value'] = json_encode($data['value']);
  779. if ($id) {
  780. $service->update($id, $data);
  781. } else {
  782. $service->save($data);
  783. }
  784. return app('json')->success($id ? '修改成功' : '添加成功');
  785. }
  786. /**
  787. * 查看数据字典
  788. * @param SystemCrudDataService $service
  789. * @param $id
  790. * @return Response
  791. * @author 等风来
  792. * @email 136327134@qq.com
  793. * @date 2023/8/7
  794. */
  795. public function getDataDictionaryOne(SystemCrudDataService $service, $id)
  796. {
  797. if (!$id) {
  798. return app('json')->fail('缺少参数');
  799. }
  800. $info = $service->get($id);
  801. if (!$info) {
  802. return app('json')->fail('没有查询到数据');
  803. }
  804. return app('json')->success($info->toArray());
  805. }
  806. /**
  807. * 获取数据字典列表
  808. * @param SystemCrudDataService $service
  809. * @return Response
  810. * @throws \ReflectionException
  811. * @throws \think\db\exception\DataNotFoundException
  812. * @throws \think\db\exception\DbException
  813. * @throws \think\db\exception\ModelNotFoundException
  814. * @author 等风来
  815. * @email 136327134@qq.com
  816. * @date 2023/8/1
  817. */
  818. public function getDataDictionary(SystemCrudDataService $service)
  819. {
  820. $name = $this->request->get('name', '');
  821. $data = $service->getlistAll($name);
  822. return app('json')->success($data);
  823. }
  824. /**
  825. * 删除数据字典
  826. * @param SystemCrudDataService $service
  827. * @param $id
  828. * @return Response
  829. * @author 等风来
  830. * @email 136327134@qq.com
  831. * @date 2023/8/4
  832. */
  833. public function deleteDataDictionary(SystemCrudDataService $service, $id)
  834. {
  835. if (!$id) {
  836. return app('json')->fail('缺少参数');
  837. }
  838. if ($service->delete($id)) {
  839. return app('json')->success('删除成功');
  840. } else {
  841. return app('json')->fail('删除失败');
  842. }
  843. }
  844. /** 数据字典新 */
  845. /**
  846. * 获取数据字典列表
  847. * @param SystemCrudListServices $service
  848. * @return Response
  849. * @throws \ReflectionException
  850. * @throws \think\db\exception\DataNotFoundException
  851. * @throws \think\db\exception\DbException
  852. * @throws \think\db\exception\ModelNotFoundException
  853. * @author wuhaotian
  854. * @email 442384644@qq.com
  855. * @date 2024/5/20
  856. */
  857. public function dataDictionaryList(SystemCrudListServices $service)
  858. {
  859. $where = $this->request->getMore([
  860. ['status', ''],
  861. ]);
  862. return app('json')->success($service->dataDictionaryList($where));
  863. }
  864. /**
  865. * 获取数据字典添加修改表单
  866. * @param SystemCrudListServices $service
  867. * @param $id
  868. * @return Response
  869. * @throws \FormBuilder\Exception\FormBuilderException
  870. * @throws \think\db\exception\DataNotFoundException
  871. * @throws \think\db\exception\DbException
  872. * @throws \think\db\exception\ModelNotFoundException
  873. * @author wuhaotian
  874. * @email 442384644@qq.com
  875. * @date 2024/5/20
  876. */
  877. public function dataDictionaryListCreate(SystemCrudListServices $service, $id)
  878. {
  879. return app('json')->success($service->dataDictionaryListCreate($id));
  880. }
  881. /**
  882. * 保存数据字典
  883. * @param SystemCrudListServices $service
  884. * @param $id
  885. * @return Response
  886. * @author wuhaotian
  887. * @email 442384644@qq.com
  888. * @date 2024/5/20
  889. */
  890. public function dataDictionaryListSave(SystemCrudListServices $service, $id)
  891. {
  892. $data = $this->request->getMore([
  893. ['name', ''],
  894. ['mark', ''],
  895. ['level', ''],
  896. ['status', ''],
  897. ]);
  898. $service->dataDictionaryListSave($id, $data);
  899. return app('json')->success('保存成功');
  900. }
  901. /**
  902. * 删除数据字典
  903. * @param SystemCrudListServices $service
  904. * @param $id
  905. * @return Response
  906. * @author wuhaotian
  907. * @email 442384644@qq.com
  908. * @date 2024/5/20
  909. */
  910. public function dataDictionaryListDel(SystemCrudListServices $service, $id)
  911. {
  912. $service->dataDictionaryListDel($id);
  913. return app('json')->success('删除成功');
  914. }
  915. /**
  916. * 数据字典内容列表
  917. * @param SystemCrudDataService $service
  918. * @param $cid
  919. * @return Response
  920. * @throws \ReflectionException
  921. * @throws \think\db\exception\DataNotFoundException
  922. * @throws \think\db\exception\DbException
  923. * @throws \think\db\exception\ModelNotFoundException
  924. * @author wuhaotian
  925. * @email 442384644@qq.com
  926. * @date 2024/5/20
  927. */
  928. public function dataDictionaryInfoList(SystemCrudDataService $service, $cid)
  929. {
  930. return app('json')->success($service->dataDictionaryInfoList($cid));
  931. }
  932. /**
  933. * 数据字典内容添加修改表单
  934. * @param SystemCrudDataService $service
  935. * @param $cid
  936. * @param $id
  937. * @param $pid
  938. * @return Response
  939. * @throws \FormBuilder\Exception\FormBuilderException
  940. * @throws \ReflectionException
  941. * @throws \think\db\exception\DataNotFoundException
  942. * @throws \think\db\exception\DbException
  943. * @throws \think\db\exception\ModelNotFoundException
  944. * @author wuhaotian
  945. * @email 442384644@qq.com
  946. * @date 2024/5/20
  947. */
  948. public function dataDictionaryInfoCreate(SystemCrudDataService $service, $cid, $id, $pid)
  949. {
  950. return app('json')->success($service->dataDictionaryInfoCreate($cid, (int)$id, (int)$pid));
  951. }
  952. /**
  953. * 保存数据字典内容
  954. * @param SystemCrudDataService $service
  955. * @param $cid
  956. * @param $id
  957. * @return Response
  958. * @author wuhaotian
  959. * @email 442384644@qq.com
  960. * @date 2024/5/20
  961. */
  962. public function dataDictionaryInfoSave(SystemCrudDataService $service, $cid, $id)
  963. {
  964. $data = $this->request->getMore([
  965. ['name', ''],
  966. ['pid', 0],
  967. ['value', ''],
  968. ['sort', 0],
  969. ]);
  970. $service->dataDictionaryInfoSave($cid, $id, $data);
  971. return app('json')->success('保存成功');
  972. }
  973. /**
  974. * 删除数据字典内容
  975. * @param SystemCrudDataService $service
  976. * @param $id
  977. * @return Response
  978. * @throws \ReflectionException
  979. * @author wuhaotian
  980. * @email 442384644@qq.com
  981. * @date 2024/5/20
  982. */
  983. public function dataDictionaryInfoDel(SystemCrudDataService $service, $id)
  984. {
  985. $service->dataDictionaryInfoDel($id);
  986. return app('json')->success('删除成功');
  987. }
  988. }