upload.html 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. {% extends "layout.html" %}
  2. {% block title %}上传文件 - 家谱管理系统{% endblock %}
  3. {% block content %}
  4. <div class="row justify-content-center">
  5. <div class="col-md-8">
  6. <div class="card shadow">
  7. <div class="card-header bg-primary text-white">
  8. <h5 class="mb-0"><i class="bi bi-cloud-upload me-2"></i>上传家谱扫描件</h5>
  9. </div>
  10. <div class="card-body p-4">
  11. <form method="POST" enctype="multipart/form-data" id="uploadForm">
  12. <div class="mb-4">
  13. <label class="form-label fw-bold">选择文件</label>
  14. <input type="file" name="file" id="fileInput" class="form-control form-control-lg" multiple accept=".jpg,.jpeg,.png,.pdf" required>
  15. <div class="form-text mt-2">
  16. 支持图片 (JPG, PNG) 或 PDF 格式的扫描件。图片支持多选(一次最多10张)。PDF文件会自动按页拆分提取。上传后将自动识别或提取页码。
  17. </div>
  18. </div>
  19. <div class="row mb-4">
  20. <div class="col-md-4">
  21. <label class="form-label fw-bold">版本名称 <span class="text-danger">*</span></label>
  22. <input type="text" name="genealogy_version" class="form-control" placeholder="如:衢州1926版" required>
  23. </div>
  24. <div class="col-md-4">
  25. <label class="form-label fw-bold">版本来源 <span class="text-danger">*</span></label>
  26. <input type="text" name="genealogy_source" class="form-control" placeholder="如:留越收藏" required>
  27. </div>
  28. <div class="col-md-4">
  29. <label class="form-label fw-bold">文件提供人</label>
  30. <input type="text" name="upload_person" class="form-control" placeholder="默认:当前系统登录账号">
  31. </div>
  32. </div>
  33. <div class="mb-4">
  34. <label class="form-label fw-bold">手动指定页码 (可选)</label>
  35. <div class="input-group">
  36. <input type="number" name="manual_page" id="initialPage" class="form-control" placeholder="如不输入则由 OCR 自动识别">
  37. <button class="btn btn-outline-secondary" type="button" onclick="document.getElementById('initialPage').value = {{ suggested_page }}">
  38. 提示:第 {{ suggested_page }} 页?
  39. </button>
  40. </div>
  41. <div class="form-text mt-1 text-muted">
  42. 建议值为当前数据库最大页码 + 1。
  43. </div>
  44. </div>
  45. <div class="alert alert-warning mb-4">
  46. <i class="bi bi-info-circle me-2"></i>
  47. 提示:文件将上传至云端 OSS 存储,处理过程可能需要几秒钟。
  48. </div>
  49. <div class="d-grid gap-2 d-md-flex justify-content-md-end">
  50. <a href="{{ url_for('index') }}" class="btn btn-light px-4">取消</a>
  51. <button type="submit" class="btn btn-primary px-5" id="submitBtn">
  52. <i class="bi bi-check-lg me-1"></i> 开始上传
  53. </button>
  54. </div>
  55. </form>
  56. </div>
  57. </div>
  58. </div>
  59. </div>
  60. {% endblock %}
  61. {% block extra_js %}
  62. <script>
  63. document.getElementById('uploadForm').addEventListener('submit', function(e) {
  64. // Prevent multiple submissions
  65. const btn = document.getElementById('submitBtn');
  66. if (btn.classList.contains('disabled')) {
  67. e.preventDefault();
  68. return;
  69. }
  70. // Show loading state without blocking submit
  71. btn.classList.add('disabled');
  72. btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 上传处理中...';
  73. // Disable after a tiny delay to ensure form submission proceeds
  74. setTimeout(() => {
  75. btn.disabled = true;
  76. }, 10);
  77. });
  78. document.getElementById('fileInput').addEventListener('change', function(e) {
  79. let files = e.target.files;
  80. let pdfCount = 0;
  81. let imgCount = 0;
  82. for (let i = 0; i < files.length; i++) {
  83. if (files[i].type === 'application/pdf' || files[i].name.toLowerCase().endsWith('.pdf')) {
  84. pdfCount++;
  85. } else {
  86. imgCount++;
  87. }
  88. }
  89. if (imgCount > 10) {
  90. alert('一次最多只能上传10张图片,请重新选择。');
  91. e.target.value = ''; // clear selection
  92. } else if (pdfCount > 0 && files.length > 1) {
  93. alert('上传PDF时,一次只能选择1个文件。');
  94. e.target.value = ''; // clear selection
  95. }
  96. });
  97. </script>
  98. {% endblock %}