common.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. # -*- coding: utf-8 -*-
  2. # @Author : YY
  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 FileUploadValidator, QueryValidator
  14. from ruoyi_common.base.model import AjaxResponse
  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('/profile/<path:resource>')
  41. @JsonSerializer()
  42. def profile_resource(resource:str):
  43. """
  44. 通过 /profile/** 访问上传资源
  45. 例如:/profile/uploads/dev/upload/2025/11/11/xxx.jpg
  46. """
  47. # 安全处理相对路径
  48. safe_path = resource.replace("..", "").lstrip("/\\")
  49. try:
  50. directory = os.path.dirname(safe_path) or "."
  51. filename = os.path.basename(safe_path)
  52. response = send_from_directory(
  53. directory=directory,
  54. path=filename,
  55. as_attachment=False,
  56. download_name=filename,
  57. )
  58. except NotFound:
  59. return AjaxResponse.from_error("文件不存在")
  60. except Exception:
  61. return AjaxResponse.from_error("读取文件失败")
  62. return response
  63. @reg.api.route('/common/upload', methods=['POST'])
  64. @FileUploadValidator()
  65. @JsonSerializer()
  66. def common_upload():
  67. file:FileStorage = request.files.get('file')
  68. if not file:
  69. return AjaxResponse.from_error("上传文件不能为空")
  70. file_name = FileUploadUtil.upload(file, RuoYiConfig().upload_path)
  71. url = request.host_url[:-1] + file_name
  72. new_file_name = FileUploadUtil.get_filename(file_name)
  73. original_filename = file.filename
  74. ajax_response = AjaxResponse.from_success()
  75. # 兼容前端组件字段(期待 fileName)
  76. setattr(ajax_response,"url",url)
  77. setattr(ajax_response,"fileName",file_name)
  78. setattr(ajax_response,"newFileName",new_file_name)
  79. setattr(ajax_response,"originalFilename",original_filename)
  80. return ajax_response
  81. @reg.api.route('/common/uploads', methods=['POST'])
  82. @FileUploadValidator()
  83. @JsonSerializer()
  84. def common_uploads():
  85. file_names = []
  86. urls = []
  87. new_file_names = []
  88. original_filenames = []
  89. if not request.files:
  90. return AjaxResponse.from_error("上传文件不能为空")
  91. for _,file in request.files.items():
  92. file_name = FileUploadUtil.upload(file, RuoYiConfig().upload_path)
  93. file_names.append(file_name)
  94. url = request.host_url[:-1] + file_name
  95. urls.append(url)
  96. new_file_name = FileUploadUtil.get_filename(file_name)
  97. new_file_names.append(new_file_name)
  98. original_filename = file.filename
  99. original_filenames.append(original_filename)
  100. ajax_response = AjaxResponse.from_success()
  101. # 兼容 camelCase
  102. setattr(ajax_response,"urls", ",".join(urls))
  103. setattr(ajax_response,"fileNames", ",".join(file_names))
  104. setattr(ajax_response,"newFileNames", ",".join(new_file_names))
  105. setattr(ajax_response,"originalFilenames", ",".join(original_filenames))
  106. return ajax_response
  107. @reg.api.route('/common/download/resource')
  108. @QueryValidator()
  109. @JsonSerializer()
  110. def common_download_resource(
  111. resource:Annotated[str,Field(annotation=str,min_length=1,max_length=100)]
  112. ):
  113. download_path = RuoYiConfig().download_path + StringUtil.substring_after(resource,Constants.RESOURCE_PREFIX)
  114. download_name = os.path.basename(download_path)
  115. try:
  116. response = send_from_directory(
  117. directory=RuoYiConfig().download_path,
  118. path=download_path,
  119. as_attachment=True,
  120. download_name=download_name,
  121. )
  122. except NotFound as e:
  123. return AjaxResponse.from_error("文件不存在")
  124. except Exception as e:
  125. return AjaxResponse.from_error("下载失败")
  126. return response