gen.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. from flask import request, send_file
  2. from zipfile import ZipFile
  3. from io import BytesIO
  4. from ruoyi_common.base.model import AjaxResponse, TableResponse
  5. from ruoyi_common.constant import HttpStatus
  6. from ruoyi_common.descriptor.serializer import JsonSerializer
  7. from ruoyi_common.descriptor.validator import QueryValidator, BodyValidator, PathValidator
  8. from ruoyi_framework.descriptor.permission import HasPerm, PreAuthorize
  9. from ruoyi_generator.controller import gen
  10. from ruoyi_generator.domain.entity import GenTable
  11. from ruoyi_generator.domain.po import GenTablePO, GenTableColumnPO
  12. from ruoyi_generator.service import GenTableService
  13. from ruoyi_generator.service.column_service import GenTableColumnService
  14. gen_table_service = GenTableService()
  15. gen_table_column_service = GenTableColumnService()
  16. @gen.route('/list', methods=["GET"])
  17. @QueryValidator(is_page=True)
  18. @PreAuthorize(HasPerm('tool:gen:list'))
  19. @JsonSerializer()
  20. def gen_list(dto: GenTablePO):
  21. """查询代码生成列表"""
  22. gen_table = GenTable()
  23. # 转换PO到Entity对象,只复制存在的字段
  24. for attr in dto.model_fields.keys():
  25. if hasattr(gen_table, attr):
  26. setattr(gen_table, attr, getattr(dto, attr))
  27. tables, total = gen_table_service.select_gen_table_list(gen_table)
  28. return TableResponse(code=HttpStatus.SUCCESS, msg='查询成功', rows=tables, total=total)
  29. @gen.route('/db/list', methods=["GET"])
  30. @QueryValidator(is_page=True)
  31. @PreAuthorize(HasPerm('tool:gen:list'))
  32. @JsonSerializer()
  33. def db_list(dto: GenTablePO):
  34. """查询数据库表列表"""
  35. gen_table = GenTable()
  36. # 转换PO到Entity对象,只复制存在的字段
  37. for attr in dto.model_fields.keys():
  38. if hasattr(gen_table, attr):
  39. setattr(gen_table, attr, getattr(dto, attr))
  40. tables, total = gen_table_service.select_db_table_list(gen_table)
  41. return TableResponse(code=HttpStatus.SUCCESS, msg='查询成功', rows=tables, total=total)
  42. @gen.route('/<int:tableId>', methods=["GET"])
  43. @PathValidator()
  44. @PreAuthorize(HasPerm('tool:gen:query'))
  45. @JsonSerializer()
  46. def get_gen_table(tableId: int):
  47. """查询代码生成详细信息"""
  48. table = gen_table_service.select_gen_table_by_id(tableId)
  49. # 如果表存在但没有字段信息,则尝试从数据库同步
  50. columns, total = gen_table_column_service.select_gen_table_column_list_by_table_id(tableId)
  51. if not columns:
  52. # 尝试同步数据库结构
  53. gen_table_service.synch_db(table.table_name)
  54. # 再次查询字段信息
  55. columns, total = gen_table_column_service.select_gen_table_column_list_by_table_id(tableId)
  56. # 获取所有表名列表
  57. all_tables_result = gen_table_service.select_gen_table_list(GenTable())
  58. all_tables = []
  59. if all_tables_result:
  60. # 确保返回的是完整的表对象而不是仅表名
  61. all_tables = all_tables_result[0]
  62. return AjaxResponse.from_success(data={
  63. 'info': table,
  64. 'rows': columns,
  65. 'tables': all_tables
  66. })
  67. @gen.route('/', methods=['POST'])
  68. @BodyValidator()
  69. @PreAuthorize(HasPerm('tool:gen:add'))
  70. @JsonSerializer()
  71. def add_gen_table(dto: GenTablePO):
  72. """新增代码生成表"""
  73. gen_table = GenTable()
  74. # 转换PO到Entity对象,只复制存在的字段
  75. for attr in dto.model_fields.keys():
  76. if hasattr(gen_table, attr):
  77. setattr(gen_table, attr, getattr(dto, attr))
  78. # 实现新增逻辑
  79. table_id = gen_table_service.insert_gen_table(gen_table)
  80. if table_id > 0:
  81. return AjaxResponse.from_success(msg='新增成功')
  82. else:
  83. return AjaxResponse.from_error(msg='新增失败')
  84. @gen.route('/importTable', methods=['POST'])
  85. @PreAuthorize(HasPerm('tool:gen:import'))
  86. @JsonSerializer()
  87. def import_table():
  88. """导入表结构"""
  89. tables = request.args.get('tables')
  90. if not tables:
  91. return AjaxResponse.from_error(msg='参数错误')
  92. table_list = [table.strip() for table in tables.split(',') if table.strip()]
  93. if not table_list:
  94. return AjaxResponse.from_error(msg='参数错误')
  95. gen_table_service.import_gen_table(table_list)
  96. return AjaxResponse.from_success(msg='导入成功')
  97. @gen.route('/<int:tableId>', methods=['PUT'])
  98. @BodyValidator()
  99. @PreAuthorize(HasPerm('tool:gen:edit'))
  100. @JsonSerializer()
  101. def update_gen_table(dto: GenTablePO):
  102. print(dto)
  103. """修改保存代码生成信息"""
  104. gen_table = GenTable()
  105. # 设置表ID
  106. gen_table.table_id = dto.table_id
  107. # 从请求数据中设置属性
  108. for attr in dto.model_fields.keys():
  109. if hasattr(gen_table, attr):
  110. setattr(gen_table, attr, getattr(dto, attr))
  111. # 处理 options 字段(包含树配置与菜单父节点)和 parentMenuId
  112. import json
  113. options_dict = {}
  114. # 如果 options 字段存在,先解析它
  115. if hasattr(dto, 'options') and dto.options:
  116. try:
  117. if isinstance(dto.options, str):
  118. options_dict = json.loads(dto.options)
  119. else:
  120. options_dict = dto.options.copy() if hasattr(dto.options, 'copy') else dto.options
  121. except Exception as e:
  122. print(f"解析 options 字段出错: {e}")
  123. options_dict = {}
  124. # 合并树配置(来自 dto 的 treeCode/treeParentCode/treeName)
  125. # 兼容:如果前端把树配置直接放在 dto 顶层,则这里写入 options
  126. if getattr(dto, 'tree_code', None):
  127. options_dict['treeCode'] = dto.tree_code
  128. if getattr(dto, 'tree_parent_code', None):
  129. options_dict['treeParentCode'] = dto.tree_parent_code
  130. if getattr(dto, 'tree_name', None):
  131. options_dict['treeName'] = dto.tree_name
  132. # 检查 params 中是否有 parentMenuId 或树配置(部分前端可能通过 params 传递)
  133. if hasattr(dto, 'params') and dto.params:
  134. if isinstance(dto.params, dict):
  135. if 'parentMenuId' in dto.params:
  136. options_dict['parentMenuId'] = dto.params.get('parentMenuId')
  137. if 'treeCode' in dto.params:
  138. options_dict['treeCode'] = dto.params.get('treeCode')
  139. if 'treeParentCode' in dto.params:
  140. options_dict['treeParentCode'] = dto.params.get('treeParentCode')
  141. if 'treeName' in dto.params:
  142. options_dict['treeName'] = dto.params.get('treeName')
  143. # 更新 options 字段(无论是否包含 parentMenuId,都要保存)
  144. if options_dict is not None:
  145. gen_table.options = json.dumps(options_dict, ensure_ascii=False)
  146. if 'parentMenuId' in options_dict:
  147. gen_table.parent_menu_id = options_dict.get('parentMenuId')
  148. print(f"设置 parentMenuId: {options_dict.get('parentMenuId')}, options: {gen_table.options}")
  149. # 特别处理columns字段
  150. if hasattr(dto, 'columns') and dto.columns is not None:
  151. print(dto.columns)
  152. # 前端传过来的已经是正确的字符串格式,直接使用
  153. gen_table.columns = dto.columns
  154. else:
  155. gen_table.columns = dto.columns
  156. gen_table_service.update_gen_table(gen_table)
  157. return AjaxResponse.from_success(msg='修改成功')
  158. @gen.route('/<tableIds>', methods=['DELETE'])
  159. @PathValidator()
  160. @PreAuthorize(HasPerm('tool:gen:remove'))
  161. @JsonSerializer()
  162. def delete_gen_table(tableIds: str):
  163. """删除代码生成表"""
  164. try:
  165. table_ids = [int(id) for id in tableIds.split(',')]
  166. gen_table_service.delete_gen_table_by_ids(table_ids)
  167. return AjaxResponse.from_success(msg='删除成功')
  168. except Exception as e:
  169. return AjaxResponse.from_error(msg=f'删除失败: {str(e)}')
  170. @gen.route('/preview/<int:tableId>', methods=["GET"])
  171. @PathValidator()
  172. @PreAuthorize(HasPerm('tool:gen:preview'))
  173. @JsonSerializer()
  174. def preview(tableId: int):
  175. """预览代码"""
  176. try:
  177. data = gen_table_service.preview_code(tableId)
  178. return AjaxResponse.from_success(data=data)
  179. except Exception as e:
  180. return AjaxResponse.from_error(msg=f'预览失败: {str(e)}')
  181. @gen.route('/download/<table_name>', methods=["GET"])
  182. @PathValidator()
  183. @PreAuthorize(HasPerm('tool:gen:code'))
  184. @JsonSerializer()
  185. def download(table_name: str):
  186. """生成代码(下载方式)"""
  187. try:
  188. data = gen_table_service.generator_code(table_name)
  189. return send_file(
  190. BytesIO(data), # 将bytes包装成BytesIO对象
  191. mimetype='application/zip',
  192. as_attachment=True,
  193. download_name=f'{table_name}.zip'
  194. )
  195. except Exception as e:
  196. return AjaxResponse.from_error(msg=f'生成失败: {str(e)}')
  197. @gen.route('/genCode/<table_name>', methods=["GET"])
  198. @PathValidator()
  199. @PreAuthorize(HasPerm('tool:gen:code'))
  200. @JsonSerializer()
  201. def gen_code(table_name: str):
  202. """生成代码(自定义路径)"""
  203. try:
  204. data = gen_table_service.generator_code(table_name)
  205. return send_file(
  206. BytesIO(data), # 将bytes包装成BytesIO对象
  207. mimetype='application/zip',
  208. as_attachment=True,
  209. download_name=f'{table_name}.zip'
  210. )
  211. except Exception as e:
  212. return AjaxResponse.from_error(msg=f'生成失败: {str(e)}')
  213. @gen.route('/batchGenCode', methods=["GET"])
  214. @PreAuthorize(HasPerm('tool:gen:code'))
  215. @JsonSerializer()
  216. def batch_gen_code():
  217. """批量生成代码"""
  218. try:
  219. tables = request.args.get('tables')
  220. if not tables:
  221. return AjaxResponse.from_error(msg='参数错误')
  222. table_list = [table.strip() for table in tables.split(',') if table.strip()]
  223. if not table_list:
  224. return AjaxResponse.from_error(msg='参数错误')
  225. # 生成代码
  226. data = gen_table_service.batch_generator_code(table_list)
  227. return send_file(
  228. BytesIO(data), # 将bytes包装成BytesIO对象
  229. mimetype='application/zip',
  230. as_attachment=True,
  231. download_name='code.zip'
  232. )
  233. except Exception as e:
  234. return AjaxResponse.from_error(msg=f'批量生成失败: {str(e)}')
  235. @gen.route('/synchDb/<table_name>', methods=["GET"])
  236. @PreAuthorize(HasPerm('tool:gen:edit'))
  237. @JsonSerializer()
  238. def synch_db(table_name):
  239. """同步数据库"""
  240. # 检查表名是否有效
  241. if not table_name or table_name.lower() == 'null':
  242. return AjaxResponse.from_error(msg='表名不能为空')
  243. try:
  244. result = gen_table_service.synch_db(table_name)
  245. if result:
  246. return AjaxResponse.from_success(msg='同步成功')
  247. else:
  248. return AjaxResponse.from_error(msg='同步失败')
  249. except Exception as e:
  250. return AjaxResponse.from_error(msg=f'同步失败: {str(e)}')
  251. @gen.route('/column/list', methods=["GET"])
  252. @QueryValidator(is_page=True)
  253. @PreAuthorize(HasPerm('tool:gen:list'))
  254. @JsonSerializer()
  255. def column_list(dto: GenTableColumnPO):
  256. """查询数据库表字段列表"""
  257. table_id = request.args.get('tableId')
  258. if table_id:
  259. columns, total = gen_table_column_service.select_gen_table_column_list_by_table_id(int(table_id))
  260. else:
  261. columns, total = [], 0
  262. return TableResponse(code=HttpStatus.SUCCESS, msg='查询成功', rows=columns, total=total)
  263. @gen.route('/export', methods=["GET"])
  264. @PreAuthorize(HasPerm('tool:gen:export'))
  265. @JsonSerializer()
  266. def export():
  267. """导出代码生成表数据"""
  268. try:
  269. tables, total = gen_table_service.select_gen_table_list(GenTable())
  270. return AjaxResponse.from_success(data=tables, msg='导出成功')
  271. except Exception as e:
  272. return AjaxResponse.from_error(msg=f'导出失败: {str(e)}')
  273. @gen.route('/tableInfo/<table_name>', methods=["GET"])
  274. @PathValidator()
  275. @PreAuthorize(HasPerm('tool:gen:list'))
  276. @JsonSerializer()
  277. def get_table_info(table_name: str):
  278. """获取表信息"""
  279. try:
  280. if not gen_table_service.validate_table_name(table_name):
  281. return AjaxResponse.from_error(msg='表名格式不正确')
  282. table_info = gen_table_service.get_table_info(table_name)
  283. return AjaxResponse.from_success(data=table_info)
  284. except Exception as e:
  285. return AjaxResponse.from_error(msg=f'获取表信息失败: {str(e)}')