仰望星辰工作室

better-staridc-MNBT

Z zfhsh first commit 2 天前
1<?php
2if (!defined('IN_CRONLITE')) {
3 exit;
4}
5mnbt_admin_include('head');
6$cfg = function_exists('webhook_notify_config') ? webhook_notify_config() : [
7 'url' => '', 'secret' => '', 'enabled' => true,
8 'events' => [
9 'host.created' => true, 'host.paused' => true, 'host.unpaused' => true,
10 'host.renewed' => true, 'host.deleted' => true, 'order.paid' => true,
11 ],
12];
13$insecure = mnbt_plugin_option_get('webhook_notify', 'insecure_ssl', 'false') === 'true';
14$logs = mnbt_plugin_option_get('webhook_notify', 'delivery_log', []);
15if (!is_array($logs)) {
16 $logs = [];
17}
18$eventLabels = [
19 'host.created' => '主机开通',
20 'host.paused' => '主机暂停',
21 'host.unpaused' => '主机恢复',
22 'host.renewed' => '主机续费',
23 'host.deleted' => '主机删除',
24 'order.paid' => '订单支付成功',
25];
26?>
27<div class="container-fluid p-t-15">
28 <div class="card">
29 <div class="card-header"><h4>Webhook 通知</h4></div>
30 <div class="card-body">
31 <p class="text-muted">事件发生时向指定 URL 发送 JSON(POST)。可选 HMAC-SHA256 签名头 <code>X-MNBT-Signature</code>。</p>
32 <div class="form-group">
33 <label>启用</label>
34 <div class="custom-control custom-switch">
35 <input type="checkbox" class="custom-control-input" id="wh-enabled" <?=!empty($cfg['enabled']) ? 'checked' : ''?>>
36 <label class="custom-control-label" for="wh-enabled">开启推送</label>
37 </div>
38 </div>
39 <div class="form-group">
40 <label>Webhook URL</label>
41 <input type="url" class="form-control" id="wh-url" value="<?=htmlspecialchars($cfg['url'], ENT_QUOTES, 'UTF-8')?>" placeholder="https://example.com/hook">
42 </div>
43 <div class="form-group">
44 <label>签名密钥(可选)</label>
45 <input type="text" class="form-control" id="wh-secret" value="<?=htmlspecialchars($cfg['secret'], ENT_QUOTES, 'UTF-8')?>" placeholder="用于 HMAC-SHA256">
46 <small class="text-muted">签名:sha256=HMAC_SHA256(body, secret),请求头 X-MNBT-Signature</small>
47 </div>
48 <div class="form-group">
49 <div class="custom-control custom-switch">
50 <input type="checkbox" class="custom-control-input" id="wh-insecure" <?=$insecure ? 'checked' : ''?>>
51 <label class="custom-control-label" for="wh-insecure">跳过 HTTPS 证书校验(不推荐)</label>
52 </div>
53 </div>
54 <div class="form-group">
55 <label>订阅事件</label>
56 <div class="row">
57 <?php foreach ($eventLabels as $ek => $lab): ?>
58 <div class="col-md-4">
59 <div class="custom-control custom-checkbox">
60 <input type="checkbox" class="custom-control-input wh-event" id="ev-<?=htmlspecialchars($ek, ENT_QUOTES, 'UTF-8')?>" data-ev="<?=htmlspecialchars($ek, ENT_QUOTES, 'UTF-8')?>" <?=!empty($cfg['events'][$ek]) ? 'checked' : ''?>>
61 <label class="custom-control-label" for="ev-<?=htmlspecialchars($ek, ENT_QUOTES, 'UTF-8')?>"><?=htmlspecialchars($lab, ENT_QUOTES, 'UTF-8')?> <code class="small"><?=$ek?></code></label>
62 </div>
63 </div>
64 <?php endforeach; ?>
65 </div>
66 </div>
67 <button type="button" class="btn btn-primary" id="wh-save">保存</button>
68 <button type="button" class="btn btn-info" id="wh-test">发送测试</button>
69 <hr>
70 <h5>投递日志</h5>
71 <pre class="bg-light p-3" style="max-height:280px;overflow:auto"><?php
72if (!$logs) {
73 echo "(暂无)\n";
74} else {
75 echo htmlspecialchars(implode("\n", $logs), ENT_QUOTES, 'UTF-8');
76}
77?></pre>
78 <h5 class="mt-3">请求体示例</h5>
79 <pre class="bg-light p-3 small">{
80 "event": "host.created",
81 "time": "2026-07-16T12:00:00+08:00",
82 "source": "mnbt",
83 "payload": {
84 "host": { "user": "demo001", "ssbt": "bt1", "btid": "12", "sqldz": "mnbt.1xxx", "datae": "2027-01-01" },
85 "ctx": { "source": "admin" }
86 }
87}</pre>
88 </div>
89 </div>
90</div>
91<script>
92function parseRes(res) {
93 try { return typeof res === 'string' ? JSON.parse(res) : res; } catch (e) { return {code: res}; }
94}
95function collectEvents() {
96 var o = {};
97 $('.wh-event').each(function () {
98 o[$(this).data('ev')] = $(this).is(':checked');
99 });
100 return o;
101}
102$('#wh-save').on('click', function () {
103 $.post('ajax.php', {
104 gn: 'p_webhook_notify_save',
105 url: $('#wh-url').val(),
106 secret: $('#wh-secret').val(),
107 enabled: $('#wh-enabled').is(':checked') ? 'true' : 'false',
108 insecure_ssl: $('#wh-insecure').is(':checked') ? 'true' : 'false',
109 events: JSON.stringify(collectEvents())
110 }, function (res) {
111 var d = parseRes(res);
112 var msg = d.msg || d.code || '完成';
113 if (typeof $.notify === 'function') $.notify({message: msg}, {type: (d.qk == 1 || d.success) ? 'success' : 'danger'});
114 else alert(msg);
115 if (d.qk == 1 || d.success) setTimeout(function () { location.reload(); }, 600);
116 });
117});
118$('#wh-test').on('click', function () {
119 $.post('ajax.php', {gn: 'p_webhook_notify_test'}, function (res) {
120 var d = parseRes(res);
121 var msg = d.msg || d.code || '完成';
122 if (typeof $.notify === 'function') $.notify({message: msg}, {type: (d.qk == 1 || d.success) ? 'success' : 'danger'});
123 else alert(msg);
124 if (d.qk == 1 || d.success) setTimeout(function () { location.reload(); }, 800);
125 });
126});
127</script>