diff --git a/crmeb/app/adminapi/controller/v1/setting/SystemCrud.php b/crmeb/app/adminapi/controller/v1/setting/SystemCrud.php index 4ca8f64b9..c874acc73 100644 --- a/crmeb/app/adminapi/controller/v1/setting/SystemCrud.php +++ b/crmeb/app/adminapi/controller/v1/setting/SystemCrud.php @@ -63,23 +63,24 @@ class SystemCrud extends AuthController * @email 136327134@qq.com * @date 2023/4/11 */ - public function save() + public function save($id = 0) { $data = $this->request->postMore([ - ['pid', 0], - ['menuName', ''], - ['tableName', ''], - ['modelName', ''], + ['pid', 0],//上级菜单id + ['menuName', ''],//菜单名 + ['tableName', ''],//表名 + ['modelName', ''],//模块名称 ['tableComment', ''],//表备注 ['tableField', []],//表字段 ['tableIndex', []],//索引 - ['filePath', []], - ['isTable', 0], + ['filePath', []],//生成文件位置 + ['isTable', 0],//是否生成表 + ['deleteField', []],//删除的表字段 ]); $fromField = $columnField = []; foreach ($data['tableField'] as $item) { - if ($item['is_table'] && !in_array($item['field_type'], ['addSoftDelete', 'addSoftDelete'])) { + if ($item['is_table'] && !in_array($item['field_type'], ['primaryKey', 'addSoftDelete', 'addSoftDelete'])) { $columnField[] = [ 'field' => $item['field'], 'name' => $item['table_name'], @@ -88,23 +89,27 @@ class SystemCrud extends AuthController } if ($item['from_type']) { $name = $item['table_name'] ?: $item['comment']; + $option = $item['options'] ?? []; if (!$name) { - return app('json')->fail($item['field'] . '字段的表单标题必须填写'); + return app('json')->fail(500056, [], ['field' => $item['field']]); + } + if (!$option && in_array($item['from_type'], ['radio', 'select'])) { + return app('json')->fail('表单类型为radio或select时,option字段不能为空'); } $fromField[] = [ 'field' => $item['field'], 'type' => $item['from_type'], 'name' => $name, 'required' => $item['required'], - 'option' => $item['option'] ?? [], + 'option' => $option, ]; } } if (!$fromField) { - return app('json')->fail('至少选择一个字段作为表单项'); + return app('json')->fail(500054); } if (!$columnField) { - return app('json')->fail('至少选择一个字段作为列展示在列表中'); + return app('json')->fail(500055); } $data['fromField'] = $fromField; $data['columnField'] = $columnField; @@ -112,7 +117,7 @@ class SystemCrud extends AuthController return app('json')->fail(500045); } - $this->services->createCrud($data); + $this->services->createCrud($id, $data); return app('json')->success(500046); } @@ -126,9 +131,8 @@ class SystemCrud extends AuthController */ public function getFilePath() { - [$tableName, $isTable] = $this->request->postMore([ + [$tableName] = $this->request->postMore([ ['tableName', ''], - ['isTable', 0], ], true); if (!$tableName) { @@ -143,28 +147,24 @@ class SystemCrud extends AuthController $key = 'id'; $tableField = []; - if ($isTable) { - $field = $this->services->getColumnNamesList($tableName); - if (!$field) { - return app('json')->fail('表不存在'); - } - foreach ($field as $item) { - if ($item['primaryKey']) { - $key = $item['name']; - } - $tableField[] = [ - 'field' => $item['name'], - 'field_type' => $item['type'], - 'primaryKey' => (bool)$item['primaryKey'], - 'default' => $item['default'], - 'limit' => $item['limit'], - 'comment' => $item['comment'], - 'required' => false, - 'is_table' => false, - 'table_name' => '', - 'from_type' => '', - ]; + + $field = $this->services->getColumnNamesList($tableName); + foreach ($field as $item) { + if ($item['primaryKey']) { + $key = $item['name']; } + $tableField[] = [ + 'field' => $item['name'], + 'field_type' => $item['type'], + 'primaryKey' => (bool)$item['primaryKey'], + 'default' => $item['default'], + 'limit' => $item['limit'], + 'comment' => $item['comment'], + 'required' => false, + 'is_table' => false, + 'table_name' => '', + 'from_type' => '', + ]; } $make = $this->services->makeFile($tableName, $routeName, false, [ @@ -234,8 +234,17 @@ class SystemCrud extends AuthController $item['name'] = $item['path']; $data[] = $item; } + $info = $info->toArray(); + foreach ((array)$info['field']['tableField'] as $key => $item) { + $item['default_field'] = $item['field']; + $item['default_limit'] = $item['limit']; + $item['default_field_type'] = $item['field_type']; + $item['default_comment'] = $item['comment']; + $item['default_default'] = $item['default']; + $info['field']['tableField'][$key] = $item; + } - return app('json')->success($data); + return app('json')->success(['file' => $data, 'crudInfo' => $info]); } /** diff --git a/crmeb/app/adminapi/controller/v1/setting/SystemRoute.php b/crmeb/app/adminapi/controller/v1/setting/SystemRoute.php index cc472f8ca..66208ac36 100644 --- a/crmeb/app/adminapi/controller/v1/setting/SystemRoute.php +++ b/crmeb/app/adminapi/controller/v1/setting/SystemRoute.php @@ -51,7 +51,7 @@ class SystemRoute extends AuthController { $this->services->syncRoute($appName); - return app('json')->success(); + return app('json')->success(100038); } /** diff --git a/crmeb/app/dao/system/SystemRouteDao.php b/crmeb/app/dao/system/SystemRouteDao.php index f222df701..9f36601ba 100644 --- a/crmeb/app/dao/system/SystemRouteDao.php +++ b/crmeb/app/dao/system/SystemRouteDao.php @@ -37,4 +37,16 @@ class SystemRouteDao extends BaseDao { return SystemRoute::class; } + + /** + * @param array $ids + * @return bool + * @author 等风来 + * @email 136327134@qq.com + * @date 2023/4/23 + */ + public function deleteRoutes(array $ids) + { + return $this->getModel()->where('id', 'in', $ids)->delete(); + } } diff --git a/crmeb/app/model/system/SystemCrud.php b/crmeb/app/model/system/SystemCrud.php index b3b7b6d18..585cd79db 100644 --- a/crmeb/app/model/system/SystemCrud.php +++ b/crmeb/app/model/system/SystemCrud.php @@ -56,4 +56,9 @@ class SystemCrud extends BaseModel return json_decode($value, true); } + + public function getRoutesIdAttr($value) + { + return json_decode($value, true); + } } diff --git a/crmeb/app/services/system/SystemCrudServices.php b/crmeb/app/services/system/SystemCrudServices.php index e76702b81..93b16d5fc 100644 --- a/crmeb/app/services/system/SystemCrudServices.php +++ b/crmeb/app/services/system/SystemCrudServices.php @@ -29,6 +29,7 @@ use crmeb\services\crud\ViewPages; use crmeb\services\crud\ViewRouter; use crmeb\services\FileService; use Phinx\Db\Adapter\AdapterFactory; +use think\exception\ValidateException; use think\facade\Db; use think\helper\Str; use think\migration\db\Table; @@ -54,7 +55,29 @@ class SystemCrudServices extends BaseServices 'shipping_templates_no_delivery', 'shipping_templates_free', 'other_order_status', 'lang_code', 'lang_country', 'app_version', 'user', 'wechat_user', 'template_message', 'store_order', 'other_order', 'store_order_cart_info', 'store_order_economize', 'store_order_invoice', 'store_order_refund', - 'store_order_status', 'store_pink' + 'store_order_status', 'store_pink', 'agent_level', 'agent_level_task', 'agent_level_task_record', + 'agreement', 'app_version', 'article', 'article_category', 'article_content', 'auxiliary', 'cache', + 'capital_flow', 'category', 'diy', 'express', 'lang_type', 'live_anchor', 'live_goods', 'live_room', + 'live_room_goods', 'luck_lottery', 'luck_lottery_record', 'luck_prize', 'member_card', 'member_card_batch', + 'member_right', 'member_ship', 'message_system', 'other_order', 'other_order_status', 'out_account', 'out_interface', + 'page_categroy', 'page_link', 'qrcode', 'shipping_templates', 'shipping_templates_free', 'shipping_templates_no_delivery', + 'shipping_templates_region', 'sms_record', 'store_advance', 'store_bargain', 'store_bargain_user', 'store_bargain_user_help', + 'store_cart', 'store_category', 'store_combination', 'store_coupon_issue', 'store_coupon_issue_user', 'store_coupon_product', + 'store_coupon_user', 'store_integral', 'store_integral_order', 'store_integral_order_status', 'store_order', 'store_order_cart_info', + 'store_order_economize', 'store_order_invoice', 'store_order_refund', 'store_order_status', 'store_pink', 'store_product', + 'store_product_attr', 'store_product_attr_result', 'store_product_attr_value', 'store_product_cate', 'store_product_coupon', + 'store_product_description', 'store_product_log', 'store_product_relation', 'store_service', 'store_service_feedback', + 'store_product_reply', 'store_product_rule', 'store_product_virtual', 'store_seckill', 'store_seckill_time', + 'store_service_log', 'store_service_record', 'store_service_speechcraft', 'store_visit', 'system_attachment', + 'system_attachment_category', 'system_city', 'system_config', 'system_config_tab', 'system_file', 'system_file_info', + 'system_group', 'system_group_data', 'system_log', 'system_notice', 'system_notice_admin', 'system_notification', + 'system_role', 'system_route', 'system_route_cate', 'system_storage', 'system_store', 'system_store_staff', + 'system_timer', 'system_user_level', 'template_message', 'upgrade_log', 'user', 'user_address', + 'user_bill', 'user_brokerage', 'user_brokerage_frozen', 'user_cancel', 'user_enter', 'user_extract', + 'user_friends', 'user_group', 'user_invoice', 'user_label', 'user_label_relation', 'user_level', 'user_money', + 'user_notice', 'user_notice_see', 'user_recharge', 'user_search', 'user_sign', 'user_spread', + 'user_visit', 'wechat_key', 'wechat_media', 'wechat_message', 'wechat_news_category', 'wechat_qrcode', + 'wechat_qrcode_cate', 'wechat_qrcode_record', 'wechat_reply', 'wechat_user' ]; /** @@ -125,6 +148,44 @@ class SystemCrudServices extends BaseServices 'addTimestamps', 'addSoftDelete', ], + 'form' => [ + [ + 'value' => 'input', + 'label' => '输入框', + ], + [ + 'value' => 'number', + 'label' => '数字输入框', + ], + [ + 'value' => 'textarea', + 'label' => '多行文本框', + ], + [ + 'value' => 'dateTime', + 'label' => '单选日期时间', + ], + [ + 'value' => 'dateTimeRange', + 'label' => '日期时间区间选择', + ], + [ + 'value' => 'radio', + 'label' => '单选框', + ], + [ + 'value' => 'select', + 'label' => '下拉框', + ], + [ + 'value' => 'frameImageOne', + 'label' => '单图选择' + ], + [ + 'value' => 'frameImages', + 'label' => '多图选择' + ], + ], 'rule' => $rule ]; } @@ -219,6 +280,98 @@ class SystemCrudServices extends BaseServices return $newData; } + /** + * 更新表字段 + * @param string $tableName + * @param string $field + * @param string $changeFiled + * @param string $type + * @param string $limit + * @param string $default + * @param string $comment + * @param array $options + * @return mixed + * @author 等风来 + * @email 136327134@qq.com + * @date 2023/4/24 + */ + protected function updateAlter(string $tableName, string $field, string $changeFiled, string $type, $limit = '', string $default = '', string $comment = '', array $options = []) + { + $tableName = $this->getTableName($tableName); + $comment = addslashes($comment); + $field = addslashes($field); + $changeFiled = addslashes($changeFiled); + $type = addslashes($type); + $default = addslashes($default); + $sql = "ALTER TABLE `$tableName` CHANGE `$field` `$changeFiled` $type($limit) NOT NULL DEFAULT '$default' COMMENT '$comment';"; + return Db::execute($sql); + } + + /** + * 删除表字段 + * @param string $tableName + * @param string $field + * @return mixed + * @author 等风来 + * @email 136327134@qq.com + * @date 2023/4/24 + */ + protected function deleteAlter(string $tableName, string $field) + { + $tableName = $this->getTableName($tableName); + $field = addslashes($field); + $sql = "ALTER TABLE `$tableName` DROP `$field`"; + return Db::execute($sql); + } + + /** + * 对比字段变动了更改 + * @param string $tableName + * @param array $deleteField + * @param array $tableField + * @author 等风来 + * @email 136327134@qq.com + * @date 2023/4/24 + */ + protected function diffAlter(string $tableName, array $deleteField, array $tableField) + { + $updateAlter = []; + //对比数据库字段 + foreach ($tableField as $item) { + if ($item['primaryKey']) { + continue; + } + + if ($item['default_field'] != $item['field'] && $item['field_type'] == 'addSoftDelete') { + throw new AdminException('伪删除字段不允许被更改'); + } + + if ($item['default_field'] != $item['field'] || + $item['default_field_type'] != $item['type'] || + $item['default_limit'] != $item['limit'] || + $item['default_comment'] != $item['comment'] || + $item['default_default'] != $item['default']) { + $updateAlter[] = [ + 'default_field' => $item['default_field'], + 'field' => $item['field'], + 'limit' => $item['limit'], + 'type' => $item['field_type'], + 'comment' => $item['comment'], + 'default' => $item['default'], + ]; + } + } + //更新数据库字段 + foreach ($updateAlter as $item) { + $this->updateAlter($tableName, $item['default_field'], $item['field'], $item['type'], $item['limit'], $item['default'], $item['comment']); + } + //删除多余字段 + foreach ($deleteField as $item) { + $this->deleteAlter($tableName, $item); + } + + } + /** * 创建 * @param array $data @@ -227,7 +380,7 @@ class SystemCrudServices extends BaseServices * @email 136327134@qq.com * @date 2023/4/11 */ - public function createCrud(array $data) + public function createCrud(int $id, array $data) { $tableName = $data['tableName']; $tableComment = $data['tableComment'] ?? $data['menuName']; @@ -239,25 +392,37 @@ class SystemCrudServices extends BaseServices throw new AdminException(500048); } + //检测是否为系统表 + if (in_array($tableName, self::NOT_CRUD_TABANAME)) { + throw new AdminException(500044); + } + $data['softDelete'] = false; + + $tableInfo = null; + if ($id) { + //删除数据库表 + $tableInfo = $this->getTableInfo($tableName); + if ($tableInfo) { + //对比字段进行更新/删除字段 + $this->diffAlter($tableName, $data['deleteField'], $tableField); + } + } //创建数据库 - if ($tableField && !$data['isTable']) { + if ($tableField && (!$data['isTable'] || !$tableInfo)) { $tableCreateInfo = $this->makeDatebase($tableName, $tableComment, $tableField); if ($tableCreateInfo['softDelete']) { $data['softDelete'] = true; } } - if (in_array($tableName, self::NOT_CRUD_TABANAME)) { - throw new AdminException(500044); - } - //读取表结构 $column = $this->getColumnNamesList($tableName); if (!$column) { throw new AdminException(500049, ['_name' => $tableName]); } + //读取数据库字段信息 $tableInfo = $this->getTableInfo($tableName); //获取主键 @@ -294,10 +459,29 @@ class SystemCrudServices extends BaseServices 'is_header' => $data['pid'] ? 0 : 1, ]; - $res = $this->transaction(function () use ($tableInfo, $modelName, $filePath, $tableName, $routeName, $data, $dataMenu) { - $menuInfo = app()->make(SystemMenusServices::class)->save($dataMenu); + $crudInfo = null; + if ($id) { + $crudInfo = $this->dao->get($id); + } + + $res = $this->transaction(function () use ($crudInfo, $tableInfo, $modelName, $filePath, $tableName, $routeName, $data, $dataMenu) { + $routeService = app()->make(SystemRouteServices::class); + //修改菜单名称 + if ($crudInfo) { + $menuInfo = app()->make(SystemMenusServices::class)->update($crudInfo->menu_id, $dataMenu); + //删除掉添加的路由权限 + if ($crudInfo->routes_id) { + $routeService->deleteRoutes($crudInfo->routes_id); + } + //删除掉权限路由 + if ($crudInfo->menu_ids) { + app()->make(SystemMenusServices::class)->deleteMenus($crudInfo->menu_ids); + } + } else { + $menuInfo = app()->make(SystemMenusServices::class)->save($dataMenu); + } //写入路由权限 - $cateId = app()->make(SystemRouteServices::class)->topCateId('adminapi'); + $cateId = app()->make(SystemRouteServices::class)->topCateId('adminapi', 'CRUD'); $ruleData = [ [ 'path' => $routeName, @@ -354,13 +538,11 @@ class SystemCrudServices extends BaseServices 'add_time' => date('Y-m-d H:i:s') ], ]; - $routeService = app()->make(SystemRouteServices::class); - foreach ($ruleData as $key => $item) { - if ($routeService->count(['method' => $item['method'], 'path' => $item['path']])) { - unset($ruleData[$key]); - } - } - app()->make(SystemRouteServices::class)->saveAll($ruleData); + + + $routeList = $routeService->saveAll($ruleData); + $routeIds = array_column($routeList->toArray(), 'id'); + //记录权限加入菜单表 $menuData = []; foreach ($ruleData as $item) { @@ -376,15 +558,14 @@ class SystemCrudServices extends BaseServices } $menus = app()->make(SystemMenusServices::class)->saveAll($menuData); $menuIds = array_column($menus->toArray(), 'id'); - array_push($menuIds, $menuInfo->id); //生成文件 - $make = $this->makeFile($tableName, $routeName, config('app.crud_make', false), $data, $filePath); + $make = $this->makeFile($tableName, $routeName, true, $data, $filePath); $makePath = []; foreach ($make as $key => $item) { $makePath[$key] = $item['path']; } - //记录crud生成 - $res = $this->dao->save([ + + $crudDate = [ 'pid' => $data['pid'], 'name' => $data['menuName'], 'model_name' => $data['modelName'], @@ -394,8 +575,16 @@ class SystemCrudServices extends BaseServices 'field' => json_encode($data),//提交的数据 'menu_ids' => json_encode($menuIds),//生成的菜单id 'make_path' => json_encode($makePath), - 'add_time' => time() - ]); + 'routes_id' => json_encode($routeIds), + ]; + + if ($crudInfo) { + $res = $this->dao->update($crudInfo->id, $crudDate); + } else { + $crudDate['add_time'] = time(); + //记录crud生成 + $res = $this->dao->save($crudDate); + } return $res; }); diff --git a/crmeb/crmeb/services/crud/Service.php b/crmeb/crmeb/services/crud/Service.php index 995a75a15..8bd49d144 100644 --- a/crmeb/crmeb/services/crud/Service.php +++ b/crmeb/crmeb/services/crud/Service.php @@ -73,7 +73,7 @@ class Service extends Make $from[] = $this->tab(2) . $this->getframeImagesPhpContent($item['field'], $item['name'], $item['required'] ?? false) . ';'; break; default: - $from[] = $this->tab(2) . '$rule[] = FormBuilder::' . $item['type'] . '("' . $item['field'] . '","' . $item['name'] . '",$info["' . $item['field'] . '"] ?? "")' . $this->getOptionContent(in_array($item['type'], ['radio']), $item['option'] ?? []) . (!empty($item['required']) ? '->required()' : '') . ';'; + $from[] = $this->tab(2) . '$rule[] = FormBuilder::' . $item['type'] . '("' . $item['field'] . '","' . $item['name'] . '",$info["' . $item['field'] . '"] ?? "")' . $this->getOptionContent(in_array($item['type'], ['radio', 'select']), $item['option'] ?? []) . ';'; break; } @@ -125,10 +125,13 @@ class Service extends Make } $php = ''; if ($option) { - $res = var_export($option, true); + $attOption = []; + foreach ($option as $item) { + $attOption[] = $this->tab(2) . "['value'=>'{$item['value']}', 'label'=>'{$item['label']}'],"; + } - $strOption = str_replace(['array', '(', ')'], ['', '[', ']'], $res); - $php = '->options(' . $strOption . ')'; + $strOption = implode("\n", $attOption); + $php = '->options([' . $strOption . '])'; } return $php; diff --git a/crmeb/crmeb/services/crud/Validate.php b/crmeb/crmeb/services/crud/Validate.php index ba19816f6..321c7934f 100644 --- a/crmeb/crmeb/services/crud/Validate.php +++ b/crmeb/crmeb/services/crud/Validate.php @@ -68,8 +68,8 @@ class Validate extends Make foreach ($field as $item) { $item['name'] = addslashes($item['name']); if ($item['required']) { - $content[] = $this->tab(2) . '\'' . $item['field'] . '\'=>\'require\''; - $message[] = $this->tab(2) . '\'' . $item['field'] . '.require\'=>\'' . $item['name'] . '必须填写\''; + $content[] = $this->tab(2) . '\'' . $item['field'] . '\'=>\'require\','; + $message[] = $this->tab(2) . '\'' . $item['field'] . '.require\'=>\'' . $item['name'] . '必须填写\','; } } return [implode("\n", $content), implode("\n", $message)]; diff --git a/crmeb/crmeb/utils/Json.php b/crmeb/crmeb/utils/Json.php index bef491937..a965b2830 100644 --- a/crmeb/crmeb/utils/Json.php +++ b/crmeb/crmeb/utils/Json.php @@ -35,8 +35,11 @@ class Json if (!is_null($data)) $res['data'] = $data; - if (is_numeric($res['msg'])) + if (is_numeric($res['msg'])) { + $res['code'] = $res['msg']; $res['msg'] = getLang($res['msg'], $replace); + } + return Response::create($res, 'json', $this->code); }