Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed __pycache__/jwFetcher.cpython-312.pyc
Binary file not shown.
Binary file removed __pycache__/main.cpython-312.pyc
Binary file not shown.
Binary file removed backend/__pycache__/cookie_manager.cpython-312.pyc
Binary file not shown.
Binary file removed backend/__pycache__/ranker.cpython-312.pyc
Binary file not shown.
Binary file removed backend/__pycache__/session_manager.cpython-312.pyc
Binary file not shown.
Binary file removed backend/__pycache__/solver.cpython-312.pyc
Binary file not shown.
6 changes: 3 additions & 3 deletions backend/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def check_conflicts(groups):
group_b = groups[j]

# Get active candidates
cands_a = [c for idx, c in enumerate(group_a['candidates']) if idx in group_a['selected_indices']]
cands_b = [c for idx, c in enumerate(group_b['candidates']) if idx in group_b['selected_indices']]
cands_a = [c for c in group_a['candidates'] if c.get('selected', False)]
cands_b = [c for c in group_b['candidates'] if c.get('selected', False)]

if not cands_a or not cands_b:
continue # Empty group cannot conflict
Expand Down Expand Up @@ -67,7 +67,7 @@ def generate_schedules(groups, max_results=1000):
# Prepare list of lists of candidates
candidate_lists = []
for g in groups:
active = [c for idx, c in enumerate(g['candidates']) if idx in g['selected_indices']]
active = [c for c in g['candidates'] if c.get('selected', False)]
if not active:
return [] # If any group has no active candidates, no solution possible
candidate_lists.append(active)
Expand Down
33 changes: 24 additions & 9 deletions static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,46 @@ createApp({
};

const createGroup = () => {
const selected = searchResults.value.filter(c => c.checked);
if (selected.length === 0) return showToast("未选择任何课程");
const selectedInSearch = searchResults.value.filter(c => c.checked);
if (selectedInSearch.length === 0) return showToast("未选择任何课程");

// Copy all search results, map checked to selected
const candidates = searchResults.value.map(c => ({
...c,
selected: c.checked
}));

groups.value.push({
id: Date.now(),
open: false,
candidates: selected, // Store full objects
selected_indices: selected.map((_, i) => i) // Default all active
candidates: candidates
});
searchResults.value = [];
currentView.value = 'planning';
showToast("已添加新课程组");
};

const getGroupName = (group) => {
if (group.candidates.length > 0) return group.candidates[0].name;
// Find first selected one to name the group, or just the first one
const first = group.candidates.find(c => c.selected) || group.candidates[0];
if (first) return first.name;
return "未知课程";
};

const getActiveCount = (group) => group.selected_indices.length;
const getActiveCount = (group) => group.candidates.filter(c => c.selected).length;

const toggleCandidate = (group, idx) => {
const i = group.selected_indices.indexOf(idx);
if (i > -1) group.selected_indices.splice(i, 1);
else group.selected_indices.push(idx);
// No-op here if using v-model, but let's keep it or remove it.
// Since we switch to v-model in the template, this function might become obsolete
// OR we can keep it if we want to programmatically toggle.
// But the previous implementation used indices.
// The template currently calls it. I will update the template to use v-model.
// So I can remove this function or just leave a placeholder.
// Actually, let's just make it toggle the boolean for the candidate at that index if needed,
// but v-model is cleaner. I'll remove it from the return object if I don't use it.
// But to be safe, I'll update it to toggle boolean.
const c = group.candidates[idx];
if (c) c.selected = !c.selected;
};

const removeGroup = (idx) => groups.value.splice(idx, 1);
Expand Down
3 changes: 1 addition & 2 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ <h2>我的课程组 ({{ groups.length }})</h2>
<div :class="['group-body', group.open ? 'open' : '']">
<label v-for="(course, cIdx) in group.candidates" :key="cIdx" class="result-item">
<input type="checkbox"
:checked="group.selected_indices.includes(cIdx)"
@change="toggleCandidate(group, cIdx)">
v-model="course.selected">
<div>
{{ course.name }} - {{ course.teacher }} <br>
<small>{{ course.location_text }}</small>
Expand Down
3 changes: 1 addition & 2 deletions tests/test_api_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ def test_generate_flow(self):
# Dummy groups
groups = [{
'id': 1,
'candidates': [{'name': 'A', 'schedule_bitmaps': [0, 3]}],
'selected_indices': [0]
'candidates': [{'name': 'A', 'schedule_bitmaps': [0, 3], 'selected': True}],
}]
prefs = {'avoid_early_morning': False}

Expand Down