feat: new channel

This commit is contained in:
hashbro
2026-08-15 02:56:38 +08:00
parent 5453d9d69b
commit 7c0066562f
45 changed files with 1686 additions and 965 deletions
+38 -86
View File
@@ -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>&lt;body&gt;</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, '&lt;') + '</pre>' +
'<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">' +
'<a class="layui-btn layui-btn-normal" href="' + url.replace(/"/g, '&quot;') + '">下载代码</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, '&lt;') + '</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, '&lt;') + '</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, '&lt;') + '</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({