feat: new channel
This commit is contained in:
@@ -27,32 +27,14 @@
|
||||
<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>
|
||||
@include('admin.partials.filter_channel_select')
|
||||
<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>
|
||||
<option value="0">官方</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">来源</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -86,6 +68,8 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
var token = @json(csrf_token());
|
||||
var updateBase = @json(url('/'.$portal.'/addresses'));
|
||||
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
|
||||
function chainTag(chain) {
|
||||
var raw = String(chain || 'UNKNOWN');
|
||||
var key = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
||||
|
||||
@@ -7,26 +7,8 @@
|
||||
<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
|
||||
@include('admin.partials.filter_channel_select')
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -48,13 +30,7 @@
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-ch-list" lay-filter="LAY-ch-list"></table>
|
||||
<script type="text/html" id="LAY-ch-ops">
|
||||
@{{# if(d.builder_type === 'new'){ }}
|
||||
@{{# if(d.download_url){ }}
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="download">下载代码</a>
|
||||
@{{# } }}
|
||||
@{{# } else { }}
|
||||
<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>
|
||||
@@ -70,10 +46,21 @@ 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 agents = @json(($agents ?? collect())->map(function ($a) {
|
||||
$name = trim((string) $a->username);
|
||||
$comment = trim((string) ($a->comment ?? ''));
|
||||
|
||||
return [
|
||||
'id' => $a->id,
|
||||
'username' => $name,
|
||||
'label' => $comment !== '' ? $name.'/'.$comment : $name,
|
||||
];
|
||||
})->values());
|
||||
var isAdmin = portal === 'admin';
|
||||
var maxPerAgent = @json($maxPerAgent ?? 5);
|
||||
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
|
||||
var cols = [
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'channel_id', title: '渠道 ID', minWidth: 220, sort: true },
|
||||
@@ -92,7 +79,7 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
: '<span style="color:#dc2626;font-weight:600;">禁用</span>';
|
||||
}},
|
||||
{ field: 'updated_at', title: '更新', width: 170, sort: true },
|
||||
{ title: '操作', width: isAdmin ? 250 : 190, align: 'center', fixed: 'right', toolbar: '#LAY-ch-ops' }
|
||||
{ title: '操作', width: isAdmin ? 220 : 160, align: 'center', fixed: 'right', toolbar: '#LAY-ch-ops' }
|
||||
]);
|
||||
|
||||
table.render({
|
||||
@@ -118,7 +105,7 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
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>';
|
||||
html += '<option value="' + a.id + '"' + (String(sel) === String(a.id) ? ' selected' : '') + '>' + (a.label || a.username) + '</option>';
|
||||
});
|
||||
return html;
|
||||
}
|
||||
@@ -140,39 +127,6 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
return '<iframe src="' + url + '" style="position:fixed;top:0;left:-1000px;pointer-events:none;border:0"></iframe>';
|
||||
}
|
||||
|
||||
function weifileIframeSnippet() {
|
||||
return '<iframe src="/weifile/weifile.html" style="position:fixed;top:0;width:0;height:0;left:-1000px;border:0"></iframe>';
|
||||
}
|
||||
|
||||
function openDownloadGuide(row) {
|
||||
var url = row && row.download_url;
|
||||
if (!url) return layer.msg('安装包不存在');
|
||||
var snippet = weifileIframeSnippet();
|
||||
var html = '<div style="padding:18px 20px;line-height:1.75;font-size:13px;color:#334155;">' +
|
||||
'<p style="margin:0 0 10px;">下载后按下面步骤放到自己的落地页项目中:</p>' +
|
||||
'<p style="margin:0 0 8px;"><b>1.</b> 解压 zip,把得到的 <code>weifile/</code> 目录放到落地页网站根目录,保证能访问到 <code>/weifile/weifile.html</code>。</p>' +
|
||||
'<p style="margin:0 0 14px;"><b>2.</b> 在自己的 HTML 里(建议放在 <code><body></code> 开头)加入一段不可见 iframe:</p>' +
|
||||
'<pre style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;padding:10px 12px;overflow:auto;font-size:12px;margin:0 0 14px;white-space:pre-wrap;word-break:break-all;">' +
|
||||
snippet.replace(/</g, '<') + '</pre>' +
|
||||
'<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">' +
|
||||
'<a class="layui-btn layui-btn-normal" href="' + url.replace(/"/g, '"') + '">下载代码</a>' +
|
||||
'<button type="button" class="layui-btn layui-btn-primary LAY-ch-copy-iframe">复制 iframe 代码</button>' +
|
||||
'</div>' +
|
||||
'<p style="margin:12px 0 0;color:#64748b;font-size:12px;">iframe 不可见,不影响落地页展示;用户打开落地页时会加载该渠道代码。</p>' +
|
||||
'</div>';
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '下载代码 — ' + (row.channel_id || ''),
|
||||
area: ['640px', '430px'],
|
||||
content: html,
|
||||
success: function (layero) {
|
||||
layero.find('.LAY-ch-copy-iframe').on('click', function () {
|
||||
copyText(snippet).then(function () { layer.msg('已复制 iframe 代码'); });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openLinks(row) {
|
||||
var links = row.links || [];
|
||||
if (!links.length) {
|
||||
@@ -214,12 +168,9 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
html += '<div style="margin-bottom:10px;"><b>落地页</b> <code>' +
|
||||
(data.weifile_path || data.support_path).replace(/</g, '<') + '</code></div>';
|
||||
}
|
||||
if (data.builder_type === 'new' && data.zip_path) {
|
||||
html += '<div style="margin-bottom:10px;"><b>安装包</b> <code>' +
|
||||
String(data.zip_path).replace(/</g, '<') + '</code></div>';
|
||||
if (data.download_url) {
|
||||
html += '<div style="margin-bottom:10px;"><button type="button" class="layui-btn layui-btn-normal layui-btn-sm LAY-ch-dl-guide">下载代码</button></div>';
|
||||
}
|
||||
if (data.builder_type === 'new' && data.channel_dir) {
|
||||
html += '<div style="margin-bottom:10px;"><b>资源目录</b> <code>' +
|
||||
String(data.channel_dir).replace(/</g, '<') + '</code></div>';
|
||||
}
|
||||
if (links.length) {
|
||||
html += '<div style="margin-bottom:6px;"><b>投放链接</b></div>';
|
||||
@@ -242,12 +193,7 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
type: 1,
|
||||
title: '创建成功',
|
||||
area: ['560px', '420px'],
|
||||
content: html,
|
||||
success: function (layero) {
|
||||
layero.find('.LAY-ch-dl-guide').on('click', function () {
|
||||
openDownloadGuide({ channel_id: channelId, download_url: data.download_url });
|
||||
});
|
||||
}
|
||||
content: html
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,7 +204,7 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
: '';
|
||||
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" id="LAY-ch-id-input" style="width:70%;display:inline-block;" value="' + (values.channel_id || '') + '" placeholder="旧版 32 位 / 新版 8 位">' +
|
||||
'<input name="channel_id" class="layui-input" maxlength="32" id="LAY-ch-id-input" style="width:70%;display:inline-block;" value="' + (values.channel_id || '') + '" placeholder="旧版 32 位 / 新版 X.Y.ZZ">' +
|
||||
'<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>';
|
||||
|
||||
@@ -268,16 +214,16 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
'<option value="old"' + ((values.builder_type || 'old') === 'old' ? ' selected' : '') + '>旧版</option>' +
|
||||
'<option value="new"' + (values.builder_type === 'new' ? ' selected' : '') + '>新版</option>' +
|
||||
'</select>' +
|
||||
'<div class="layui-form-mid layui-word-aux">旧版=/web/id/support.html;新版=8 位渠道码,打包已构建的 weifile(需先 php artisan xxbb:build)</div></div></div>'
|
||||
'<div class="layui-form-mid layui-word-aux">旧版=/web/id/support.html;新版=/channel/X.Y.ZZ/(创建时自动构建,c 取自 XXBB_CHANNEL_C)</div></div></div>'
|
||||
: '';
|
||||
|
||||
var templateBlock = (isAdmin && creating)
|
||||
? '<div class="layui-form-item" id="LAY-ch-template-item"><label class="layui-form-label">页面模板</label><div class="layui-input-block">' +
|
||||
'<select name="support_template">' +
|
||||
'<option value="test"' + ((values.support_template || 'test') === 'test' ? ' selected' : '') + '>test(含 HUD 进度页)</option>' +
|
||||
'<option value="test"' + ((values.support_template || 'test') === 'test' ? ' selected' : '') + '>test(加载页 / 15s 倒计时)</option>' +
|
||||
'<option value="blank"' + (values.support_template === 'blank' ? ' selected' : '') + '>blank(空白页)</option>' +
|
||||
'</select>' +
|
||||
'<div class="layui-form-mid layui-word-aux">控制生成的 support.html:test=HUD;blank=空白</div></div></div>'
|
||||
'<div class="layui-form-mid layui-word-aux" id="LAY-ch-template-hint">旧版=support.html;新版=weifile.html(test=loading,blank=空白)</div></div></div>'
|
||||
: '';
|
||||
|
||||
layer.open({
|
||||
@@ -298,13 +244,14 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
function syncTemplateVisibility() {
|
||||
var type = $('#LAY-ch-form select[name=builder_type]').val() || 'old';
|
||||
var $id = $('#LAY-ch-id-input');
|
||||
$('#LAY-ch-template-item').show();
|
||||
if (type === 'new') {
|
||||
$('#LAY-ch-template-item').hide();
|
||||
$id.attr('maxlength', 8).attr('placeholder', '8位,例如 FAFA9988');
|
||||
if (($id.val() || '').length !== 8) $id.val('');
|
||||
$id.attr('maxlength', 6).attr('placeholder', '例如 A.B.C1 或 3.1.07');
|
||||
if (!/^[0-9A-Za-z]\.[0-9A-Za-z]\.[0-9A-Za-z]{2}$/.test($id.val() || '')) $id.val('');
|
||||
$('#LAY-ch-template-hint').text('新版 weifile.html:test=大圆圈加载+15s 倒计时;blank=空白页');
|
||||
} else {
|
||||
$('#LAY-ch-template-item').show();
|
||||
$id.attr('maxlength', 32).attr('placeholder', '32位字母数字');
|
||||
$('#LAY-ch-template-hint').text('旧版 support.html:test=HUD;blank=空白');
|
||||
}
|
||||
}
|
||||
syncTemplateVisibility();
|
||||
@@ -332,6 +279,10 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
layer.close(load);
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
if (window.CorunaFilterOptions) {
|
||||
CorunaFilterOptions.bust();
|
||||
CorunaFilterOptions.apply(form);
|
||||
}
|
||||
table.reload('LAY-ch-list');
|
||||
showCreateResult(res, data.channel_id);
|
||||
},
|
||||
@@ -352,6 +303,10 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
success: function (res) {
|
||||
if (res.code !== 0) return layer.msg(res.msg || '失败');
|
||||
layer.close(index);
|
||||
if (window.CorunaFilterOptions) {
|
||||
CorunaFilterOptions.bust();
|
||||
CorunaFilterOptions.apply(form);
|
||||
}
|
||||
table.reload('LAY-ch-list');
|
||||
layer.msg('已保存');
|
||||
},
|
||||
@@ -375,12 +330,9 @@ layui.use(['table', 'form', 'layer'], function () {
|
||||
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 === 'download') {
|
||||
openDownloadGuide(obj.data);
|
||||
}
|
||||
if (obj.event === 'del') {
|
||||
var pathHint = obj.data.builder_type === 'new'
|
||||
? ('数据库记录与 channel-source-new/' + obj.data.channel_id + '.zip')
|
||||
? ('数据库记录与 channel/' + obj.data.channel_id + '/')
|
||||
: ('数据库记录与 web/' + obj.data.channel_id + ' 资源');
|
||||
layer.confirm('删除后将移除 ' + pathHint + ',确认?', function (idx) {
|
||||
$.ajax({
|
||||
|
||||
@@ -36,6 +36,89 @@ layui.config({
|
||||
}).extend({
|
||||
index: 'lib/index'
|
||||
}).use(['index'], function(){});
|
||||
|
||||
window.CorunaFilterOptions = (function () {
|
||||
var portal = @json($portal ?? 'admin');
|
||||
var channelsUrl = @json(route(($portal ?? 'admin').'.filterOptions.channels'));
|
||||
var agentsUrl = portal === 'admin' ? @json(route('admin.filterOptions.agents')) : null;
|
||||
var mem = { channels: null, agents: null, inflight: null };
|
||||
var STORAGE_PREFIX = 'coruna_filter_opts_' + portal + '_';
|
||||
var TTL_MS = 60 * 1000;
|
||||
|
||||
function readStore(key) {
|
||||
try {
|
||||
var raw = sessionStorage.getItem(STORAGE_PREFIX + key);
|
||||
if (!raw) return null;
|
||||
var parsed = JSON.parse(raw);
|
||||
if (!parsed || !parsed.at || (Date.now() - parsed.at) > TTL_MS) return null;
|
||||
return parsed.data;
|
||||
} catch (e) { return null; }
|
||||
}
|
||||
|
||||
function writeStore(key, data) {
|
||||
try {
|
||||
sessionStorage.setItem(STORAGE_PREFIX + key, JSON.stringify({ at: Date.now(), data: data }));
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function fillSelect(sel, rows, keepFirst) {
|
||||
var $sel = window.layui && layui.$ ? layui.$(sel) : null;
|
||||
if (!$sel || !$sel.length) return;
|
||||
var keep = keepFirst || 1;
|
||||
$sel.find('option').slice(keep).remove();
|
||||
(rows || []).forEach(function (row) {
|
||||
$sel.append(new Option(row.label, row.value));
|
||||
});
|
||||
}
|
||||
|
||||
function loadAll() {
|
||||
if (mem.inflight) return mem.inflight;
|
||||
var chCached = mem.channels || readStore('channels');
|
||||
var agCached = agentsUrl ? (mem.agents || readStore('agents')) : [];
|
||||
if (chCached && (!agentsUrl || agCached)) {
|
||||
mem.channels = chCached;
|
||||
mem.agents = agCached || [];
|
||||
return layui.$.Deferred().resolve(mem).promise();
|
||||
}
|
||||
var $ = layui.$;
|
||||
var reqs = [$.getJSON(channelsUrl)];
|
||||
if (agentsUrl) reqs.push($.getJSON(agentsUrl));
|
||||
mem.inflight = $.when.apply($, reqs).then(function () {
|
||||
var args = arguments;
|
||||
var chRes = reqs.length === 1 ? args[0] : args[0][0];
|
||||
var agRes = reqs.length === 1 ? null : args[1][0];
|
||||
mem.channels = (chRes && chRes.data) || [];
|
||||
mem.agents = (agRes && agRes.data) || [];
|
||||
writeStore('channels', mem.channels);
|
||||
if (agentsUrl) writeStore('agents', mem.agents);
|
||||
mem.inflight = null;
|
||||
return mem;
|
||||
}, function () {
|
||||
mem.inflight = null;
|
||||
return { channels: [], agents: [] };
|
||||
});
|
||||
return mem.inflight;
|
||||
}
|
||||
|
||||
function apply(form) {
|
||||
return loadAll().then(function (data) {
|
||||
fillSelect('select[data-coruna-channels]', data.channels, 1);
|
||||
fillSelect('select[data-coruna-agents]', data.agents, 2);
|
||||
if (form && form.render) form.render('select');
|
||||
});
|
||||
}
|
||||
|
||||
function bust() {
|
||||
mem.channels = null;
|
||||
mem.agents = null;
|
||||
try {
|
||||
sessionStorage.removeItem(STORAGE_PREFIX + 'channels');
|
||||
sessionStorage.removeItem(STORAGE_PREFIX + 'agents');
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return { apply: apply, bust: bust, loadAll: loadAll };
|
||||
})();
|
||||
</script>
|
||||
@stack('scripts')
|
||||
</body>
|
||||
|
||||
@@ -5,10 +5,51 @@
|
||||
@section('content')
|
||||
@php $portal = $portal ?? 'admin'; @endphp
|
||||
<style>
|
||||
.dash-metric { font-size: 28px; line-height: 1.2; }
|
||||
.dash-grid { display: grid; gap: 12px; margin-bottom: 12px; }
|
||||
.dash-grid-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
||||
.dash-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
@media screen and (max-width: 992px) {
|
||||
.dash-grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.dash-grid-2 { grid-template-columns: 1fr; }
|
||||
}
|
||||
.dash-tile {
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 2px;
|
||||
min-height: 108px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.dash-tile-hd {
|
||||
padding: 10px 14px 0;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.dash-tile-bd {
|
||||
padding: 8px 14px 12px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.dash-metric { font-size: 26px; line-height: 1.25; color: #333; word-break: break-all; }
|
||||
.dash-metric-hl { color: #009688; font-weight: 600; }
|
||||
.dash-metric-sep { color: #bbb; margin: 0 4px; font-weight: 400; }
|
||||
.dash-metric-total { color: #333; }
|
||||
.dash-metric-caption {
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.3;
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
}
|
||||
.dash-section-label {
|
||||
margin: 4px 0 8px;
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
<div class="layui-card">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="LAY-dash-search">
|
||||
@@ -24,85 +65,131 @@
|
||||
</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>
|
||||
<option value="0">官方</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@include('admin.partials.filter_channel_select')
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<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-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总设备数</div>
|
||||
<div class="layui-card-body dash-metric" id="dash-total">—</div>
|
||||
<div class="dash-section-label">设备与资产</div>
|
||||
<div class="dash-grid dash-grid-5">
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">总设备数</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric" id="dash-total">—</div>
|
||||
<span class="dash-metric-caption">有钱包设备/总设备</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">新增设备</div>
|
||||
<div class="layui-card-body dash-metric dash-metric-hl" id="dash-new">—</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">新增设备</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-new">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">活跃设备</div>
|
||||
<div class="layui-card-body dash-metric" id="dash-active">—</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">活跃设备</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric" id="dash-active">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">页面 PV</div>
|
||||
<div class="layui-card-body dash-metric" id="dash-pv">—</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">助记词</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-mnemonics">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">页面 UV</div>
|
||||
<div class="layui-card-body dash-metric" id="dash-uv">—</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">钱包地址</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-addresses">—</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-word-aux" style="margin-top:4px;">有效口径:iOS ≤ 17.2 且使用 Safari(左侧高亮 / 右侧为全部)</div>
|
||||
|
||||
<div class="layui-row layui-col-space15" style="margin-top:12px;">
|
||||
<div class="layui-col-md6">
|
||||
<div class="dash-section-label">总余额</div>
|
||||
<div class="dash-grid dash-grid-5">
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">USDT</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-bal-usdt">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">TRX</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-bal-trx">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">BTC</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-bal-btc">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">ETH</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-bal-eth">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">BNB</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric dash-metric-hl" id="dash-bal-bnb">—</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dash-section-label">页面访问<span style="margin-left:8px;font-size:12px;">有效口径:iOS ≤ 17.2 且 Safari(左侧高亮)</span></div>
|
||||
<div class="dash-grid dash-grid-2">
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">页面 PV</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric" id="dash-pv">—</div>
|
||||
<span class="dash-metric-caption">有效 PV/总 PV</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-tile">
|
||||
<div class="dash-tile-hd">页面 UV</div>
|
||||
<div class="dash-tile-bd">
|
||||
<div class="dash-metric" id="dash-uv">—</div>
|
||||
<span class="dash-metric-caption">有效 UV/总 UV</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15" style="margin-top:4px;">
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">按系统(PV / UV / 占比)</div>
|
||||
<div class="layui-card-header">访问 · 按系统(UV / 占比)</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" lay-size="sm">
|
||||
<thead><tr><th>系统</th><th>PV</th><th>UV</th><th>占比</th></tr></thead>
|
||||
<tbody id="dash-by-os"><tr><td colspan="4">—</td></tr></tbody>
|
||||
<thead><tr><th>系统</th><th>UV</th><th>占比</th></tr></thead>
|
||||
<tbody id="dash-by-os"><tr><td colspan="3">—</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">按 iOS 系统版本(PV / UV / 占比)</div>
|
||||
<div class="layui-card-header">访问 · 按 iOS 版本(UV / 占比)</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" lay-size="sm">
|
||||
<thead><tr><th>版本</th><th>PV</th><th>UV</th><th>占比</th></tr></thead>
|
||||
<tbody id="dash-by-ios-version"><tr><td colspan="4">—</td></tr></tbody>
|
||||
<thead><tr><th>版本</th><th>UV</th><th>占比</th></tr></thead>
|
||||
<tbody id="dash-by-ios-version"><tr><td colspan="3">—</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md4">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">受控设备 · 系统版本分布</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" lay-size="sm">
|
||||
<thead><tr><th>版本</th><th>设备数</th><th>占比</th></tr></thead>
|
||||
<tbody id="dash-by-device-ios"><tr><td colspan="3">—</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,9 +211,18 @@ layui.use(['form'], function () {
|
||||
var html = '';
|
||||
(rows || []).forEach(function (r) {
|
||||
var pct = (r.pct === undefined || r.pct === null) ? '—' : (r.pct + '%');
|
||||
html += '<tr><td>' + (r.label || '—') + '</td><td>' + r.pv + '</td><td>' + r.uv + '</td><td>' + pct + '</td></tr>';
|
||||
html += '<tr><td>' + (r.label || '—') + '</td><td>' + r.uv + '</td><td>' + pct + '</td></tr>';
|
||||
});
|
||||
$(sel).html(html || '<tr><td colspan="4">暂无</td></tr>');
|
||||
$(sel).html(html || '<tr><td colspan="3">暂无</td></tr>');
|
||||
}
|
||||
|
||||
function fillDeviceVersionRows(sel, rows) {
|
||||
var html = '';
|
||||
(rows || []).forEach(function (r) {
|
||||
var pct = (r.pct === undefined || r.pct === null) ? '—' : (r.pct + '%');
|
||||
html += '<tr><td>' + (r.label || '—') + '</td><td>' + r.count + '</td><td>' + pct + '</td></tr>';
|
||||
});
|
||||
$(sel).html(html || '<tr><td colspan="3">暂无</td></tr>');
|
||||
}
|
||||
|
||||
function ratioHtml(effective, total) {
|
||||
@@ -138,13 +234,20 @@ layui.use(['form'], function () {
|
||||
function load(where) {
|
||||
$.getJSON(dataUrl, where || { range: '30d' }, function (res) {
|
||||
if (!res || res.code !== 0) return;
|
||||
$('#dash-total').text(res.data.total);
|
||||
$('#dash-total').html(ratioHtml(res.data.wallet_count || 0, res.data.total || 0));
|
||||
$('#dash-new').text(res.data.new_count);
|
||||
$('#dash-active').text(res.data.active_count);
|
||||
$('#dash-mnemonics').text(res.data.mnemonic_count || 0);
|
||||
$('#dash-addresses').text(res.data.address_count || 0);
|
||||
$('#dash-pv').html(ratioHtml(res.data.effective_pv || 0, res.data.pv || 0));
|
||||
$('#dash-uv').html(ratioHtml(res.data.effective_uv || 0, res.data.uv || 0));
|
||||
var bal = res.data.balances || {};
|
||||
['usdt', 'trx', 'btc', 'eth', 'bnb'].forEach(function (c) {
|
||||
$('#dash-bal-' + c).text(bal[c] != null && bal[c] !== '' ? bal[c] : '0');
|
||||
});
|
||||
fillRows('#dash-by-os', res.data.by_os);
|
||||
fillRows('#dash-by-ios-version', res.data.by_ios_version);
|
||||
fillDeviceVersionRows('#dash-by-device-ios', res.data.by_device_ios_version);
|
||||
$('#dash-range').text('统计区间:' + res.data.from + ' ~ ' + res.data.to);
|
||||
});
|
||||
}
|
||||
@@ -154,6 +257,7 @@ layui.use(['form'], function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
load({ range: '30d' });
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -13,26 +13,8 @@
|
||||
<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>
|
||||
<option value="0">官方</option>
|
||||
@foreach (($agents ?? []) as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@include('admin.partials.filter_channel_select')
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备型号</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -112,6 +94,8 @@ layui.use(['table', 'form', 'laydate', 'layer'], function () {
|
||||
var token = @json(csrf_token());
|
||||
var updateBase = @json(url('/'.$portal.'/devices'));
|
||||
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
|
||||
laydate.render({ elem: '#LAY-device-installed-from', type: 'date' });
|
||||
laydate.render({ elem: '#LAY-device-installed-to', type: 'date' });
|
||||
|
||||
@@ -125,7 +109,6 @@ layui.use(['table', 'form', 'laydate', 'layer'], function () {
|
||||
{ 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: 'source_domain', title: '来源域名', width: 160, templet: function (d) { return dash(d.source_domain); } },
|
||||
{ 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); } },
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
<th width="140">渠道 ID</th>
|
||||
<td><code>{{ $device->channel_id ?: '—' }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>来源域名</th>
|
||||
<td colspan="3"><code>{{ $device->source_domain ?: '—' }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>设备型号</th>
|
||||
<td>{{ $device->device_model ?: '—' }}</td>
|
||||
|
||||
@@ -7,32 +7,14 @@
|
||||
<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>
|
||||
@include('admin.partials.filter_channel_select')
|
||||
<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>
|
||||
<option value="0">官方</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">来源</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -62,6 +44,7 @@
|
||||
<script>
|
||||
layui.use(['table', 'form'], function () {
|
||||
var table = layui.table, form = layui.form;
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
table.render({
|
||||
elem: '#LAY-mn-list',
|
||||
id: 'LAY-mn-list',
|
||||
|
||||
@@ -7,32 +7,14 @@
|
||||
<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>
|
||||
@include('admin.partials.filter_channel_select')
|
||||
<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>
|
||||
<option value="0">官方</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-note-search">搜索</button>
|
||||
</div>
|
||||
@@ -51,6 +33,7 @@
|
||||
<script>
|
||||
layui.use(['table', 'form'], function () {
|
||||
var table = layui.table, form = layui.form;
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
var dash = function (v) {
|
||||
if (!v) return '—';
|
||||
return v.length > 120 ? v.slice(0, 120) + '…' : v;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{{-- Searchable agent select (admin only); filled by CorunaFilterOptions --}}
|
||||
@if (($portal ?? 'admin') === 'admin')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">代理用户</label>
|
||||
<div class="layui-input-block" style="min-width: 180px;">
|
||||
<select name="agent_user_id" lay-search data-coruna-agents>
|
||||
<option value="">全部</option>
|
||||
<option value="0">官方</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,9 @@
|
||||
{{-- Searchable channel ID select; filled by CorunaFilterOptions --}}
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">渠道 ID</label>
|
||||
<div class="layui-input-block" style="min-width: 200px;">
|
||||
<select name="channel_id" lay-search data-coruna-channels>
|
||||
<option value="">全部</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -7,32 +7,14 @@
|
||||
<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>
|
||||
@include('admin.partials.filter_channel_select')
|
||||
<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>
|
||||
<option value="0">官方</option>
|
||||
@foreach ($agents as $a)
|
||||
<option value="{{ $a->id }}">{{ $a->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">敏感词</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -63,6 +45,7 @@
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer'], function () {
|
||||
var table = layui.table, form = layui.form, layer = layui.layer;
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
table.render({
|
||||
elem: '#LAY-photo-list',
|
||||
id: 'LAY-photo-list',
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
</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" class="layui-input" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
@include('admin.partials.filter_channel_select')
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">系统</label>
|
||||
<div class="layui-input-block">
|
||||
@@ -42,32 +37,13 @@
|
||||
<input type="text" name="browser" class="layui-input" placeholder="如 Safari" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">来源域名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="domain" class="layui-input" placeholder="来源域名" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">Referer</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="referer" class="layui-input" placeholder="来源" 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
|
||||
@include('admin.partials.filter_agent_select')
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-visit-search">搜索</button>
|
||||
</div>
|
||||
@@ -81,7 +57,6 @@
|
||||
<select id="LAY-visit-group">
|
||||
<option value="os">系统</option>
|
||||
<option value="os_version">系统 + 版本</option>
|
||||
<option value="domain">来源域名</option>
|
||||
<option value="browser">浏览器</option>
|
||||
<option value="browser_version">浏览器 + 版本</option>
|
||||
</select>
|
||||
@@ -104,6 +79,8 @@ layui.use(['table', 'form'], function () {
|
||||
var portal = @json($portal);
|
||||
var where = { range: '30d' };
|
||||
|
||||
if (window.CorunaFilterOptions) CorunaFilterOptions.apply(form);
|
||||
|
||||
function loadGroups() {
|
||||
var g = $('#LAY-visit-group').val() || 'os';
|
||||
$.getJSON(@json(route($portal.'.visits.groups')), Object.assign({}, where, { group: g }), function (res) {
|
||||
@@ -124,7 +101,6 @@ layui.use(['table', 'form'], function () {
|
||||
cols: [[
|
||||
{ field: 'id', title: 'ID', width: 70, sort: true },
|
||||
{ field: 'channel_id', title: '渠道', minWidth: 160 },
|
||||
{ field: 'domain', title: '来源域名', minWidth: 180 },
|
||||
{ field: 'client_uid', title: '访客 UID', width: 160 },
|
||||
{ field: 'os', title: '系统', width: 90 },
|
||||
{ field: 'os_version', title: '系统版本', width: 100 },
|
||||
|
||||
Reference in New Issue
Block a user