加入部分消息通知入口,同步前端管理

This commit is contained in:
2026-03-19 10:45:58 +08:00
parent 1e25c085a5
commit c25c766223
10 changed files with 454 additions and 5 deletions

View File

@@ -966,7 +966,64 @@ def admin_panel():
except Exception:
codes = []
return render_template('admin.html', users=users, invite_codes=codes, user=session.get('user'))
# 获取系统配置
try:
resp = api_request('GET', f'{AUTH_BASE_URL}/admin/config')
config = resp.json().get('data', {}) if resp.status_code == 200 else {}
except Exception:
config = {}
return render_template('admin.html', users=users, invite_codes=codes, config=config, user=session.get('user'))
@app.route('/admin/config/save', methods=['POST'])
@admin_required
def save_config():
"""保存系统配置"""
try:
config_data = {
'webhook_url': request.form.get('webhook_url', '').strip(),
'daily_report_hour': request.form.get('daily_report_hour', '23').strip(),
'daily_report_minute': request.form.get('daily_report_minute', '30').strip(),
}
resp = api_request('PUT', f'{AUTH_BASE_URL}/admin/config', json=config_data)
data = resp.json()
if resp.status_code == 200 and data.get('success'):
flash('配置已保存,调度器将自动重新加载', 'success')
else:
flash(data.get('message', '保存失败'), 'danger')
except Exception as e:
flash(f'连接错误: {str(e)}', 'danger')
return redirect(url_for('admin_panel'))
@app.route('/admin/webhook/test', methods=['POST'])
@admin_required
def test_webhook():
"""测试 Webhook 推送"""
try:
webhook_url = request.form.get('webhook_url', '').strip()
if not webhook_url:
return jsonify({'success': False, 'message': 'Webhook 地址为空'}), 400
import httpx
# 飞书格式
if 'open.feishu.cn' in webhook_url:
payload = {"msg_type": "text", "content": {"text": "🔔 微博超话签到系统 Webhook 测试\n如果你看到这条消息,说明推送配置正确。"}}
elif 'qyapi.weixin.qq.com' in webhook_url:
payload = {"msgtype": "text", "text": {"content": "🔔 微博超话签到系统 Webhook 测试\n如果你看到这条消息,说明推送配置正确。"}}
elif 'oapi.dingtalk.com' in webhook_url:
payload = {"msgtype": "text", "text": {"content": "🔔 微博超话签到系统 Webhook 测试\n如果你看到这条消息,说明推送配置正确。"}}
else:
payload = {"text": "🔔 微博超话签到系统 Webhook 测试"}
resp = httpx.post(webhook_url, json=payload, timeout=10)
if resp.status_code == 200:
return jsonify({'success': True, 'message': '测试消息已发送'})
else:
return jsonify({'success': False, 'message': f'推送失败: HTTP {resp.status_code}'}), 400
except Exception as e:
return jsonify({'success': False, 'message': str(e)}), 500
@app.route('/admin/invite-codes/create', methods=['POST'])

View File

@@ -4,3 +4,4 @@ requests==2.31.0
python-dotenv==1.0.0
Werkzeug==3.0.1
qrcode[pil]==7.4.2
httpx==0.25.2

View File

@@ -111,5 +111,58 @@
{% endfor %}
</div>
</div>
<!-- 推送设置 -->
<div class="card" style="margin-bottom: 24px;">
<div class="card-header">🔔 消息推送设置</div>
<form method="POST" action="{{ url_for('save_config') }}">
<div class="form-group">
<label>Webhook 地址</label>
<input type="text" name="webhook_url" value="{{ config.get('webhook_url', '') }}"
placeholder="飞书/企业微信/钉钉机器人 Webhook URL" style="font-size:13px;">
<div style="font-size:11px; color:#94a3b8; margin-top:4px;">支持飞书、企业微信、钉钉自定义机器人</div>
</div>
<div style="display:flex; gap:12px; align-items:flex-end;">
<div class="form-group" style="flex:1;">
<label>推送时间(时)</label>
<select name="daily_report_hour">
{% for h in range(24) %}
<option value="{{ h }}" {{ 'selected' if config.get('daily_report_hour', '23')|string == h|string }}>{{ '%02d'|format(h) }}</option>
{% endfor %}
</select>
</div>
<div class="form-group" style="flex:1;">
<label>推送时间(分)</label>
<select name="daily_report_minute">
{% for m in range(0, 60, 5) %}
<option value="{{ m }}" {{ 'selected' if config.get('daily_report_minute', '30')|string == m|string }}>{{ '%02d'|format(m) }}</option>
{% endfor %}
</select>
</div>
</div>
<div style="display:flex; gap:8px; margin-top:8px;">
<button type="submit" class="btn btn-primary" style="flex:1;">💾 保存配置</button>
<button type="button" class="btn btn-secondary" onclick="testWebhook()" id="test-btn">📤 测试推送</button>
</div>
</form>
</div>
</div>
<script>
async function testWebhook() {
const btn = document.getElementById('test-btn');
const url = document.querySelector('input[name="webhook_url"]').value.trim();
if (!url) { alert('请先填写 Webhook 地址'); return; }
btn.disabled = true; btn.textContent = '⏳ 发送中...';
try {
const form = new FormData();
form.append('webhook_url', url);
const resp = await fetch('{{ url_for("test_webhook") }}', {method: 'POST', body: form});
const data = await resp.json();
alert(data.success ? '✅ ' + data.message : '❌ ' + data.message);
} catch(e) { alert('请求失败: ' + e.message); }
btn.disabled = false; btn.textContent = '📤 测试推送';
}
</script>
{% endblock %}