/** * 飞书提醒规则管理前端 */ let eventTypes = []; let currentRules = []; //页面加载 document.addEventListener('DOMContentLoaded', async () => { await loadEventTypes(); await loadRules(); }); //加载事件类型 async function loadEventTypes() { try { const res = await fetch('/api/lark/events'); const data = await res.json(); if (data.success) { eventTypes = data.events; const select = document.getElementById('ruleEvent'); eventTypes.forEach(e => { const opt = document.createElement('option'); opt.value = e.value; opt.text = e.label; select.add(opt); }); } } catch (e) { console.error('Failed to load event types:', e); } } //加载规则列表 async function loadRules() { const container = document.getElementById('rulesList'); try { const res = await fetch('/api/lark/rules'); const data = await res.json(); if (data.success) { currentRules = data.rules; renderRules(); } else { container.innerHTML = `
${data.error}
`; } } catch (e) { container.innerHTML = `
加载失败: ${e.message}
`; } } //渲染规则列表 function renderRules() { const container = document.getElementById('rulesList'); if (currentRules.length === 0) { container.innerHTML = `
暂无规则,点击上方按钮新建
`; return; } container.innerHTML = currentRules.map(rule => { const eventLabel = eventTypes.find(e => e.value === rule.event)?.label || rule.event; const channelLabel = rule.channel === 'group' ? '群聊' : '私聊'; const statusClass = rule.enabled ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'; const statusLabel = rule.enabled ? '启用' : '禁用'; const targetInfo = rule.channel === 'private' && rule.target ? `→ ${rule.target}` : ''; const filterInfo = rule.filterValue ? `过滤: ${escapeHtml(rule.filterValue)}` : ''; return `
${escapeHtml(rule.name)} ${statusLabel}
事件: ${eventLabel} ${filterInfo} 渠道: ${channelLabel} ${targetInfo} ${rule.atUsers?.length ? `@ ${rule.atUsers.length}人` : ''}
`; }).join(''); } //显示规则编辑窗口 function showRuleModal(rule = null) { document.getElementById('modalTitle').textContent = rule ? '编辑规则' : '新建规则'; document.getElementById('ruleId').value = rule?.id || ''; document.getElementById('ruleName').value = rule?.name || ''; document.getElementById('ruleEvent').value = rule?.event || ''; document.getElementById('ruleChannel').value = rule?.channel || 'group'; document.getElementById('targetContact').value = rule?.target || ''; document.getElementById('atUsers').value = rule?.atUsers?.join(',') || ''; document.getElementById('ruleEnabled').checked = rule?.enabled !== false; document.getElementById('ruleFilterValue').value = rule?.filterValue || ''; //不需要设置 filterKey,因为它由 event 决定 toggleChannelFields(); handleEventChange(); // 更新过滤字段显示 hideModalError(); document.getElementById('ruleModal').classList.remove('hidden'); } //关闭模态窗口 function closeRuleModal() { document.getElementById('ruleModal').classList.add('hidden'); } //切换渠道相关字段 function toggleChannelFields() { const channel = document.getElementById('ruleChannel').value; document.getElementById('privateFields').classList.toggle('hidden', channel !== 'private'); document.getElementById('atUsersField').classList.toggle('hidden', channel !== 'group'); } //处理事件变更,显示/隐藏过滤字段 function handleEventChange() { const event = document.getElementById('ruleEvent').value; const container = document.getElementById('filterField'); const label = document.getElementById('filterLabel'); const input = document.getElementById('ruleFilterValue'); const keyInput = document.getElementById('ruleFilterKey'); const help = document.getElementById('filterHelp'); // 默认隐藏 container.classList.add('hidden'); keyInput.value = ''; if (event === 'issue.assigned') { container.classList.remove('hidden'); label.textContent = '指定被指派人 (用户名)'; input.placeholder = '例如: zhangsan'; keyInput.value = 'assignee'; help.textContent = '留空则通知所有指派事件,填写用户名则仅当指派给该用户时通知'; } else if (event === 'issue.label_updated') { container.classList.remove('hidden'); label.textContent = '指定标签 (名称)'; input.placeholder = '例如: bug'; keyInput.value = 'label'; help.textContent = '留空则通知所有标签变更,填写标签名则仅当该标签变更时通知'; } } //保存规则 async function saveRule() { const id = document.getElementById('ruleId').value; const channel = document.getElementById('ruleChannel').value; const filterKey = document.getElementById('ruleFilterKey').value; const filterValue = document.getElementById('ruleFilterValue').value.trim(); const rule = { name: document.getElementById('ruleName').value.trim(), event: document.getElementById('ruleEvent').value, channel, enabled: document.getElementById('ruleEnabled').checked, atUsers: [], filterKey: filterKey || null, filterValue: filterValue || null }; if (channel === 'private') { rule.target = document.getElementById('targetContact').value.trim(); } else { rule.atUsers = document.getElementById('atUsers').value.split(',').map(s => s.trim()).filter(Boolean); } if (!rule.name || !rule.event) { showModalError('请填写规则名称和选择事件'); return; } if (channel === 'private' && !rule.target) { showModalError('请填写接收者手机号或邮箱'); return; } try { const url = id ? `/api/lark/rules/${id}` : '/api/lark/rules'; const method = id ? 'PUT' : 'POST'; const res = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(rule) }); const data = await res.json(); if (data.success) { closeRuleModal(); await loadRules(); } else { showModalError(data.error); } } catch (e) { showModalError('保存失败: ' + e.message); } } //编辑规则 function editRule(id) { const rule = currentRules.find(r => r.id === id); if (rule) showRuleModal(rule); } //删除规则 async function deleteRule(id) { if (!confirm('确定要删除这条规则吗?')) return; try { const res = await fetch(`/api/lark/rules/${id}`, { method: 'DELETE' }); const data = await res.json(); if (data.success) { await loadRules(); } else { alert('删除失败: ' + data.error); } } catch (e) { alert('删除失败: ' + e.message); } } //测试发送 async function testSend() { const channel = document.getElementById('ruleChannel').value; const payload = { channel, atUsers: [], message: '这是一条测试消息\n来自 Gitea-Jira 同步机器人' }; if (channel === 'private') { payload.target = document.getElementById('targetContact').value.trim(); if (!payload.target) { showModalError('请先填写接收者手机号或邮箱'); return; } } else { payload.atUsers = document.getElementById('atUsers').value.split(',').map(s => s.trim()).filter(Boolean); } try { const res = await fetch('/api/lark/test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await res.json(); if (data.success) { alert('测试消息发送成功!请检查飞书。'); } else { showModalError('发送失败: ' + data.error); } } catch (e) { showModalError('发送失败: ' + e.message); } } //显示/隐藏错误 function showModalError(msg) { const el = document.getElementById('modalError'); el.textContent = msg; el.classList.remove('hidden'); } function hideModalError() { document.getElementById('modalError').classList.add('hidden'); } //HTML 转义 function escapeHtml(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; }