2026-01-08 20:32:03 +08:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<title>多 Agent 决策工作坊</title>
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
2026-01-08 20:32:03 +08:00
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
|
|
|
<div class="container">
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<!-- 页面标题 -->
|
|
|
|
|
|
<header>
|
|
|
|
|
|
<h1>多 Agent 决策工作坊</h1>
|
|
|
|
|
|
<p>通过多角色辩论生成更全面的决策方案</p>
|
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 创建工作坊按钮 -->
|
|
|
|
|
|
<button onclick="window.location.href='{{ url_for('create_workshop') }}'" class="btn-primary">创建新工作坊</button>
|
2026-01-08 20:32:03 +08:00
|
|
|
|
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<!-- 流程指南 -->
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
|
<h3>工作流程指南</h3>
|
|
|
|
|
|
<div class="process-indicator">
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="process-step-number">1</div>
|
|
|
|
|
|
<div class="process-step-text">创建工作坊</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="process-arrow">→</div>
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="process-step-number">2</div>
|
|
|
|
|
|
<div class="process-step-text">配置角色</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="process-arrow">→</div>
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="process-step-number">3</div>
|
|
|
|
|
|
<div class="process-step-text">开始辩论</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="process-arrow">→</div>
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="process-step-number">4</div>
|
|
|
|
|
|
<div class="process-step-text">查看结果</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 工作坊列表 -->
|
|
|
|
|
|
<div class="workshop-header">
|
2026-01-08 20:32:03 +08:00
|
|
|
|
<h2>工作坊列表</h2>
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<!-- 多选选项和排序按钮 -->
|
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
|
<!-- 多选选项 -->
|
|
|
|
|
|
<div class="select-options">
|
|
|
|
|
|
<button id="multiSelectToggle" class="btn-secondary">多选</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 排序按钮 -->
|
|
|
|
|
|
<div class="sort-buttons">
|
|
|
|
|
|
<button onclick="sortWorkshops('time')" class="btn-secondary {% if sort_by == 'time' %}active{% endif %}">按时间排序</button>
|
|
|
|
|
|
<button onclick="sortWorkshops('name')" class="btn-secondary {% if sort_by == 'name' %}active{% endif %}">按名称首字母排序</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 批量操作按钮 -->
|
|
|
|
|
|
<div class="batch-actions" id="batchActions" style="display: none;">
|
|
|
|
|
|
<button onclick="batchDeleteWorkshops()" class="btn-danger">批量删除</button>
|
|
|
|
|
|
<span id="selectedCount">已选择 0 个工作坊</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="workshop-list" id="workshopList">
|
2026-01-08 20:32:03 +08:00
|
|
|
|
{% if workshops %}
|
|
|
|
|
|
{% for workshop_id, workshop in workshops.items() %}
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<div class="workshop-card">
|
|
|
|
|
|
<!-- 复选框 -->
|
|
|
|
|
|
<div class="card-checkbox" style="display: none;">
|
|
|
|
|
|
<input type="checkbox" class="workshop-checkbox" data-id="{{ workshop_id }}">
|
|
|
|
|
|
</div>
|
2026-01-08 20:32:03 +08:00
|
|
|
|
<h3>{{ workshop.name }}</h3>
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<p>{{ workshop.goal }}</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="workshop-details">
|
|
|
|
|
|
<p><strong>角色数量:</strong> {{ workshop.roles|length }}</p>
|
|
|
|
|
|
<p><strong>辩论内容:</strong> {{ workshop.debate_content|length }} 条观点</p>
|
|
|
|
|
|
<p><strong>创建时间:</strong> {{ workshop.created_at.strftime('%Y-%m-%d %H:%M') if workshop.created_at else '未知' }}</p>
|
|
|
|
|
|
{% if workshop.final_decision_time %}
|
|
|
|
|
|
<p><strong>最终决策时间:</strong> {{ workshop.final_decision_time.strftime('%Y-%m-%d %H:%M') }}</p>
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 最终决策 -->
|
|
|
|
|
|
<div class="final-decision">
|
|
|
|
|
|
<p><strong>最终决策:</strong>
|
|
|
|
|
|
{% if workshop.final_decision %}
|
|
|
|
|
|
<span class="decision-text">{{ workshop.final_decision }}</span>
|
|
|
|
|
|
{% else %}
|
|
|
|
|
|
<span class="decision-pending">决策尚未确定</span>
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 工作坊状态 -->
|
|
|
|
|
|
{% if workshop.roles|length > 0 and workshop.debate_content|length > 0 %}
|
|
|
|
|
|
<span class="status-badge completed">已完成辩论</span>
|
|
|
|
|
|
{% elif workshop.roles|length > 0 %}
|
|
|
|
|
|
<span class="status-badge active">已配置角色</span>
|
|
|
|
|
|
{% else %}
|
|
|
|
|
|
<span class="status-badge">已创建</span>
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 操作按钮 -->
|
2026-01-08 20:32:03 +08:00
|
|
|
|
<div class="workshop-actions">
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<button onclick="window.location.href='{{ url_for('configure_roles', workshop_id=workshop_id) }}'" class="btn-secondary">配置角色</button>
|
|
|
|
|
|
<button onclick="window.location.href='{{ url_for('start_debate', workshop_id=workshop_id) }}'" class="btn-primary">开始辩论</button>
|
|
|
|
|
|
<button onclick="window.location.href='{{ url_for('show_results', workshop_id=workshop_id) }}'" class="btn-success">查看结果</button>
|
|
|
|
|
|
<button onclick="deleteWorkshop({{ workshop_id }})" class="btn-danger">删除</button>
|
2026-01-08 20:32:03 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endfor %}
|
|
|
|
|
|
{% else %}
|
2026-01-09 04:04:55 +08:00
|
|
|
|
<div class="card">
|
|
|
|
|
|
<div class="empty-state">
|
|
|
|
|
|
<button onclick="window.location.href='{{ url_for('create_workshop') }}'" class="btn-primary">创建第一个工作坊</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-08 20:32:03 +08:00
|
|
|
|
{% endif %}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-09 04:04:55 +08:00
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
// 无刷新排序工作坊
|
|
|
|
|
|
function sortWorkshops(sortBy) {
|
|
|
|
|
|
// 更新按钮的active状态
|
|
|
|
|
|
const buttons = document.querySelectorAll('.sort-buttons button');
|
|
|
|
|
|
buttons.forEach(button => {
|
|
|
|
|
|
button.classList.remove('active');
|
|
|
|
|
|
});
|
|
|
|
|
|
// 为当前点击的按钮添加active状态
|
|
|
|
|
|
if (sortBy === 'time') {
|
|
|
|
|
|
buttons[0].classList.add('active');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
buttons[1].classList.add('active');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送AJAX请求获取排序后的数据
|
|
|
|
|
|
// 将time转换为time_asc,实现按时间升序排序
|
|
|
|
|
|
const sortParam = sortBy === 'time' ? 'time_asc' : sortBy;
|
|
|
|
|
|
fetch(`/api/workshops?sort_by=${sortParam}`)
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
// 更新工作坊列表
|
|
|
|
|
|
const workshopList = document.getElementById('workshopList');
|
|
|
|
|
|
workshopList.innerHTML = '';
|
|
|
|
|
|
|
|
|
|
|
|
if (data.length > 0) {
|
|
|
|
|
|
data.forEach(workshop => {
|
|
|
|
|
|
// 创建工作坊卡片
|
|
|
|
|
|
const workshopCard = document.createElement('div');
|
|
|
|
|
|
workshopCard.className = 'workshop-card';
|
|
|
|
|
|
|
|
|
|
|
|
// 构建卡片内容
|
|
|
|
|
|
let cardContent = `
|
|
|
|
|
|
<!-- 复选框 -->
|
|
|
|
|
|
<div class="card-checkbox" style="display: none;">
|
|
|
|
|
|
<input type="checkbox" class="workshop-checkbox" data-id="${workshop.id}">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h3>${workshop.name}</h3>
|
|
|
|
|
|
<p>${workshop.goal}</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="workshop-details">
|
|
|
|
|
|
<p><strong>角色数量:</strong> ${workshop.roles.length}</p>
|
|
|
|
|
|
<p><strong>辩论内容:</strong> ${workshop.debate_content.length} 条观点</p>
|
|
|
|
|
|
<p><strong>创建时间:</strong> ${workshop.created_at || '未知'}</p>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加最终决策时间(如果有)
|
|
|
|
|
|
if (workshop.final_decision_time) {
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
<p><strong>最终决策时间:</strong> ${workshop.final_decision_time}</p>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加最终决策
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 最终决策 -->
|
|
|
|
|
|
<div class="final-decision">
|
|
|
|
|
|
<p><strong>最终决策:</strong>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加最终决策内容
|
|
|
|
|
|
if (workshop.final_decision) {
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
<span class="decision-text">${workshop.final_decision}</span>
|
|
|
|
|
|
`;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
<span class="no-decision">暂无</span>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加工作坊状态
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 工作坊状态 -->
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
if (workshop.roles.length > 0 && workshop.debate_content.length > 0) {
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
<span class="status-badge completed">已完成辩论</span>
|
|
|
|
|
|
`;
|
|
|
|
|
|
} else if (workshop.roles.length > 0) {
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
<span class="status-badge active">已配置角色</span>
|
|
|
|
|
|
`;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
<span class="status-badge">已创建</span>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加操作按钮
|
|
|
|
|
|
cardContent += `
|
|
|
|
|
|
<!-- 操作按钮 -->
|
|
|
|
|
|
<div class="workshop-actions">
|
|
|
|
|
|
<button onclick="window.location.href='/workshop/${workshop.id}/configure_roles'" class="btn-secondary">配置角色</button>
|
|
|
|
|
|
<button onclick="window.location.href='/workshop/${workshop.id}/debate'" class="btn-primary">开始辩论</button>
|
|
|
|
|
|
<button onclick="window.location.href='/workshop/${workshop.id}/results'" class="btn-success">查看结果</button>
|
|
|
|
|
|
<button onclick="deleteWorkshop(${workshop.id})" class="btn-danger">删除</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
workshopCard.innerHTML = cardContent;
|
|
|
|
|
|
workshopList.appendChild(workshopCard);
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 显示空状态
|
|
|
|
|
|
workshopList.innerHTML = `
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
|
<div class="empty-state">
|
|
|
|
|
|
<p>暂无工作坊,请创建新工作坊</p>
|
|
|
|
|
|
<button onclick="window.location.href='/create'" class="btn-primary">创建第一个工作坊</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('获取数据失败:', error);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除单个工作坊
|
|
|
|
|
|
function deleteWorkshop(id) {
|
|
|
|
|
|
if (confirm('确定要删除这个工作坊吗?')) {
|
|
|
|
|
|
fetch(`/api/workshop/${id}`, {
|
|
|
|
|
|
method: 'DELETE'
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
// 重新获取工作坊列表
|
|
|
|
|
|
sortWorkshops(document.querySelector('.sort-buttons button.active') ? 'name' : 'time');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
alert('删除失败: ' + data.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('删除失败:', error);
|
|
|
|
|
|
alert('删除失败,请稍后重试');
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 批量删除工作坊
|
|
|
|
|
|
function batchDeleteWorkshops() {
|
|
|
|
|
|
const selectedIds = getSelectedWorkshopIds();
|
|
|
|
|
|
if (selectedIds.length === 0) {
|
|
|
|
|
|
alert('请先选择要删除的工作坊');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (confirm(`确定要删除选中的 ${selectedIds.length} 个工作坊吗?`)) {
|
|
|
|
|
|
fetch('/api/workshops/batch_delete', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({ workshop_ids: selectedIds })
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
// 重新获取工作坊列表
|
|
|
|
|
|
sortWorkshops(document.querySelector('.sort-buttons button.active') ? 'name' : 'time');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
alert('批量删除失败: ' + data.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('批量删除失败:', error);
|
|
|
|
|
|
alert('批量删除失败,请稍后重试');
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取选中的工作坊ID
|
|
|
|
|
|
function getSelectedWorkshopIds() {
|
|
|
|
|
|
const checkboxes = document.querySelectorAll('.workshop-checkbox:checked');
|
|
|
|
|
|
return Array.from(checkboxes).map(checkbox => parseInt(checkbox.dataset.id));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新选中状态
|
|
|
|
|
|
function updateSelectionStatus() {
|
|
|
|
|
|
const selectedIds = getSelectedWorkshopIds();
|
|
|
|
|
|
const selectedCount = selectedIds.length;
|
|
|
|
|
|
const batchActions = document.getElementById('batchActions');
|
|
|
|
|
|
const selectedCountElement = document.getElementById('selectedCount');
|
|
|
|
|
|
|
|
|
|
|
|
if (selectedCount > 0) {
|
|
|
|
|
|
batchActions.style.display = 'flex';
|
|
|
|
|
|
selectedCountElement.textContent = `已选择 ${selectedCount} 个工作坊`;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
batchActions.style.display = 'none';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新全选复选框状态
|
|
|
|
|
|
const allCheckboxes = document.querySelectorAll('.workshop-checkbox');
|
|
|
|
|
|
const selectAllCheckbox = document.getElementById('selectAllCheckbox');
|
|
|
|
|
|
if (selectAllCheckbox) {
|
|
|
|
|
|
if (allCheckboxes.length > 0) {
|
|
|
|
|
|
selectAllCheckbox.checked = allCheckboxes.length === selectedIds.length;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
selectAllCheckbox.checked = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换多选模式
|
|
|
|
|
|
let isMultiSelectMode = false;
|
|
|
|
|
|
function toggleMultiSelectMode() {
|
|
|
|
|
|
const checkboxes = document.querySelectorAll('.card-checkbox');
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有工作坊(即是否有复选框)
|
|
|
|
|
|
if (checkboxes.length === 0) {
|
|
|
|
|
|
return; // 没有工作坊时,不执行任何操作
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
isMultiSelectMode = !isMultiSelectMode;
|
|
|
|
|
|
const multiSelectToggle = document.getElementById('multiSelectToggle');
|
|
|
|
|
|
const batchActions = document.getElementById('batchActions');
|
|
|
|
|
|
|
|
|
|
|
|
if (isMultiSelectMode) {
|
|
|
|
|
|
// 进入多选模式
|
|
|
|
|
|
checkboxes.forEach(checkbox => {
|
|
|
|
|
|
checkbox.style.display = 'block';
|
|
|
|
|
|
});
|
|
|
|
|
|
multiSelectToggle.textContent = '取消多选';
|
|
|
|
|
|
multiSelectToggle.classList.remove('btn-secondary');
|
|
|
|
|
|
multiSelectToggle.classList.add('btn-primary');
|
|
|
|
|
|
// 显示批量操作按钮
|
|
|
|
|
|
batchActions.style.display = 'flex';
|
|
|
|
|
|
// 重置选中状态
|
|
|
|
|
|
document.querySelectorAll('.workshop-checkbox').forEach(checkbox => {
|
|
|
|
|
|
checkbox.checked = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
updateSelectionStatus();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 退出多选模式
|
|
|
|
|
|
checkboxes.forEach(checkbox => {
|
|
|
|
|
|
checkbox.style.display = 'none';
|
|
|
|
|
|
});
|
|
|
|
|
|
multiSelectToggle.textContent = '多选';
|
|
|
|
|
|
multiSelectToggle.classList.remove('btn-primary');
|
|
|
|
|
|
multiSelectToggle.classList.add('btn-secondary');
|
|
|
|
|
|
// 隐藏批量操作按钮
|
|
|
|
|
|
batchActions.style.display = 'none';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 全选/取消全选
|
|
|
|
|
|
function toggleSelectAll() {
|
|
|
|
|
|
const checkboxes = document.querySelectorAll('.workshop-checkbox');
|
|
|
|
|
|
const firstCheckbox = checkboxes[0];
|
|
|
|
|
|
if (firstCheckbox) {
|
|
|
|
|
|
const shouldCheck = !firstCheckbox.checked;
|
|
|
|
|
|
checkboxes.forEach(checkbox => {
|
|
|
|
|
|
checkbox.checked = shouldCheck;
|
|
|
|
|
|
});
|
|
|
|
|
|
updateSelectionStatus();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 监听工作坊复选框变化
|
|
|
|
|
|
document.addEventListener('change', function(event) {
|
|
|
|
|
|
if (event.target.classList.contains('workshop-checkbox')) {
|
|
|
|
|
|
updateSelectionStatus();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化时绑定事件
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
// 绑定排序按钮事件
|
|
|
|
|
|
const sortButtons = document.querySelectorAll('.sort-buttons button');
|
|
|
|
|
|
sortButtons.forEach(button => {
|
|
|
|
|
|
button.addEventListener('click', function() {
|
|
|
|
|
|
const sortBy = this.textContent.includes('时间') ? 'time' : 'name';
|
|
|
|
|
|
sortWorkshops(sortBy);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定多选模式切换按钮事件
|
|
|
|
|
|
const multiSelectToggle = document.getElementById('multiSelectToggle');
|
|
|
|
|
|
multiSelectToggle.addEventListener('click', toggleMultiSelectMode);
|
|
|
|
|
|
|
|
|
|
|
|
// 初始更新选中状态
|
|
|
|
|
|
updateSelectionStatus();
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
2026-01-08 20:32:03 +08:00
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|