export.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. """Export API routes for Excel report generation."""
  2. from flask import request, send_file
  3. from flask_restx import Namespace, Resource, fields
  4. from app.services.export_service import ExportService
  5. from app.utils.auth_decorator import require_auth
  6. export_ns = Namespace('export', description='Excel导出接口')
  7. # Response models for Swagger documentation
  8. error_response = export_ns.model('ExportErrorResponse', {
  9. 'success': fields.Boolean(description='操作是否成功'),
  10. 'error': fields.String(description='错误信息'),
  11. 'code': fields.String(description='错误代码')
  12. })
  13. @export_ns.route('/monthly')
  14. class MonthlyExport(Resource):
  15. """Resource for monthly Excel export."""
  16. @export_ns.doc('export_monthly')
  17. @export_ns.param('year', '年份 (例如: 2024)', required=True, type=int)
  18. @export_ns.param('month', '月份 (1-12)', required=True, type=int)
  19. @export_ns.response(200, 'Excel文件下载')
  20. @export_ns.response(400, '参数错误', error_response)
  21. @export_ns.response(500, '服务器错误', error_response)
  22. @export_ns.produces(['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'])
  23. @require_auth
  24. def get(self):
  25. """导出月度工作报表Excel
  26. 生成包含以下内容的Excel文件:
  27. - 明细表: 人员、日期、物品、单价、数量、总价
  28. - 月度汇总: 每人总金额及合计
  29. """
  30. # Get and validate parameters
  31. year = request.args.get('year', type=int)
  32. month = request.args.get('month', type=int)
  33. if year is None:
  34. return {
  35. 'success': False,
  36. 'error': 'Year parameter is required',
  37. 'code': 'VALIDATION_ERROR'
  38. }, 400
  39. if month is None:
  40. return {
  41. 'success': False,
  42. 'error': 'Month parameter is required',
  43. 'code': 'VALIDATION_ERROR'
  44. }, 400
  45. try:
  46. excel_file, error = ExportService.export_monthly(year, month)
  47. if error:
  48. return {
  49. 'success': False,
  50. 'error': error,
  51. 'code': 'VALIDATION_ERROR'
  52. }, 400
  53. filename = f'work_report_{year}_{month:02d}.xlsx'
  54. return send_file(
  55. excel_file,
  56. mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  57. as_attachment=True,
  58. download_name=filename
  59. )
  60. except Exception as e:
  61. return {
  62. 'success': False,
  63. 'error': f'Failed to generate Excel: {str(e)}',
  64. 'code': 'SERVER_ERROR'
  65. }, 500
  66. @export_ns.route('/yearly')
  67. class YearlyExport(Resource):
  68. """Resource for yearly Excel export."""
  69. @export_ns.doc('export_yearly')
  70. @export_ns.param('year', '年份 (例如: 2024)', required=True, type=int)
  71. @export_ns.response(200, 'Excel文件下载')
  72. @export_ns.response(400, '参数错误', error_response)
  73. @export_ns.response(500, '服务器错误', error_response)
  74. @export_ns.produces(['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'])
  75. @require_auth
  76. def get(self):
  77. """导出年度工作报表Excel
  78. 生成包含以下内容的Excel文件:
  79. - 明细表: 人员、日期、物品、单价、数量、总价
  80. - 年度汇总: 每人按月统计及年度合计
  81. """
  82. # Get and validate parameters
  83. year = request.args.get('year', type=int)
  84. if year is None:
  85. return {
  86. 'success': False,
  87. 'error': 'Year parameter is required',
  88. 'code': 'VALIDATION_ERROR'
  89. }, 400
  90. try:
  91. excel_file, error = ExportService.export_yearly(year)
  92. if error:
  93. return {
  94. 'success': False,
  95. 'error': error,
  96. 'code': 'VALIDATION_ERROR'
  97. }, 400
  98. filename = f'work_report_{year}.xlsx'
  99. return send_file(
  100. excel_file,
  101. mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  102. as_attachment=True,
  103. download_name=filename
  104. )
  105. except Exception as e:
  106. return {
  107. 'success': False,
  108. 'error': f'Failed to generate Excel: {str(e)}',
  109. 'code': 'SERVER_ERROR'
  110. }, 500