mirror of
https://github.com/skyle1995/NetworkAuth.git
synced 2026-05-25 02:24:05 +08:00
993 lines
50 KiB
HTML
993 lines
50 KiB
HTML
{{ define "apps.html" }}
|
||
<section>
|
||
<h2>应用管理</h2>
|
||
<div class="layui-btn-container" style="margin:12px 0">
|
||
<button class="layui-btn" id="btnAddApp"><i class="layui-icon layui-icon-add-1"></i> 新增应用</button>
|
||
<button class="layui-btn layui-btn-danger" id="btnBatchDeleteApps"><i class="layui-icon layui-icon-delete"></i> 批量删除</button>
|
||
<button class="layui-btn layui-btn-normal" id="btnBatchEnableApps"><i class="layui-icon layui-icon-ok-circle"></i> 批量启用</button>
|
||
<button class="layui-btn layui-btn-warm" id="btnBatchDisableApps"><i class="layui-icon layui-icon-close-fill"></i> 批量禁用</button>
|
||
</div>
|
||
|
||
<div class="layui-card" style="margin-top:12px">
|
||
<div class="layui-card-header">筛选</div>
|
||
<div class="layui-card-body">
|
||
<form class="layui-form layui-form-pane" id="appFilterForm" lay-filter="appFilterForm">
|
||
<div class="layui-form-item">
|
||
<div class="layui-inline">
|
||
<label class="layui-form-label">搜索</label>
|
||
<div class="layui-input-inline">
|
||
<input type="text" name="search" placeholder="应用名称/UUID" autocomplete="off" class="layui-input" />
|
||
</div>
|
||
</div>
|
||
<div class="layui-inline">
|
||
<button type="button" class="layui-btn" id="btnSearchApps">查询</button>
|
||
<button type="button" class="layui-btn layui-btn-primary" id="btnResetApps">重置</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="layui-card" style="margin-top:12px">
|
||
<div class="layui-card-header">应用列表</div>
|
||
<div class="layui-card-body">
|
||
<table id="appsTable" lay-filter="appsTableFilter"></table>
|
||
<script type="text/html" id="tpl-apps-ops">
|
||
<div style="white-space: nowrap;">
|
||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="more">
|
||
更多 <i class="layui-icon layui-icon-down"></i>
|
||
</a>
|
||
</div>
|
||
</script>
|
||
<script type="text/html" id="tpl-apps-status">
|
||
{{`{{# if(d.status === 1) { }}`}}
|
||
<span class="layui-badge layui-bg-green">启用</span>
|
||
{{`{{# } else { }}`}}
|
||
<span class="layui-badge">禁用</span>
|
||
{{`{{# } }}`}}
|
||
</script>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 隐藏的表单弹层内容:新增/编辑应用 -->
|
||
<div id="appFormModal" style="display:none;padding:16px">
|
||
<form class="layui-form layui-form-pane" id="appForm">
|
||
<input type="hidden" name="id" />
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label">应用名称</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="name" placeholder="请输入应用名称" autocomplete="off" class="layui-input" lay-verify="required" />
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<label class="layui-form-label">应用版本</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="version" placeholder="请输入应用版本,默认1.0.0" autocomplete="off" class="layui-input" />
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item" pane>
|
||
<label class="layui-form-label">应用状态</label>
|
||
<div class="layui-input-block">
|
||
<input type="checkbox" name="status" lay-skin="switch" lay-text="启用|禁用" checked>
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item" pane>
|
||
<label class="layui-form-label">强制更新</label>
|
||
<div class="layui-input-block">
|
||
<input type="checkbox" name="force_update" lay-skin="switch" lay-text="开启|关闭">
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item" pane>
|
||
<label class="layui-form-label">更新方式</label>
|
||
<div class="layui-input-block">
|
||
<input type="radio" name="download_type" value="0" title="不启用" checked lay-filter="downloadTypeChange">
|
||
<input type="radio" name="download_type" value="1" title="自动更新" lay-filter="downloadTypeChange">
|
||
<input type="radio" name="download_type" value="2" title="手动下载" lay-filter="downloadTypeChange">
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item" id="downloadUrlItem">
|
||
<label class="layui-form-label">下载地址</label>
|
||
<div class="layui-input-block">
|
||
<input type="text" name="download_url" placeholder="请输入下载地址" autocomplete="off" class="layui-input" />
|
||
</div>
|
||
</div>
|
||
<div class="layui-form-item">
|
||
<div class="layui-input-block">
|
||
<button type="submit" class="layui-btn" lay-submit lay-filter="appFormSubmit">提交</button>
|
||
<button type="button" class="layui-btn layui-btn-primary" id="btnCancelApp">取消</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<script>
|
||
layui.use(['table', 'form', 'layer', 'element', 'dropdown'], function() {
|
||
const table = layui.table;
|
||
const form = layui.form;
|
||
const layer = layui.layer;
|
||
const dropdown = layui.dropdown;
|
||
const $ = layui.$;
|
||
|
||
// 格式化时间函数
|
||
function formatDateTime(dateStr) {
|
||
if (!dateStr) return '-';
|
||
return new Date(dateStr).toLocaleString();
|
||
}
|
||
|
||
// 渲染表格
|
||
const appsTable = table.render({
|
||
elem: '#appsTable',
|
||
id: 'appsTable',
|
||
url: '/admin/api/apps/list',
|
||
parseData: function(res) {
|
||
// 后端返回的数据结构处理
|
||
return {
|
||
code: res.code,
|
||
msg: res.msg || '',
|
||
count: res.count || 0,
|
||
data: res.data || []
|
||
};
|
||
},
|
||
request: {
|
||
pageName: 'page', // 页码的参数名称,默认:page
|
||
limitName: 'page_size' // 每页数据量的参数名称,默认:limit
|
||
},
|
||
method: 'GET',
|
||
page: true,
|
||
limit: 20,
|
||
limits: [10, 20, 50, 100],
|
||
loading: true,
|
||
done: function(res, curr, count) {
|
||
// 表格渲染完成后的回调
|
||
},
|
||
cols: [[
|
||
{ type: 'checkbox', width: 50 },
|
||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||
{ field: 'name', title: '应用名称', minWidth: 180 },
|
||
{ field: 'uuid', title: 'UUID', minWidth: 320 },
|
||
{ field: 'version', title: '应用版本', width: 100 },
|
||
{
|
||
field: 'status',
|
||
title: '应用状态',
|
||
width: 100,
|
||
templet: (d) => {
|
||
if (d.status === 1) return '<span style="color: #5FB878;">启用</span>';
|
||
return '<span style="color: #FF5722;">禁用</span>';
|
||
}
|
||
},
|
||
{
|
||
field: 'secret',
|
||
title: '密钥',
|
||
minWidth: 320,
|
||
templet: (d) => '<span style="font-family: monospace;">' + d.secret + '</span>'
|
||
},
|
||
{
|
||
field: 'created_at',
|
||
title: '创建时间',
|
||
width: 180,
|
||
templet: (d) => formatDateTime(d.created_at)
|
||
},
|
||
{ fixed: 'right', title: '操作', toolbar: '#tpl-apps-ops', width: 180 }
|
||
]]
|
||
});
|
||
|
||
// 搜索功能
|
||
$('#btnSearchApps').on('click', function() {
|
||
const search = $('input[name="search"]').val();
|
||
appsTable.reload({
|
||
where: {
|
||
search: search
|
||
},
|
||
page: {
|
||
curr: 1
|
||
}
|
||
});
|
||
});
|
||
|
||
// 重置搜索
|
||
$('#btnResetApps').on('click', function() {
|
||
$('#appFilterForm')[0].reset();
|
||
appsTable.reload({
|
||
where: {},
|
||
page: {
|
||
curr: 1
|
||
}
|
||
});
|
||
});
|
||
|
||
// 新增应用
|
||
$('#btnAddApp').on('click', function() {
|
||
$('#appForm')[0].reset();
|
||
$('input[name="id"]').val('');
|
||
|
||
layer.open({
|
||
type: 1,
|
||
title: '新增应用',
|
||
content: $('#appFormModal'),
|
||
area: ['500px', '460px'],
|
||
btn: false,
|
||
shadeClose: false
|
||
});
|
||
form.render();
|
||
});
|
||
|
||
// 监听更新方式切换(保留事件监听器以备将来扩展)
|
||
form.on('radio(downloadTypeChange)', function(data) {
|
||
// 下载地址字段现在始终显示,无需切换显示状态
|
||
});
|
||
|
||
// 表单提交
|
||
form.on('submit(appFormSubmit)', function(data) {
|
||
const isEdit = data.field.id !== '';
|
||
const url = isEdit ? '/admin/api/apps/update' : '/admin/api/apps/create';
|
||
|
||
// 转换字段类型为正确的数据类型
|
||
const formData = {
|
||
...data.field,
|
||
status: data.field.status === 'on' ? 1 : 0, // switch开关处理
|
||
download_type: parseInt(data.field.download_type) || 0,
|
||
force_update: data.field.force_update === 'on' ? 1 : 0 // switch开关处理
|
||
};
|
||
|
||
// 如果是编辑模式,确保id也是整数
|
||
if (isEdit) {
|
||
formData.id = parseInt(data.field.id);
|
||
}
|
||
|
||
$.ajax({
|
||
url: url,
|
||
type: 'POST',
|
||
data: JSON.stringify(formData),
|
||
contentType: 'application/json',
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg(res.msg, {icon: 1});
|
||
layer.closeAll();
|
||
appsTable.reload();
|
||
} else {
|
||
layer.msg(res.msg || '操作失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function(xhr) {
|
||
layer.msg(xhr.responseText || '操作失败', {icon: 2});
|
||
}
|
||
});
|
||
return false;
|
||
});
|
||
|
||
// 取消按钮
|
||
$('#btnCancelApp').on('click', function() {
|
||
layer.closeAll();
|
||
});
|
||
|
||
// 表格工具栏事件
|
||
table.on('tool(appsTableFilter)', function(obj) {
|
||
const data = obj.data;
|
||
|
||
if (obj.event === 'edit') {
|
||
// 编辑
|
||
$('#appForm')[0].reset();
|
||
$('input[name="id"]').val(data.id);
|
||
$('input[name="name"]').val(data.name);
|
||
$('input[name="version"]').val(data.version);
|
||
// 设置应用状态开关
|
||
$('input[name="status"]').prop('checked', data.status === 1);
|
||
// 设置更新方式单选按钮
|
||
$('input[name="download_type"][value="' + (data.download_type || 0) + '"]').prop('checked', true);
|
||
$('input[name="download_url"]').val(data.download_url || '');
|
||
// 设置强制更新开关
|
||
$('input[name="force_update"]').prop('checked', data.force_update === 1);
|
||
|
||
layer.open({
|
||
type: 1,
|
||
title: '编辑应用',
|
||
content: $('#appFormModal'),
|
||
area: ['500px', '460px'],
|
||
btn: false,
|
||
shadeClose: false
|
||
});
|
||
form.render();
|
||
|
||
} else if (obj.event === 'del') {
|
||
// 删除
|
||
layer.confirm('确定删除该应用吗?', {icon: 3, title: '提示'}, function(index) {
|
||
$.ajax({
|
||
url: '/admin/api/apps/delete',
|
||
type: 'POST',
|
||
data: JSON.stringify({id: data.id}),
|
||
contentType: 'application/json',
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg(res.msg, {icon: 1});
|
||
appsTable.reload();
|
||
} else {
|
||
layer.msg(res.msg || '删除失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function(xhr) {
|
||
layer.msg(xhr.responseText || '删除失败', {icon: 2});
|
||
}
|
||
});
|
||
layer.close(index);
|
||
});
|
||
} else if (obj.event === 'more') {
|
||
// 更多操作下拉菜单
|
||
dropdown.render({
|
||
elem: this, // 使用 this 而不是查找元素
|
||
show: true, // 外部事件触发即显示
|
||
data: [
|
||
{
|
||
title: '程序公告',
|
||
id: 'announcement'
|
||
},
|
||
{
|
||
title: '多开配置',
|
||
id: 'multi_instance'
|
||
},
|
||
{
|
||
title: '绑定设置',
|
||
id: 'bind_settings'
|
||
},
|
||
{
|
||
title: '注册设置',
|
||
id: 'register_settings'
|
||
},
|
||
{
|
||
title: '重置密钥',
|
||
id: 'reset_secret'
|
||
}
|
||
],
|
||
click: function(menudata, othis) {
|
||
if (menudata.id === 'announcement') {
|
||
// 程序公告
|
||
// 先获取当前公告内容
|
||
$.ajax({
|
||
url: '/admin/api/apps/get_announcement?uuid=' + obj.data.uuid,
|
||
type: 'GET',
|
||
success: function(res) {
|
||
var currentAnnouncement = '';
|
||
if (res.code === 0 && res.data && res.data.announcement) {
|
||
currentAnnouncement = res.data.announcement;
|
||
}
|
||
|
||
// 显示编辑弹窗
|
||
layer.open({
|
||
type: 1,
|
||
title: '编辑程序公告 - ' + obj.data.name,
|
||
area: ['600px', '400px'],
|
||
content: '<div style="padding: 20px;">' +
|
||
'<textarea id="announcementEditor" class="layui-textarea" placeholder="请输入程序公告内容..." style="height: 250px;">' +
|
||
currentAnnouncement +
|
||
'</textarea>' +
|
||
'</div>',
|
||
btn: ['保存', '取消'],
|
||
yes: function(index, layero) {
|
||
var announcementContent = $('#announcementEditor').val();
|
||
|
||
// 发送更新请求
|
||
$.ajax({
|
||
url: '/admin/api/apps/update_announcement',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify({
|
||
uuid: obj.data.uuid,
|
||
announcement: announcementContent
|
||
}),
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg('程序公告更新成功!', {
|
||
icon: 1,
|
||
time: 2000
|
||
});
|
||
layer.close(index);
|
||
} else {
|
||
layer.msg(res.msg || '更新程序公告失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function() {
|
||
layer.msg('网络错误,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
},
|
||
btn2: function(index) {
|
||
layer.close(index);
|
||
}
|
||
});
|
||
},
|
||
error: function() {
|
||
layer.msg('获取程序公告失败,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
} else if (menudata.id === 'multi_instance') {
|
||
// 多开配置
|
||
$.ajax({
|
||
url: '/admin/api/apps/get_multi_config?uuid=' + obj.data.uuid,
|
||
type: 'GET',
|
||
success: function(config) {
|
||
layer.open({
|
||
type: 1,
|
||
title: '多开配置 - ' + obj.data.name,
|
||
area: ['550px', '450px'],
|
||
content: '<div style="padding: 20px;">' +
|
||
'<form class="layui-form layui-form-pane" lay-filter="multiConfigForm">' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">登录方式</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="login_type" value="0" title="顶号登录" ' + (config.login_type === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="login_type" value="1" title="非顶号登录" ' + (config.login_type === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">多开范围</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="multi_open_scope" value="0" title="单电脑" ' + (config.multi_open_scope === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="multi_open_scope" value="1" title="单IP" ' + (config.multi_open_scope === 1 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="multi_open_scope" value="2" title="全部电脑" ' + (config.multi_open_scope === 2 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<div class="layui-inline">' +
|
||
'<label class="layui-form-label">清理间隔</label>' +
|
||
'<div class="layui-input-inline">' +
|
||
'<input type="number" name="clean_interval" class="layui-input" value="' + config.clean_interval + '" placeholder="请输入" lay-verify="required|number" min="1">' +
|
||
'</div>' +
|
||
'<div class="layui-form-mid layui-text-em">小时</div>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<div class="layui-inline">' +
|
||
'<label class="layui-form-label">校验间隔</label>' +
|
||
'<div class="layui-input-inline">' +
|
||
'<input type="number" name="check_interval" class="layui-input" value="' + config.check_interval + '" placeholder="请输入" lay-verify="required|number" min="1">' +
|
||
'</div>' +
|
||
'<div class="layui-form-mid layui-text-em">分钟</div>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">多开数量</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="multi_open_count" class="layui-input" value="' + config.multi_open_count + '" placeholder="请输入允许的多开数量" lay-verify="required|number" min="1">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'</form>' +
|
||
'</div>',
|
||
btn: ['保存', '取消'],
|
||
yes: function(index, layero) {
|
||
var formData = {
|
||
uuid: obj.data.uuid,
|
||
login_type: parseInt($('input[name="login_type"]:checked').val()),
|
||
multi_open_scope: parseInt($('input[name="multi_open_scope"]:checked').val()),
|
||
clean_interval: parseInt($('input[name="clean_interval"]').val()),
|
||
check_interval: parseInt($('input[name="check_interval"]').val()),
|
||
multi_open_count: parseInt($('input[name="multi_open_count"]').val())
|
||
};
|
||
|
||
// 验证数据
|
||
if (isNaN(formData.login_type) || formData.login_type < 0 || formData.login_type > 1) {
|
||
layer.msg('请选择登录方式', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.multi_open_scope) || formData.multi_open_scope < 0 || formData.multi_open_scope > 2) {
|
||
layer.msg('请选择多开范围', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.clean_interval) || formData.clean_interval < 1) {
|
||
layer.msg('清理间隔必须大于0', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.check_interval) || formData.check_interval < 1) {
|
||
layer.msg('校验间隔必须大于0', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.multi_open_count) || formData.multi_open_count < 1) {
|
||
layer.msg('多开数量必须大于0', {icon: 2});
|
||
return;
|
||
}
|
||
|
||
// 发送更新请求
|
||
$.ajax({
|
||
url: '/admin/api/apps/update_multi_config',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(formData),
|
||
success: function(res) {
|
||
if (res.message) {
|
||
layer.msg('多开配置更新成功', {icon: 1});
|
||
layer.close(index);
|
||
table.reload('appsTable');
|
||
} else {
|
||
layer.msg(res.msg || '更新多开配置失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function() {
|
||
layer.msg('网络错误,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
},
|
||
btn2: function(index) {
|
||
layer.close(index);
|
||
},
|
||
success: function() {
|
||
// 重新渲染表单
|
||
form.render();
|
||
}
|
||
});
|
||
},
|
||
error: function() {
|
||
layer.msg('获取多开配置失败,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
} else if (menudata.id === 'reset_secret') {
|
||
// 重置密钥
|
||
layer.confirm('确定重置该应用的密钥吗?重置后原密钥将失效!', {icon: 3, title: '提示'}, function(index) {
|
||
// 发送重置密钥请求
|
||
$.ajax({
|
||
url: '/admin/api/apps/reset_secret',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify({
|
||
uuid: obj.data.uuid
|
||
}),
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg('密钥重置成功!', {
|
||
icon: 1,
|
||
time: 2000 // 显示2秒
|
||
});
|
||
// 刷新表格数据
|
||
table.reload('appsTable');
|
||
} else {
|
||
layer.msg(res.msg || '重置密钥失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function(xhr) {
|
||
let errorMsg = '重置密钥失败';
|
||
if (xhr.responseText) {
|
||
try {
|
||
const errorRes = JSON.parse(xhr.responseText);
|
||
errorMsg = errorRes.msg || errorMsg;
|
||
} catch (e) {
|
||
errorMsg = xhr.responseText;
|
||
}
|
||
}
|
||
layer.msg(errorMsg, {icon: 2});
|
||
}
|
||
});
|
||
layer.close(index);
|
||
});
|
||
} else if (menudata.id === 'bind_settings') {
|
||
// 绑定设置
|
||
$.ajax({
|
||
url: '/admin/api/apps/get_bind_config?uuid=' + obj.data.uuid,
|
||
type: 'GET',
|
||
success: function(config) {
|
||
layer.open({
|
||
type: 1,
|
||
title: '绑定设置 - ' + obj.data.name,
|
||
area: ['650px', '600px'],
|
||
content: '<div style="padding: 20px;">' +
|
||
'<form class="layui-form layui-form-pane" lay-filter="bindConfigForm">' +
|
||
|
||
// 机器码验证设置
|
||
'<fieldset class="layui-elem-field layui-field-title">' +
|
||
'<legend>机器码验证设置</legend>' +
|
||
'</fieldset>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">机器码验证</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="machine_code_verify" value="0" title="关闭" ' + (config.machine_code_verify === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="machine_code_verify" value="1" title="开启" ' + (config.machine_code_verify === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">机器码重绑</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="machine_code_rebind_enabled" value="0" title="关闭" ' + (config.machine_code_rebind_enabled === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="machine_code_rebind_enabled" value="1" title="开启" ' + (config.machine_code_rebind_enabled === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">机器码选项</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="machine_code_option" value="0" title="每天" ' + (config.machine_code_option === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="machine_code_option" value="1" title="永久" ' + (config.machine_code_option === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">免费次数</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="machine_code_free_count" class="layui-input" value="' + config.machine_code_free_count + '" placeholder="请输入" lay-verify="number" min="0">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">重绑次数</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="machine_code_rebind_count" class="layui-input" value="' + config.machine_code_rebind_count + '" placeholder="请输入" lay-verify="number" min="0">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">重绑扣除</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="machine_code_rebind_deduct" class="layui-input" value="' + config.machine_code_rebind_deduct + '" placeholder="请输入重绑扣除时间(分钟)" lay-verify="number" min="0">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
|
||
// IP地址验证设置
|
||
'<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">' +
|
||
'<legend>IP地址验证设置</legend>' +
|
||
'</fieldset>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">IP地址验证</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="ip_verify" value="0" title="关闭" ' + (config.ip_verify === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="ip_verify" value="1" title="开启" ' + (config.ip_verify === 1 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="ip_verify" value="2" title="开启(市)" ' + (config.ip_verify === 2 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="ip_verify" value="3" title="开启(省)" ' + (config.ip_verify === 3 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">IP地址重绑</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="ip_rebind_enabled" value="0" title="关闭" ' + (config.ip_rebind_enabled === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="ip_rebind_enabled" value="1" title="开启" ' + (config.ip_rebind_enabled === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">IP地址选项</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="ip_option" value="0" title="每天" ' + (config.ip_option === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="ip_option" value="1" title="永久" ' + (config.ip_option === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">免费次数</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="ip_free_count" class="layui-input" value="' + config.ip_free_count + '" placeholder="请输入" lay-verify="number" min="0">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">重绑次数</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="ip_rebind_count" class="layui-input" value="' + config.ip_rebind_count + '" placeholder="请输入" lay-verify="number" min="0">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">重绑扣除</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="ip_rebind_deduct" class="layui-input" value="' + config.ip_rebind_deduct + '" placeholder="请输入重绑扣除时间(分钟)" lay-verify="number" min="0">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
|
||
'</form>' +
|
||
'</div>',
|
||
btn: ['保存', '取消'],
|
||
yes: function(index, layero) {
|
||
var formData = {
|
||
uuid: obj.data.uuid,
|
||
machine_code_verify: parseInt($('input[name="machine_code_verify"]:checked').val()),
|
||
machine_code_rebind_enabled: parseInt($('input[name="machine_code_rebind_enabled"]:checked').val()),
|
||
machine_code_option: parseInt($('input[name="machine_code_option"]:checked').val()),
|
||
machine_code_free_count: parseInt($('input[name="machine_code_free_count"]').val()) || 0,
|
||
machine_code_rebind_count: parseInt($('input[name="machine_code_rebind_count"]').val()) || 0,
|
||
machine_code_rebind_deduct: parseInt($('input[name="machine_code_rebind_deduct"]').val()) || 0,
|
||
ip_verify: parseInt($('input[name="ip_verify"]:checked').val()),
|
||
ip_rebind_enabled: parseInt($('input[name="ip_rebind_enabled"]:checked').val()),
|
||
ip_option: parseInt($('input[name="ip_option"]:checked').val()),
|
||
ip_free_count: parseInt($('input[name="ip_free_count"]').val()) || 0,
|
||
ip_rebind_count: parseInt($('input[name="ip_rebind_count"]').val()) || 0,
|
||
ip_rebind_deduct: parseInt($('input[name="ip_rebind_deduct"]').val()) || 0
|
||
};
|
||
|
||
// 验证数据
|
||
if (isNaN(formData.machine_code_verify) || formData.machine_code_verify < 0 || formData.machine_code_verify > 1) {
|
||
layer.msg('请选择机器码验证选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.machine_code_rebind_enabled) || formData.machine_code_rebind_enabled < 0 || formData.machine_code_rebind_enabled > 1) {
|
||
layer.msg('请选择机器码重绑选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.machine_code_option) || formData.machine_code_option < 0 || formData.machine_code_option > 1) {
|
||
layer.msg('请选择机器码选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.ip_verify) || formData.ip_verify < 0 || formData.ip_verify > 3) {
|
||
layer.msg('请选择IP地址验证选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.ip_rebind_enabled) || formData.ip_rebind_enabled < 0 || formData.ip_rebind_enabled > 1) {
|
||
layer.msg('请选择IP地址重绑选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.ip_option) || formData.ip_option < 0 || formData.ip_option > 1) {
|
||
layer.msg('请选择IP地址选项', {icon: 2});
|
||
return;
|
||
}
|
||
|
||
// 发送更新请求
|
||
$.ajax({
|
||
url: '/admin/api/apps/update_bind_config',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(formData),
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg('绑定设置更新成功', {icon: 1});
|
||
layer.close(index);
|
||
table.reload('appsTable');
|
||
} else {
|
||
layer.msg(res.msg || '更新绑定设置失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function() {
|
||
layer.msg('网络错误,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
},
|
||
btn2: function(index) {
|
||
layer.close(index);
|
||
},
|
||
success: function() {
|
||
// 重新渲染表单
|
||
form.render();
|
||
}
|
||
});
|
||
},
|
||
error: function() {
|
||
layer.msg('获取绑定设置失败,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
} else if (menudata.id === 'register_settings') {
|
||
// 注册设置
|
||
$.ajax({
|
||
url: '/admin/api/apps/get_register_config?uuid=' + obj.data.uuid,
|
||
type: 'GET',
|
||
success: function(config) {
|
||
layer.open({
|
||
type: 1,
|
||
title: '注册设置 - ' + obj.data.name,
|
||
area: ['550px', '500px'],
|
||
content: '<div style="padding: 20px;">' +
|
||
'<form class="layui-form layui-form-pane" lay-filter="registerConfigForm">' +
|
||
|
||
// 账号注册设置
|
||
'<fieldset class="layui-elem-field layui-field-title">' +
|
||
'<legend>账号注册设置</legend>' +
|
||
'</fieldset>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">账号注册</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="register_enabled" value="0" title="关闭" ' + (config.register_enabled === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="register_enabled" value="1" title="开启" ' + (config.register_enabled === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">注册限制</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="register_limit_enabled" value="0" title="关闭" ' + (config.register_limit_enabled === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="register_limit_enabled" value="1" title="开启" ' + (config.register_limit_enabled === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">限制时间</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="register_limit_time" value="0" title="每天" ' + (config.register_limit_time === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="register_limit_time" value="1" title="永久" ' + (config.register_limit_time === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">注册次数</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="register_count" class="layui-input" value="' + config.register_count + '" placeholder="请输入" lay-verify="required|number" min="1">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
|
||
// 领取试用设置
|
||
'<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">' +
|
||
'<legend>领取试用设置</legend>' +
|
||
'</fieldset>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">领取试用</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="trial_enabled" value="0" title="关闭" ' + (config.trial_enabled === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="trial_enabled" value="1" title="开启" ' + (config.trial_enabled === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item" pane>' +
|
||
'<label class="layui-form-label">限制时间</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="radio" name="trial_limit_time" value="0" title="每天" ' + (config.trial_limit_time === 0 ? 'checked' : '') + '>' +
|
||
'<input type="radio" name="trial_limit_time" value="1" title="永久" ' + (config.trial_limit_time === 1 ? 'checked' : '') + '>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="layui-form-item">' +
|
||
'<label class="layui-form-label">试用时间</label>' +
|
||
'<div class="layui-input-block">' +
|
||
'<input type="number" name="trial_duration" class="layui-input" value="' + config.trial_duration + '" placeholder="请输入试用时间(分钟)" lay-verify="number" min="0">' +
|
||
'</div>' +
|
||
'</div>' +
|
||
|
||
'</form>' +
|
||
'</div>',
|
||
btn: ['保存', '取消'],
|
||
yes: function(index, layero) {
|
||
var formData = {
|
||
uuid: obj.data.uuid,
|
||
register_enabled: parseInt($('input[name="register_enabled"]:checked').val()),
|
||
register_limit_enabled: parseInt($('input[name="register_limit_enabled"]:checked').val()),
|
||
register_limit_time: parseInt($('input[name="register_limit_time"]:checked').val()),
|
||
register_count: parseInt($('input[name="register_count"]').val()) || 1,
|
||
trial_enabled: parseInt($('input[name="trial_enabled"]:checked').val()),
|
||
trial_limit_time: parseInt($('input[name="trial_limit_time"]:checked').val()),
|
||
trial_duration: parseInt($('input[name="trial_duration"]').val()) || 0
|
||
};
|
||
|
||
// 验证数据
|
||
if (isNaN(formData.register_enabled) || formData.register_enabled < 0 || formData.register_enabled > 1) {
|
||
layer.msg('请选择账号注册选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.register_limit_enabled) || formData.register_limit_enabled < 0 || formData.register_limit_enabled > 1) {
|
||
layer.msg('请选择注册限制选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.register_limit_time) || formData.register_limit_time < 0 || formData.register_limit_time > 1) {
|
||
layer.msg('请选择限制时间选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.register_count) || formData.register_count < 1) {
|
||
layer.msg('注册次数必须大于0', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.trial_enabled) || formData.trial_enabled < 0 || formData.trial_enabled > 1) {
|
||
layer.msg('请选择领取试用选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.trial_limit_time) || formData.trial_limit_time < 0 || formData.trial_limit_time > 1) {
|
||
layer.msg('请选择试用限制时间选项', {icon: 2});
|
||
return;
|
||
}
|
||
if (isNaN(formData.trial_duration) || formData.trial_duration < 0) {
|
||
layer.msg('试用时间不能小于0', {icon: 2});
|
||
return;
|
||
}
|
||
|
||
// 发送更新请求
|
||
$.ajax({
|
||
url: '/admin/api/apps/update_register_config',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(formData),
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg('注册设置更新成功', {icon: 1});
|
||
layer.close(index);
|
||
table.reload('appsTable');
|
||
} else {
|
||
layer.msg(res.msg || '更新注册设置失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function() {
|
||
layer.msg('网络错误,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
},
|
||
btn2: function(index) {
|
||
layer.close(index);
|
||
},
|
||
success: function() {
|
||
// 重新渲染表单
|
||
form.render();
|
||
}
|
||
});
|
||
},
|
||
error: function() {
|
||
layer.msg('获取注册设置失败,请稍后重试', {icon: 2});
|
||
}
|
||
});
|
||
}
|
||
},
|
||
align: 'right', // 右对齐弹出
|
||
style: 'box-shadow: 1px 1px 10px rgb(0 0 0 / 12%);' // 设置额外样式
|
||
});
|
||
}
|
||
});
|
||
|
||
// 批量删除
|
||
$('#btnBatchDeleteApps').on('click', function() {
|
||
const checkStatus = table.checkStatus('appsTable');
|
||
const data = checkStatus.data;
|
||
|
||
if (data.length === 0) {
|
||
layer.msg('请选择要删除的应用', {icon: 2});
|
||
return;
|
||
}
|
||
|
||
layer.confirm('确定删除选中的 ' + data.length + ' 个应用吗?', {icon: 3, title: '提示'}, function(index) {
|
||
const ids = data.map(item => item.id);
|
||
$.ajax({
|
||
url: '/admin/api/apps/batch_delete',
|
||
type: 'POST',
|
||
data: JSON.stringify({ids: ids}),
|
||
contentType: 'application/json',
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg(res.msg, {icon: 1});
|
||
appsTable.reload();
|
||
} else {
|
||
layer.msg(res.msg || '批量删除失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function(xhr) {
|
||
layer.msg(xhr.responseText || '批量删除失败', {icon: 2});
|
||
}
|
||
});
|
||
layer.close(index);
|
||
});
|
||
});
|
||
|
||
// 批量启用
|
||
$('#btnBatchEnableApps').on('click', function() {
|
||
const checkStatus = table.checkStatus('appsTable');
|
||
const data = checkStatus.data;
|
||
|
||
if (data.length === 0) {
|
||
layer.msg('请选择要启用的应用', {icon: 2});
|
||
return;
|
||
}
|
||
|
||
const ids = data.map(item => item.id);
|
||
$.ajax({
|
||
url: '/admin/api/apps/batch_update_status',
|
||
type: 'POST',
|
||
data: JSON.stringify({ids: ids, status: 1}),
|
||
contentType: 'application/json',
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg(res.msg, {icon: 1});
|
||
appsTable.reload();
|
||
} else {
|
||
layer.msg(res.msg || '批量启用失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function(xhr) {
|
||
layer.msg(xhr.responseText || '批量启用失败', {icon: 2});
|
||
}
|
||
});
|
||
});
|
||
|
||
// 批量禁用
|
||
$('#btnBatchDisableApps').on('click', function() {
|
||
const checkStatus = table.checkStatus('appsTable');
|
||
const data = checkStatus.data;
|
||
|
||
if (data.length === 0) {
|
||
layer.msg('请选择要禁用的应用', {icon: 2});
|
||
return;
|
||
}
|
||
|
||
const ids = data.map(item => item.id);
|
||
$.ajax({
|
||
url: '/admin/api/apps/batch_update_status',
|
||
type: 'POST',
|
||
data: JSON.stringify({ids: ids, status: 0}),
|
||
contentType: 'application/json',
|
||
success: function(res) {
|
||
if (res.code === 0) {
|
||
layer.msg(res.msg, {icon: 1});
|
||
appsTable.reload();
|
||
} else {
|
||
layer.msg(res.msg || '批量禁用失败', {icon: 2});
|
||
}
|
||
},
|
||
error: function(xhr) {
|
||
layer.msg(xhr.responseText || '批量禁用失败', {icon: 2});
|
||
}
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
</section>
|
||
{{ end }} |