evaluations.html 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. {% extends "base.html" %}
  2. {% block title %}知识评价 - 满意错题本{% endblock %}
  3. {% block page_title %}知识评价{% endblock %}
  4. {% block content %}
  5. <div class="flex items-center justify-between mb-6">
  6. <div class="flex items-center gap-4">
  7. <div class="w-10 h-10 rounded-xl bg-amber-100 flex items-center justify-center text-amber-600">
  8. <i class="fa-solid fa-clipboard-check text-lg"></i>
  9. </div>
  10. <div>
  11. <p class="text-sm font-semibold text-gray-700">知识评价</p>
  12. <p class="text-xs text-gray-400 mt-0.5">记录老师定期评价结果</p>
  13. </div>
  14. </div>
  15. <button onclick="openModal()" class="inline-flex items-center gap-2 bg-amber-500 text-white px-5 py-2.5 rounded-xl text-sm font-medium hover:bg-amber-600 transition shadow-sm">
  16. <i class="fa-solid fa-plus"></i>新增评价
  17. </button>
  18. </div>
  19. <!-- Subject filter -->
  20. <div class="bg-white rounded-2xl border border-gray-100 p-3 mb-6 flex items-center gap-2 overflow-x-auto">
  21. <a href="/evaluations" class="flex-shrink-0 px-4 py-1.5 rounded-xl text-xs font-medium transition {% if not current_subject %}bg-amber-500 text-white shadow-sm{% else %}bg-gray-50 text-gray-500 hover:bg-gray-100{% endif %}">全部</a>
  22. {% for s in subjects %}
  23. <a href="/evaluations?subject_id={{ s.id }}" class="flex-shrink-0 px-4 py-1.5 rounded-xl text-xs font-medium transition {% if current_subject == s.id %}bg-amber-500 text-white shadow-sm{% else %}bg-gray-50 text-gray-500 hover:bg-gray-100{% endif %}">
  24. <span class="w-2 h-2 rounded-full inline-block mr-1.5" style="background-color:{{ s.color }}"></span>{{ s.name }}
  25. </a>
  26. {% endfor %}
  27. </div>
  28. {% if evaluations %}
  29. <div class="space-y-3">
  30. {% for ev in evaluations %}
  31. {% set subject = subjects | selectattr('id','equalto',ev.subject_id) | first %}
  32. <div class="bg-white rounded-2xl border border-gray-100 p-5 hover:shadow-sm transition">
  33. <div class="flex items-start gap-4">
  34. {% if subject %}
  35. <span class="w-3 h-3 rounded-full mt-1.5 flex-shrink-0" style="background-color:{{ subject.color }};box-shadow:0 0 0 3px {{ subject.color }}20"></span>
  36. {% endif %}
  37. <div class="flex-1 min-w-0">
  38. <div class="flex items-center gap-3 mb-1 flex-wrap">
  39. <h4 class="font-bold text-gray-800 text-sm">{{ ev.title }}</h4>
  40. <span class="text-xs text-gray-400 bg-gray-100 px-2.5 py-0.5 rounded-full">{{ ev.date }}</span>
  41. {% if subject %}<span class="text-xs text-gray-400">· {{ subject.name }}</span>{% endif %}
  42. </div>
  43. {% if ev.content %}
  44. <p class="text-sm text-gray-500 leading-relaxed mt-2">{{ ev.content }}</p>
  45. {% endif %}
  46. {% if ev.filename %}
  47. <div class="mt-3 flex items-center gap-2">
  48. <a href="/static/uploads/{{ ev.filename }}" target="_blank" class="inline-flex items-center gap-2 text-xs text-amber-600 hover:text-amber-700 bg-amber-50 px-3 py-1.5 rounded-lg transition">
  49. <i class="fa-solid fa-paperclip"></i>{{ ev.filename }}
  50. </a>
  51. </div>
  52. {% endif %}
  53. </div>
  54. <div class="flex-shrink-0 flex items-center gap-3">
  55. <span class="text-xs text-gray-300 hidden sm:block">{{ ev.upload_time.strftime('%m-%d %H:%M') }}</span>
  56. <form method="POST" action="/evaluation/{{ ev.id }}/delete" onsubmit="return confirm('确定删除此评价?')">
  57. <button type="submit" class="text-gray-300 hover:text-red-400 transition" title="删除"><i class="fa-solid fa-trash-can"></i></button>
  58. </form>
  59. </div>
  60. </div>
  61. </div>
  62. {% endfor %}
  63. </div>
  64. {% else %}
  65. <div class="bg-white rounded-2xl border border-gray-100 p-16 text-center">
  66. <div class="text-6xl text-gray-200 mb-4"><i class="fa-solid fa-clipboard"></i></div>
  67. <p class="text-gray-400 mb-6">暂无评价记录</p>
  68. <button onclick="openModal()" class="inline-flex items-center gap-2 bg-amber-500 text-white px-6 py-3 rounded-xl text-sm font-medium hover:bg-amber-600 transition">
  69. <i class="fa-solid fa-plus"></i>新增第一条评价
  70. </button>
  71. </div>
  72. {% endif %}
  73. <!-- Modal -->
  74. <div id="evalModal" class="fixed inset-0 z-50 items-center justify-center modal-overlay bg-black/40" style="display:none">
  75. <div class="bg-white rounded-2xl w-full max-w-lg mx-4 shadow-2xl max-h-[90vh] overflow-y-auto">
  76. <div class="px-6 py-5 border-b border-gray-100 flex items-center justify-between sticky top-0 bg-white z-10 rounded-t-2xl">
  77. <h3 class="font-bold text-gray-800">新增知识评价</h3>
  78. <button onclick="closeModal()" class="text-gray-400 hover:text-gray-600"><i class="fa-solid fa-xmark text-lg"></i></button>
  79. </div>
  80. <form method="POST" action="/evaluations/add" enctype="multipart/form-data" class="p-6 space-y-5">
  81. <div>
  82. <label class="block text-sm font-medium text-gray-600 mb-2">科目 <span class="text-red-400">*</span></label>
  83. <select name="subject_id" required class="w-full border border-gray-200 rounded-xl px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-amber-300 focus:border-amber-400 transition bg-white">
  84. <option value="">请选择科目</option>
  85. {% for s in subjects %}
  86. <option value="{{ s.id }}">{{ s.name }}</option>
  87. {% endfor %}
  88. </select>
  89. </div>
  90. <div class="grid grid-cols-2 gap-4">
  91. <div>
  92. <label class="block text-sm font-medium text-gray-600 mb-2">评价日期</label>
  93. <input type="date" name="date" required value="{{ today }}"
  94. class="w-full border border-gray-200 rounded-xl px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-amber-300 transition">
  95. </div>
  96. <div>
  97. <label class="block text-sm font-medium text-gray-600 mb-2">标题</label>
  98. <input type="text" name="title" required placeholder="简要描述评价内容"
  99. class="w-full border border-gray-200 rounded-xl px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-amber-300 transition">
  100. </div>
  101. </div>
  102. <div>
  103. <label class="block text-sm font-medium text-gray-600 mb-2">详细内容</label>
  104. <textarea name="content" rows="4" placeholder="描述老师的评价内容、知识点掌握情况、改进建议等..."
  105. class="w-full border border-gray-200 rounded-xl px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-amber-300 transition resize-none"></textarea>
  106. </div>
  107. <div>
  108. <label class="block text-sm font-medium text-gray-600 mb-2">附件(可选)</label>
  109. <input type="file" name="file" accept=".pdf,.jpg,.jpeg,.png,.webp"
  110. class="w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-xl file:border-0 file:text-sm file:font-medium file:bg-amber-50 file:text-amber-600 hover:file:bg-amber-100">
  111. </div>
  112. <div class="flex gap-3 pt-2">
  113. <button type="button" onclick="closeModal()" class="flex-1 border border-gray-200 text-gray-600 py-2.5 rounded-xl text-sm font-medium hover:bg-gray-50 transition">取消</button>
  114. <button type="submit" class="flex-1 bg-amber-500 text-white py-2.5 rounded-xl text-sm font-medium hover:bg-amber-600 transition">保存评价</button>
  115. </div>
  116. </form>
  117. </div>
  118. </div>
  119. {% endblock %}
  120. {% block extra_js %}
  121. <script>
  122. const today=new Date().toISOString().slice(0,10);
  123. document.querySelectorAll('input[name="date"][value]').forEach(el=>{if(!el.value)el.value=today;});
  124. function openModal(){const m=document.getElementById('evalModal');m.style.display='flex';}
  125. function closeModal(){const m=document.getElementById('evalModal');m.style.display='none';}
  126. </script>
  127. {% endblock %}