/**
* 飞书提醒规则管理前端
*/
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;
}