diff --git a/app/templates/classes.html b/app/templates/classes.html
index 92eee60..3132df7 100644
--- a/app/templates/classes.html
+++ b/app/templates/classes.html
@@ -128,61 +128,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+{% set modal_title = '分配目标' %}
+{% include "fragments/assign_goal_modal.html" with context %}
{% endblock %}
{% block extra_js %}
@@ -354,59 +301,59 @@ document.getElementById('addClassBtn').onclick = () => {
// ========== 分配目标功能 ==========
-let classAssignGoalModal;
+let assignGoalModal;
-document.getElementById('classAssignGoalModal').addEventListener('show.bs.modal', function () {
+document.getElementById('assignGoalModal').addEventListener('show.bs.modal', function () {
loadClassGoalOptions();
});
function openAssignGoalModal(classId, className) {
currentClassId = classId;
- document.getElementById('classAssignGoalClassName').textContent = className;
+ document.getElementById('assignGoalModalSubtitle').textContent = ' - ' + className;
// 重置表单
- document.getElementById('class-assign-assessment-days').value = '';
- document.getElementById('class-assign-assessment-date').value = '';
- document.getElementById('class-assign-start-date').value = '';
- classAssignGoalModal = new bootstrap.Modal(document.getElementById('classAssignGoalModal'));
- classAssignGoalModal.show();
+ document.getElementById('assign-assessment-days').value = '';
+ document.getElementById('assign-assessment-date').value = '';
+ document.getElementById('assign-start-date').value = '';
+ assignGoalModal = new bootstrap.Modal(document.getElementById('assignGoalModal'));
+ assignGoalModal.show();
}
async function loadClassGoalOptions() {
const res = await fetch('/api/goals');
const goals = await res.json();
- const select = document.getElementById('class-assign-goal-select');
+ const select = document.getElementById('assign-goal-select');
select.innerHTML = goals.map(g => ``).join('');
// 设置默认开始日期为今天,评估日期为90天后
- document.getElementById('class-assign-start-date').value = new Date().toISOString().split('T')[0];
- document.getElementById('class-assign-assessment-days').value = '90';
+ document.getElementById('assign-start-date').value = new Date().toISOString().split('T')[0];
+ document.getElementById('assign-assessment-days').value = '90';
const d = new Date();
d.setDate(d.getDate() + 90);
- document.getElementById('class-assign-assessment-date').value = d.toISOString().split('T')[0];
+ document.getElementById('assign-assessment-date').value = d.toISOString().split('T')[0];
}
// 评估日期联动
-document.getElementById('class-assign-assessment-days').addEventListener('change', function() {
+document.getElementById('assign-assessment-days').addEventListener('change', function() {
const days = parseInt(this.value);
if (days) {
const d = new Date();
d.setDate(d.getDate() + days);
- document.getElementById('class-assign-assessment-date').value = d.toISOString().split('T')[0];
+ document.getElementById('assign-assessment-date').value = d.toISOString().split('T')[0];
}
});
-document.getElementById('class-assign-assessment-date').addEventListener('change', function() {
+document.getElementById('assign-assessment-date').addEventListener('change', function() {
if (this.value) {
- document.getElementById('class-assign-assessment-days').value = '';
+ document.getElementById('assign-assessment-days').value = '';
}
});
// 确认分配目标
-document.getElementById('confirm-class-assign-goal').addEventListener('click', async () => {
- const goalId = document.getElementById('class-assign-goal-select').value;
- const assessmentDays = document.getElementById('class-assign-assessment-days').value;
- const assessmentDate = document.getElementById('class-assign-assessment-date').value;
- const startDate = document.getElementById('class-assign-start-date').value;
+document.getElementById('confirm-assign-goal').addEventListener('click', async () => {
+ const goalId = document.getElementById('assign-goal-select').value;
+ const assessmentDays = document.getElementById('assign-assessment-days').value;
+ const assessmentDate = document.getElementById('assign-assessment-date').value;
+ const startDate = document.getElementById('assign-start-date').value;
if (!goalId) { alert('请选择目标'); return; }
if (!assessmentDays && !assessmentDate) { alert('请选择评估方式'); return; }
@@ -428,7 +375,7 @@ document.getElementById('confirm-class-assign-goal').addEventListener('click', a
if (res.ok) {
const data = await res.json();
- classAssignGoalModal.hide();
+ assignGoalModal.hide();
alert(data.message + (data.skipped_count ? `(${data.skipped_count}个学员已分配此目标,跳过)` : ''));
} else {
const err = await res.json();
diff --git a/app/templates/fragments/assign_goal_modal.html b/app/templates/fragments/assign_goal_modal.html
new file mode 100644
index 0000000..43c9583
--- /dev/null
+++ b/app/templates/fragments/assign_goal_modal.html
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/templates/student.html b/app/templates/student.html
index 5bd398d..37d83ac 100644
--- a/app/templates/student.html
+++ b/app/templates/student.html
@@ -252,61 +252,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+{% include "fragments/assign_goal_modal.html" with context %}
diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md
index bf62e2f..8e9d023 100644
--- a/docs/DEVELOPMENT.md
+++ b/docs/DEVELOPMENT.md
@@ -143,6 +143,54 @@ deploy: v1.2.0 生产环境部署
---
+## 代码复用规范(铁律)
+
+### DRY 原则(Don't Repeat Yourself)
+
+> **复制粘贴代码是严重的 Code Smell。任何重复代码必须提取为可复用组件。**
+
+### 前端模板复用
+
+| 场景 | 复用方式 |
+|------|---------|
+| 多个页面共用 Modal | 提取为 `app/templates/fragments/` 下的 Fragment,用 `{% include %}` 引用 |
+| 多个页面共用样式 | 在 `base.html` 或页面级别 `