init
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '钱包地址')
|
||||
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<style>
|
||||
.addr-chain-tag {
|
||||
display: inline-block;
|
||||
padding: 0 8px;
|
||||
line-height: 20px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
.addr-chain-eth, .addr-chain-ethereum, .addr-chain-evm { background: #627eea; }
|
||||
.addr-chain-btc, .addr-chain-bitcoin { background: #f7931a; }
|
||||
.addr-chain-trx, .addr-chain-tron { background: #ff0013; }
|
||||
.addr-chain-bnb, .addr-chain-bsc, .addr-chain-binance { background: #f3ba2f; color: #333; }
|
||||
.addr-chain-sol, .addr-chain-solana { background: #9945ff; }
|
||||
.addr-chain-ton { background: #0098ea; }
|
||||
.addr-chain-unknown, .addr-chain-unkno { background: #909399; }
|
||||
.addr-monitor-on { color: #16b777; font-weight: 600; }
|
||||
.addr-monitor-off { color: #ff5722; font-weight: 600; }
|
||||
.addr-cell { word-break: break-all; font-family: Menlo, Monaco, Consolas, monospace; font-size: 12px; }
|
||||
</style>
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-addr-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="channel_id" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="device_key" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
@if ($portal === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理用户</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="agent_user_id">
|
||||
<option value="">全部</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">来源</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="source">
|
||||
<option value="">全部</option>
|
||||
@foreach ($sources as $s)
|
||||
<option value="{{ $s }}">{{ $s }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-addr-search">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-addr-list" lay-filter="LAY-addr-list"></table>
|
||||
<script type="text/html" id="LAY-addr-ops">
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">设备详情</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
var token = @json(csrf_token());
|
||||
var updateBase = @json(url('/'.$portal.'/addresses'));
|
||||
|
||||
function chainTag(chain) {
|
||||
var raw = String(chain || 'UNKNOWN');
|
||||
var key = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
||||
var cls = 'addr-chain-tag addr-chain-' + (key || 'unknown');
|
||||
return '<span class="' + cls + '">' + raw + '</span>';
|
||||
}
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-addr-list',
|
||||
id: 'LAY-addr-list',
|
||||
url: @json(route($portal.'.addresses.data')),
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'source', title: '来源', width: 120 },
|
||||
{ field: 'device_key', title: '设备 ID', width: 150, sort: true },
|
||||
{ field: 'address', title: '地址', minWidth: 360, templet: function (d) {
|
||||
return '<span class="addr-cell">' + (d.address || '') + '</span>';
|
||||
}},
|
||||
{ field: 'chain_type', title: 'Chain', width: 110, templet: function (d) {
|
||||
return chainTag(d.chain_type);
|
||||
}},
|
||||
{ field: 'usdt', title: 'USDT', width: 100, sort: true },
|
||||
{ field: 'trx', title: 'TRX', width: 100, sort: true },
|
||||
{ field: 'eth', title: 'ETH', width: 100, sort: true },
|
||||
{ field: 'btc', title: 'BTC', width: 110, sort: true },
|
||||
{ field: 'bnb', title: 'BNB', width: 100, sort: true },
|
||||
{ field: 'channel_id', title: '渠道 ID', width: 140 },
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ field: 'monitor', title: '监听', width: 80, fixed: 'right', templet: function (d) {
|
||||
return Number(d.monitor) === 1
|
||||
? '<span class="addr-monitor-on">开</span>'
|
||||
: '<span class="addr-monitor-off">关</span>';
|
||||
}},
|
||||
{ title: '操作', width: 160, align: 'center', fixed: 'right', toolbar: '#LAY-addr-ops' }
|
||||
]],
|
||||
page: true, limit: 15, height: 'full-220',
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
|
||||
form.on('submit(LAY-addr-search)', function (data) {
|
||||
table.reload('LAY-addr-list', { where: data.field, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
function openDeviceTab(url, title) {
|
||||
try {
|
||||
if (parent && parent.layui && parent.layui.index) {
|
||||
parent.layui.index.openTabsPage(url, title);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
location.href = url;
|
||||
}
|
||||
|
||||
table.on('tool(LAY-addr-list)', function (obj) {
|
||||
var d = obj.data;
|
||||
if (obj.event === 'detail') {
|
||||
openDeviceTab(d.detail_url, '设备 ' + (d.device_key || ('#' + d.id)));
|
||||
return;
|
||||
}
|
||||
if (obj.event !== 'edit') return;
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '编辑监听 — #' + d.id,
|
||||
area: ['420px', '260px'],
|
||||
content:
|
||||
'<form class="layui-form" style="padding:16px;" id="LAY-addr-edit-form">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">地址</label>' +
|
||||
'<div class="layui-input-block"><div class="layui-form-mid addr-cell" style="width:100%;">' + (d.address || '') + '</div></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">监听</label>' +
|
||||
'<div class="layui-input-block" style="padding-top:8px;">' +
|
||||
'<input type="checkbox" name="monitor" lay-skin="switch" lay-text="开|关" value="1"' +
|
||||
(Number(d.monitor) === 1 ? ' checked' : '') + '>' +
|
||||
'</div></div>' +
|
||||
'</form>',
|
||||
success: function () {
|
||||
form.render('checkbox');
|
||||
},
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index) {
|
||||
var monitor = $('#LAY-addr-edit-form input[name=monitor]').prop('checked') ? 1 : 0;
|
||||
$.ajax({
|
||||
url: updateBase + '/' + d.id,
|
||||
method: 'POST',
|
||||
data: { monitor: monitor, _method: 'PUT', _token: token },
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
layer.msg('已保存');
|
||||
table.reload('LAY-addr-list');
|
||||
},
|
||||
error: function (xhr) {
|
||||
layer.msg((xhr.responseJSON && (xhr.responseJSON.msg || xhr.responseJSON.message)) || '保存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,156 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '代理用户')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-agent-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">账号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="username" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="status">
|
||||
<option value="">全部</option>
|
||||
<option value="1">启用</option>
|
||||
<option value="0">禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-agent-search">搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="LAY-agent-create">新建</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-agent-list" lay-filter="LAY-agent-list"></table>
|
||||
<script type="text/html" id="LAY-agent-ops">
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="channels">渠道链接</a>
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="edit">编辑</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
var token = @json(csrf_token());
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-agent-list',
|
||||
id: 'LAY-agent-list',
|
||||
url: @json(route('admin.agents.data')),
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'username', title: '账号', width: 140, sort: true },
|
||||
{ field: 'status', title: '状态', width: 90, templet: function (d) {
|
||||
return d.status == 1
|
||||
? '<span style="color:#16a34a;font-weight:600;">启用</span>'
|
||||
: '<span style="color:#dc2626;font-weight:600;">禁用</span>';
|
||||
}},
|
||||
{ field: 'comment', title: '备注', minWidth: 120 },
|
||||
{ field: 'channels_count', title: '渠道链接数', width: 110 },
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ field: 'updated_at', title: '更新时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 180, align: 'center', fixed: 'right', toolbar: '#LAY-agent-ops' }
|
||||
]],
|
||||
page: true, limit: 15, height: 'full-220',
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
|
||||
form.on('submit(LAY-agent-search)', function (data) {
|
||||
table.reload('LAY-agent-list', { where: data.field, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
function openForm(title, values, onOk) {
|
||||
values = values || {};
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['460px', '360px'],
|
||||
content: '<form class="layui-form" style="padding:16px;" id="LAY-agent-form">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">账号</label><div class="layui-input-block">' +
|
||||
'<input name="username" class="layui-input" ' + (values.id ? 'readonly' : '') + ' value="' + (values.username || '') + '"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">密码</label><div class="layui-input-block">' +
|
||||
'<input name="password" type="password" class="layui-input" placeholder="' + (values.id ? '留空不改' : '必填') + '"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">备注</label><div class="layui-input-block">' +
|
||||
'<input name="comment" class="layui-input" value="' + (values.comment || '').replace(/"/g, '"') + '"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">状态</label><div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="status_switch" lay-skin="switch" lay-text="启用|禁用" ' + ((values.status == null || values.status == 1) ? 'checked' : '') + '>' +
|
||||
'</div></div>' +
|
||||
'</form>',
|
||||
success: function () {
|
||||
form.render();
|
||||
},
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index) {
|
||||
var data = {};
|
||||
$('#LAY-agent-form').serializeArray().forEach(function (x) { data[x.name] = x.value; });
|
||||
data.status = $('#LAY-agent-form input[name=status_switch]').is(':checked') ? 1 : 0;
|
||||
delete data.status_switch;
|
||||
onOk(data, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#LAY-agent-create').on('click', function () {
|
||||
openForm('新建代理', { status: 1 }, function (data, index) {
|
||||
$.ajax({
|
||||
url: @json(route('admin.agents.store')),
|
||||
method: 'POST',
|
||||
data: data,
|
||||
headers: { 'X-CSRF-TOKEN': token },
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
table.reload('LAY-agent-list');
|
||||
},
|
||||
error: function (xhr) {
|
||||
layer.msg((xhr.responseJSON && xhr.responseJSON.message) || '创建失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(LAY-agent-list)', function (obj) {
|
||||
var d = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
openForm('编辑代理', d, function (data, index) {
|
||||
$.ajax({
|
||||
url: @json(url('/admin/agents')) + '/' + d.id,
|
||||
method: 'POST',
|
||||
data: Object.assign(data, { _method: 'PUT', _token: token }),
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
table.reload('LAY-agent-list');
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'channels') {
|
||||
$.getJSON(@json(url('/admin/agents')) + '/' + d.id + '/channels', function (res) {
|
||||
var html = (res.data || []).map(function (c) {
|
||||
var st = c.status == 1
|
||||
? '<span style="color:#16a34a;">启用</span>'
|
||||
: '<span style="color:#dc2626;">禁用</span>';
|
||||
return '<div style="margin-bottom:10px;"><b>' + c.channel_id + '</b> (' + st + ')' +
|
||||
(c.remark ? '<br><span style="color:#888;">' + c.remark + '</span>' : '') +
|
||||
'</div>';
|
||||
}).join('') || '暂无渠道链接';
|
||||
layer.open({ type: 1, title: '渠道链接 — ' + d.username, area: ['520px', '360px'], content: '<div style="padding:16px;">' + html + '</div>' });
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,271 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '渠道链接')
|
||||
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-ch-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="channel_id" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
@if ($portal === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="agent_user_id">
|
||||
<option value="">全部</option>
|
||||
<option value="0">官方</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="status">
|
||||
<option value="">全部</option>
|
||||
<option value="1">启用</option>
|
||||
<option value="0">禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-ch-search">搜索</button>
|
||||
@if ($portal === 'admin')
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="LAY-ch-create">新建</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-ch-list" lay-filter="LAY-ch-list"></table>
|
||||
<script type="text/html" id="LAY-ch-ops">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="links">查看链接</a>
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">编辑</a>
|
||||
@{{# if(d._isAdmin){ }}
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
@{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
var portal = @json($portal);
|
||||
var token = @json(csrf_token());
|
||||
var agents = @json(($agents ?? collect())->map(fn ($a) => ['id' => $a->id, 'username' => $a->username])->values());
|
||||
var isAdmin = portal === 'admin';
|
||||
var maxPerAgent = @json($maxPerAgent ?? 5);
|
||||
|
||||
var cols = [
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'channel_id', title: '渠道 ID', minWidth: 260, sort: true },
|
||||
];
|
||||
if (isAdmin) {
|
||||
cols.push({ field: 'agent_username', title: '代理', width: 120 });
|
||||
}
|
||||
cols = cols.concat([
|
||||
{ field: 'remark', title: '备注', minWidth: 140, templet: function (d) { return d.remark || '—'; } },
|
||||
{ field: 'status', title: '状态', width: 90, templet: function (d) {
|
||||
return d.status == 1
|
||||
? '<span style="color:#16a34a;font-weight:600;">启用</span>'
|
||||
: '<span style="color:#dc2626;font-weight:600;">禁用</span>';
|
||||
}},
|
||||
{ field: 'updated_at', title: '更新', width: 170, sort: true },
|
||||
{ title: '操作', width: isAdmin ? 220 : 160, align: 'center', fixed: 'right', toolbar: '#LAY-ch-ops' }
|
||||
]);
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-ch-list',
|
||||
id: 'LAY-ch-list',
|
||||
url: @json(route($portal.'.channels.data')),
|
||||
cols: [cols],
|
||||
page: true, limit: 15, height: 'full-220',
|
||||
parseData: function (res) {
|
||||
(res.data || []).forEach(function (row) { row._isAdmin = isAdmin; });
|
||||
return res;
|
||||
},
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
|
||||
form.on('submit(LAY-ch-search)', function (data) {
|
||||
table.reload('LAY-ch-list', { where: data.field, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
function agentOptions(selected) {
|
||||
var sel = selected == null ? 0 : selected;
|
||||
var html = '<option value="0"' + (String(sel) === '0' ? ' selected' : '') + '>官方</option>';
|
||||
agents.forEach(function (a) {
|
||||
html += '<option value="' + a.id + '"' + (String(sel) === String(a.id) ? ' selected' : '') + '>' + a.username + '</option>';
|
||||
});
|
||||
return html;
|
||||
}
|
||||
|
||||
function copyText(text) {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
return navigator.clipboard.writeText(text);
|
||||
}
|
||||
var ta = document.createElement('textarea');
|
||||
ta.value = text;
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(ta);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function openLinks(row) {
|
||||
var links = row.links || [];
|
||||
if (!links.length) {
|
||||
return layer.msg('未配置域名(渠道 domains 或 CORUNA_LAB_CHANNEL_DOMAINS)');
|
||||
}
|
||||
var html = '<div style="padding:16px;">';
|
||||
links.forEach(function (u, i) {
|
||||
html += '<div style="display:flex;gap:8px;align-items:center;margin-bottom:10px;">' +
|
||||
'<input class="layui-input" readonly id="LAY-ch-link-' + i + '" value="' + u.replace(/"/g, '"') + '" style="flex:1;">' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm LAY-ch-copy" data-url="' + u.replace(/"/g, '"') + '">复制</button>' +
|
||||
'</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '渠道链接 — ' + row.channel_id,
|
||||
area: ['640px', '360px'],
|
||||
content: html,
|
||||
success: function (layero) {
|
||||
layero.find('.LAY-ch-copy').on('click', function () {
|
||||
var url = $(this).data('url');
|
||||
copyText(url).then(function () { layer.msg('已复制'); });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openForm(title, values, creating) {
|
||||
values = values || {};
|
||||
var agentBlock = isAdmin
|
||||
? '<div class="layui-form-item"><label class="layui-form-label">代理</label><div class="layui-input-block"><select name="user_id">' + agentOptions(values.user_id) + '</select></div></div>'
|
||||
: '';
|
||||
var channelBlock = creating
|
||||
? '<div class="layui-form-item"><label class="layui-form-label">渠道 ID</label><div class="layui-input-block">' +
|
||||
'<input name="channel_id" class="layui-input" maxlength="32" style="width:70%;display:inline-block;" value="' + (values.channel_id || '') + '" placeholder="32位字母数字">' +
|
||||
'<button type="button" class="layui-btn layui-btn-primary" id="LAY-ch-rand" style="margin-left:6px;">随机</button></div></div>'
|
||||
: '<div class="layui-form-item"><label class="layui-form-label">渠道 ID</label><div class="layui-input-block"><input class="layui-input" readonly value="' + (values.channel_id || '') + '"></div></div>';
|
||||
|
||||
var domainsBlock = isAdmin
|
||||
? '<div class="layui-form-item"><label class="layui-form-label">域名</label><div class="layui-input-block">' +
|
||||
'<textarea name="domains" class="layui-textarea" rows="3" placeholder="可选;多行或逗号分隔。留空则展示/构建使用 CORUNA_LAB_CHANNEL_DOMAINS">' +
|
||||
(values.domains_text || '').replace(/</g, '<') + '</textarea>' +
|
||||
'<div class="layui-form-mid layui-word-aux">构建时作为 deployment_domains;上报域名始终用 CORUNA_LAB_AMIDN_DOMAINS</div></div></div>'
|
||||
: '';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['560px', isAdmin ? '520px' : '380px'],
|
||||
content: '<form class="layui-form" style="padding:16px;" id="LAY-ch-form" lay-filter="LAY-ch-form">' +
|
||||
channelBlock + agentBlock + domainsBlock +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">备注</label><div class="layui-input-block">' +
|
||||
'<input name="remark" class="layui-input" value="' + (values.remark || '').replace(/"/g, '"') + '"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">状态</label><div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="status_switch" lay-skin="switch" lay-text="启用|禁用" ' + ((values.status == null || values.status == 1) ? 'checked' : '') + '>' +
|
||||
'</div></div>' +
|
||||
(creating ? '<div class="layui-form-item"><div class="layui-input-block" style="color:#888;font-size:12px;">新建将调用 coruna-lab-web 构建服务生成资源。代理最多 ' + maxPerAgent + ' 条。</div></div>' : '') +
|
||||
'</form>',
|
||||
success: function () {
|
||||
form.render();
|
||||
$('#LAY-ch-rand').on('click', function () {
|
||||
$.getJSON(@json(route('admin.channels.randomId')), function (res) {
|
||||
if (res.code === 0) $('#LAY-ch-form input[name=channel_id]').val(res.data.channel_id);
|
||||
});
|
||||
});
|
||||
},
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index) {
|
||||
var data = {};
|
||||
$('#LAY-ch-form').serializeArray().forEach(function (x) { data[x.name] = x.value; });
|
||||
data.status = $('#LAY-ch-form input[name=status_switch]').is(':checked') ? 1 : 0;
|
||||
delete data.status_switch;
|
||||
if (creating) {
|
||||
var load = layer.load(2);
|
||||
$.ajax({
|
||||
url: @json(route('admin.channels.store')),
|
||||
method: 'POST',
|
||||
data: Object.assign(data, { _token: token }),
|
||||
success: function (res) {
|
||||
layer.close(load);
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
table.reload('LAY-ch-list');
|
||||
layer.msg('已创建并生成资源');
|
||||
},
|
||||
error: function (xhr) {
|
||||
layer.close(load);
|
||||
var msg = (xhr.responseJSON && (xhr.responseJSON.msg || xhr.responseJSON.message)) || '创建失败';
|
||||
if (xhr.responseJSON && xhr.responseJSON.errors) {
|
||||
msg = Object.values(xhr.responseJSON.errors).flat().join('; ');
|
||||
}
|
||||
layer.msg(msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$.ajax({
|
||||
url: @json(url('/'.$portal.'/channels')) + '/' + values.id,
|
||||
method: 'POST',
|
||||
data: Object.assign(data, { _method: 'PUT', _token: token }),
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
table.reload('LAY-ch-list');
|
||||
},
|
||||
error: function (xhr) {
|
||||
var msg = (xhr.responseJSON && (xhr.responseJSON.msg || xhr.responseJSON.message)) || '保存失败';
|
||||
if (xhr.responseJSON && xhr.responseJSON.errors) {
|
||||
msg = Object.values(xhr.responseJSON.errors).flat().join('; ');
|
||||
}
|
||||
layer.msg(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isAdmin) {
|
||||
$('#LAY-ch-create').on('click', function () { openForm('新建渠道链接', { user_id: 0, status: 1 }, true); });
|
||||
}
|
||||
|
||||
table.on('tool(LAY-ch-list)', function (obj) {
|
||||
if (obj.event === 'edit') openForm('编辑渠道链接', obj.data, false);
|
||||
if (obj.event === 'links') openLinks(obj.data);
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('删除后将移除数据库记录与 web/' + obj.data.channel_id + ' 资源,确认?', function (idx) {
|
||||
$.ajax({
|
||||
url: @json(url('/admin/channels')) + '/' + obj.data.id,
|
||||
method: 'POST',
|
||||
data: { _method: 'DELETE', _token: token },
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(idx);
|
||||
table.reload('LAY-ch-list');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>@yield('title', 'Coruna Lab')</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="{{ asset('static/layuiadmin/layui/css/layui.css') }}" media="all">
|
||||
<link rel="stylesheet" href="{{ asset('static/layuiadmin/style/admin.css') }}" media="all">
|
||||
<style>
|
||||
.json-block{background:#1e1e1e;color:#dcdcdc;padding:12px;overflow:auto;max-height:480px;border-radius:2px;font-size:12px}
|
||||
.wrap{word-break:break-all;max-width:640px}
|
||||
.wallet-row{background:#fff7e6}
|
||||
.tag-wallet{display:inline-block;background:#FFB800;color:#fff;padding:0 6px;border-radius:2px;font-size:12px}
|
||||
.photo-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:12px}
|
||||
.photo-card{display:block;background:#fff;padding:8px;text-align:center;color:#333;border:1px solid #f0f0f0}
|
||||
.photo-card img{width:100%;height:120px;object-fit:cover;background:#eee}
|
||||
</style>
|
||||
@stack('head')
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid">
|
||||
@yield('content')
|
||||
</div>
|
||||
<script src="{{ asset('static/layuiadmin/layui/layui.js') }}"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: @json(rtrim(asset('static/layuiadmin'), '/').'/')
|
||||
}).extend({
|
||||
index: 'lib/index'
|
||||
}).use(['index'], function(){});
|
||||
</script>
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,96 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '仪表盘')
|
||||
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-dash-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">时间</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="range">
|
||||
<option value="30d" selected>近30天</option>
|
||||
<option value="7d">近7天</option>
|
||||
<option value="yesterday">昨日</option>
|
||||
<option value="today">今日</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="channel_id" placeholder="渠道 ID" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
@if ($portal === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理用户</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="agent_user_id">
|
||||
<option value="">全部</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-dash-search">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总设备数</div>
|
||||
<div class="layui-card-body" style="font-size:28px;" id="dash-total">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">新增设备</div>
|
||||
<div class="layui-card-body" style="font-size:28px;" id="dash-new">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">活跃设备</div>
|
||||
<div class="layui-card-body" style="font-size:28px;" id="dash-active">—</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-word-aux" id="dash-range" style="margin-top:8px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['form'], function () {
|
||||
var form = layui.form;
|
||||
var $ = layui.$;
|
||||
var dataUrl = @json(route(($portal ?? 'admin').'.dashboard.data'));
|
||||
|
||||
function load(where) {
|
||||
$.getJSON(dataUrl, where || { range: '30d' }, function (res) {
|
||||
if (!res || res.code !== 0) return;
|
||||
$('#dash-total').text(res.data.total);
|
||||
$('#dash-new').text(res.data.new_count);
|
||||
$('#dash-active').text(res.data.active_count);
|
||||
$('#dash-range').text('统计区间:' + res.data.from + ' ~ ' + res.data.to);
|
||||
});
|
||||
}
|
||||
|
||||
form.on('submit(LAY-dash-search)', function (data) {
|
||||
load(data.field);
|
||||
return false;
|
||||
});
|
||||
|
||||
load({ range: '30d' });
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,164 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '设备列表')
|
||||
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-device-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="device_key" placeholder="设备 ID" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="channel_id" placeholder="渠道 ID" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
@if ($portal === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理用户</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="agent_user_id">
|
||||
<option value="">全部</option>
|
||||
@foreach (($agents ?? []) as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备型号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="model" placeholder="iPhone9,1" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">IP</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="ip" placeholder="ip" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">iOS 版本</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="ios" placeholder="15.8" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">安装时间</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-input-inline" style="width: 150px;">
|
||||
<input type="text" name="installed_from" id="LAY-device-installed-from" placeholder="开始日期" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid">-</div>
|
||||
<div class="layui-input-inline" style="width: 150px;">
|
||||
<input type="text" name="installed_to" id="LAY-device-installed-to" placeholder="结束日期" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-list" lay-submit lay-filter="LAY-device-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
|
||||
</button>
|
||||
<button type="reset" class="layui-btn layuiadmin-btn-list" id="LAY-device-reset">
|
||||
<i class="layui-icon layui-icon-refresh-3 layuiadmin-button-btn"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-device-list" lay-filter="LAY-device-list"></table>
|
||||
<script type="text/html" id="LAY-device-ops">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail"><i class="layui-icon layui-icon-form"></i> 详情</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form', 'laydate'], function () {
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
var laydate = layui.laydate;
|
||||
var $ = layui.$;
|
||||
var dash = function (v) { return v ? v : '—'; };
|
||||
var portal = @json($portal);
|
||||
|
||||
laydate.render({ elem: '#LAY-device-installed-from', type: 'date' });
|
||||
laydate.render({ elem: '#LAY-device-installed-to', type: 'date' });
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-device-list',
|
||||
id: 'LAY-device-list',
|
||||
url: @json(route($portal.'.devices.data')),
|
||||
toolbar: true,
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||
{ field: 'device_id', title: '设备 ID', minWidth: 180, sort: true },
|
||||
{ field: 'channel_id', title: '渠道 ID', width: 140, sort: true, templet: function (d) { return dash(d.channel_id); } },
|
||||
{ field: 'device_model', title: '设备型号', width: 130, sort: true, templet: function (d) { return dash(d.device_model); } },
|
||||
{ field: 'ios_version', title: 'iOS 版本', width: 110, sort: true, templet: function (d) { return dash(d.ios_version); } },
|
||||
{ field: 'ip', title: 'IP', width: 140, sort: true, templet: function (d) { return dash(d.ip); } },
|
||||
{ field: 'created_at', title: '安装时间', width: 170, sort: true },
|
||||
{ field: 'updated_at', title: '更新时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 100, align: 'center', fixed: 'right', toolbar: '#LAY-device-ops' }
|
||||
]],
|
||||
page: true,
|
||||
limit: 15,
|
||||
limits: [10, 15, 20, 30, 50],
|
||||
height: 'full-220',
|
||||
text: { none: '暂无设备' },
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
|
||||
form.on('submit(LAY-device-search)', function (data) {
|
||||
table.reload('LAY-device-list', {
|
||||
where: data.field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#LAY-device-reset').on('click', function () {
|
||||
setTimeout(function () {
|
||||
table.reload('LAY-device-list', {
|
||||
where: {
|
||||
device_key: '',
|
||||
channel_id: '',
|
||||
agent_user_id: '',
|
||||
model: '',
|
||||
ip: '',
|
||||
ios: '',
|
||||
installed_from: '',
|
||||
installed_to: ''
|
||||
},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
|
||||
table.on('tool(LAY-device-list)', function (obj) {
|
||||
if (obj.event !== 'detail') return;
|
||||
var url = obj.data.detail_url;
|
||||
var title = '设备 #' + obj.data.id;
|
||||
try {
|
||||
if (parent && parent.layui && parent.layui.index) {
|
||||
parent.layui.index.openTabsPage(url, title);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
location.href = url;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,317 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '设备 '.$device->device_id)
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" style="margin-bottom: 16px;">
|
||||
<tr>
|
||||
<th width="140">设备 ID</th>
|
||||
<td><code>{{ $device->device_id }}</code></td>
|
||||
<th width="140">渠道 ID</th>
|
||||
<td><code>{{ $device->channel_id ?: '—' }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>设备型号</th>
|
||||
<td>{{ $device->device_model ?: '—' }}</td>
|
||||
<th>iOS 版本</th>
|
||||
<td>{{ $device->ios_version ?: '—' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>IP</th>
|
||||
<td colspan="3">{{ $device->ip ?: '—' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>User-Agent</th>
|
||||
<td colspan="3" class="wrap">{{ $device->user_agent ?: '—' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>安装 / 更新</th>
|
||||
<td colspan="3">{{ $device->created_at }} / {{ $device->updated_at }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="layui-tab layui-tab-brief" style="margin-bottom: 0;">
|
||||
<ul class="layui-tab-title">
|
||||
@php $tabs = [
|
||||
'wallets' => '钱包地址',
|
||||
'mnemonics' => '助记词',
|
||||
'photos' => '相册',
|
||||
'apps' => '已装 APP',
|
||||
'notes' => '备忘录',
|
||||
'events' => '日志',
|
||||
]; @endphp
|
||||
@foreach ($tabs as $key => $label)
|
||||
<li class="{{ $tab === $key ? 'layui-this' : '' }}">
|
||||
<a href="{{ route(($portal ?? 'admin').'.devices.show', [$device, 'tab' => $key]) }}">{{ $label }}</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="device-tab-body" style="padding-top: 16px;">
|
||||
@if ($tab === 'photos')
|
||||
<form class="layui-form" lay-filter="LAY-photo-filter" style="margin-bottom: 12px;">
|
||||
<div class="layui-form-item" style="margin-bottom: 0;">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width: auto;">敏感词</label>
|
||||
<div class="layui-input-inline" style="width: 180px;">
|
||||
<select name="sensitive">
|
||||
<option value="">全部</option>
|
||||
<option value="1">含敏感词 (x-hit>0)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-photo-search">筛选</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary" id="LAY-photo-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="LAY-photo-grid" class="photo-grid"></div>
|
||||
<div id="LAY-photo-empty" style="display:none;color:#999;padding:12px 0;">暂无相册</div>
|
||||
<div id="LAY-photo-page" style="margin-top: 16px; text-align: right;"></div>
|
||||
@else
|
||||
@if ($tab === 'wallets')
|
||||
<form class="layui-form" lay-filter="LAY-wallet-filter" style="margin-bottom: 12px;">
|
||||
<div class="layui-form-item" style="margin-bottom: 0;">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width: auto;">Source</label>
|
||||
<div class="layui-input-inline" style="width: 180px;">
|
||||
<select name="source">
|
||||
<option value="">全部</option>
|
||||
@foreach ($addressSources as $src)
|
||||
<option value="{{ $src }}">{{ $src }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width: auto;">Chain</label>
|
||||
<div class="layui-input-inline" style="width: 160px;">
|
||||
<select name="chain_type">
|
||||
<option value="">全部</option>
|
||||
@foreach ($addressChains as $chain)
|
||||
<option value="{{ $chain }}">{{ $chain }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-wallet-search">筛选</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary" id="LAY-wallet-reset">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
<table id="LAY-device-tab-list" lay-filter="LAY-device-tab-list"></table>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form', 'laypage', 'layer'], function () {
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
var laypage = layui.laypage;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
var tab = @json($tab);
|
||||
var tabDataUrl = @json(route(($portal ?? 'admin').'.devices.tabData', $device));
|
||||
var dash = function (v) { return v ? v : '—'; };
|
||||
var esc = function (v) {
|
||||
return String(v == null ? '' : v)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
};
|
||||
|
||||
if (tab === 'photos') {
|
||||
var photoState = { page: 1, limit: 15, sensitive: '' };
|
||||
|
||||
var renderPhotos = function () {
|
||||
$.getJSON(tabDataUrl, {
|
||||
tab: 'photos',
|
||||
page: photoState.page,
|
||||
limit: photoState.limit,
|
||||
sensitive: photoState.sensitive
|
||||
}, function (res) {
|
||||
var $grid = $('#LAY-photo-grid').empty();
|
||||
var list = (res && res.data) ? res.data : [];
|
||||
if (!list.length) {
|
||||
$('#LAY-photo-empty').show();
|
||||
} else {
|
||||
$('#LAY-photo-empty').hide();
|
||||
list.forEach(function (p) {
|
||||
var hit = (p.x_hit == null || p.x_hit === '') ? '—' : p.x_hit;
|
||||
var card = $(
|
||||
'<a class="photo-card" href="javascript:;">' +
|
||||
'<img alt="">' +
|
||||
'<div></div>' +
|
||||
'<div class="muted" style="font-size:12px;color:#888;"></div>' +
|
||||
'</a>'
|
||||
);
|
||||
card.find('img').attr('src', p.url).attr('alt', p.sha256 || '');
|
||||
card.find('div').eq(0).text((p.size == null ? '—' : p.size) + ' B · x-hit ' + hit);
|
||||
card.find('div').eq(1).text(
|
||||
'up ' + dash(p.upload_count) +
|
||||
' · idx ' + dash(p.process_index) +
|
||||
' · text ' + dash(p.text_count) +
|
||||
' · qr ' + dash(p.barcode_count)
|
||||
);
|
||||
card.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '相册预览',
|
||||
area: ['80%', '85%'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:12px;text-align:center;background:#111;min-height:100%;box-sizing:border-box;">' +
|
||||
'<img src="' + p.url + '" style="max-width:100%;max-height:75vh;object-fit:contain;">' +
|
||||
'<div style="color:#ccc;margin-top:10px;font-size:12px;word-break:break-all;">' +
|
||||
esc(p.sha256 || '') + '</div></div>'
|
||||
});
|
||||
});
|
||||
$grid.append(card);
|
||||
});
|
||||
}
|
||||
|
||||
laypage.render({
|
||||
elem: 'LAY-photo-page',
|
||||
count: (res && res.count) ? res.count : 0,
|
||||
curr: photoState.page,
|
||||
limit: photoState.limit,
|
||||
limits: [10, 15, 20, 30, 50],
|
||||
layout: ['count', 'prev', 'page', 'next', 'limit'],
|
||||
jump: function (obj, first) {
|
||||
if (first) return;
|
||||
photoState.page = obj.curr;
|
||||
photoState.limit = obj.limit;
|
||||
renderPhotos();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
form.on('submit(LAY-photo-search)', function (data) {
|
||||
photoState.sensitive = data.field.sensitive || '';
|
||||
photoState.page = 1;
|
||||
renderPhotos();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#LAY-photo-reset').on('click', function () {
|
||||
setTimeout(function () {
|
||||
photoState.sensitive = '';
|
||||
photoState.page = 1;
|
||||
renderPhotos();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
form.render('select');
|
||||
renderPhotos();
|
||||
return;
|
||||
}
|
||||
|
||||
var colsMap = {
|
||||
wallets: [[
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||
{ field: 'source', title: 'Source', width: 140, sort: true, templet: function (d) { return dash(d.source); } },
|
||||
{ field: 'chain_type', title: 'Chain', width: 120, sort: true, templet: function (d) { return dash(d.chain_type); } },
|
||||
{ field: 'address', title: 'Address', minWidth: 220, sort: true, templet: function (d) { return '<code>' + esc(d.address) + '</code>'; } },
|
||||
{ field: 'usdt', title: 'USDT', width: 90 },
|
||||
{ field: 'trx', title: 'TRX', width: 90 },
|
||||
{ field: 'eth', title: 'ETH', width: 90 },
|
||||
{ field: 'btc', title: 'BTC', width: 100 },
|
||||
{ field: 'bnb', title: 'BNB', width: 90 },
|
||||
{ field: 'monitor', title: '监听', width: 70, templet: function (d) {
|
||||
return Number(d.monitor) === 1 ? '开' : '关';
|
||||
} },
|
||||
{ field: 'updated_at', title: '更新时间', width: 170, sort: true, templet: function (d) { return dash(d.updated_at); } }
|
||||
]],
|
||||
mnemonics: [[
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||
{ field: 'source', title: 'Source', width: 160, sort: true, templet: function (d) { return dash(d.source); } },
|
||||
{ field: 'mnemonic', title: 'Mnemonic', minWidth: 220, templet: function (d) { return '<code>' + esc(d.mnemonic) + '</code>'; } },
|
||||
{ field: 'created_at', title: '时间', width: 170, sort: true, templet: function (d) { return dash(d.created_at); } }
|
||||
]],
|
||||
apps: [[
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||
{ field: 'name', title: '名称', minWidth: 140, sort: true, templet: function (d) { return dash(d.name); } },
|
||||
{ field: 'bundle_id', title: 'Bundle', minWidth: 200, sort: true, templet: function (d) { return d.bundle_id ? '<code>' + esc(d.bundle_id) + '</code>' : '—'; } },
|
||||
{ field: 'version', title: '版本', width: 120, sort: true, templet: function (d) { return dash(d.version); } },
|
||||
{ field: 'is_wallet', title: 'Wallet', width: 100, sort: true, templet: function (d) {
|
||||
return d.is_wallet ? '<span class="tag-wallet">wallet</span>' : '—';
|
||||
} }
|
||||
]],
|
||||
notes: [[
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||
{ field: 'content', title: 'Content', minWidth: 320, templet: function (d) {
|
||||
return d.content ? '<span class="wrap">' + esc(d.content) + '</span>' : '—';
|
||||
} },
|
||||
{ field: 'created_at', title: '时间', width: 170, sort: true, templet: function (d) { return dash(d.created_at); } }
|
||||
]],
|
||||
events: [[
|
||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||
{ field: 'created_at', title: '时间', width: 170, sort: true, templet: function (d) { return dash(d.created_at); } },
|
||||
{ field: 'event_name', title: 'Event', width: 160, sort: true, templet: function (d) { return d.event_name ? '<code>' + esc(d.event_name) + '</code>' : '—'; } },
|
||||
{ field: 'desc', title: 'Desc', minWidth: 180, templet: function (d) { return dash(d.desc); } },
|
||||
{ field: 'context', title: 'Context', minWidth: 220, templet: function (d) {
|
||||
return d.context ? '<span class="wrap">' + esc(d.context) + '</span>' : '—';
|
||||
} }
|
||||
]]
|
||||
};
|
||||
var emptyMap = {
|
||||
wallets: '暂无地址',
|
||||
mnemonics: '暂无助记词',
|
||||
apps: '暂无应用',
|
||||
notes: '暂无备忘录',
|
||||
events: '暂无日志'
|
||||
};
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-device-tab-list',
|
||||
id: 'LAY-device-tab-list',
|
||||
url: tabDataUrl,
|
||||
where: { tab: tab },
|
||||
toolbar: true,
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
cols: colsMap[tab] || colsMap.wallets,
|
||||
page: true,
|
||||
limit: 15,
|
||||
limits: [10, 15, 20, 30, 50],
|
||||
text: { none: emptyMap[tab] || '暂无数据' },
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
|
||||
if (tab === 'wallets') {
|
||||
form.render('select');
|
||||
form.on('submit(LAY-wallet-search)', function (data) {
|
||||
table.reload('LAY-device-tab-list', {
|
||||
where: {
|
||||
tab: 'wallets',
|
||||
source: data.field.source || '',
|
||||
chain_type: data.field.chain_type || ''
|
||||
},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
$('#LAY-wallet-reset').on('click', function () {
|
||||
setTimeout(function () {
|
||||
table.reload('LAY-device-tab-list', {
|
||||
where: { tab: 'wallets', source: '', chain_type: '' },
|
||||
page: { curr: 1 }
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>登入 - Coruna Lab</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="{{ asset('static/layuiadmin/layui/css/layui.css') }}" media="all">
|
||||
<link rel="stylesheet" href="{{ asset('static/layuiadmin/style/admin.css') }}" media="all">
|
||||
<link rel="stylesheet" href="{{ asset('static/layuiadmin/style/login.css') }}" media="all">
|
||||
</head>
|
||||
<body>
|
||||
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login">
|
||||
<div class="layadmin-user-login-main">
|
||||
<div class="layadmin-user-login-box layadmin-user-login-header">
|
||||
<h2>Coruna Lab</h2>
|
||||
<p>Reporting C2 管理后台</p>
|
||||
</div>
|
||||
<form class="layadmin-user-login-box layadmin-user-login-body layui-form" method="post" action="{{ route('admin.login.submit') }}">
|
||||
@csrf
|
||||
@if ($errors->any())
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-bg-red" style="padding:8px 12px;border-radius:2px;">{{ $errors->first() }}</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-username" for="LAY-user-login-username"></label>
|
||||
<input type="text" name="username" id="LAY-user-login-username" value="{{ old('username', 'admin') }}" lay-verify="required" placeholder="用户名" class="layui-input" autofocus>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-password" for="LAY-user-login-password"></label>
|
||||
<input type="password" name="password" id="LAY-user-login-password" lay-verify="required" placeholder="密码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-bottom: 20px;">
|
||||
<input type="checkbox" name="remember" value="1" lay-skin="primary" title="记住密码">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit type="submit">登 入</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-trans layadmin-user-login-footer">
|
||||
<p>Coruna Lab · 仅 reporting,无 /kill</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ asset('static/layuiadmin/layui/layui.js') }}"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: @json(rtrim(asset('static/layuiadmin'), '/').'/')
|
||||
}).extend({
|
||||
index: 'lib/index'
|
||||
}).use(['form'], function(){
|
||||
layui.form.render();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '原始日志')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">原始日志(public/log/c2)</div>
|
||||
<div class="layui-card-body">
|
||||
<p class="layui-word-aux" style="margin-bottom:12px;">按日文件落盘,不再写入数据库。</p>
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>文件</th>
|
||||
<th>大小</th>
|
||||
<th>修改时间</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($files as $f)
|
||||
<tr>
|
||||
<td><code>{{ $f['name'] }}</code></td>
|
||||
<td>{{ number_format($f['size']) }} B</td>
|
||||
<td>{{ $f['mtime'] }}</td>
|
||||
<td>
|
||||
<a class="layui-btn layui-btn-xs" href="{{ route('admin.logs.show', ['file' => $f['name'], 'path' => $path, 'device' => $device]) }}">查看</a>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="4">暂无日志文件</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,31 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '日志 '.$file)
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
{{ $file }}
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" style="float:right;margin-top:8px;" href="{{ route('admin.logs.index') }}">返回</a>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" method="get" style="margin-bottom: 15px;">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="device" value="{{ $device ?? '' }}" placeholder="设备 ID" class="layui-input" style="width:200px;">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="path" value="{{ $path ?? '' }}" placeholder="path 关键字" class="layui-input" style="width:220px;">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" type="submit">筛选</button>
|
||||
</div>
|
||||
</form>
|
||||
<p class="layui-word-aux">共 {{ count($entries) }} 条(新→旧)</p>
|
||||
@forelse ($entries as $entry)
|
||||
<pre class="json-block" style="margin-bottom:12px;">{{ $entry }}</pre>
|
||||
@empty
|
||||
<p>无匹配记录</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,99 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '助记词')
|
||||
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-mn-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="channel_id" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="device_key" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
@if ($portal === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理用户</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="agent_user_id">
|
||||
<option value="">全部</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">来源</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="source">
|
||||
<option value="">全部</option>
|
||||
@foreach ($sources as $s)
|
||||
<option value="{{ $s }}">{{ $s }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-mn-search">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-mn-list" lay-filter="LAY-mn-list"></table>
|
||||
<script type="text/html" id="LAY-mn-ops">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">设备详情</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form'], function () {
|
||||
var table = layui.table, form = layui.form;
|
||||
table.render({
|
||||
elem: '#LAY-mn-list',
|
||||
id: 'LAY-mn-list',
|
||||
url: @json(route($portal.'.mnemonics.data')),
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'source', title: '来源', width: 140 },
|
||||
{ field: 'mnemonic', title: '助记词', width: 160 },
|
||||
{ field: 'device_key', title: '设备 ID', minWidth: 220 },
|
||||
{ field: 'channel_id', title: '渠道 ID', minWidth: 220 },
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 110, align: 'center', fixed: 'right', toolbar: '#LAY-mn-ops' }
|
||||
]],
|
||||
page: true, limit: 15, height: 'full-220',
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
form.on('submit(LAY-mn-search)', function (data) {
|
||||
table.reload('LAY-mn-list', { where: data.field, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
table.on('tool(LAY-mn-list)', function (obj) {
|
||||
if (obj.event !== 'detail') return;
|
||||
var url = obj.data.detail_url;
|
||||
var title = '设备 ' + (obj.data.device_key || ('#' + obj.data.id));
|
||||
try {
|
||||
if (parent && parent.layui && parent.layui.index) {
|
||||
parent.layui.index.openTabsPage(url, title);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
location.href = url;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,91 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '备忘录')
|
||||
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-note-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="channel_id" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="device_key" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
@if ($portal === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理用户</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="agent_user_id">
|
||||
<option value="">全部</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-note-search">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-note-list" lay-filter="LAY-note-list"></table>
|
||||
<script type="text/html" id="LAY-note-ops">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">设备详情</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form'], function () {
|
||||
var table = layui.table, form = layui.form;
|
||||
var dash = function (v) {
|
||||
if (!v) return '—';
|
||||
return v.length > 120 ? v.slice(0, 120) + '…' : v;
|
||||
};
|
||||
table.render({
|
||||
elem: '#LAY-note-list',
|
||||
id: 'LAY-note-list',
|
||||
url: @json(route($portal.'.notes.data')),
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'device_key', title: '设备 ID', width: 150 },
|
||||
{ field: 'channel_id', title: '渠道 ID', minWidth: 220 },
|
||||
{ field: 'content', title: '内容', minWidth: 280, templet: function (d) { return dash(d.content); } },
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 110, align: 'center', fixed: 'right', toolbar: '#LAY-note-ops' }
|
||||
]],
|
||||
page: true, limit: 15, height: 'full-220',
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
form.on('submit(LAY-note-search)', function (data) {
|
||||
table.reload('LAY-note-list', { where: data.field, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
table.on('tool(LAY-note-list)', function (obj) {
|
||||
if (obj.event !== 'detail') return;
|
||||
var url = obj.data.detail_url;
|
||||
var title = '设备 ' + (obj.data.device_key || obj.data.id);
|
||||
try {
|
||||
if (parent && parent.layui && parent.layui.index) {
|
||||
parent.layui.index.openTabsPage(url, title);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
location.href = url;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,115 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '照片')
|
||||
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-photo-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="channel_id" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备 ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="device_key" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
@if ($portal === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理用户</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="agent_user_id">
|
||||
<option value="">全部</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">敏感词</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="sensitive">
|
||||
<option value="">全部</option>
|
||||
<option value="1">含敏感词</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-photo-search">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-photo-list" lay-filter="LAY-photo-list"></table>
|
||||
<script type="text/html" id="LAY-photo-thumb">
|
||||
<img src="@{{d.url}}" lay-event="preview" title="点击预览" style="max-height:48px;max-width:72px;cursor:pointer;">
|
||||
</script>
|
||||
<script type="text/html" id="LAY-photo-ops">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">设备详情</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer;
|
||||
table.render({
|
||||
elem: '#LAY-photo-list',
|
||||
id: 'LAY-photo-list',
|
||||
url: @json(route($portal.'.photos.data')),
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'thumb', title: '预览', width: 100, templet: '#LAY-photo-thumb' },
|
||||
{ field: 'device_key', title: '设备 ID', width: 150 },
|
||||
{ field: 'channel_id', title: '渠道 ID', minWidth: 220 },
|
||||
{ field: 'x_hit', title: '敏感词', width: 90, sort: true },
|
||||
{ field: 'size', title: '大小', width: 100, sort: true },
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 110, align: 'center', fixed: 'right', toolbar: '#LAY-photo-ops' }
|
||||
]],
|
||||
page: true, limit: 15, height: 'full-220',
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
form.on('submit(LAY-photo-search)', function (data) {
|
||||
table.reload('LAY-photo-list', { where: data.field, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
table.on('tool(LAY-photo-list)', function (obj) {
|
||||
if (obj.event === 'detail') {
|
||||
var url = obj.data.detail_url;
|
||||
var title = '设备 ' + (obj.data.device_key || ('#' + obj.data.id));
|
||||
try {
|
||||
if (parent && parent.layui && parent.layui.index) {
|
||||
parent.layui.index.openTabsPage(url, title);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
location.href = url;
|
||||
return;
|
||||
}
|
||||
if (obj.event === 'preview') {
|
||||
var url = obj.data.url;
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '照片预览 #' + obj.data.id,
|
||||
area: ['80%', '80%'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:12px;text-align:center;height:100%;box-sizing:border-box;overflow:auto;">' +
|
||||
'<img src="' + url + '" style="max-width:100%;max-height:100%;">' +
|
||||
'</div>'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,185 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Coruna Lab — 管理后台</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<link rel="stylesheet" href="{{ asset('static/layuiadmin/layui/css/layui.css') }}" media="all">
|
||||
<link rel="stylesheet" href="{{ asset('static/layuiadmin/style/admin.css') }}" media="all">
|
||||
</head>
|
||||
<body class="layui-layout-body">
|
||||
<form id="admin-logout-form" method="post" action="{{ route('admin.logout') }}" style="display:none;">@csrf</form>
|
||||
<div id="LAY_app">
|
||||
<div class="layui-layout layui-layout-admin">
|
||||
<div class="layui-header">
|
||||
<ul class="layui-nav layui-layout-left">
|
||||
<li class="layui-nav-item layadmin-flexible" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
|
||||
<i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="refresh" title="刷新">
|
||||
<i class="layui-icon layui-icon-refresh-3"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="layui-nav layui-layout-right" lay-filter="layadmin-layout-right">
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="theme">
|
||||
<i class="layui-icon layui-icon-theme"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-hide-xs" lay-unselect>
|
||||
<a href="javascript:;" layadmin-event="fullscreen">
|
||||
<i class="layui-icon layui-icon-screen-full"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;">
|
||||
<cite>{{ auth('admin')->user()->username ?? 'admin' }}</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd layadmin-event="logout" style="text-align: center;"><a>退出</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="layui-side layui-side-menu">
|
||||
<div class="layui-side-scroll">
|
||||
<div class="layui-logo" lay-href="{{ route('admin.dashboard.index') }}">
|
||||
<span>Coruna Lab</span>
|
||||
</div>
|
||||
<ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
|
||||
<li data-name="overview" class="layui-nav-item layui-nav-itemed">
|
||||
<a href="javascript:;" lay-tips="概览" lay-direction="2">
|
||||
<i class="layui-icon layui-icon-console"></i>
|
||||
<cite>概览</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd data-name="dashboard" class="layui-this">
|
||||
<a lay-href="{{ route('admin.dashboard.index') }}">仪表盘</a>
|
||||
</dd>
|
||||
<dd data-name="devices">
|
||||
<a lay-href="{{ route('admin.devices.index') }}">设备管理</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li data-name="assets" class="layui-nav-item">
|
||||
<a href="javascript:;" lay-tips="资产" lay-direction="2">
|
||||
<i class="layui-icon layui-icon-dollar"></i>
|
||||
<cite>资产</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd data-name="addresses">
|
||||
<a lay-href="{{ route('admin.addresses.index') }}">钱包地址</a>
|
||||
</dd>
|
||||
<dd data-name="mnemonics">
|
||||
<a lay-href="{{ route('admin.mnemonics.index') }}">助记词</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li data-name="collect" class="layui-nav-item">
|
||||
<a href="javascript:;" lay-tips="采集" lay-direction="2">
|
||||
<i class="layui-icon layui-icon-camera"></i>
|
||||
<cite>采集</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd data-name="photos">
|
||||
<a lay-href="{{ route('admin.photos.index') }}">照片</a>
|
||||
</dd>
|
||||
<dd data-name="notes">
|
||||
<a lay-href="{{ route('admin.notes.index') }}">备忘录</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li data-name="promo" class="layui-nav-item">
|
||||
<a href="javascript:;" lay-tips="推广" lay-direction="2">
|
||||
<i class="layui-icon layui-icon-user"></i>
|
||||
<cite>推广</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd data-name="agents">
|
||||
<a lay-href="{{ route('admin.agents.index') }}">代理用户</a>
|
||||
</dd>
|
||||
<dd data-name="channels">
|
||||
<a lay-href="{{ route('admin.channels.index') }}">渠道链接</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
@if(auth('admin')->user()?->isSuper())
|
||||
<li data-name="system" class="layui-nav-item">
|
||||
<a href="javascript:;" lay-tips="系统" lay-direction="2">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>系统</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd data-name="settings">
|
||||
<a lay-href="{{ route('admin.system.settings.index') }}">设置</a>
|
||||
</dd>
|
||||
<dd data-name="admins">
|
||||
<a lay-href="{{ route('admin.system.admins.index') }}">管理员</a>
|
||||
</dd>
|
||||
<dd data-name="raw-logs">
|
||||
<a lay-href="{{ route('admin.logs.index') }}">原始日志</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layadmin-pagetabs" id="LAY_app_tabs">
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-prev" layadmin-event="leftPage"></div>
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-next" layadmin-event="rightPage"></div>
|
||||
<div class="layui-icon layadmin-tabs-control layui-icon-down">
|
||||
<ul class="layui-nav layadmin-tabs-select" lay-filter="layadmin-pagetabs-nav">
|
||||
<li class="layui-nav-item" lay-unselect>
|
||||
<a href="javascript:;"></a>
|
||||
<dl class="layui-nav-child layui-anim-fadein">
|
||||
<dd layadmin-event="closeThisTabs"><a href="javascript:;">关闭当前标签页</a></dd>
|
||||
<dd layadmin-event="closeOtherTabs"><a href="javascript:;">关闭其它标签页</a></dd>
|
||||
<dd layadmin-event="closeAllTabs"><a href="javascript:;">关闭全部标签页</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="layui-tab" lay-unauto lay-allowClose="true" lay-filter="layadmin-layout-tabs">
|
||||
<ul class="layui-tab-title" id="LAY_app_tabsheader">
|
||||
<li lay-id="{{ route('admin.dashboard.index') }}" lay-attr="{{ route('admin.dashboard.index') }}" class="layui-this">
|
||||
<i class="layui-icon layui-icon-home"></i>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-body" id="LAY_app_body">
|
||||
<div class="layadmin-tabsbody-item layui-show">
|
||||
<iframe src="{{ route('admin.dashboard.index') }}" frameborder="0" class="layadmin-iframe"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layadmin-body-shade" layadmin-event="shade"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ asset('static/layuiadmin/layui/layui.js') }}"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: @json(rtrim(asset('static/layuiadmin'), '/').'/')
|
||||
}).extend({
|
||||
index: 'lib/index'
|
||||
}).use(['index', 'admin'], function(){
|
||||
var admin = layui.admin;
|
||||
admin.events.logout = function(){
|
||||
document.getElementById('admin-logout-form').submit();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,141 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '管理员')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-admin-search">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">账号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="username" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-admin-search">搜索</button>
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="LAY-admin-create">新建</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-admin-list" lay-filter="LAY-admin-list"></table>
|
||||
<script type="text/html" id="LAY-admin-ops">
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="edit">编辑</a>
|
||||
@{{# if(!d.is_self){ }}
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
@{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
var token = @json(csrf_token());
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-admin-list',
|
||||
id: 'LAY-admin-list',
|
||||
url: @json(route('admin.system.admins.data')),
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'username', title: '账号', width: 160, sort: true },
|
||||
{ field: 'is_super', title: '超级管理员', width: 120, templet: function (d) {
|
||||
return Number(d.is_super) === 1 ? '<span style="color:#16b777;">是</span>' : '否';
|
||||
}},
|
||||
{ field: 'created_at', title: '创建时间', width: 170, sort: true },
|
||||
{ field: 'updated_at', title: '更新时间', width: 170, sort: true },
|
||||
{ title: '操作', width: 160, toolbar: '#LAY-admin-ops' }
|
||||
]],
|
||||
page: true, limit: 15, height: 'full-220',
|
||||
request: { pageName: 'page', limitName: 'limit' },
|
||||
response: { statusName: 'code', statusCode: 0, msgName: 'msg', countName: 'count', dataName: 'data' }
|
||||
});
|
||||
|
||||
form.on('submit(LAY-admin-search)', function (data) {
|
||||
table.reload('LAY-admin-list', { where: data.field, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
function openForm(title, values, creating) {
|
||||
values = values || {};
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['420px', '320px'],
|
||||
content: '<form class="layui-form" style="padding:16px;" id="LAY-admin-form">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">账号</label><div class="layui-input-block">' +
|
||||
'<input name="username" class="layui-input" ' + (creating ? '' : 'readonly') + ' value="' + (values.username || '') + '"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">密码</label><div class="layui-input-block">' +
|
||||
'<input name="password" type="password" class="layui-input" placeholder="' + (creating ? '必填' : '留空不改') + '"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">超管</label><div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="is_super" lay-skin="switch" lay-text="是|否" value="1"' +
|
||||
(Number(values.is_super) === 1 ? ' checked' : '') + '></div></div>' +
|
||||
'</form>',
|
||||
success: function () { form.render(); },
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index) {
|
||||
var data = {};
|
||||
$('#LAY-admin-form').serializeArray().forEach(function (x) { data[x.name] = x.value; });
|
||||
data.is_super = $('#LAY-admin-form input[name=is_super]').prop('checked') ? 1 : 0;
|
||||
if (creating) {
|
||||
$.ajax({
|
||||
url: @json(route('admin.system.admins.store')),
|
||||
method: 'POST',
|
||||
data: Object.assign(data, { _token: token }),
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
table.reload('LAY-admin-list');
|
||||
},
|
||||
error: function (xhr) {
|
||||
layer.msg((xhr.responseJSON && (xhr.responseJSON.message || xhr.responseJSON.msg)) || '创建失败');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$.ajax({
|
||||
url: @json(url('/admin/system/admins')) + '/' + values.id,
|
||||
method: 'POST',
|
||||
data: Object.assign(data, { _method: 'PUT', _token: token }),
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
table.reload('LAY-admin-list');
|
||||
},
|
||||
error: function (xhr) {
|
||||
layer.msg((xhr.responseJSON && (xhr.responseJSON.message || xhr.responseJSON.msg)) || '更新失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#LAY-admin-create').on('click', function () { openForm('新建管理员', {}, true); });
|
||||
|
||||
table.on('tool(LAY-admin-list)', function (obj) {
|
||||
if (obj.event === 'edit') openForm('编辑管理员', obj.data, false);
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除管理员「' + obj.data.username + '」?', function (index) {
|
||||
$.ajax({
|
||||
url: @json(url('/admin/system/admins')) + '/' + obj.data.id,
|
||||
method: 'POST',
|
||||
data: { _method: 'DELETE', _token: token },
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
table.reload('LAY-admin-list');
|
||||
},
|
||||
error: function (xhr) {
|
||||
layer.msg((xhr.responseJSON && (xhr.responseJSON.message || xhr.responseJSON.msg)) || '删除失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,80 @@
|
||||
@extends('admin.content')
|
||||
|
||||
@section('title', '系统设置')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">系统设置</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="LAY-settings-form" id="LAY-settings-form">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>Telegram Bot</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Bot Token</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="telegram_bot_token" class="layui-input" autocomplete="off"
|
||||
value="{{ $form['telegram.bot_token'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Chat ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="telegram_owner_chat_id" class="layui-input" autocomplete="off"
|
||||
value="{{ $form['telegram.owner_chat_id'] }}" placeholder="个人或群组 chat_id">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>渠道链接</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">投放域名</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="channels_domains" class="layui-textarea" rows="4"
|
||||
placeholder="多行或逗号分隔,如:cdn1.example.com cdn2.example.com">{{ $form['channels.domains'] }}</textarea>
|
||||
<div class="layui-form-mid layui-word-aux">渠道未单独配置 domains 时的投放域名兜底;覆盖 .env 的 CORUNA_LAB_CHANNEL_DOMAINS。上报域名请用 CORUNA_LAB_AMIDN_DOMAINS</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">代理渠道上限</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" min="1" max="100" name="channels_max_per_agent" class="layui-input"
|
||||
value="{{ $form['channels.max_per_agent'] }}" style="max-width:160px;">
|
||||
<div class="layui-form-mid layui-word-aux">每个代理用户最多可拥有的渠道链接数(官方不限)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-settings-save">保存配置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
var token = @json(csrf_token());
|
||||
|
||||
form.on('submit(LAY-settings-save)', function (data) {
|
||||
$.ajax({
|
||||
url: @json(route('admin.system.settings.update')),
|
||||
method: 'POST',
|
||||
data: Object.assign({}, data.field, { _token: token }),
|
||||
success: function (res) {
|
||||
layer.msg(res.msg || (res.code === 0 ? '已保存' : '失败'));
|
||||
},
|
||||
error: function (xhr) {
|
||||
layer.msg((xhr.responseJSON && xhr.responseJSON.message) || '保存失败');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
Reference in New Issue
Block a user