common.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. # -*- coding: utf-8 -*-
  2. # @Author : shaw-lee
  3. import os
  4. import time
  5. from flask import request, send_from_directory
  6. from pydantic import Field
  7. from typing_extensions import Annotated
  8. from werkzeug.datastructures import FileStorage
  9. from werkzeug.exceptions import NotFound
  10. from ruoyi_common.config import RuoYiConfig
  11. from ruoyi_common.constant import Constants
  12. from ruoyi_common.descriptor.serializer import JsonSerializer
  13. from ruoyi_common.descriptor.validator import FileValidator, QueryValidator
  14. from ruoyi_common.base.model import AjaxResponse, MultiFile
  15. from ruoyi_common.utils import FileUploadUtil, FileUtil, StringUtil
  16. from ... import reg
  17. @reg.api.route('/common/download')
  18. @QueryValidator()
  19. @JsonSerializer()
  20. def common_download(
  21. file_name: Annotated[str, Field(min_length=1, max_length=100)],
  22. delete: Annotated[bool, Field(annotations=bool, default=False)],
  23. ):
  24. file_path = RuoYiConfig.download_path + file_name
  25. download_name = time.time() * 1000 + file_name[file_name.index("_") + 1:]
  26. try:
  27. response = send_from_directory(
  28. directory=RuoYiConfig.download_path,
  29. path=file_name,
  30. as_attachment=True,
  31. download_name=download_name,
  32. )
  33. if delete:
  34. FileUtil.delete_file(file_path)
  35. except NotFound as e:
  36. return AjaxResponse.from_error("文件不存在")
  37. except Exception as e:
  38. return AjaxResponse.from_error("下载失败")
  39. return response
  40. @reg.api.route('/common/upload', methods=['POST'])
  41. @FileValidator()
  42. @JsonSerializer()
  43. def common_upload(file: MultiFile):
  44. file: FileStorage = file.one()
  45. file_name = FileUploadUtil.upload(file, RuoYiConfig.upload_path)
  46. url = request.host_url[:-1] + file_name
  47. new_file_name = FileUploadUtil.get_filename(file_name)
  48. original_filename = file.filename
  49. ajax_response = AjaxResponse.from_success()
  50. # 为了兼容若依 Vue 前端,这里的字段名与 Java 版保持一致(驼峰命名)
  51. setattr(ajax_response, "url", url)
  52. setattr(ajax_response, "fileName", file_name)
  53. setattr(ajax_response, "newFileName", new_file_name)
  54. setattr(ajax_response, "originalFilename", original_filename)
  55. return ajax_response
  56. @reg.api.route('/common/uploads', methods=['POST'])
  57. @FileValidator()
  58. @JsonSerializer()
  59. def common_uploads(files: MultiFile):
  60. file_names = []
  61. urls = []
  62. new_file_names = []
  63. original_filenames = []
  64. for _, file in files.items():
  65. file_name = FileUploadUtil.upload(file, RuoYiConfig.upload_path)
  66. file_names.append(file_name)
  67. url = request.host_url[:-1] + file_name
  68. urls.append(url)
  69. new_file_name = FileUploadUtil.get_filename(file_name)
  70. new_file_names.append(new_file_name)
  71. original_filename = file.filename
  72. original_filenames.append(original_filename)
  73. ajax_response = AjaxResponse.from_success()
  74. # 多文件上传字段命名也与若依保持一致
  75. setattr(ajax_response, "urls", ",".join(urls))
  76. setattr(ajax_response, "fileNames", ",".join(file_names))
  77. setattr(ajax_response, "newFileNames", ",".join(new_file_names))
  78. setattr(ajax_response, "originalFilenames", ",".join(original_filenames))
  79. return ajax_response
  80. @reg.api.route('/common/download/resource')
  81. @QueryValidator()
  82. @JsonSerializer()
  83. def common_download_resource(
  84. resource: Annotated[str, Field(annotation=str, min_length=1, max_length=100)]
  85. ):
  86. download_path = RuoYiConfig.download_path + StringUtil.substring_after(resource, Constants.RESOURCE_PREFIX)
  87. download_name = os.path.basename(download_path)
  88. try:
  89. response = send_from_directory(
  90. directory=RuoYiConfig.download_path,
  91. path=download_path,
  92. as_attachment=True,
  93. download_name=download_name,
  94. )
  95. except NotFound as e:
  96. return AjaxResponse.from_error("文件不存在")
  97. except Exception as e:
  98. return AjaxResponse.from_error("下载失败")
  99. return response
  100. @reg.api.route(f"{Constants.RESOURCE_PREFIX}/<path:resource>")
  101. def common_profile_resource(resource: str):
  102. """
  103. 静态资源访问:
  104. 将 /profile/** 映射到配置的 profile 物理目录下,与 Java 版若依保持一致。
  105. 例如:
  106. ruoyi.profile = G:/ruoyi/uploadPath
  107. URL: /profile/upload/2025/11/18/xxx.jpg
  108. 实际: G:/ruoyi/uploadPath/upload/2025/11/18/xxx.jpg
  109. """
  110. try:
  111. return send_from_directory(
  112. directory=RuoYiConfig.profile,
  113. path=resource,
  114. )
  115. except NotFound:
  116. return AjaxResponse.from_error("文件不存在")