+186
-27
@@ -580,6 +580,39 @@
|
||||
padding: 14px 24px; border-top: 1px solid var(--border); gap: 10px;
|
||||
}
|
||||
|
||||
/* ════ 下载队列 ════ */
|
||||
.submit-row { display: flex; gap: 6px; align-items: stretch; }
|
||||
.btn-add-queue {
|
||||
padding: 9px 14px; border-radius: 7px;
|
||||
background: transparent; border: 1px solid var(--border);
|
||||
color: var(--muted); font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; transition: all .15s; white-space: nowrap;
|
||||
}
|
||||
.btn-add-queue:hover { border-color: var(--accent); color: var(--accent); }
|
||||
.queue-item {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 9px 2px; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.queue-item:last-child { border-bottom: none; }
|
||||
.queue-num {
|
||||
width: 22px; height: 22px; border-radius: 50%;
|
||||
background: rgba(88,166,255,.12); border: 1px solid rgba(88,166,255,.25);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 11px; font-weight: 700; color: var(--accent); flex-shrink: 0;
|
||||
}
|
||||
.queue-info { flex: 1; min-width: 0; }
|
||||
.queue-name { font-size: 13px; font-weight: 500;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.queue-filter { font-size: 11px; color: var(--muted); margin-top: 2px;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.queue-del {
|
||||
width: 26px; height: 26px; border: none; background: none;
|
||||
color: var(--muted); cursor: pointer; border-radius: 4px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 13px; flex-shrink: 0; transition: all .12s;
|
||||
}
|
||||
.queue-del:hover { background: rgba(248,81,73,.15); color: var(--red); }
|
||||
|
||||
/* 响应式:手机适配(≤ 768px) */
|
||||
@media (max-width: 768px) {
|
||||
/* 顶部导航变两行,把 --hdr-h 调大供 formbar margin 跟随 */
|
||||
@@ -629,7 +662,10 @@
|
||||
}
|
||||
.fb-field { padding: 0; width: 100%; border-right: none !important; min-width: 0; }
|
||||
.fb-field-submit { padding: 0; }
|
||||
.submit-row { flex-direction: column; gap: 8px; }
|
||||
.btn-add-queue { width: 100%; padding: 11px; font-size: 13px; }
|
||||
.btn-submit { width: 100%; justify-content: center; padding: 12px; font-size: 14px; }
|
||||
.queue-filter { font-size: 10px; }
|
||||
|
||||
/* 验证下拉宽度自适应,避免溢出 */
|
||||
.val-drop { width: auto; left: 12px; right: 12px; }
|
||||
@@ -927,9 +963,14 @@
|
||||
|
||||
<!-- 提交 -->
|
||||
<div class="fb-field fb-field-submit">
|
||||
<button class="btn-submit" id="save-btn" onclick="saveAndRestart()">
|
||||
🔄 保存并重启下载
|
||||
</button>
|
||||
<div class="submit-row">
|
||||
<button class="btn-add-queue" id="add-queue-btn" onclick="addToQueue()">
|
||||
➕ 加入队列
|
||||
</button>
|
||||
<button class="btn-submit" id="save-btn" onclick="saveAndRestart()" style="flex:1">
|
||||
🔄 保存并重启下载
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -958,6 +999,18 @@
|
||||
<div style="font-size:11px;color:var(--muted);flex-shrink:0;">当前任务</div>
|
||||
</div>
|
||||
|
||||
<!-- 下载队列(待处理) -->
|
||||
<div class="card" id="queue-card" style="display:none">
|
||||
<div class="card-hd">
|
||||
<span>
|
||||
待处理队列
|
||||
<span class="card-hd-badge" id="queue-count" style="margin-left:6px">0 个</span>
|
||||
</span>
|
||||
<button class="btn-clear" onclick="clearQueue()">清空</button>
|
||||
</div>
|
||||
<div class="card-bd" id="queue-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- 历史频道 -->
|
||||
<div class="card">
|
||||
<div class="hist-head" onclick="toggleHist()">
|
||||
@@ -1211,41 +1264,147 @@
|
||||
});
|
||||
});
|
||||
|
||||
// ── 保存并重启 ──
|
||||
function saveAndRestart() {
|
||||
// ── 下载队列 ──
|
||||
let downloadQueue = [];
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({
|
||||
'&':'&','<':'<','>':'>','"':'"',"'":'''
|
||||
})[c]);
|
||||
}
|
||||
|
||||
function buildFilterFromForm(startDate, endDate) {
|
||||
const custom = filterExpression || '';
|
||||
if (custom) return custom;
|
||||
if (!startDate) return '';
|
||||
return 'message_date >= ' + startDate + ' 00:00:00' +
|
||||
(endDate ? ' and message_date <= ' + endDate + ' 23:59:59' : '');
|
||||
}
|
||||
|
||||
function renderQueue() {
|
||||
const card = document.getElementById('queue-card');
|
||||
const list = document.getElementById('queue-list');
|
||||
const count = document.getElementById('queue-count');
|
||||
if (!downloadQueue.length) { card.style.display = 'none'; return; }
|
||||
card.style.display = '';
|
||||
count.textContent = downloadQueue.length + ' 个';
|
||||
list.innerHTML = downloadQueue.map((q, i) => `
|
||||
<div class="queue-item">
|
||||
<div class="queue-num">${i + 1}</div>
|
||||
<div class="queue-info">
|
||||
<div class="queue-name">${escapeHtml(q.chat_title || q.chat_id)}</div>
|
||||
<div class="queue-filter" title="${escapeHtml(q.download_filter || '')}">${escapeHtml(q.download_filter || '无过滤条件')}</div>
|
||||
</div>
|
||||
<button class="queue-del" onclick="removeFromQueue(${i})" title="移除">✕</button>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function addToQueue() {
|
||||
const channelId = parseChannelId(document.getElementById('channel-input').value);
|
||||
const startDate = document.getElementById('start-date').value;
|
||||
const endDate = document.getElementById('end-date').value;
|
||||
if (!channelId) { toast('请输入有效的频道', 'err'); return; }
|
||||
if (!startDate) { toast('请选择开始日期', 'err'); return; }
|
||||
if (downloadQueue.some(q => q.chat_id === channelId)) {
|
||||
toast('该频道已在队列中', 'err'); return;
|
||||
}
|
||||
|
||||
const doSave = (chatTitle, chatType) => {
|
||||
const btn = document.getElementById('save-btn');
|
||||
btn.disabled = true; btn.innerHTML = '<span class="spin"></span> 重启中…';
|
||||
const submittedFilter = filterExpression || '';
|
||||
const builtFilter = startDate
|
||||
? ('message_date >= ' + startDate + ' 00:00:00' + (endDate ? ' and message_date <= ' + endDate + ' 23:59:59' : ''))
|
||||
: '';
|
||||
fetch('/api/save_and_restart', {
|
||||
method:'POST', headers:{'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ chat_id:channelId, start_date:startDate, end_date:endDate, chat_title:chatTitle, chat_type:chatType||'', download_filter:submittedFilter })
|
||||
}).then(r => r.json()).then(d => {
|
||||
if (d.success) {
|
||||
currentFilter = submittedFilter || builtFilter;
|
||||
updateBannerFilter();
|
||||
toast('✅ ' + d.message + ',5秒后刷新…'); setTimeout(() => location.reload(), 5000);
|
||||
} else { toast('失败: ' + (d.error||''), 'err'); btn.disabled = false; btn.textContent = '🔄 保存并重启下载'; }
|
||||
}).catch(e => { toast('操作失败: ' + e.message, 'err'); btn.disabled = false; btn.textContent = '🔄 保存并重启下载'; });
|
||||
const doAdd = (chatTitle, chatType) => {
|
||||
downloadQueue.push({
|
||||
chat_id: channelId,
|
||||
chat_title: chatTitle || channelId,
|
||||
chat_type: chatType || '',
|
||||
download_filter: buildFilterFromForm(startDate, endDate),
|
||||
start_date: startDate,
|
||||
end_date: endDate,
|
||||
});
|
||||
renderQueue();
|
||||
// 清空表单以便继续添加下一个频道
|
||||
document.getElementById('channel-input').value = '';
|
||||
validatedChannel = null;
|
||||
const valBox = document.getElementById('val-result');
|
||||
if (valBox) valBox.className = 'val-drop';
|
||||
toast('已加入队列: ' + (chatTitle || channelId));
|
||||
};
|
||||
|
||||
if (validatedChannel) {
|
||||
doSave(validatedChannel.chat_title, validatedChannel.chat_type);
|
||||
const btn = document.getElementById('add-queue-btn');
|
||||
if (validatedChannel && validatedChannel.chat_id === channelId) {
|
||||
doAdd(validatedChannel.chat_title, validatedChannel.chat_type);
|
||||
} else {
|
||||
const btn = document.getElementById('save-btn');
|
||||
btn.disabled = true; btn.innerHTML = '<span class="spin"></span> 验证中…';
|
||||
btn.disabled = true;
|
||||
fetch('/api/validate_chat', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ chat_id: channelId }) })
|
||||
.then(r => r.json()).then(d => {
|
||||
if (d.valid) { showVal(d); validatedChannel = d; doSave(d.chat_title, d.chat_type); }
|
||||
btn.disabled = false;
|
||||
if (d.valid) { showVal(d); validatedChannel = d; doAdd(d.chat_title, d.chat_type); }
|
||||
else { showVal(d); toast('频道验证失败', 'err'); }
|
||||
}).catch(e => { btn.disabled = false; toast('验证失败: ' + e.message, 'err'); });
|
||||
}
|
||||
}
|
||||
|
||||
function removeFromQueue(idx) {
|
||||
downloadQueue.splice(idx, 1);
|
||||
renderQueue();
|
||||
}
|
||||
|
||||
function clearQueue() {
|
||||
if (!downloadQueue.length) return;
|
||||
if (!confirm('确认清空队列里的 ' + downloadQueue.length + ' 个频道?')) return;
|
||||
downloadQueue = [];
|
||||
renderQueue();
|
||||
}
|
||||
|
||||
// ── 保存并重启(队列 + 表单一起提交) ──
|
||||
function saveAndRestart() {
|
||||
const channelId = parseChannelId(document.getElementById('channel-input').value);
|
||||
const startDate = document.getElementById('start-date').value;
|
||||
const endDate = document.getElementById('end-date').value;
|
||||
|
||||
const hasForm = !!channelId;
|
||||
const hasQueue = downloadQueue.length > 0;
|
||||
if (!hasForm && !hasQueue) { toast('请输入频道或先加入队列', 'err'); return; }
|
||||
if (hasForm && !startDate) { toast('请选择开始日期', 'err'); return; }
|
||||
|
||||
const btn = document.getElementById('save-btn');
|
||||
btn.disabled = true; btn.innerHTML = '<span class="spin"></span> 重启中…';
|
||||
|
||||
const submitAll = (formItem) => {
|
||||
const items = downloadQueue.slice();
|
||||
if (formItem && !items.some(q => q.chat_id === formItem.chat_id)) items.push(formItem);
|
||||
fetch('/api/save_and_restart_multi', {
|
||||
method:'POST', headers:{'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ items })
|
||||
}).then(r => r.json()).then(d => {
|
||||
if (d.success) {
|
||||
toast('✅ ' + d.message + ',5秒后刷新…');
|
||||
setTimeout(() => location.reload(), 5000);
|
||||
} else {
|
||||
toast('失败: ' + (d.error||''), 'err');
|
||||
btn.disabled = false; btn.textContent = '🔄 保存并重启下载';
|
||||
}
|
||||
}).catch(e => {
|
||||
toast('操作失败: ' + e.message, 'err');
|
||||
btn.disabled = false; btn.textContent = '🔄 保存并重启下载';
|
||||
});
|
||||
};
|
||||
|
||||
if (!hasForm) { submitAll(null); return; }
|
||||
|
||||
const buildFormItem = (chatTitle, chatType) => ({
|
||||
chat_id: channelId,
|
||||
chat_title: chatTitle || channelId,
|
||||
chat_type: chatType || '',
|
||||
download_filter: buildFilterFromForm(startDate, endDate),
|
||||
start_date: startDate,
|
||||
end_date: endDate,
|
||||
});
|
||||
|
||||
if (validatedChannel && validatedChannel.chat_id === channelId) {
|
||||
submitAll(buildFormItem(validatedChannel.chat_title, validatedChannel.chat_type));
|
||||
} else {
|
||||
fetch('/api/validate_chat', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ chat_id: channelId }) })
|
||||
.then(r => r.json()).then(d => {
|
||||
if (d.valid) { showVal(d); validatedChannel = d; submitAll(buildFormItem(d.chat_title, d.chat_type)); }
|
||||
else { showVal(d); toast('频道验证失败', 'err'); btn.disabled = false; btn.textContent = '🔄 保存并重启下载'; }
|
||||
}).catch(e => { toast('验证失败: ' + e.message, 'err'); btn.disabled = false; btn.textContent = '🔄 保存并重启下载'; });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user