const PollsPage = { async render() { return '
'; }, async mount() { document.getElementById('page-title').textContent = '投票'; document.getElementById('page-actions').innerHTML = Auth.isOwner() ? '' : ''; await this.load(); }, async load() { const ct = document.getElementById('page-content'); try { const groups = await API.get('/polls/active'); const entries = Object.entries(groups); if (entries.length === 0) { ct.innerHTML = '

暂无进行中的投票

'; return; } ct.innerHTML = entries.map(([group, polls]) => `

${U.esc(group)}

${polls.map(p => this.renderPoll(p)).join('')}
`).join(''); for (const [group, polls] of entries) for (const p of polls) this.bindVote(p); } catch (e) { ct.innerHTML = `
${e.message}
`; } }, renderPoll(p) { const opts = p.options || []; const timed = p.start_time || p.end_time; return `
${U.esc(p.server_name)} ?${U.esc(p.title)} ${timed ? `${p.start_time?'? '+U.date(p.start_time):''} ${p.end_time?'? '+U.date(p.end_time):''}`:''} ${p.total||0} ?/span> ${Auth.isOwner() ? `` : ''}
${p.description?`

${U.esc(p.description)}

`:''} ${p.voted ? `
已投?/div>` : ''}
${opts.map((o,i) => { const v = p.voted ? 0 : (p.votes?.[i] || 0); const pct = p.voted ? 0 : (p.total ? Math.round(v/p.total*100) : 0); const my = p.my_vote === i; return `
${!p.voted ? `
` : ''}
${my?' ':''}${U.esc(o)} ${!p.voted ? `${v}?${pct}%` : ''}
`; }).join('')}
`; }, bindVote(p) { if (p.voted) return; const card = document.getElementById('poll-'+p.id); if (!card) return; card.querySelectorAll('.poll-opt').forEach(el => { el.addEventListener('click', async () => { try { await API.post(`/polls/${p.id}/vote`, { option_index: parseInt(el.dataset.idx) }); this.load(); } catch (ex) { alert(ex.message); } }); }); }, showCreate() { this.loadGroups().then(groups => { const opts = groups.map(g => ``).join(''); U.modal('创建投票', `
`); document.getElementById('poll-form').onsubmit = async e => { e.preventDefault(); const [group_name, server_name] = document.getElementById('pl-gs').value.split('::'); const opts = document.getElementById('pl-opts').value.split('\n').map(s=>s.trim()).filter(s=>s); if (opts.length < 2) return alert('至少需?个选项'); try { await API.post('/polls', { title: document.getElementById('pl-title').value, description: document.getElementById('pl-desc').value, options: opts, group_name, server_name, start_time: document.getElementById('pl-start').value||null, end_time: document.getElementById('pl-end').value||null }); App.closeModal(); this.load(); } catch (ex) { alert(ex.message); } }; }); }, async loadGroups() { try { return await API.get('/polls/groups'); } catch { return []; } }, showGroupMgr() { this.loadGroups().then(groups => { const list = groups.map(g => `
${U.esc(g.group_name)} / ${U.esc(g.server_name)}
`).join(''); U.modal('管理分组', `
${list||'

暂无

'}
`); document.getElementById('gm-form').onsubmit = async e => { e.preventDefault(); try { await API.post('/polls/groups', { group_name: document.getElementById('gm-group').value, server_name: document.getElementById('gm-server').value }); App.closeModal(); this.showGroupMgr(); } catch(ex){alert(ex.message);} }; }); }, async delGroup(id) { try { await API.req('DELETE', '/polls/groups/'+id); App.closeModal(); this.showGroupMgr(); } catch(ex){alert(ex.message);} }, async showEdit(id) { const p = await API.get('/polls/'+id); document.getElementById('modal-title').textContent = '编辑投票'; document.getElementById('modal-body').innerHTML = `
`; document.getElementById('modal-overlay').classList.remove('hidden'); document.getElementById('pe-form').onsubmit = async e => { e.preventDefault(); const opts = document.getElementById('pe-opts').value.split('\n').map(s=>s.trim()).filter(s=>s); try { await API.put('/polls/'+id, { title: document.getElementById('pe-title').value, active: document.getElementById('pe-active').value==='1', options: opts.length>=2?opts:undefined }); App.closeModal(); this.load(); } catch (ex) { alert(ex.message); } }; }, async deletePoll(id) { if (!await U.confirm('确认删除?)) return; try { await API.req('DELETE', '/polls/'+id); App.closeModal(); this.load(); } catch(ex){alert(ex.message);} } };