添加项目文件。
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<div style="text-align:center;padding:40px;color:#999;">此页面已废弃,奖池配置已整合到列表页</div>
|
||||
@@ -0,0 +1,708 @@
|
||||
<title>奖池抽奖活动</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>活动</cite></a>
|
||||
<a><cite>奖池抽奖活动</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<!-- 活动配置 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">活动配置</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="lottery-form">
|
||||
<input type="hidden" name="activityId" id="activityId">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">活动名称</label>
|
||||
<div class="layui-input-inline" style="width:400px;">
|
||||
<input type="text" name="activityName" lay-verify="required" placeholder="请输入活动名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="isOpen">
|
||||
<option value="false">关闭</option>
|
||||
<option value="true">开启</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">开始时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="startTime" id="startTime" placeholder="yyyy-MM-dd HH:mm:ss" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">留空=立即开始</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">结束时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="endTime" id="endTime" placeholder="yyyy-MM-dd HH:mm:ss" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">留空=不限制</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">炮台价格</label>
|
||||
<div class="layui-input-inline" style="width:400px;"><input type="text" name="costsCannon" class="layui-input" placeholder="炮台奖池每次抽取消耗(必填)"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">战神价格</label>
|
||||
<div class="layui-input-inline" style="width:400px;"><input type="text" name="costsGodWar" class="layui-input" placeholder="战神奖池每次抽取消耗(必填)"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">翅膀价格</label>
|
||||
<div class="layui-input-inline" style="width:400px;"><input type="text" name="costsWing" class="layui-input" placeholder="翅膀奖池每次抽取消耗(必填)"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">每人上限</label>
|
||||
<div class="layui-input-inline" style="width:120px;">
|
||||
<input type="number" name="userMaxDraw" value="100" placeholder="次数" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">单用户最大抽奖次数(0=不限制)</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 奖池等级 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">奖池等级</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="lottery-pool-type">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this" lay-id="1">炮台奖池</li>
|
||||
<li lay-id="2">战神奖池</li>
|
||||
<li lay-id="3">翅膀奖池</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="layui-btn-container" style="margin-bottom:10px;">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add-pool"><i class="layui-icon layui-icon-add-1"></i> 添加等级</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" id="btn-init-lottery"><i class="layui-icon layui-icon-refresh"></i> 初始化整个配置数据</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" id="btn-save"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" id="btn-reload"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
</div>
|
||||
<table id="table-pool" lay-filter="table-pool"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 奖池等级操作栏 -->
|
||||
<script type="text/html" id="bar-pool">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="prize">奖项</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
|
||||
<!-- 奖项管理对话框模板 -->
|
||||
<script type="text/html" id="prize-dialog-tpl">
|
||||
<div class="prize-container">
|
||||
<div class="prize-left">
|
||||
<div class="prize-toolbar">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add-prize"><i class="layui-icon layui-icon-add-1"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete-prize"><i class="layui-icon layui-icon-delete"></i> 删除</button>
|
||||
</div>
|
||||
<div class="prize-table-wrap">
|
||||
<table id="table-prize-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prize-right">
|
||||
<h4>奖项详情</h4>
|
||||
<div class="layui-form" lay-filter="prize-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">奖项ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="prizeId" id="prizeId" class="layui-input" placeholder="唯一标识">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">奖项名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="prizeName" id="prizeName" class="layui-input" placeholder="如:1000金币">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图标</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="prizeIcon" id="prizeIcon" class="layui-input" placeholder="图标URL">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="prizeType" id="prizeType" lay-filter="prizeType">
|
||||
<option value="1">金币</option>
|
||||
<option value="2">钻石</option>
|
||||
<option value="3">道具</option>
|
||||
<option value="4">道具碎片</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="prizeCount" id="prizeCount" class="layui-input" placeholder="奖励数量">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item prize-prop-select" style="display:none;">
|
||||
<label class="layui-form-label">道具编号</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="prizeOtherId" id="prizeOtherId" lay-filter="prizeOtherId">
|
||||
<option value="">请选择道具/碎片</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">权重</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="prizeWeight" id="prizeWeight" class="layui-input" placeholder="抽中权重,越大越易中">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">总库存</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="prizeTotalCount" id="prizeTotalCount" class="layui-input" placeholder="0=无限">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-top:20px;">
|
||||
<button class="layui-btn layui-btn-normal" id="btn-save-prize" style="width:100%;">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer', 'laydate', 'util', 'element'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
laydate = layui.laydate,
|
||||
util = layui.util,
|
||||
element = layui.element,
|
||||
setter = layui.setter;
|
||||
|
||||
// ============ 数据 ============
|
||||
var activityData = null; // 完整活动数据(camelCase keys,来自服务端)
|
||||
var poolsData = []; // 奖池等级列表(本地编辑,camelCase keys)
|
||||
var currentPoolIndex = -1; // 当前编辑的奖池等级索引
|
||||
var currentPrizeIndex = -1; // 当前编辑的奖项索引
|
||||
var currentPoolType = 1; // 1=炮台,2=战神,3=翅膀
|
||||
var propList = []; // 道具列表
|
||||
var propFragmentList = []; // 碎片单独存于 PropFragments,不在 PropConfig 中
|
||||
function propIcon(number) {
|
||||
var key = String(number || '').trim();
|
||||
var prop = propList.find(function(p) { return String(p.number) === key; });
|
||||
if (prop) return prop.imageUrl || prop.icon || '';
|
||||
var fragment = propFragmentList.find(function(p) { return String(p.number) === key; });
|
||||
if (!fragment) return '';
|
||||
var parent = propList.find(function(p) { return String(p.number) === String(fragment.productNumber); });
|
||||
return fragment.imageUrl || (parent && parent.imageUrl) || '';
|
||||
}
|
||||
|
||||
function prizeIcon(prize) {
|
||||
// 道具和碎片使用最新配置图片,兼容历史奖项保存的失效 icon。
|
||||
var type = parseInt(prize.type, 10);
|
||||
return ((type === 3 || type === 4) ? propIcon(prize.otherId) : '') || prize.icon || (prize.product && prize.product.imageUrl) || '';
|
||||
}
|
||||
|
||||
function newClientId() {
|
||||
return 'pool_' + Date.now() + '_' + Math.random().toString(16).slice(2);
|
||||
}
|
||||
|
||||
function findPoolIndex(row) {
|
||||
if (!row) return -1;
|
||||
return poolsData.findIndex(function(p) { return p._clientId === row._clientId; });
|
||||
}
|
||||
|
||||
// 初始化:防止loading残影
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
// ============ 数据加载 ============
|
||||
function loadActivity() {
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/Lottery/list',
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
if (res.data && res.data.length > 0) {
|
||||
activityData = res.data[0];
|
||||
} else {
|
||||
activityData = {
|
||||
activityId: '',
|
||||
activityName: '',
|
||||
isOpen: false,
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
costsByPool: {},
|
||||
userMaxDraw: 100,
|
||||
pools: []
|
||||
};
|
||||
}
|
||||
poolsData = (activityData.pools || []).map(function(p) {
|
||||
var item = $.extend({}, p);
|
||||
item.poolType = parseInt(item.poolType) || 1;
|
||||
item._clientId = newClientId();
|
||||
return item;
|
||||
});
|
||||
fillForm();
|
||||
renderPoolTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadProps() {
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/GameConfig',
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
propList = res.data.propConfig || [];
|
||||
propFragmentList = res.data.propFragments || [];
|
||||
renderPoolTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============ 表单回填 ============
|
||||
function fillForm() {
|
||||
if (!activityData) return;
|
||||
// 先用 jQuery 清空再赋值,避免 layui form.val 累积
|
||||
var costsByPool = activityData.costsByPool || {};
|
||||
$('input[name="costsCannon"]').val((costsByPool['1'] || []).join(','));
|
||||
$('input[name="costsGodWar"]').val((costsByPool['2'] || []).join(','));
|
||||
$('input[name="costsWing"]').val((costsByPool['3'] || []).join(','));
|
||||
$('input[name="activityName"]').val(activityData.activityName || '');
|
||||
$('input[name="userMaxDraw"]').val(activityData.userMaxDraw || 100);
|
||||
$('select[name="isOpen"]').val(activityData.isOpen ? 'true' : 'false');
|
||||
$('#activityId').val(activityData.activityId || '');
|
||||
|
||||
if (activityData.startTime) {
|
||||
var sd = new Date(activityData.startTime * 1000);
|
||||
$('#startTime').val(util.toDateString(sd, 'yyyy-MM-dd HH:mm:ss'));
|
||||
}
|
||||
if (activityData.endTime) {
|
||||
var ed = new Date(activityData.endTime * 1000);
|
||||
$('#endTime').val(util.toDateString(ed, 'yyyy-MM-dd HH:mm:ss'));
|
||||
}
|
||||
form.render();
|
||||
}
|
||||
|
||||
// ============ 日期选择器 ============
|
||||
laydate.render({ elem: '#startTime', type: 'datetime' });
|
||||
laydate.render({ elem: '#endTime', type: 'datetime' });
|
||||
|
||||
// ============ 奖池等级表格 ============
|
||||
function renderPoolTable() {
|
||||
table.render({
|
||||
elem: '#table-pool',
|
||||
data: poolsData.filter(function(p) { return (parseInt(p.poolType) || 1) === currentPoolType; }),
|
||||
page: false,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'level', title: '等级', width: 100 },
|
||||
{ field: 'count', title: '数量', width: 80 },
|
||||
{ field: 'weight', title: '权重', width: 80 },
|
||||
{ title: '奖项数', width: 80, templet: function(d) {
|
||||
return (d.prizeList && d.prizeList.length) ? d.prizeList.length + '项' : '无';
|
||||
}},
|
||||
{ title: '操作', width: 200, fixed: 'right', toolbar: '#bar-pool' }
|
||||
]]
|
||||
});
|
||||
}
|
||||
|
||||
// ============ 奖池等级事件 ============
|
||||
table.on('tool(table-pool)', function(obj) {
|
||||
var idx = findPoolIndex(obj.data);
|
||||
if (idx < 0) {
|
||||
layer.msg('未找到当前奖池,请刷新页面后重试');
|
||||
return;
|
||||
}
|
||||
var data = poolsData[idx];
|
||||
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除等级「' + (data.level || '') + '」吗?', function(ix) {
|
||||
poolsData.splice(idx, 1);
|
||||
renderPoolTable();
|
||||
layer.close(ix);
|
||||
});
|
||||
} else if (obj.event === 'edit') {
|
||||
showPoolEdit(data, false);
|
||||
} else if (obj.event === 'prize') {
|
||||
currentPoolIndex = idx;
|
||||
showPrizeDialog(data);
|
||||
}
|
||||
});
|
||||
|
||||
// 添加等级
|
||||
$('#btn-add-pool').on('click', function() {
|
||||
var newItem = { _clientId: newClientId(), poolType: currentPoolType, level: '', count: 0, weight: 10, prizeList: [] };
|
||||
showPoolEdit(newItem, true);
|
||||
});
|
||||
|
||||
// 保存配置
|
||||
$('#btn-save').on('click', function() {
|
||||
saveActivity();
|
||||
});
|
||||
|
||||
$('#btn-init-lottery').on('click', function() {
|
||||
layer.confirm('将用当前线上奖池制作的模板覆盖整个奖池活动配置(3组奖池、等级、奖项、权重和价格)。活动会保持关闭,玩家抽奖历史不清除。确定继续吗?', function(index) {
|
||||
layer.close(index);
|
||||
admin.req({
|
||||
method: 'post',
|
||||
url: setter.baseurl + 'adminapi/Lottery/initialize',
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('初始化成功,活动保持关闭');
|
||||
loadActivity();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 刷新
|
||||
$('#btn-reload').on('click', function() {
|
||||
loadActivity();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
element.on('tab(lottery-pool-type)', function() {
|
||||
currentPoolType = parseInt($(this).attr('lay-id')) || 1;
|
||||
currentPoolIndex = -1;
|
||||
currentPrizeIndex = -1;
|
||||
renderPoolTable();
|
||||
});
|
||||
|
||||
// ============ 奖池等级编辑弹窗 ============
|
||||
function showPoolEdit(data, isAdd) {
|
||||
var title = isAdd ? '添加等级' : '编辑等级';
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="level" value="' + (data.level || '') + '" placeholder="如: A, B, C" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="count" value="' + (data.count || 0) + '" placeholder="奖项总数量" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">权重</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="weight" value="' + (data.weight || 10) + '" placeholder="等级权重,越大越易中" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['450px', '300px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
success: function(layero) { form.render(); },
|
||||
yes: function(idx, layero) {
|
||||
var level = layero.find('input[name="level"]').val();
|
||||
var count = parseInt(layero.find('input[name="count"]').val()) || 0;
|
||||
var weight = parseInt(layero.find('input[name="weight"]').val()) || 10;
|
||||
|
||||
if (!level) { layer.msg('等级不能为空'); return; }
|
||||
|
||||
if (isAdd) {
|
||||
poolsData.push({ _clientId: data._clientId || newClientId(), poolType: currentPoolType, level: level, count: count, weight: weight, prizeList: [] });
|
||||
} else {
|
||||
data.level = level;
|
||||
data.count = count;
|
||||
data.weight = weight;
|
||||
}
|
||||
layer.close(idx);
|
||||
renderPoolTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============ 奖项管理弹窗 ============
|
||||
function showPrizeDialog(poolData) {
|
||||
if (!poolData.prizeList) poolData.prizeList = [];
|
||||
currentPrizeIndex = -1;
|
||||
|
||||
var dialogContent = $('#prize-dialog-tpl').html();
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '等级「' + (poolData.level || '') + '」- 奖项管理',
|
||||
area: ['1000px', '620px'],
|
||||
content: dialogContent,
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
// 必须先渲染 form,否则 select 不显示
|
||||
form.render(null, 'prize-form');
|
||||
|
||||
renderPrizeTable(layero, poolData);
|
||||
|
||||
// 绑定按钮事件
|
||||
layero.find('#btn-add-prize').on('click', function() {
|
||||
poolData.prizeList.push({
|
||||
prizeId: '', name: '', icon: '', type: 1, count: 0,
|
||||
otherId: '', weight: 10, totalCount: 0, drawnCount: 0
|
||||
});
|
||||
currentPrizeIndex = poolData.prizeList.length - 1;
|
||||
renderPrizeTable(layero, poolData, currentPrizeIndex);
|
||||
loadPrizeForm(poolData.prizeList[currentPrizeIndex], layero);
|
||||
});
|
||||
|
||||
layero.find('#btn-delete-prize').on('click', function() {
|
||||
if (currentPrizeIndex < 0) return layer.msg('请先选择要删除的奖项');
|
||||
poolData.prizeList.splice(currentPrizeIndex, 1);
|
||||
currentPrizeIndex = -1;
|
||||
clearPrizeForm(layero);
|
||||
renderPrizeTable(layero, poolData, -1);
|
||||
});
|
||||
|
||||
layero.find('#btn-save-prize').on('click', function() {
|
||||
savePrizeItem(layero, poolData);
|
||||
});
|
||||
|
||||
// 类型切换(filter 名必须与 HTML lay-filter 一致)
|
||||
form.on('select(prizeType)', function(obj) {
|
||||
if (obj.value === '3' || obj.value === '4') {
|
||||
layero.find('.prize-prop-select').show();
|
||||
renderPrizeProductOptions(layero, parseInt(obj.value, 10), '');
|
||||
} else {
|
||||
layero.find('.prize-prop-select').hide();
|
||||
}
|
||||
});
|
||||
form.on('select(prizeOtherId)', function(obj) {
|
||||
var type = parseInt(layero.find('#prizeType').val(), 10);
|
||||
var source = type === 4 ? propFragmentList : propList;
|
||||
var product = source.find(function(item) { return String(item.number) === String(obj.value); });
|
||||
if (!product) return;
|
||||
layero.find('#prizeName').val(product.name || '');
|
||||
layero.find('#prizeIcon').val(propIcon(product.number));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderPrizeTable(layero, poolData, selectIndex) {
|
||||
var list = poolData.prizeList || [];
|
||||
|
||||
table.render({
|
||||
elem: layero.find('#table-prize-list'),
|
||||
data: list,
|
||||
page: false,
|
||||
height: 380,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'prizeId', title: 'ID', width: 80 },
|
||||
{ field: 'name', title: '名称', minWidth: 100 },
|
||||
{ title: '图标', width: 70, templet: function(d) {
|
||||
var src = prizeIcon(d);
|
||||
return src ? '<img src="' + src + '" style="width:32px;height:32px;object-fit:contain" alt="图标">' : '';
|
||||
}},
|
||||
{ field: 'type', title: '类型', width: 80, templet: function(d) {
|
||||
var map = {1: '金币', 2: '钻石', 3: '道具', 4: '碎片'};
|
||||
return map[d.type] || '金币';
|
||||
}},
|
||||
{ field: 'count', title: '数量', width: 80 },
|
||||
{ field: 'weight', title: '权重', width: 60 },
|
||||
{ field: 'totalCount', title: '库存', width: 60, templet: function(d) {
|
||||
return d.totalCount || '∞';
|
||||
}}
|
||||
]],
|
||||
done: function() {
|
||||
if (list.length > 0 && (selectIndex === undefined || selectIndex < 0)) {
|
||||
selectIndex = 0;
|
||||
}
|
||||
if (selectIndex >= 0 && selectIndex < list.length) {
|
||||
currentPrizeIndex = selectIndex;
|
||||
var $tr = layero.find('#table-prize-list + .layui-table-view tr[data-index="' + selectIndex + '"]');
|
||||
if ($tr.length) {
|
||||
$tr.addClass('layui-table-click');
|
||||
loadPrizeForm(list[selectIndex], layero);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 行点击切换
|
||||
layero.find('#table-prize-list + .layui-table-view').off('click').on('click', 'tr[data-index]', function() {
|
||||
var idx = parseInt($(this).attr('data-index'));
|
||||
if (idx >= 0 && idx < list.length) {
|
||||
currentPrizeIndex = idx;
|
||||
layero.find('tr[data-index]').removeClass('layui-table-click');
|
||||
$(this).addClass('layui-table-click');
|
||||
loadPrizeForm(list[idx], layero);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadPrizeForm(data, layero) {
|
||||
layero.find('#prizeId').val(data.prizeId || '');
|
||||
layero.find('#prizeName').val(data.name || '');
|
||||
layero.find('#prizeIcon').val(prizeIcon(data));
|
||||
layero.find('#prizeType').val(data.type || 1);
|
||||
layero.find('#prizeCount').val(data.count || 0);
|
||||
renderPrizeProductOptions(layero, parseInt(data.type, 10) || 1, data.otherId || '');
|
||||
layero.find('#prizeWeight').val(data.weight || 10);
|
||||
layero.find('#prizeTotalCount').val(data.totalCount || 0);
|
||||
|
||||
if (data.type === 3 || data.type === 4) {
|
||||
layero.find('.prize-prop-select').show();
|
||||
} else {
|
||||
layero.find('.prize-prop-select').hide();
|
||||
}
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
function renderPrizeProductOptions(layero, type, selected) {
|
||||
var select = layero.find('#prizeOtherId');
|
||||
var source = type === 4 ? propFragmentList : propList;
|
||||
select.empty().append('<option value="">请选择道具/碎片</option>');
|
||||
source.forEach(function(item) {
|
||||
var number = String(item.number || '');
|
||||
select.append($('<option></option>').val(number).text(number + ' - ' + (item.name || '')));
|
||||
});
|
||||
select.val(String(selected || ''));
|
||||
form.render('select', 'prize-form');
|
||||
}
|
||||
|
||||
function clearPrizeForm(layero) {
|
||||
layero.find('#prizeId').val('');
|
||||
layero.find('#prizeName').val('');
|
||||
layero.find('#prizeIcon').val('');
|
||||
layero.find('#prizeType').val('1');
|
||||
layero.find('#prizeCount').val('0');
|
||||
layero.find('#prizeOtherId').val('');
|
||||
layero.find('#prizeWeight').val('10');
|
||||
layero.find('#prizeTotalCount').val('0');
|
||||
layero.find('.prize-prop-select').hide();
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
function savePrizeItem(layero, poolData) {
|
||||
if (currentPrizeIndex < 0) return layer.msg('请先选择要编辑的奖项');
|
||||
var list = poolData.prizeList;
|
||||
list[currentPrizeIndex] = {
|
||||
prizeId: layero.find('#prizeId').val() || '',
|
||||
name: layero.find('#prizeName').val() || '',
|
||||
icon: layero.find('#prizeIcon').val() || propIcon(layero.find('#prizeOtherId').val()) || '',
|
||||
type: parseInt(layero.find('#prizeType').val()) || 1,
|
||||
count: parseInt(layero.find('#prizeCount').val()) || 0,
|
||||
otherId: layero.find('#prizeOtherId').val() || '',
|
||||
weight: parseInt(layero.find('#prizeWeight').val()) || 10,
|
||||
totalCount: parseInt(layero.find('#prizeTotalCount').val()) || 0,
|
||||
drawnCount: 0
|
||||
};
|
||||
renderPrizeTable(layero, poolData, currentPrizeIndex);
|
||||
renderPoolTable();
|
||||
layer.msg('保存成功');
|
||||
}
|
||||
|
||||
// ============ 保存活动 ============
|
||||
function saveActivity() {
|
||||
var activityName = $('input[name="activityName"]').val();
|
||||
if (!activityName) { layer.msg('活动名称不能为空'); return; }
|
||||
|
||||
var startTimeStr = $('input[name="startTime"]').val();
|
||||
var endTimeStr = $('input[name="endTime"]').val();
|
||||
function parseCosts(name) {
|
||||
var value = $('input[name="' + name + '"]').val() || '';
|
||||
return value.split(',').map(function(s) { return parseInt(s.trim()) || 0; }).filter(function(n) { return n > 0; });
|
||||
}
|
||||
|
||||
var costsCannon = parseCosts('costsCannon');
|
||||
var costsGodWar = parseCosts('costsGodWar');
|
||||
var costsWing = parseCosts('costsWing');
|
||||
if (costsCannon.length === 0) { layer.msg('请配置炮台奖池消耗金币'); return; }
|
||||
if (costsGodWar.length === 0) { layer.msg('请配置战神奖池消耗金币'); return; }
|
||||
if (costsWing.length === 0) { layer.msg('请配置翅膀奖池消耗金币'); return; }
|
||||
|
||||
var startTs = startTimeStr ? Math.floor(new Date(startTimeStr).getTime() / 1000) : 0;
|
||||
var endTs = endTimeStr ? Math.floor(new Date(endTimeStr).getTime() / 1000) : 0;
|
||||
|
||||
var param = {
|
||||
activityId: $('#activityId').val() || '',
|
||||
activityName: activityName,
|
||||
isOpen: $('select[name="isOpen"]').val() === 'true',
|
||||
startTime: startTs,
|
||||
endTime: endTs,
|
||||
userMaxDraw: parseInt($('input[name="userMaxDraw"]').val()) || 100,
|
||||
costsByPool: {
|
||||
1: costsCannon,
|
||||
2: costsGodWar,
|
||||
3: costsWing
|
||||
},
|
||||
// _clientId 仅用于解决 Layui 行副本定位问题,不提交到服务端。
|
||||
pools: poolsData.map(function(p) {
|
||||
var copy = $.extend(true, {}, p);
|
||||
delete copy._clientId;
|
||||
(copy.prizeList || []).forEach(function(prize) {
|
||||
var type = parseInt(prize.type, 10);
|
||||
if (type === 3 || type === 4) {
|
||||
prize.icon = prize.icon || propIcon(prize.otherId) || '';
|
||||
}
|
||||
});
|
||||
return copy;
|
||||
})
|
||||
};
|
||||
|
||||
admin.req({
|
||||
method: 'post',
|
||||
contentType: 'application/json;charset=UTF-8',
|
||||
url: setter.baseurl + 'adminapi/Lottery/save',
|
||||
data: JSON.stringify(param),
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功');
|
||||
loadActivity();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============ 启动 ============
|
||||
loadProps();
|
||||
loadActivity();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.prize-container { display: flex; height: 480px; padding: 10px; }
|
||||
.prize-left { flex: 1; margin-right: 15px; }
|
||||
.prize-table-wrap { height: 400px; overflow: auto; }
|
||||
.prize-right { width: 300px; border-left: 1px solid #e6e6e6; padding-left: 15px; }
|
||||
.prize-right h4 { margin-bottom: 15px; color: #333; font-size: 16px; padding-bottom: 10px; border-bottom: 1px solid #eee; }
|
||||
.prize-toolbar { margin-bottom: 10px; }
|
||||
.prize-toolbar .layui-btn { margin-right: 5px; }
|
||||
.prize-right .layui-form-item { margin-bottom: 10px; }
|
||||
.prize-right .layui-form-label { padding: 9px 0; width: 60px; }
|
||||
.prize-right .layui-input-block { margin-left: 70px; }
|
||||
</style>
|
||||
@@ -0,0 +1,298 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>后台充值/扣除</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, maximum-scale=1">
|
||||
<link rel="stylesheet" href="../../../layui/css/layui.css">
|
||||
<script src="../../../layui/layui.js"></script>
|
||||
<script src="../../../layui/xm-select.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">后台充值/扣除</div>
|
||||
<div class="layui-card-body">
|
||||
<!-- 操作表单 -->
|
||||
<form class="layui-form" lay-filter="operation-form" style="margin-bottom:20px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">目标用户</label>
|
||||
<div class="layui-input-inline" style="width:300px;">
|
||||
<input type="text" name="targetUserId" id="targetUser" required lay-verify="required"
|
||||
placeholder="请输入用户ID或用户名" class="layui-input">
|
||||
<input type="hidden" id="searchedUserId" value="">
|
||||
<div class="layui-form-mid layui-word-aux">支持ID或用户名搜索</div>
|
||||
</div>
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="btn-search-user">
|
||||
<i class="layui-icon layui-icon-search"></i> 搜索
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">操作类型</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="radio" name="operationType" value="1" title="充值" checked>
|
||||
<input type="radio" name="operationType" value="2" title="扣除">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">货币类型</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="currencyType" lay-verify="required">
|
||||
<option value="1">金币</option>
|
||||
<option value="2">钻石</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">操作数量</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="amount" required lay-verify="required|number"
|
||||
placeholder="请输入数量" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-inline" style="width:400px;">
|
||||
<input type="text" name="remark" placeholder="备注信息" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-danger" lay-submit lay-filter="btn-deduct">扣除</button>
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="btn-charge">充值</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 操作日志查询 -->
|
||||
<div class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="adminUser" id="adminUser-search"
|
||||
placeholder="后台操作者ID/用户名" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="targetUserSearch" id="targetUser-search"
|
||||
placeholder="目标用户ID/用户名" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="operationTypeSearch" id="operationType-search">
|
||||
<option value="">全部</option>
|
||||
<option value="1">充值</option>
|
||||
<option value="2">扣除</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" id="btn-search-logs">
|
||||
<i class="layui-icon layui-icon-search"></i> 查询
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作日志表格 -->
|
||||
<table id="table-logs" lay-filter="table-logs"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['table', 'form', 'layer'], function(){
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
var setter = layui.setter;
|
||||
|
||||
// 渲染表单元素
|
||||
form.render();
|
||||
|
||||
// 货币类型名称映射
|
||||
var currencyNames = { 1: '金币', 2: '钻石' };
|
||||
|
||||
// 初始化操作日志表格
|
||||
var tableIns = table.render({
|
||||
elem: '#table-logs',
|
||||
url: setter.baseurl + 'adminapi/BackgroundOperation/logs',
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
method: 'get',
|
||||
page: true,
|
||||
limit: 20,
|
||||
limits: [20, 50, 100],
|
||||
where: {
|
||||
adminUserId: '',
|
||||
targetUserId: '',
|
||||
operationType: ''
|
||||
},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'OperationTime', title: '操作时间', width: 160, templet: function(d) {
|
||||
return formatDateTime(d.operationTime);
|
||||
}},
|
||||
{ field: 'adminUserName', title: '操作者', width: 120 },
|
||||
{ field: 'targetUserName', title: '目标用户', width: 120 },
|
||||
{ field: 'operationType', title: '操作类型', width: 100, templet: function(d) {
|
||||
return d.operationType === 1 ?
|
||||
'<span class="layui-badge layui-bg-green">充值</span>' :
|
||||
'<span class="layui-badge layui-bg-red">扣除</span>';
|
||||
}},
|
||||
{ field: 'currencyType', title: '货币类型', width: 100, templet: function(d) {
|
||||
return currencyNames[d.currencyType] || '未知(' + d.currencyType + ')';
|
||||
}},
|
||||
{ field: 'amount', title: '数量', width: 100 },
|
||||
{ field: 'remark', title: '备注', minWidth: 200 }
|
||||
]],
|
||||
response: {
|
||||
statusCode: 0, // 规定成功的状态码,默认:0
|
||||
msgName: 'info', // 规定状态信息的字段名称,默认:msg
|
||||
countName: 'count', // 规定数据总数的字段名称,默认:count
|
||||
dataName: 'data' // 规定数据列表的字段名称,默认:data
|
||||
}
|
||||
});
|
||||
|
||||
// 搜索用户(用于绑定目标用户)
|
||||
$('#btn-search-user').click(function(){
|
||||
var keyword = $('#targetUser').val().trim();
|
||||
if (!keyword) {
|
||||
layer.msg('请输入用户ID或用户名');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载中
|
||||
var loading = layer.load(1);
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/BackgroundOperation/search-user',
|
||||
type: 'get',
|
||||
data: { keyword: keyword },
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
layer.close(loading);
|
||||
if (res.code === 0) {
|
||||
// 搜索成功,显示用户信息并保存 userId
|
||||
var user = res.data;
|
||||
$('#searchedUserId').val(user.userId);
|
||||
layer.alert(
|
||||
'用户信息:<br>' +
|
||||
'用户ID:' + user.userId + '<br>' +
|
||||
'用户名:' + user.userName + '<br>' +
|
||||
'手机号:' + (user.userPhone || '未绑定') + '<br>' +
|
||||
'金币:' + user.gold + '<br>' +
|
||||
'钻石:' + user.diamond + '<br>' +
|
||||
'注册时间:' + formatDateTime(user.registerTime),
|
||||
{
|
||||
icon: 1,
|
||||
title: '用户信息'
|
||||
}
|
||||
);
|
||||
} else {
|
||||
layer.msg(res.info || '用户不存在');
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
layer.close(loading);
|
||||
console.error('搜索用户失败:', error);
|
||||
layer.msg('搜索用户失败,请检查网络连接');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 充值按钮
|
||||
form.on('submit(btn-charge)', function(data){
|
||||
var field = data.field;
|
||||
field.operationType = 1; // 充值
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/BackgroundOperation/charge',
|
||||
type: 'post',
|
||||
contentType: 'application/json',
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
data: JSON.stringify({
|
||||
targetUserId: $('#searchedUserId').val(),
|
||||
currencyType: parseInt(field.currencyType),
|
||||
amount: parseFloat(field.amount),
|
||||
remark: field.remark || ''
|
||||
}),
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('充值成功', {icon: 1});
|
||||
tableIns.reload();
|
||||
} else {
|
||||
layer.msg(res.info || '充值失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 扣除按钮
|
||||
form.on('submit(btn-deduct)', function(data){
|
||||
var field = data.field;
|
||||
field.operationType = 2; // 扣除
|
||||
|
||||
layer.confirm('确认要扣除 ' + field.amount + ' ' +
|
||||
(field.currencyType == 1 ? '金币' : '钻石') + '?', function(idx) {
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/BackgroundOperation/deduct',
|
||||
type: 'post',
|
||||
contentType: 'application/json',
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
data: JSON.stringify({
|
||||
targetUserId: $('#searchedUserId').val(),
|
||||
currencyType: parseInt(field.currencyType),
|
||||
amount: parseFloat(field.amount),
|
||||
remark: field.remark || ''
|
||||
}),
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('扣除成功', {icon: 1});
|
||||
tableIns.reload();
|
||||
} else {
|
||||
layer.msg(res.info || '扣除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
layer.close(idx);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 查询日志
|
||||
$('#btn-search-logs').click(function(){
|
||||
var where = {};
|
||||
var adminUser = $('#adminUser-search').val().trim();
|
||||
var targetUser = $('#targetUser-search').val().trim();
|
||||
var operationType = $('#operationType-search').val();
|
||||
|
||||
if (adminUser) where.adminUserId = adminUser;
|
||||
if (targetUser) where.targetUserId = targetUser;
|
||||
if (operationType) where.operationType = parseInt(operationType);
|
||||
|
||||
tableIns.reload({
|
||||
where: where,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
function formatDateTime(timestamp) {
|
||||
if (!timestamp) return '';
|
||||
var date = new Date(timestamp * 1000);
|
||||
return date.toLocaleString('zh-CN');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,715 @@
|
||||
|
||||
<title>靓号管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>靓号管理</cite></a>
|
||||
<a><cite>靓号列表</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-beautifulnumber-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">靓号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="numberSearch" placeholder="靓号搜索" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">等级</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="level">
|
||||
<option value="">全部</option>
|
||||
<option value="S">S级</option>
|
||||
<option value="A">A级</option>
|
||||
<option value="B">B级</option>
|
||||
<option value="C">C级</option>
|
||||
<option value="D">D级</option>
|
||||
</select>
|
||||
</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="0">未售</option>
|
||||
<option value="1">已售</option>
|
||||
<option value="2">冻结</option>
|
||||
<option value="3">普通号</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-beautifulnumber" lay-submit lay-filter="LAY-beautifulnumber-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-beautifulnumber-front-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="addNumber">
|
||||
<i class="layui-icon layui-icon-add-circle"></i> 添加靓号
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="batchAddNumbers">
|
||||
<i class="layui-icon layui-icon-add-circle"></i> 批量添加
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="initRules">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 初始化规则
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-event="initNumbers">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 根据规则生成靓号
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<table id="LAY-beautifulnumber-back-manage" lay-filter="LAY-beautifulnumber-back-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-beautifulnumber-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="give"><i class="layui-icon layui-icon-gift"></i>赠送</a>
|
||||
<!--<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>-->
|
||||
<a class="layui-btn layui-btn-xs" lay-event="editPrice"><i class="layui-icon layui-icon-edit"></i>改价</a>
|
||||
{{# if(d.status === 0){ }}
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="freeze"><i class="layui-icon layui-icon-close"></i>冻结</a>
|
||||
{{# } else if(d.status === 2){ }}
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="unfreeze"><i class="layui-icon layui-icon-ok"></i>解冻</a>
|
||||
{{# } }}
|
||||
{{# if(d.status !== 3){ }}
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="setNormal"><i class="layui-icon layui-icon-set"></i>普通号</a>
|
||||
{{# } }}
|
||||
{{# if(d.status !== 1){ }}
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form'], function () {
|
||||
var i = (layui.$, layui.admin),
|
||||
$ = layui.$,
|
||||
admin = layui.admin,
|
||||
view = layui.view,
|
||||
table = layui.table,
|
||||
setter = layui.setter,
|
||||
form = layui.form;
|
||||
|
||||
form.render(null, 'layadmin-beautifulnumber-formlist');
|
||||
|
||||
//监听搜索
|
||||
form.on('submit(LAY-beautifulnumber-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
// 转换状态为数字
|
||||
if (field.status) {
|
||||
field.status = parseInt(field.status);
|
||||
}
|
||||
//执行重载
|
||||
table.reload('LAY-beautifulnumber-back-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 监听重置
|
||||
$('.layui-btn-group').on('click', '[lay-event="refresh"]', function () {
|
||||
table.reload('LAY-beautifulnumber-back-manage');
|
||||
});
|
||||
|
||||
// 添加单个靓号
|
||||
$('.layui-btn-group').on('click', '[lay-event="addNumber"]', function () {
|
||||
var content =
|
||||
'<form class="layui-form" style="padding: 20px;" lay-filter="layuiadmin-form-add-number">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">靓号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="number" class="layui-input" placeholder="输入靓号" required>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="level">' +
|
||||
'<option value="S">S级</option>' +
|
||||
'<option value="A">A级</option>' +
|
||||
'<option value="B">B级</option>' +
|
||||
'<option value="C">C级</option>' +
|
||||
'<option value="D" selected>D级</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="price" class="layui-input" placeholder="金币数量" value="0">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="LAY-add-number-submit">添加</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '添加靓号',
|
||||
area: ['600px', '450px'],
|
||||
content: content
|
||||
});
|
||||
|
||||
layui.form.render();
|
||||
layui.form.on('submit(LAY-add-number-submit)', function(dataField) {
|
||||
var param = {
|
||||
number: dataField.field.number,
|
||||
level: dataField.field.level,
|
||||
price: parseInt(dataField.field.price) || 0
|
||||
};
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/add-number",
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.closeAll();
|
||||
layer.msg('添加成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '添加失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// 批量添加靓号
|
||||
$('.layui-btn-group').on('click', '[lay-event="batchAddNumbers"]', function () {
|
||||
var content =
|
||||
'<form class="layui-form" style="padding: 20px;" lay-filter="layuiadmin-form-batch-add">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">靓号列表</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<textarea name="numbers" class="layui-textarea" placeholder="每行一个号码" style="height: 200px;" required></textarea>' +
|
||||
'<div style="color:#999;font-size:12px;margin-top:5px;">每行输入一个靓号,系统会自动过滤已存在的号码</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="level">' +
|
||||
'<option value="S">S级</option>' +
|
||||
'<option value="A">A级</option>' +
|
||||
'<option value="B">B级</option>' +
|
||||
'<option value="C">C级</option>' +
|
||||
'<option value="D" selected>D级</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="price" class="layui-input" placeholder="金币数量" value="0">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="LAY-batch-add-submit">批量添加</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '批量添加靓号',
|
||||
area: ['500px', '500px'],
|
||||
content: content
|
||||
});
|
||||
|
||||
layui.form.render();
|
||||
layui.form.on('submit(LAY-batch-add-submit)', function(dataField) {
|
||||
var numbersText = dataField.field.numbers.trim();
|
||||
if (!numbersText) {
|
||||
layer.msg('请输入靓号列表');
|
||||
return false;
|
||||
}
|
||||
var numbers = numbersText.split('\n').map(function(n) { return n.trim(); }).filter(function(n) { return n; });
|
||||
var param = {
|
||||
numbers: numbers,
|
||||
level: dataField.field.level,
|
||||
price: parseInt(dataField.field.price) || 0
|
||||
|
||||
};
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/batch-add-numbers",
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.closeAll();
|
||||
layer.msg(res.data ? res.data.message : '添加成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '添加失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// 监听初始化规则
|
||||
$('.layui-btn-group').on('click', '[lay-event="initRules"]', function () {
|
||||
layer.confirm("确定初始化靓号规则吗?", function (idx) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/init-rules",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
layer.close(idx);
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// 监听根据规则生成靓号
|
||||
$('.layui-btn-group').on('click', '[lay-event="initNumbers"]', function () {
|
||||
layer.confirm("确定根据规则生成靓号吗?已售出的靓号不会被删除,未售出的靓号将按规则重新生成。", function (idx) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/init-numbers",
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg(res.info || '初始化成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-beautifulnumber-back-manage",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/list",
|
||||
method: "get",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
where: {},
|
||||
request: {
|
||||
pageName: 'page',
|
||||
limitName: 'size'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "number", title: "靓号", width: 150 },
|
||||
{ field: "ruleName", title: "规则", width: 120 },
|
||||
{
|
||||
field: "level", title: "等级", width: 80,
|
||||
templet: function (d) {
|
||||
var colors = { 'S': '#ff4d4f', 'A': '#faad14', 'B': '#722ed1', 'C': '#1890ff', 'D': '#8c8c8c' };
|
||||
return '<span style="color:' + (colors[d.level] || '#8c8c8c') + ';font-weight:bold;">' + d.level + '</span>';
|
||||
}
|
||||
},
|
||||
{ field: "price", title: "价格", width: 120, templet: function (d) { return formatNumber(d.price); } },
|
||||
{
|
||||
field: "status", title: "状态", width: 100,
|
||||
templet: function (d) {
|
||||
var statusMap = { 0: '<span class="layui-badge">未售</span>', 1: '<span class="layui-badge layui-bg-green">已售</span>', 2: '<span class="layui-badge layui-bg-orange">冻结</span>', 3: '<span class="layui-badge layui-bg-gray">普通号</span>' };
|
||||
return statusMap[d.status] || '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: "saleTime", title: "售出时间", width: 160,
|
||||
templet: function (d) {
|
||||
return d.saleTime ? formatTimestamp(d.saleTime) : '-';
|
||||
}
|
||||
},
|
||||
{ field: "userId", title: "购买者ID", width: 150 },
|
||||
|
||||
{ width: 450, title: "操作", align: "center", fixed: "right", toolbar: "#table-beautifulnumber-admin" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
table.on("tool(LAY-beautifulnumber-back-manage)", function (e) {
|
||||
var l = e.data;
|
||||
|
||||
if ("del" === e.event) {
|
||||
layer.confirm("确定删除此靓号么?", function (i) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/delete",
|
||||
data: JSON.stringify({ id: l.id }),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
e.del(), layer.close(i);
|
||||
layer.msg('删除成功');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if ("editPrice" === e.event) {
|
||||
i.popup({
|
||||
title: "修改价格",
|
||||
area: ["400px", "200px"],
|
||||
id: "LAY-popup-edit-price",
|
||||
success: function (div, idx) {
|
||||
$(div).html(
|
||||
'<form class="layui-form" style="padding: 20px;" lay-filter="layadmin-form-edit-price">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">靓号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" class="layui-input" value="' + (l.number || '') + '" disabled>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">新价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="price" class="layui-input" value="' + (l.price || 0) + '" required>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="LAY-edit-price-submit">修改</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>'
|
||||
);
|
||||
form.render(null, "layadmin-form-edit-price");
|
||||
form.on("submit(LAY-edit-price-submit)", function (data) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/update-price",
|
||||
data: JSON.stringify({ id: l.id, price: parseInt(data.field.price) }),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.close(idx);
|
||||
layer.msg('修改成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '修改失败');
|
||||
}
|
||||
}
|
||||
})
|
||||
return false;
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if ("freeze" === e.event) {
|
||||
layer.confirm("确定冻结此靓号么?", function (i) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/freeze",
|
||||
data: JSON.stringify({ id: l.id }),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('冻结成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '冻结失败');
|
||||
}
|
||||
layer.close(i);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if ("unfreeze" === e.event) {
|
||||
layer.confirm("确定解冻此靓号么?", function (i) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/unfreeze",
|
||||
data: JSON.stringify({ id: l.id }),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('解冻成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '解冻失败');
|
||||
}
|
||||
layer.close(i);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if ("setNormal" === e.event) {
|
||||
layer.confirm("确定将此靓号设为普通号么?", function (i) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/set-normal",
|
||||
data: JSON.stringify({ id: l.id }),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('设置成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '设置失败');
|
||||
}
|
||||
layer.close(i);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if ("give" === e.event) {
|
||||
i.popup({
|
||||
title: "赠送靓号给用户",
|
||||
area: ["600px", "380px"],
|
||||
id: "LAY-popup-give-number",
|
||||
success: function (div, idx) {
|
||||
$(div).html(
|
||||
'<div style="padding:20px;">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label" style="width:70px;">靓号</label>' +
|
||||
'<div class="layui-input-block" style="left:90px;">' +
|
||||
'<span class="layui-badge layui-bg-blue" style="padding:6px 15px;font-size:14px;">' + (l.number || '') + '</span>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item" style="margin-bottom:5px;">' +
|
||||
'<label class="layui-form-label" style="width:70px;">选择用户</label>' +
|
||||
'<div class="layui-input-block" style="left:90px;position:relative;">' +
|
||||
'<input type="text" id="user-search-input" class="layui-input" style="padding-right:35px;" placeholder="输入用户名、昵称、用户编号或手机号搜索">' +
|
||||
'<i class="layui-icon layui-icon-loading layui-anim layui-anim-loop" id="search-loading" style="position:absolute;right:10px;top:10px;display:none;"></i>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div id="user-dropdown" class="user-dropdown-list" style="display:none;position:absolute;left:90px;width:calc(100% - 90px);max-height:250px;overflow-y:auto;background:#fff;border:1px solid #e6e6e6;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,.1);z-index:99999;"></div>' +
|
||||
'<div style="margin-top:10px;color:#999;font-size:12px;margin-left:70px;">提示:可按用户名、昵称、用户编号、手机号进行模糊搜索</div>' +
|
||||
'<div id="selected-user-info" style="margin-top:15px;padding:15px;background:#e8f4ff;border-radius:6px;border:1px solid #b8d6f0;display:none;margin-left:70px;">' +
|
||||
'<div style="display:flex;align-items:center;justify-content:space-between;">' +
|
||||
'<div>' +
|
||||
'<span style="color:#666;">已选择用户:</span>' +
|
||||
'<span id="selected-user-text" style="color:#1e88e5;font-weight:bold;font-size:15px;"></span>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="btn-clear-user"><i class="layui-icon layui-icon-close"></i> 清除</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div style="margin-top:20px;text-align:center;">' +
|
||||
'<button type="button" class="layui-btn layui-btn-primary layui-btn-sm" id="btn-cancel-give" style="margin-right:15px;">取消</button>' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm" id="btn-confirm-give"><i class="layui-icon layui-icon-ok"></i> 确认赠送</button>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
|
||||
var selectedUser = null;
|
||||
var searchTimer = null;
|
||||
var $dropdown = $('#user-dropdown');
|
||||
var $input = $('#user-search-input');
|
||||
|
||||
function renderDropdown(users) {
|
||||
if (!users || users.length === 0) {
|
||||
$dropdown.html('<div style="padding:15px;color:#999;text-align:center;">未找到匹配的用户</div>').show();
|
||||
return;
|
||||
}
|
||||
var html = '';
|
||||
users.forEach(function(user) {
|
||||
var number = user.baseInfo ? user.baseInfo.number : '';
|
||||
var name = user.baseInfo ? user.baseInfo.userName : '';
|
||||
var mobile = user.baseInfo ? user.baseInfo.mobile : '';
|
||||
html += '<div class="user-dropdown-item" data-id="' + user.id + '" data-number="' + number + '" data-name="' + name + '" data-mobile="' + mobile + '" style="padding:12px 15px;cursor:pointer;border-bottom:1px solid #f0f0f0;">' +
|
||||
'<div style="display:flex;justify-content:space-between;align-items:center;">' +
|
||||
'<div><span style="font-weight:bold;color:#333;font-size:14px;">' + name + '</span> <span style="color:#666;font-size:12px;">[' + number + ']</span></div>' +
|
||||
(mobile ? '<span style="color:#999;font-size:12px;">' + mobile + '</span>' : '<span style="color:#999;font-size:12px;">无手机号</span>') +
|
||||
'</div></div>';
|
||||
});
|
||||
$dropdown.html(html).show();
|
||||
}
|
||||
|
||||
function searchUsers(keyword) {
|
||||
if (!keyword || keyword.length < 1) {
|
||||
$dropdown.hide();
|
||||
return;
|
||||
}
|
||||
$('#search-loading').show();
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/AdminUser/GetUserList",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
data: JSON.stringify({ keyWord: keyword, pageIndex: 1, pageSize: 20 }),
|
||||
done: function (res) {
|
||||
$('#search-loading').hide();
|
||||
if (res.data && res.data.length > 0) {
|
||||
renderDropdown(res.data);
|
||||
} else {
|
||||
renderDropdown([]);
|
||||
}
|
||||
},
|
||||
fail: function() {
|
||||
$('#search-loading').hide();
|
||||
renderDropdown([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$input.on('input', function() {
|
||||
var keyword = $(this).val().trim();
|
||||
clearTimeout(searchTimer);
|
||||
if (keyword.length < 1) {
|
||||
$dropdown.hide();
|
||||
return;
|
||||
}
|
||||
searchTimer = setTimeout(function() {
|
||||
searchUsers(keyword);
|
||||
}, 300);
|
||||
});
|
||||
|
||||
$input.on('focus', function() {
|
||||
var keyword = $(this).val().trim();
|
||||
if (keyword.length >= 1 && $dropdown.find('.user-dropdown-item').length > 0) {
|
||||
$dropdown.show();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).off('click', '.user-dropdown-item').on('click', '.user-dropdown-item', function() {
|
||||
var userId = $(this).data('id');
|
||||
var userNumber = $(this).data('number');
|
||||
var userName = $(this).data('name');
|
||||
var userMobile = $(this).data('mobile');
|
||||
selectedUser = { id: userId, number: userNumber, name: userName, mobile: userMobile };
|
||||
$input.val(name + ' [' + userNumber + ']' + (userMobile ? ' ' + userMobile : ''));
|
||||
$dropdown.hide();
|
||||
$('#selected-user-text').text(userName + ' [' + userNumber + ']' + (userMobile ? ' ' + userMobile : ''));
|
||||
$('#selected-user-info').show();
|
||||
});
|
||||
|
||||
$(document).on('click', function(e) {
|
||||
if (!$(e.target).closest('#user-search-input, #user-dropdown').length) {
|
||||
$dropdown.hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('#btn-clear-user').on('click', function() {
|
||||
selectedUser = null;
|
||||
$input.val('').focus();
|
||||
$('#selected-user-info').hide();
|
||||
});
|
||||
|
||||
$('#btn-cancel-give').on('click', function() {
|
||||
layer.close(idx);
|
||||
});
|
||||
|
||||
$('#btn-confirm-give').on('click', function() {
|
||||
if (!selectedUser) {
|
||||
layer.msg('请先选择用户');
|
||||
return;
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/give-to-user",
|
||||
data: JSON.stringify({ number: l.number, userId: selectedUser.id }),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.close(idx);
|
||||
layer.msg('赠送成功');
|
||||
table.reload("LAY-beautifulnumber-back-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '赠送失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// 数字格式化
|
||||
function formatNumber(num) {
|
||||
if (!num) return '0';
|
||||
return num.toString().replace(/\B(?=(\d{4})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
// 时间戳格式化
|
||||
function formatTimestamp(timestamp, format = 'yyyy-MM-dd hh:mm:ss') {
|
||||
if (!timestamp) return '-';
|
||||
const date = new Date(timestamp * 1000);
|
||||
const o = {
|
||||
'M+': date.getMonth() + 1,
|
||||
'd+': date.getDate(),
|
||||
'h+': date.getHours(),
|
||||
'm+': date.getMinutes(),
|
||||
's+': date.getSeconds()
|
||||
};
|
||||
if (/(y+)/.test(format)) {
|
||||
format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (const k in o) {
|
||||
if (new RegExp('(' + k + ')').test(format)) {
|
||||
format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
// e("beautifulnumber", {})
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,520 @@
|
||||
|
||||
<title>靓号规则配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>靓号管理</cite></a>
|
||||
<a><cite>规则配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add">
|
||||
<i class="layui-icon layui-icon-add-circle"></i> 添加规则
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm" id="btn-save">
|
||||
<i class="layui-icon layui-icon-ok"></i> 保存规则
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" id="btn-init">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 初始化规则
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" id="btn-reload">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-rules-manage" lay-filter="LAY-rules-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-rule-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="toolbar-rule">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add">添加规则</button>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var rules = [];
|
||||
|
||||
function loadRules() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/rules",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
rules = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-rules-manage',
|
||||
data: rules,
|
||||
cols: [[
|
||||
{ field: "ruleName", title: "规则名称", width: 150, edit: 'text' },
|
||||
{ field: "rulePattern", title: "生成模式", width: 150 },
|
||||
{ field: "level", title: "等级", width: 70, edit: 'text' },
|
||||
{ field: "price", title: "价格(金币)", width: 100, edit: 'text' },
|
||||
{ field: "sort", title: "排序", width: 70, edit: 'text' },
|
||||
{
|
||||
field: "isEnable",
|
||||
title: "启用",
|
||||
width: 80,
|
||||
templet: function(d) {
|
||||
return d.isEnable ? '<span class="layui-badge">是</span>' : '<span class="layui-badge layui-bg-gray">否</span>';
|
||||
}
|
||||
},
|
||||
{ width: 250, title: "操作", align: "center", fixed: "right", toolbar: "#table-rule-admin" }
|
||||
]],
|
||||
toolbar: '#toolbar-rule'
|
||||
});
|
||||
}
|
||||
|
||||
$('#btn-reload').on('click', function() {
|
||||
loadRules();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$('#btn-add').on('click', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$('#btn-init').on('click', function() {
|
||||
layer.confirm('确定初始化靓号规则吗?这将覆盖现有规则!', function(idx) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/init-rules",
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadRules();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn-save').on('click', function() {
|
||||
layer.confirm('确定保存所有规则吗?', function(idx) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/update-rules",
|
||||
data: JSON.stringify(rules),
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadRules();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
table.on("tool(LAY-rules-manage)", function (obj) {
|
||||
var data = obj.data;
|
||||
|
||||
if ("del" === obj.event) {
|
||||
layer.confirm("确定删除此规则么?", function (i) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/delete-rule",
|
||||
data: JSON.stringify({ id: data.id }),
|
||||
done: function (res) {
|
||||
layer.close(i);
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('删除成功');
|
||||
loadRules();
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ("edit" === obj.event) {
|
||||
showEditDialog(data, obj);
|
||||
}
|
||||
});
|
||||
|
||||
table.on('toolbar(LAY-rules-manage)', function(obj){
|
||||
if(obj.event === 'add'){
|
||||
showAddDialog();
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
var content =
|
||||
'<form class="layui-form" style="padding: 20px;" lay-filter="layuiadmin-form-add-rule">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">规则名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="ruleName" class="layui-input" placeholder="如:AAAA、ABBB、ABCDEFGH、AAAABBBX">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="level">' +
|
||||
'<option value="S">S级</option>' +
|
||||
'<option value="A">A级</option>' +
|
||||
'<option value="B">B级</option>' +
|
||||
'<option value="C">C级</option>' +
|
||||
'<option value="D">D级</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="price" class="layui-input" placeholder="金币数量">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">排序</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="sort" class="layui-input" placeholder="数字越小越靠前" value="0">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="LAY-add-rule-submit">添加</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '添加规则',
|
||||
area: ['650px', '500px'],
|
||||
content: content
|
||||
});
|
||||
|
||||
layui.form.render();
|
||||
layui.form.on('submit(LAY-add-rule-submit)', function(dataField) {
|
||||
var ruleName = dataField.field.ruleName.toUpperCase().trim();
|
||||
if (!ruleName) {
|
||||
layer.msg('请输入规则名称');
|
||||
return false;
|
||||
}
|
||||
|
||||
var newRule = {
|
||||
ruleName: ruleName,
|
||||
rulePattern: ruleName,
|
||||
level: dataField.field.level,
|
||||
price: parseInt(dataField.field.price) || 0,
|
||||
sort: parseInt(dataField.field.sort) || 0,
|
||||
isEnable: true
|
||||
};
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/add-rule",
|
||||
data: JSON.stringify(newRule),
|
||||
done: function (res) {
|
||||
layer.closeAll();
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('添加成功');
|
||||
loadRules();
|
||||
} else {
|
||||
layer.msg(res.info || '添加失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function showEditDialog(data, obj) {
|
||||
var level = data.level || 'D';
|
||||
var isEnabled = data.isEnable ? 'checked' : '';
|
||||
var content =
|
||||
'<form class="layui-form" style="padding: 20px;" lay-filter="layuiadmin-form-edit-rule">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">规则名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="ruleName" class="layui-input" value="' + (data.ruleName || '') + '" placeholder="如:KKKKKKKK KKKKTTTT ABCDEFGH KKKKXXXX">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="level">' +
|
||||
'<option value="S" ' + (level === 'S' ? 'selected' : '') + '>S级</option>' +
|
||||
'<option value="A" ' + (level === 'A' ? 'selected' : '') + '>A级</option>' +
|
||||
'<option value="B" ' + (level === 'B' ? 'selected' : '') + '>B级</option>' +
|
||||
'<option value="C" ' + (level === 'C' ? 'selected' : '') + '>C级</option>' +
|
||||
'<option value="D" ' + (level === 'D' ? 'selected' : '') + '>D级</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="price" class="layui-input" value="' + (data.price || 0) + '" placeholder="金币数量">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">排序</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="sort" class="layui-input" value="' + (data.sort || 0) + '" placeholder="数字越小越靠前">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">启用</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="isEnable" lay-skin="switch" lay-text="开启|关闭" ' + isEnabled + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="LAY-edit-rule-submit">保存</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '编辑规则',
|
||||
area: ['500px', '450px'],
|
||||
content: content
|
||||
});
|
||||
|
||||
layui.form.render();
|
||||
layui.form.on('submit(LAY-edit-rule-submit)', function(formData) {
|
||||
var isEnable = $(formData.form).find('input[name="isEnable"]').prop('checked');
|
||||
var ruleName = formData.field.ruleName.toUpperCase().trim();
|
||||
|
||||
if (!ruleName) {
|
||||
layer.msg('请输入规则名称');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var updatedRule = {
|
||||
id: data.id,
|
||||
ruleName: ruleName,
|
||||
|
||||
level: formData.field.level,
|
||||
price: parseInt(formData.field.price) || 0,
|
||||
sort: parseInt(formData.field.sort) || 0,
|
||||
isEnable: isEnable
|
||||
};
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/BeautifulNumber/update-rule",
|
||||
data: JSON.stringify(updatedRule),
|
||||
done: function (res) {
|
||||
layer.closeAll();
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadRules();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function generateRegexPattern(ruleName) {
|
||||
if (!ruleName) {
|
||||
return { valid: false, message: '请输入规则名称' };
|
||||
}
|
||||
|
||||
ruleName = ruleName.toUpperCase().trim();
|
||||
|
||||
if (ruleName.length!=8) {
|
||||
return { valid: false, message: '规则名称长度必须是8位' };
|
||||
}
|
||||
|
||||
// 检查是否全部是连续字母A-H (如 ABCDEFGH 表示8连号)
|
||||
var isAllConsecutive = true;
|
||||
var expectedChar = 'A';
|
||||
for (var i = 0; i < ruleName.length; i++) {
|
||||
if (ruleName[i] !== expectedChar) {
|
||||
isAllConsecutive = false;
|
||||
break;
|
||||
}
|
||||
expectedChar = String.fromCharCode(expectedChar.charCodeAt(0) + 1);
|
||||
}
|
||||
|
||||
// 如果是 ABCDEFGH 这种连续字母,表示全部是连续数字
|
||||
if (isAllConsecutive) {
|
||||
var len = ruleName.length;
|
||||
// 生成匹配连续数字的正则: 01234567, 12345678, 23456789
|
||||
var patterns = [];
|
||||
for (var start = 0; start <= 9 - len; start++) {
|
||||
var seq = '';
|
||||
for (var k = 0; k < len; k++) {
|
||||
seq += (start + k);
|
||||
}
|
||||
if (patterns.length > 0 && patterns.length < 10) {
|
||||
patterns.push(seq);
|
||||
}
|
||||
}
|
||||
if (patterns.length > 0) {
|
||||
return {
|
||||
valid: true,
|
||||
rulePattern: "^(" + patterns.join('|') + ")$"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var regex = "^";
|
||||
var prevGroup = '';
|
||||
|
||||
for (var i = 0; i < ruleName.length; i++) {
|
||||
var char = ruleName[i];
|
||||
|
||||
if (char === 'A') {
|
||||
if (prevGroup !== 'A') {
|
||||
var aLen = 0;
|
||||
var j = i;
|
||||
while (j < ruleName.length && ruleName[j] === 'A') {
|
||||
aLen++;
|
||||
j++;
|
||||
}
|
||||
if (aLen === 1) {
|
||||
regex += "(\\d)";
|
||||
} else {
|
||||
regex += "(\\d)\\1{" + (aLen - 1) + "}";
|
||||
}
|
||||
prevGroup = 'A';
|
||||
}
|
||||
} else if (char === 'B') {
|
||||
if (prevGroup !== 'B') {
|
||||
var bLen = 0;
|
||||
var j = i;
|
||||
while (j < ruleName.length && ruleName[j] === 'B') {
|
||||
bLen++;
|
||||
j++;
|
||||
}
|
||||
regex += "(\\d{" + bLen + "})";
|
||||
prevGroup = 'B';
|
||||
}
|
||||
} else if (char === 'X') {
|
||||
regex += "\\d";
|
||||
prevGroup = 'X';
|
||||
} else if (char >= '0' && char <= '9') {
|
||||
regex += char;
|
||||
prevGroup = 'N';
|
||||
} else if (char >= 'A' && char <= 'H') {
|
||||
// C-H 也当作连续数字处理
|
||||
if (prevGroup !== 'CONSECUTIVE') {
|
||||
var cLen = 0;
|
||||
var j = i;
|
||||
while (j < ruleName.length) {
|
||||
var c = ruleName[j];
|
||||
if (c >= 'A' && c <= 'H') {
|
||||
cLen++;
|
||||
j++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
regex += "(\\d{" + cLen + "})";
|
||||
prevGroup = 'CONSECUTIVE';
|
||||
i = j - 1;
|
||||
}
|
||||
} else {
|
||||
return { valid: false, message: '规则名称只能包含A-H、X和数字' };
|
||||
}
|
||||
}
|
||||
|
||||
regex += "$";
|
||||
|
||||
try {
|
||||
new RegExp(regex);
|
||||
} catch(e) {
|
||||
return { valid: false, message: '生成的正则表达式无效: ' + regex };
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
rulePattern: regex
|
||||
};
|
||||
}
|
||||
|
||||
window.generateRegex = function() {
|
||||
var ruleName = $('#ruleNameInput').val().toUpperCase().trim();
|
||||
if (ruleName) {
|
||||
var result = generateRegexPattern(ruleName);
|
||||
if (result.valid) {
|
||||
$('#rulePatternInput').val(result.rulePattern);
|
||||
}
|
||||
} else {
|
||||
$('#rulePatternInput').val('');
|
||||
}
|
||||
};
|
||||
|
||||
window.generateEditRegex = function() {
|
||||
var ruleName = $('#editRuleNameInput').val().toUpperCase().trim();
|
||||
if (ruleName) {
|
||||
var result = generateRegexPattern(ruleName);
|
||||
if (result.valid) {
|
||||
$('#editRulePatternInput').val(result.rulePattern);
|
||||
}
|
||||
} else {
|
||||
$('#editRulePatternInput').val('');
|
||||
}
|
||||
};
|
||||
|
||||
table.on('edit(LAY-rules-manage)', function(obj){
|
||||
var field = obj.field;
|
||||
var value = obj.value;
|
||||
var data = obj.data;
|
||||
|
||||
if (!isNaN(value) && value !== '') {
|
||||
if (field === 'price' || field === 'sort') {
|
||||
data[field] = parseInt(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (field === 'ruleName') {
|
||||
data.rulePattern = value;
|
||||
renderTable();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
loadRules();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,59 @@
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-admin" style="padding: 20px 30px 0 0;">
|
||||
<input type="hidden" name="id">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务编号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="number" placeholder="" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务描述</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="remark" placeholder="" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务类型</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="taskType">
|
||||
<option value="1">每日任务</option>
|
||||
<option value="2">在线时长</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务事件</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="taskEvent">
|
||||
<option value="1">整点在线奖励</option>
|
||||
<option value="2">在线时长</option>
|
||||
<option value="3">捕获任意鱼</option>
|
||||
<option value="4">捕获黄金鱼</option>
|
||||
<option value="5">捕获Boss鱼</option>
|
||||
<option value="6">赢取金币</option>
|
||||
<option value="7">使用狂暴</option>
|
||||
<option value="8">开炮任务</option>
|
||||
<option value="9">登录任务</option>
|
||||
<option value="10">充值任务</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">任务条件</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="taskCount" placeholder="" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">战令经验</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="exp" placeholder="" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-back-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,231 @@
|
||||
|
||||
<title>任务管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏配置</cite></a>
|
||||
<a><cite>任务管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-taskadmin-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="state">
|
||||
<option value="-1">全部</option>
|
||||
<option value="1">启用</option>
|
||||
<option value="2">禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">任务类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="taskType">
|
||||
<option value="-1">全部</option>
|
||||
<option value="1">每日任务</option>
|
||||
<option value="2">在线时长</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">任务事件</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="taskEvent">
|
||||
<option value="-1">全部</option>
|
||||
<option value="1">整点在线奖励</option>
|
||||
<option value="2">在线时长</option>
|
||||
<option value="3">捕获任意鱼</option>
|
||||
<option value="4">捕获黄金鱼</option>
|
||||
<option value="5">捕获Boss鱼</option>
|
||||
<option value="6">赢取金币</option>
|
||||
<option value="7">使用狂暴</option>
|
||||
<option value="8">开炮任务</option>
|
||||
<option value="9">登录任务</option>
|
||||
<option value="10">充值任务</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="layui-btn layuiadmin-btn-admin" data-type="add">添加</button>
|
||||
</div>
|
||||
|
||||
<table id="LAY-task-back-manage" lay-filter="LAY-task-back-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-taskadmin-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="state"><i class="layui-icon layui-icon-edit"></i>状态</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
layui.use('task', layui.factory('task')).use(['admin','task', 'table'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, view = layui.view
|
||||
, table = layui.table
|
||||
, setter = layui.setter
|
||||
, form = layui.form;
|
||||
|
||||
|
||||
form.render('select'); //刷新select选择框渲染
|
||||
form.on('select', function (data) {
|
||||
var data1 = form.val("layadmin-taskadmin-formlist");
|
||||
data1.state = parseInt(data1.state);
|
||||
data1.taskType = parseInt(data1.taskType);
|
||||
data1.taskEvent = parseInt(data1.taskEvent);
|
||||
table.reload('LAY-task-back-manage', {
|
||||
where: data1
|
||||
});
|
||||
});
|
||||
//监听搜索
|
||||
form.on('submit(LAY-user-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
|
||||
//执行重载
|
||||
table.reload('LAY-task-back-manage', {
|
||||
where: field
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(LAY-task-back-manage)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
admin.popup({
|
||||
title: '编辑任务'
|
||||
, area: ["500px", "600px"]
|
||||
, id: 'LAY-popup-user-edit'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('config/TaskForm').done(function () {
|
||||
form.val('layuiadmin-form-admin', {
|
||||
id: data.id || '',
|
||||
number: data.number || '',
|
||||
remark: data.remark || '',
|
||||
taskType: data.taskType || 1,
|
||||
taskEvent: data.taskEvent || 1,
|
||||
taskCount: data.taskCount || 0,
|
||||
exp: data.exp || 0,
|
||||
state: data.state || 1
|
||||
});
|
||||
form.render(null, 'layuiadmin-form-admin');
|
||||
form.on('submit(LAY-user-back-submit)', function (formData) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/task/UpdateTask",
|
||||
async: false,
|
||||
data: JSON.stringify(formData.field),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layui.table.reload('LAY-task-back-manage');
|
||||
layer.close(index);
|
||||
} else {
|
||||
layer.msg(res.info || '操作失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除吗?', function (index) {
|
||||
admin.req({
|
||||
url: setter.baseurl + "adminapi/task/DeleteTask",
|
||||
data: { id: data.id },
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
obj.del();
|
||||
layer.close(index);
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (obj.event === 'state') {
|
||||
var newState = data.state === 1 ? 2 : 1;
|
||||
admin.req({
|
||||
url: setter.baseurl + "adminapi/task/UpdateTaskState",
|
||||
data: { id: data.id, state: newState },
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
obj.update({ state: newState });
|
||||
} else {
|
||||
layer.msg(res.info || '状态更新失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//事件
|
||||
var active = {
|
||||
add: function () {
|
||||
|
||||
admin.popup({
|
||||
title: '添加任务'
|
||||
, area: ["500px", "600px"]
|
||||
, id: 'LAY-popup-user-add'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('config/TaskForm').done(function () {
|
||||
form.render(null, 'layuiadmin-form-admin');
|
||||
|
||||
//监听提交
|
||||
form.on('submit(LAY-user-back-submit)', function (data) {
|
||||
|
||||
console.log(data.field)
|
||||
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/task/AddTask",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(data.field),
|
||||
done: function (res) {
|
||||
|
||||
//$.ajax({});
|
||||
layui.table.reload('LAY-task-back-manage'); //重载表格
|
||||
layer.close(index); //执行关闭
|
||||
}
|
||||
})
|
||||
//提交 Ajax 成功后,关闭当前弹层并重载表格
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$('.layui-btn.layuiadmin-btn-admin').on('click', function () {
|
||||
|
||||
var type = $(this).data('type');
|
||||
active[type] ? active[type].call(this) : '';
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,254 @@
|
||||
|
||||
<title>聊天记录</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a lay-href="customer/conversation"><cite>会话列表</cite></a>
|
||||
<a><cite>聊天记录</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<span id="conversation-title">聊天记录</span>
|
||||
<div>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" onclick="deleteAllMessages()">清空记录</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-chatlog-manage" lay-filter="LAY-chatlog-manage"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-chatlog">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="deleteSelected">批量删除</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-chatlog-toolbar">
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function getParameterByName(name) {
|
||||
// 优先从 hash 中查找
|
||||
var hash = window.location.hash;
|
||||
if (hash && hash.includes('?')) {
|
||||
var searchPart = hash.substring(hash.indexOf('?'));
|
||||
var params = new URLSearchParams(searchPart);
|
||||
return params.get(name);
|
||||
}
|
||||
|
||||
// 如果 hash 中没有,再从主 URL 查找
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
return params.get(name);
|
||||
}
|
||||
|
||||
layui.use(['admin', 'table'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
setter = layui.setter;
|
||||
|
||||
// 获取URL参数
|
||||
var conversationId = getParameterByName('conversationId') || '';
|
||||
var userName = getParameterByName('userName') || '';
|
||||
var customerName = getParameterByName('customerName') || '';
|
||||
|
||||
console.log(conversationId)
|
||||
// 设置标题
|
||||
document.getElementById('conversation-title').textContent = '聊天记录 - ' + userName + ' 与 ' + customerName;
|
||||
|
||||
console.log('conversationId:', conversationId);
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-chatlog-manage",
|
||||
url: setter.baseurl + "adminapi/customer/chatlog/" + conversationId,
|
||||
method: "get",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: false,
|
||||
toolbar: '#toolbar-chatlog',
|
||||
defaultToolbar: [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{
|
||||
field: "senderType",
|
||||
title: "发送者",
|
||||
width: 100,
|
||||
templet: function(d) {
|
||||
return d.senderType == 1 ? '<span class="layui-badge layui-bg-blue">用户</span>' : '<span class="layui-badge">客服</span>';
|
||||
}
|
||||
},
|
||||
{ field: "senderName", title: "发送者名称", width: 150 },
|
||||
{
|
||||
field: "contentType",
|
||||
title: "类型",
|
||||
width: 100,
|
||||
templet: function(d) {
|
||||
return d.contentType == 1 ? '<span class="layui-badge layui-bg-green">文字</span>' : '<span class="layui-badge">图片</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: "content",
|
||||
title: "内容",
|
||||
templet: function(d) {
|
||||
if (d.contentType == 2) {
|
||||
return '<img src="' + d.content + '" style="max-width:200px;max-height:100px;cursor:pointer;" lay-event="viewImage">';
|
||||
}
|
||||
return d.content || '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: "createTime",
|
||||
title: "发送时间",
|
||||
width: 180,
|
||||
templet: function(d) {
|
||||
return d.createTime ? formatTimestamp(d.createTime) : '-';
|
||||
}
|
||||
},
|
||||
{ title: "操作", width: 100, align: "center", fixed: "right", toolbar: "#table-chatlog-toolbar" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
// 点击图片查看大图
|
||||
table.on('tool(LAY-chatlog-manage)', function(e) {
|
||||
if (e.event === 'viewImage') {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '图片预览',
|
||||
area: ['800px', '600px'],
|
||||
content: '<div style="text-align:center;padding:20px;"><img src="' + e.data.content + '" style="max-width:100%;max-height:100%;"></div>'
|
||||
});
|
||||
}
|
||||
if (e.event === 'delete') {
|
||||
layer.confirm("确定删除此消息吗?", function(index) {
|
||||
admin.req({
|
||||
method: "delete",
|
||||
url: setter.baseurl + "adminapi/customer/message/" + e.data.id,
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload("LAY-chatlog-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
table.on('toolbar(LAY-chatlog-manage)', function(obj) {
|
||||
var checkStatus = table.checkStatus(obj.config.id);
|
||||
if (obj.event === 'deleteSelected') {
|
||||
var data = checkStatus.data;
|
||||
if (data.length === 0) {
|
||||
layer.msg('请选择要删除的消息');
|
||||
return;
|
||||
}
|
||||
layer.confirm("确定删除选中的 " + data.length + " 条消息吗?", function(index) {
|
||||
var ids = data.map(function(d) { return d.id; });
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/customer/messages/delete-batch",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
data: JSON.stringify({ ids: ids }),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload("LAY-chatlog-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 清空所有记录
|
||||
window.deleteAllMessages = function() {
|
||||
if (!conversationId) {
|
||||
layer.msg('无效的会话ID');
|
||||
return;
|
||||
}
|
||||
layer.confirm("确定清空此会话的所有聊天记录吗?此操作不可恢复!", function(index) {
|
||||
admin.req({
|
||||
method: "delete",
|
||||
url: setter.baseurl + "adminapi/customer/messages/" + conversationId,
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('清空成功');
|
||||
table.reload("LAY-chatlog-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '清空失败');
|
||||
}
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 时间戳格式化
|
||||
function formatTimestamp(timestamp) {
|
||||
if (!timestamp) return '-';
|
||||
// 处理时间戳,可能是字符串或数字
|
||||
var date;
|
||||
if (typeof timestamp === 'string') {
|
||||
// 如果是ISO格式字符串,直接解析
|
||||
date = new Date(timestamp);
|
||||
} else {
|
||||
// 如果是时间戳,假设是毫秒级别
|
||||
date = new Date(timestamp);
|
||||
}
|
||||
|
||||
// 转换为北京时间 (UTC+8)
|
||||
var utc = date.getTime() + (date.getTimezoneOffset() * 60000);
|
||||
var beijingDate = new Date(utc + (3600000 * 8));
|
||||
|
||||
var o = {
|
||||
'M+': beijingDate.getMonth() + 1,
|
||||
'd+': beijingDate.getDate(),
|
||||
'h+': beijingDate.getHours(),
|
||||
'm+': beijingDate.getMinutes(),
|
||||
's+': beijingDate.getSeconds()
|
||||
};
|
||||
var format = 'yyyy-MM-dd hh:mm:ss';
|
||||
if (/(y+)/.test(format)) {
|
||||
format = format.replace(RegExp.$1, (beijingDate.getFullYear() + '').substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp('(' + k + ')').test(format)) {
|
||||
format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return format;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,215 @@
|
||||
|
||||
<title>会话管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>客服管理</cite></a>
|
||||
<a><cite>会话列表</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-conversation-formlist">
|
||||
<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="userId" 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="customerId" placeholder="请输入客服ID" autocomplete="off" class="layui-input">
|
||||
</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="0">等待中</option>
|
||||
<option value="1">进行中</option>
|
||||
<option value="2">已结束</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-conversation" lay-submit lay-filter="LAY-conversation-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-conversation-front-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<table id="LAY-conversation-manage" lay-filter="LAY-conversation-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-conversation-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="chatlog"><i class="layui-icon layui-icon-log"></i>聊天记录</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
view = layui.view,
|
||||
table = layui.table,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter,
|
||||
form = layui.form,
|
||||
customerApiUrl = setter.customerApiUrl || setter.baseurl;
|
||||
|
||||
form.render(null, 'layadmin-conversation-formlist');
|
||||
|
||||
//监听搜索
|
||||
form.on('submit(LAY-conversation-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
//执行重载
|
||||
table.reload('LAY-conversation-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 监听重置
|
||||
$('.layui-btn-group').on('click', '[lay-event="refresh"]', function () {
|
||||
table.reload('LAY-conversation-manage');
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-conversation-manage",
|
||||
url: customerApiUrl + "customerapi/customer/conversations",
|
||||
method: "get",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
where: {
|
||||
userId: "",
|
||||
customerId: "",
|
||||
status: ""
|
||||
},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ field: "userName", title: "用户名称", width: 150 },
|
||||
{ field: "userId", title: "用户ID", width: 200 },
|
||||
{ field: "customerName", title: "客服名称", width: 150 },
|
||||
{ field: "customerId", title: "客服ID", width: 200 },
|
||||
{
|
||||
field: "status",
|
||||
title: "状态",
|
||||
width: 100,
|
||||
templet: function(d) {
|
||||
var statusMap = {
|
||||
0: '<span class="layui-badge">等待中</span>',
|
||||
1: '<span class="layui-badge layui-bg-green">进行中</span>',
|
||||
2: '<span class="layui-badge layui-bg-gray">已结束</span>'
|
||||
};
|
||||
return statusMap[d.status] || '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: "createTime",
|
||||
title: "创建时间",
|
||||
width: 180,
|
||||
templet: function(d) {
|
||||
return d.createTime ? formatTimestamp(d.createTime) : '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: "endTime",
|
||||
title: "结束时间",
|
||||
width: 180,
|
||||
templet: function(d) {
|
||||
return d.endTime ? formatTimestamp(d.endTime) : '-';
|
||||
}
|
||||
},
|
||||
{ width: 190, title: "操作", align: "center", fixed: "right", toolbar: "#table-conversation-admin" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
// 监听工具条
|
||||
table.on("tool(LAY-conversation-manage)", function (e) {
|
||||
var l = e.data;
|
||||
|
||||
if ("chatlog" === e.event) {
|
||||
// 打开新页面查看聊天记录
|
||||
var url = 'customer/chatlog.html?conversationId=' + l.id + '&userName=' + encodeURIComponent(l.userName || '') + '&customerName=' + encodeURIComponent(l.customerName || '');
|
||||
window.location.hash = '/' + url;
|
||||
} else if ("delete" === e.event) {
|
||||
layer.confirm('确定删除该会话及全部聊天记录吗?此操作不可恢复。', function(index) {
|
||||
admin.req({
|
||||
method: 'delete',
|
||||
// 删除属于后台管理操作,必须走带鉴权的 AdminApi。
|
||||
url: setter.baseurl + 'adminapi/Customer/conversation/' + encodeURIComponent(l.id),
|
||||
done: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
e.del();
|
||||
layer.close(index);
|
||||
layer.msg(res.info || '删除成功');
|
||||
table.reload('LAY-conversation-manage');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 时间戳格式化
|
||||
function formatTimestamp(timestamp) {
|
||||
if (!timestamp) return '-';
|
||||
var date = new Date(timestamp);
|
||||
var o = {
|
||||
'M+': date.getMonth() + 1,
|
||||
'd+': date.getDate(),
|
||||
'h+': date.getHours(),
|
||||
'm+': date.getMinutes(),
|
||||
's+': date.getSeconds()
|
||||
};
|
||||
var format = 'yyyy-MM-dd hh:mm:ss';
|
||||
if (/(y+)/.test(format)) {
|
||||
format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp('(' + k + ')').test(format)) {
|
||||
format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return format;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,452 @@
|
||||
|
||||
<title>客服管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>客服管理</cite></a>
|
||||
<a><cite>客服列表</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-customer-formlist">
|
||||
<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" placeholder="请输入客服名称" autocomplete="off" class="layui-input">
|
||||
</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="0">离线</option>
|
||||
<option value="1">在线</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-customer" lay-submit lay-filter="LAY-customer-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-customer-front-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add">
|
||||
<i class="layui-icon layui-icon-add-1"></i> 添加客服
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<table id="LAY-customer-manage" lay-filter="LAY-customer-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-customer-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.avatar-upload-box { position: relative; display: inline-block; }
|
||||
.avatar-upload-box .upload-btn { position: absolute; top: 0; left: 0; width: 80px; height: 80px; opacity: 0; cursor: pointer; }
|
||||
.avatar-upload-preview { width: 80px; height: 80px; border: 1px dashed #ddd; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: #fafafa; cursor: pointer; overflow: hidden; }
|
||||
.avatar-upload-preview:hover { border-color: #009688; }
|
||||
.avatar-upload-preview img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.avatar-upload-preview .placeholder { color: #999; font-size: 12px; text-align: center; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
view = layui.view,
|
||||
table = layui.table,
|
||||
setter = layui.setter,
|
||||
form = layui.form,
|
||||
layer = layui.layer;
|
||||
|
||||
form.render(null, 'layadmin-customer-formlist');
|
||||
|
||||
//监听搜索
|
||||
form.on('submit(LAY-customer-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
//执行重载
|
||||
table.reload('LAY-customer-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 监听重置
|
||||
$('.layui-btn-group').on('click', '[lay-event="refresh"]', function () {
|
||||
table.reload('LAY-customer-manage');
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-customer-manage",
|
||||
url: setter.baseurl + "adminapi/customer/list",
|
||||
method: "get",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
where: {
|
||||
userName: "",
|
||||
status: ""
|
||||
},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ field: "userName", title: "客服名称", width: 150 },
|
||||
{ field: "userId", title: "客服ID", width: 200 },
|
||||
{
|
||||
field: "avatar",
|
||||
title: "头像",
|
||||
width: 100,
|
||||
templet: function(d) {
|
||||
return d.avatar ? '<img src="' + d.avatar + '" style="width:40px;height:40px;">' : '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: "status",
|
||||
title: "状态",
|
||||
width: 100,
|
||||
templet: function(d) {
|
||||
return d.status == 1 ? '<span class="layui-badge layui-bg-green">在线</span>' : '<span class="layui-badge">离线</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: "createTime",
|
||||
title: "创建时间",
|
||||
width: 180,
|
||||
templet: function(d) {
|
||||
return d.createTime ? formatTimestamp(d.createTime) : '-';
|
||||
}
|
||||
},
|
||||
{ width: 180, title: "操作", align: "center", fixed: "right", toolbar: "#table-customer-admin" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
// 监听工具条
|
||||
table.on("tool(LAY-customer-manage)", function (e) {
|
||||
var l = e.data;
|
||||
|
||||
if ("del" === e.event) {
|
||||
layer.confirm("确定删除此客服吗?", function (i) {
|
||||
admin.req({
|
||||
method: "delete",
|
||||
url: setter.baseurl + "adminapi/customer/" + e.data.id,
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
e.del();
|
||||
layer.close(i);
|
||||
layer.msg('删除成功');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ("edit" === e.event) {
|
||||
var avatarHtml = l.avatar
|
||||
? '<img src="' + l.avatar + '" style="width:100%;height:100%;">'
|
||||
: '<div class="placeholder">点击上传</div>';
|
||||
admin.popup({
|
||||
title: "编辑客服",
|
||||
area: ["500px", "450px"],
|
||||
id: "LAY-popup-customer-edit",
|
||||
success: function (div, idx) {
|
||||
$(div).html(
|
||||
'<form class="layui-form" style="padding: 20px;" lay-filter="layuiadmin-form-customer">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">客服名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="userName" class="layui-input" value="' + (l.userName || '') + '" required>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">头像</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="avatar-upload-box">' +
|
||||
'<div class="avatar-upload-preview" id="avatarPreview">' + avatarHtml + '</div>' +
|
||||
'<input type="file" class="upload-btn" accept="image/*" id="avatarUpload">' +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="avatar" id="avatarInput" value="' + (l.avatar || '') + '">' +
|
||||
'<div style="margin-top:8px;color:#999;font-size:12px;">点击图片可预览,支持jpg、png格式</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">状态</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="status">' +
|
||||
'<option value="0" ' + (l.status == 0 ? 'selected' : '') + '>离线</option>' +
|
||||
'<option value="1" ' + (l.status == 1 ? 'selected' : '') + '>在线</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="LAY-customer-edit-submit">提交</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>'
|
||||
);
|
||||
form.render(null, "layuiadmin-form-customer");
|
||||
|
||||
var $preview = $('#avatarPreview');
|
||||
var $input = $('#avatarInput');
|
||||
var $fileInput = $('#avatarUpload');
|
||||
|
||||
$preview.on('click', function() {
|
||||
var url = $input.val();
|
||||
if (url) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '头像预览',
|
||||
area: ['auto', 'auto'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:20px;text-align:center;"><img src="' + url + '" style="max-width:300px;max-height:300px;border-radius:50%;"></div>'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (file) {
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/temp',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
success: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
var path = res.data.path;
|
||||
$input.val(path);
|
||||
$preview.html('<img src="' + path + '" style="width:100%;height:100%;">');
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('上传失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on("submit(LAY-customer-edit-submit)", function (data) {
|
||||
var param = {
|
||||
id: l.id,
|
||||
userName: data.field.userName,
|
||||
avatar: data.field.avatar,
|
||||
status: parseInt(data.field.status)
|
||||
};
|
||||
admin.req({
|
||||
method: "put",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/customer",
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(idx);
|
||||
layer.msg('修改成功');
|
||||
table.reload("LAY-customer-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '修改失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 添加客服
|
||||
$('.layui-btn-group').on('click', '[lay-event="add"]', function () {
|
||||
admin.popup({
|
||||
title: "添加客服",
|
||||
area: ["500px", "450px"],
|
||||
id: "LAY-popup-customer-add",
|
||||
success: function (div, idx) {
|
||||
$(div).html(
|
||||
'<form class="layui-form" style="padding: 20px;" lay-filter="layuiadmin-form-customer-add">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">客服ID</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="userId" id="userIdInput" class="layui-input" placeholder="请输入客服用户ID" required>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">客服名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="userName" class="layui-input" placeholder="请输入客服名称" required>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">头像</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="avatar-upload-box">' +
|
||||
'<div class="avatar-upload-preview" id="avatarPreviewAdd">' +
|
||||
'<div class="placeholder">点击上传</div>' +
|
||||
'</div>' +
|
||||
'<input type="file" class="upload-btn" accept="image/*" id="avatarUploadAdd">' +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="avatar" id="avatarInputAdd" value="">' +
|
||||
'<div style="margin-top:8px;color:#999;font-size:12px;">点击图片可预览,支持jpg、png格式</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="LAY-customer-add-submit">添加</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>'
|
||||
);
|
||||
form.render(null, "layuiadmin-form-customer-add");
|
||||
|
||||
var $preview = $('#avatarPreviewAdd');
|
||||
var $input = $('#avatarInputAdd');
|
||||
var $fileInput = $('#avatarUploadAdd');
|
||||
|
||||
$preview.on('click', function() {
|
||||
var url = $input.val();
|
||||
if (url) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '头像预览',
|
||||
area: ['auto', 'auto'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:20px;text-align:center;"><img src="' + url + '" style="max-width:300px;max-height:300px;border-radius:50%;"></div>'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (file) {
|
||||
var userId = $('#userIdInput').val() || ('new_' + Date.now());
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/temp',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
success: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
var path = res.data.path;
|
||||
$input.val(path);
|
||||
$preview.html('<img src="' + path + '" style="width:100%;height:100%;">');
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('上传失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.on("submit(LAY-customer-add-submit)", function (data) {
|
||||
var param = {
|
||||
userId: data.field.userId,
|
||||
userName: data.field.userName,
|
||||
avatar: data.field.avatar
|
||||
};
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/customer",
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(idx);
|
||||
layer.msg('添加成功');
|
||||
table.reload("LAY-customer-manage");
|
||||
} else {
|
||||
layer.msg(res.info || '添加失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 时间戳格式化
|
||||
function formatTimestamp(timestamp) {
|
||||
if (!timestamp) return '-';
|
||||
var date = new Date(timestamp);
|
||||
var o = {
|
||||
'M+': date.getMonth() + 1,
|
||||
'd+': date.getDate(),
|
||||
'h+': date.getHours(),
|
||||
'm+': date.getMinutes(),
|
||||
's+': date.getSeconds()
|
||||
};
|
||||
var format = 'yyyy-MM-dd hh:mm:ss';
|
||||
if (/(y+)/.test(format)) {
|
||||
format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp('(' + k + ')').test(format)) {
|
||||
format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return format;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,238 @@
|
||||
|
||||
<title>邮件管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>用户</cite></a>
|
||||
<a><cite>邮件管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-emaillist-filter">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">关键词</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="userNumber" placeholder="编号/昵称/标题/内容" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">已读状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="readStatus">
|
||||
<option value="">全部</option>
|
||||
<option value="1">已读</option>
|
||||
<option value="2">未读</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">领取状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="rewardStatus">
|
||||
<option value="">全部</option>
|
||||
<option value="1">已领取</option>
|
||||
<option value="2">未领取</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">发送时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="timeRange" id="timeRange" placeholder="选择时间范围" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-list" lay-submit lay-filter="LAY-emaillist-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-emaillist-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-emaillist-manage" lay-filter="LAY-emaillist-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-emaillist-toolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="batchdel">
|
||||
<i class="layui-icon layui-icon-delete"></i> 批量删除
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-emaillist-bar">
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="isReadTpl">
|
||||
{{# if(d.isRead){ }}
|
||||
<span class="layui-badge layui-bg-blue">已读</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-gray">未读</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="isRewardTpl">
|
||||
{{# if(d.isReward){ }}
|
||||
<span class="layui-badge layui-bg-green">已领取</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-orange">未领取</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'laydate'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
laydate = layui.laydate,
|
||||
setter = layui.setter;
|
||||
|
||||
laydate.render({
|
||||
elem: '#timeRange',
|
||||
type: 'datetime',
|
||||
range: '~'
|
||||
});
|
||||
|
||||
form.render(null, 'layadmin-emaillist-filter');
|
||||
|
||||
form.on('submit(LAY-emaillist-search)', function (data) {
|
||||
var field = data.field;
|
||||
if (field.timeRange) {
|
||||
var times = field.timeRange.split('~');
|
||||
field.startTime = new Date(times[0].trim()).getTime();
|
||||
field.endTime = new Date(times[1].trim()).getTime();
|
||||
}
|
||||
delete field.timeRange;
|
||||
if (field.readStatus) field.readStatus = parseInt(field.readStatus);
|
||||
if (field.rewardStatus) field.rewardStatus = parseInt(field.rewardStatus);
|
||||
|
||||
table.reload('LAY-emaillist-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
form.on('submit(LAY-emaillist-reset)', function () {
|
||||
$('input[name="userNumber"]').val('');
|
||||
$('select[name="readStatus"]').val('');
|
||||
$('select[name="rewardStatus"]').val('');
|
||||
$('input[name="timeRange"]').val('');
|
||||
form.render('select');
|
||||
table.reload('LAY-emaillist-manage', {
|
||||
where: {},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-emaillist-manage",
|
||||
url: setter.baseurl + "adminapi/AdminUser/GetEmailList",
|
||||
method: "post",
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
toolbar: '#table-emaillist-toolbar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "userId", title: "用户ID", width: 280 },
|
||||
{ field: "userName", title: "用户昵称", width: 120, templet: function(d) { return d.userName || '-'; } },
|
||||
{ field: "userNumber", title: "用户编号", width: 120, templet: function(d) { return d.userNumber || '-'; } },
|
||||
{ field: "title", title: "邮件标题", minWidth: 200 },
|
||||
{ field: "rewardText", title: "奖励内容", width: 180 },
|
||||
{ field: "isRead", title: "已读", width: 70, templet: '#isReadTpl' },
|
||||
{ field: "isReward", title: "领取", width: 80, templet: '#isRewardTpl' },
|
||||
{ field: "sendTime", title: "发送时间", width: 160, templet: function(d) {
|
||||
if (!d.sendTime) return '-';
|
||||
var dt = new Date(d.sendTime * 1000);
|
||||
return dt.getFullYear() + '-' + pad(dt.getMonth()+1) + '-' + pad(dt.getDate()) + ' ' + pad(dt.getHours()) + ':' + pad(dt.getMinutes()) + ':' + pad(dt.getSeconds());
|
||||
}},
|
||||
{ width: 80, title: "操作", align: "center", fixed: "right", toolbar: "#table-emaillist-bar" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
function pad(n) { return (n < 10 ? '0' : '') + n; }
|
||||
|
||||
table.on("tool(LAY-emaillist-manage)", function (e) {
|
||||
var l = e.data;
|
||||
if ("del" === e.event) {
|
||||
layer.confirm('确定删除该邮件吗?', function (idx) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/AdminUser/DeleteEmail?id=' + l.id,
|
||||
method: 'get',
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
table.reload('LAY-emaillist-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
table.on('toolbar(LAY-emaillist-manage)', function (obj) {
|
||||
if (obj.event === 'batchdel') {
|
||||
var checkStatus = table.checkStatus('LAY-emaillist-manage');
|
||||
var data = checkStatus.data;
|
||||
if (data.length === 0) return layer.msg('请选择要删除的数据');
|
||||
layer.confirm('确定删除选中的 ' + data.length + ' 条邮件吗?', function (idx) {
|
||||
var ids = data.map(function (item) { return item.id; });
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/AdminUser/BatchDeleteEmail',
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify(ids),
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.info || '删除成功');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
table.reload('LAY-emaillist-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,646 @@
|
||||
<title>战令配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>战令配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">基础配置</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="bo-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">是否开启</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="isOpen" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">结束时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="endTime" id="endTime" class="layui-input" placeholder="选择日期时间">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">规则描述</label>
|
||||
<div class="layui-input-inline" style="width:400px;">
|
||||
<input type="text" name="ruleDesc" class="layui-input" placeholder="规则描述">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">购买描述</label>
|
||||
<div class="layui-input-inline" style="width:400px;">
|
||||
<input type="text" name="buyDesc" class="layui-input" placeholder="购买描述">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">进阶描述</label>
|
||||
<div class="layui-input-inline" style="width:400px;">
|
||||
<input type="text" name="advanceGiftDesc" class="layui-input" placeholder="进阶奖励描述">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="save-base">保存基础配置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">等级配置</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-container" style="margin-bottom:10px;">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-level"><i class="layui-icon layui-icon-refresh"></i> 初始化</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-level"><i class="layui-icon layui-icon-add-1"></i> 添加等级</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-levels"><i class="layui-icon layui-icon-ok"></i> 保存</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveAct('BattleOrderConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
<table id="table-level" lay-filter="table-level"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">进阶配置</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-container" style="margin-bottom:10px;">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-advance"><i class="layui-icon layui-icon-refresh"></i> 初始化</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-advance"><i class="layui-icon layui-icon-add-1"></i> 添加进阶</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-advances"><i class="layui-icon layui-icon-ok"></i> 保存</button>
|
||||
</div>
|
||||
<table id="table-advance" lay-filter="table-advance"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="bar-level">
|
||||
<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>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="bar-advance">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="reward">奖励</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-payType">
|
||||
{{# var m = {1:'金币',2:'钻石',3:'现金'}; }}
|
||||
{{= m[d.payType] || '金币' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-advance-type">
|
||||
{{# var m = {1:'豪华',2:'至尊',3:'豪华+至尊'}; }}
|
||||
{{= m[d.type] || '豪华' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="reward-dialog-tpl">
|
||||
<div class="reward-tabs" style="padding:10px;">
|
||||
<div class="layui-tab" lay-filter="reward-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">普通奖励</li>
|
||||
<li>豪华奖励</li>
|
||||
<li>至尊奖励</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="height:480px;">
|
||||
<div class="layui-tab-item layui-show" data-key="normalGiftList"></div>
|
||||
<div class="layui-tab-item" data-key="luxuryGiftList"></div>
|
||||
<div class="layui-tab-item" data-key="supremeGiftList"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="gift-editor-tpl">
|
||||
<div class="gift-container">
|
||||
<div class="gift-left">
|
||||
<div class="gift-toolbar">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add-gift"><i class="layui-icon layui-icon-add-1"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete-gift"><i class="layui-icon layui-icon-delete"></i> 删除</button>
|
||||
</div>
|
||||
<div class="gift-table-wrap"><table id="table-gift-list"></table></div>
|
||||
</div>
|
||||
<div class="gift-right">
|
||||
<h4>礼包项详情</h4>
|
||||
<div class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select id="giftType" lay-filter="giftType">
|
||||
<option value="1">金币</option>
|
||||
<option value="2">钻石</option>
|
||||
<option value="3">道具</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数量</label>
|
||||
<div class="layui-input-block"><input type="number" id="giftCount" class="layui-input" placeholder="数量"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">随机</label>
|
||||
<div class="layui-input-block"><input type="checkbox" id="giftIsRandom" lay-skin="switch" lay-text="是|否"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最小值</label>
|
||||
<div class="layui-input-block"><input type="number" id="giftMinCount" class="layui-input" placeholder="最小值"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最大值</label>
|
||||
<div class="layui-input-block"><input type="number" id="giftMaxCount" class="layui-input" placeholder="最大值"></div>
|
||||
</div>
|
||||
<div class="layui-form-item gift-prop-select" style="display:none;">
|
||||
<label class="layui-form-label">道具编号</label>
|
||||
<div class="layui-input-block"><input type="text" id="giftProductNumber" class="layui-input" placeholder="输入道具编号"></div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-top:10px;">
|
||||
<button class="layui-btn layui-btn-normal" id="btn-save-gift" style="width:100%;">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer', 'laydate', 'element', 'upload'], function () {
|
||||
var $ = layui.$, admin = layui.admin, table = layui.table, form = layui.form,
|
||||
layer = layui.layer, laydate = layui.laydate, setter = layui.setter, element = layui.element, upload = layui.upload;
|
||||
|
||||
var activityConfig = null;
|
||||
var rewardCtx = null; // { giftList, title }
|
||||
|
||||
setTimeout(function() {
|
||||
$('.layui-layer-shade').remove(); layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
laydate.render({ elem: '#endTime', type: 'datetime' });
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({ method: 'get', url: setter.baseurl + 'adminapi/ActivityConfig/Get',
|
||||
done: function(r2) {
|
||||
activityConfig = (r2.code === 0 && r2.data) ? r2.data : { battleOrderConfig: {} };
|
||||
initForm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bo() {
|
||||
if (!activityConfig.battleOrderConfig) activityConfig.battleOrderConfig = {};
|
||||
return activityConfig.battleOrderConfig;
|
||||
}
|
||||
|
||||
function initForm() {
|
||||
var b = bo();
|
||||
$('input[name="isOpen"]').prop('checked', b.isOpen);
|
||||
$('input[name="endTime"]').val(b.endTime ? new Date(b.endTime * 1000).toLocaleString() : '');
|
||||
$('input[name="ruleDesc"]').val(b.ruleDesc || '');
|
||||
$('input[name="buyDesc"]').val(b.buyDesc || '');
|
||||
$('input[name="advanceGiftDesc"]').val(b.advanceGiftDesc || '');
|
||||
form.render();
|
||||
renderLevelTable();
|
||||
renderAdvanceTable();
|
||||
}
|
||||
|
||||
function save(msg) {
|
||||
admin.req({
|
||||
method: 'post', contentType: 'application/json;charset=UTF-8',
|
||||
url: setter.baseurl + 'adminapi/ActivityConfig/UpdateBattleOrder',
|
||||
data: JSON.stringify(activityConfig.battleOrderConfig),
|
||||
done: function(r) {
|
||||
r.code === 0 ? (layer.msg(msg || '保存成功'), loadConfig()) : layer.msg(r.info || '保存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
form.on('submit(save-base)', function(d) {
|
||||
var b = bo();
|
||||
b.isOpen = d.field.isOpen === 'on';
|
||||
b.ruleDesc = d.field.ruleDesc || '';
|
||||
b.buyDesc = d.field.buyDesc || '';
|
||||
b.advanceGiftDesc = d.field.advanceGiftDesc || '';
|
||||
if (d.field.endTime) b.endTime = Math.floor(new Date(d.field.endTime).getTime() / 1000);
|
||||
save('保存成功'); return false;
|
||||
});
|
||||
|
||||
// ==================== 等级表格 ====================
|
||||
function renderLevelTable() {
|
||||
var levels = bo().levelConfig || [];
|
||||
table.render({ elem: '#table-level', data: levels, page: true,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'level', title: '等级', width: 70, sort: true },
|
||||
{ field: 'exp', title: '升级经验', width: 90 },
|
||||
{ title: '普通奖励', width: 90, templet: function(d) { return (d.normalGiftList||[]).length + '项'; } },
|
||||
{ title: '豪华奖励', width: 90, templet: function(d) { return (d.luxuryGiftList||[]).length + '项'; } },
|
||||
{ title: '至尊奖励', width: 90, templet: function(d) { return (d.supremeGiftList||[]).length + '项'; } },
|
||||
{ field: 'payType', title: '付费', width: 70, templet: '#tpl-payType' },
|
||||
{ field: 'payCount', title: '费用', width: 80 },
|
||||
{ title: '操作', width: 200, fixed: 'right', toolbar: '#bar-level' }
|
||||
]]
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 进阶表格 ====================
|
||||
function renderAdvanceTable() {
|
||||
var list = bo().advanceGift || [];
|
||||
table.render({ elem: '#table-advance', data: list, page: false,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'type', title: '类型', width: 80, templet: '#tpl-advance-type' },
|
||||
{ field: 'name', title: '名称', width: 120 },
|
||||
{ field: 'count', title: '数量', width: 80 },
|
||||
{ field: 'payType', title: '付费', width: 70, templet: '#tpl-payType' },
|
||||
{ field: 'payCount', title: '费用', width: 80 },
|
||||
{ title: '奖励', width: 80, templet: function(d) { return (d.giftList||[]).length + '项'; } },
|
||||
{ title: '操作', width: 180, fixed: 'right', toolbar: '#bar-advance' }
|
||||
]]
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 等级 CRUD ====================
|
||||
function showLevelEdit(data, isAdd) {
|
||||
var readonly = isAdd ? '' : 'readonly';
|
||||
var html = '<div style="padding:15px;"><form class="layui-form">' +
|
||||
'<div class="layui-row"><div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">等级</label><div class="layui-input-block"><input type="number" id="dlg-level" value="'+(data.level||'')+'" class="layui-input" '+readonly+'></div></div></div>' +
|
||||
'<div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">升级经验</label><div class="layui-input-block"><input type="number" id="dlg-exp" value="'+(data.exp||0)+'" class="layui-input"></div></div></div></div>' +
|
||||
'<div class="layui-row"><div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">付费类型</label><div class="layui-input-block"><select id="dlg-payType"><option value="1"'+(data.payType===1?' selected':'')+'>金币</option><option value="2"'+(data.payType===2?' selected':'')+'>钻石</option><option value="3"'+(data.payType===3?' selected':'')+'>现金</option></select></div></div></div>' +
|
||||
'<div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">付费金额</label><div class="layui-input-block"><input type="number" id="dlg-payCount" value="'+(data.payCount||0)+'" class="layui-input"></div></div></div></div>' +
|
||||
'<div style="margin-top:10px;border-top:1px solid #eee;padding-top:10px;"><div class="layui-tab" lay-filter="dlg-reward-tab"><ul class="layui-tab-title"><li class="layui-this">普通奖励</li><li>豪华奖励</li><li>至尊奖励</li></ul>' +
|
||||
'<div class="layui-tab-content" style="height:300px;padding:5px 0;">' +
|
||||
'<div class="layui-tab-item layui-show"><div class="inplace-gift" data-key="normalGiftList"></div></div>' +
|
||||
'<div class="layui-tab-item"><div class="inplace-gift" data-key="luxuryGiftList"></div></div>' +
|
||||
'<div class="layui-tab-item"><div class="inplace-gift" data-key="supremeGiftList"></div></div>' +
|
||||
'</div></div></div></form></div>';
|
||||
layer.open({ type:1, title:isAdd?'添加等级':'编辑等级', area:['850px','580px'], content:html, btn:['保存','取消'],
|
||||
success:function(l){
|
||||
form.render('select');
|
||||
element.render('tab');
|
||||
var keys = ['normalGiftList','luxuryGiftList','supremeGiftList'];
|
||||
var tgt = {};
|
||||
keys.forEach(function(k){ tgt[k] = data[k] || []; });
|
||||
renderInplaceGift(l.find('.inplace-gift[data-key="normalGiftList"]'), tgt.normalGiftList);
|
||||
element.on('tab(dlg-reward-tab)', function(o){
|
||||
var k = keys[o.index];
|
||||
var ph = l.find('.inplace-gift[data-key="'+k+'"]');
|
||||
if (ph.is(':empty')) renderInplaceGift(ph, tgt[k]);
|
||||
});
|
||||
window._dlgGiftData = tgt;
|
||||
},
|
||||
yes:function(idx,l){
|
||||
var tgt = window._dlgGiftData || {};
|
||||
var item = {
|
||||
level: parseInt(l.find('#dlg-level').val()) || data.level,
|
||||
exp: parseInt(l.find('#dlg-exp').val()) || 0,
|
||||
normalGiftList: tgt.normalGiftList || [],
|
||||
luxuryGiftList: tgt.luxuryGiftList || [],
|
||||
supremeGiftList: tgt.supremeGiftList || [],
|
||||
payType: parseInt(l.find('#dlg-payType').val()) || 1,
|
||||
payCount: parseInt(l.find('#dlg-payCount').val()) || 0
|
||||
};
|
||||
var b = bo();
|
||||
if (!b.levelConfig) b.levelConfig = [];
|
||||
if (isAdd) {
|
||||
if (b.levelConfig.some(function(x) { return x.level === item.level; }))
|
||||
{ layer.msg('等级已存在'); return; }
|
||||
b.levelConfig.push(item);
|
||||
} else {
|
||||
var i = b.levelConfig.findIndex(function(x) { return x.level === data.level; });
|
||||
if (i > -1) b.levelConfig[i] = item;
|
||||
}
|
||||
delete window._dlgGiftData;
|
||||
layer.close(idx); save(isAdd?'添加成功':'保存成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
function renderInplaceGift(container, giftList) {
|
||||
if (!giftList) giftList = [];
|
||||
var html = '<div style="margin-bottom:8px;"><button class="layui-btn layui-btn-xs layui-btn-normal btn-ip-add"><i class="layui-icon layui-icon-add-1"></i> 新增奖励项</button></div>' +
|
||||
'<table class="ip-gift-table"><thead><tr><th style="width:60px">类型</th><th style="width:60px">数量</th><th style="width:60px">最小值</th><th style="width:60px">最大值</th><th style="width:60px">随机</th><th style="width:100px">道具ID</th><th style="width:60px">操作</th></tr></thead><tbody></tbody></table>';
|
||||
container.html(html);
|
||||
var tbody = container.find('tbody');
|
||||
function renderRows(){
|
||||
tbody.empty();
|
||||
giftList.forEach(function(g,idx){
|
||||
var typeMap = {1:'金币',2:'钻石',3:'道具'};
|
||||
var tr = $('<tr><td>'+ (typeMap[g.type]||'金币') +'</td><td>'+ (g.count||0) +'</td><td>'+ (g.minCount||0) +'</td><td>'+ (g.maxCount||0) +'</td><td>'+ (g.isRandom?'是':'否') +'</td><td>'+ (g.otherId||'') +'</td><td><button class="layui-btn layui-btn-xs btn-ip-edit" data-idx="'+idx+'">编辑</button><button class="layui-btn layui-btn-xs layui-btn-danger btn-ip-del" data-idx="'+idx+'">删除</button></td></tr>');
|
||||
tbody.append(tr);
|
||||
});
|
||||
}
|
||||
renderRows();
|
||||
container.find('.btn-ip-add').off('click').on('click', function(){
|
||||
giftList.push({type:1,count:100,isRandom:false,minCount:0,maxCount:0,otherId:''});
|
||||
renderRows();
|
||||
});
|
||||
container.off('click','.btn-ip-del').on('click','.btn-ip-del', function(){
|
||||
var idx = parseInt($(this).data('idx'));
|
||||
giftList.splice(idx,1);
|
||||
renderRows();
|
||||
});
|
||||
container.off('click','.btn-ip-edit').on('click','.btn-ip-edit', function(){
|
||||
var idx = parseInt($(this).data('idx'));
|
||||
var g = giftList[idx];
|
||||
if (!g) return;
|
||||
var ehtml = '<div style="padding:15px;"><form class="layui-form"><div class="layui-form-item"><label class="layui-form-label">类型</label><div class="layui-input-block"><select id="ip-type"><option value="1"'+(g.type===1?' selected':'')+'>金币</option><option value="2"'+(g.type===2?' selected':'')+'>钻石</option><option value="3"'+(g.type===3?' selected':'')+'>道具</option></select></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">数量</label><div class="layui-input-block"><input type="number" id="ip-count" value="'+(g.count||0)+'" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">随机</label><div class="layui-input-block"><input type="checkbox" id="ip-random" lay-skin="switch" lay-text="是|否"'+(g.isRandom?' checked':'')+'></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">最小值</label><div class="layui-input-block"><input type="number" id="ip-min" value="'+(g.minCount||0)+'" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">最大值</label><div class="layui-input-block"><input type="number" id="ip-max" value="'+(g.maxCount||0)+'" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item gift-prop-select" style="'+(g.type===3?'':'display:none;')+'"><label class="layui-form-label">道具编号</label><div class="layui-input-block"><input type="text" id="ip-oid" class="layui-input" value="'+(g.otherId||'')+'" placeholder="输入道具编号"></div></div></form></div>';
|
||||
layer.open({type:1,title:'编辑奖励项',area:['420px','420px'],content:ehtml,btn:['保存','取消'],
|
||||
success:function(el){ form.render(); form.on('select(ip-type)', function(o){ el.find('.gift-prop-select').toggle(o.value==='3'); }); },
|
||||
yes:function(ei,el){
|
||||
var t = parseInt(el.find('#ip-type').val())||1;
|
||||
var propNum = t===3 ? (el.find('#ip-oid').val()||'') : '';
|
||||
giftList[idx] = {
|
||||
type:t, count: parseInt(el.find('#ip-count').val())||0,
|
||||
isRandom: el.find('#ip-random')[0].checked,
|
||||
minCount: parseInt(el.find('#ip-min').val())||0,
|
||||
maxCount: parseInt(el.find('#ip-max').val())||0,
|
||||
otherId: propNum
|
||||
};
|
||||
layer.close(ei);
|
||||
renderRows();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 进阶 CRUD ====================
|
||||
function showAdvanceEdit(data, isAdd) {
|
||||
var readonly = isAdd ? '' : 'readonly';
|
||||
var html = '<div style="padding:20px;"><form class="layui-form">' +
|
||||
'<div class="layui-row"><div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">类型</label><div class="layui-input-block"><select id="dlg-type" '+readonly+'><option value="1"'+(data.type===1?' selected':'')+'>豪华</option><option value="2"'+(data.type===2?' selected':'')+'>至尊</option><option value="3"'+(data.type===3?' selected':'')+'>豪华+至尊</option></select></div></div></div>' +
|
||||
'<div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">名称</label><div class="layui-input-block"><input type="text" id="dlg-name" value="'+(data.name||'')+'" class="layui-input"></div></div></div></div>' +
|
||||
'<div class="layui-row"><div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">奖励数量</label><div class="layui-input-block"><input type="number" id="dlg-count" value="'+(data.count||0)+'" class="layui-input"></div></div></div>' +
|
||||
'<div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">图片</label><div class="layui-input-block" style="display:flex;"><input type="text" id="dlg-image" value="'+(data.imageUrl||'')+'" class="layui-input" placeholder="图片URL" style="flex:1;margin-right:5px;"><button type="button" id="btn-upload-advance-img" class="layui-btn layui-btn-sm"><i class="layui-icon layui-icon-upload"></i></button></div></div></div></div>' +
|
||||
'<div class="layui-row"><div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">付费类型</label><div class="layui-input-block"><select id="dlg-payType"><option value="1"'+(data.payType===1?' selected':'')+'>金币</option><option value="2"'+(data.payType===2?' selected':'')+'>钻石</option><option value="3"'+(data.payType===3?' selected':'')+'>现金</option></select></div></div></div>' +
|
||||
'<div class="layui-col-md6"><div class="layui-form-item"><label class="layui-form-label">付费金额</label><div class="layui-input-block"><input type="number" id="dlg-payCount" value="'+(data.payCount||0)+'" class="layui-input"></div></div></div></div>' +
|
||||
'</form></div>';
|
||||
layer.open({ type:1, title:isAdd?'添加进阶':'编辑进阶', area:['550px','380px'], content:html, btn:['保存','取消'],
|
||||
success:function(l){
|
||||
form.render('select');
|
||||
layui.upload.render({
|
||||
elem: l.find('#btn-upload-advance-img'),
|
||||
url: (layui.setter.baseurl||'/')+'adminapi/ImageUpload/upload/temp',
|
||||
done: function(r) {
|
||||
if (r.code === 0) l.find('#dlg-image').val(r.data.path);
|
||||
}
|
||||
});
|
||||
},
|
||||
yes:function(idx,l){
|
||||
var item = {
|
||||
type: parseInt(l.find('#dlg-type').val()) || 1,
|
||||
name: l.find('#dlg-name').val() || '',
|
||||
count: parseInt(l.find('#dlg-count').val()) || 0,
|
||||
imageUrl: l.find('#dlg-image').val() || '',
|
||||
payType: parseInt(l.find('#dlg-payType').val()) || 1,
|
||||
payCount: parseInt(l.find('#dlg-payCount').val()) || 0,
|
||||
giftList: data.giftList || []
|
||||
};
|
||||
var b = bo();
|
||||
if (!b.advanceGift) b.advanceGift = [];
|
||||
if (isAdd) {
|
||||
if (b.advanceGift.some(function(x) { return x.type === item.type; }))
|
||||
{ layer.msg('类型已存在'); return; }
|
||||
b.advanceGift.push(item);
|
||||
} else {
|
||||
var i = b.advanceGift.findIndex(function(x) { return x.type === data.type; });
|
||||
if (i > -1) b.advanceGift[i] = item;
|
||||
}
|
||||
layer.close(idx); save(isAdd?'添加成功':'保存成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 奖励编辑弹窗(三层tab,与奖池页面一致) ====================
|
||||
function showRewardDialog(title, levelData) {
|
||||
rewardCtx = { normal: levelData.normalGiftList || [], luxury: levelData.luxuryGiftList || [], supreme: levelData.supremeGiftList || [] };
|
||||
var html = '<div class="reward-tabs" style="padding:10px;"><div class="layui-tab" lay-filter="reward-tab">' +
|
||||
'<ul class="layui-tab-title"><li class="layui-this">普通奖励</li><li>豪华奖励</li><li>至尊奖励</li></ul>' +
|
||||
'<div class="layui-tab-content" style="height:480px;">' +
|
||||
'<div class="layui-tab-item layui-show"><div class="gift-placeholder" data-key="normalGiftList"></div></div>' +
|
||||
'<div class="layui-tab-item"><div class="gift-placeholder" data-key="luxuryGiftList"></div></div>' +
|
||||
'<div class="layui-tab-item"><div class="gift-placeholder" data-key="supremeGiftList"></div></div>' +
|
||||
'</div></div></div>';
|
||||
|
||||
layer.open({
|
||||
type: 1, title: title, area: ['1000px', '620px'],
|
||||
content: html, shade: 0.1, shadeClose: true,
|
||||
success: function(layero) {
|
||||
// 初始化第一个tab的编辑器
|
||||
initGiftEditor(layero, rewardCtx.normal);
|
||||
// tab切换时重新初始化编辑器
|
||||
form.on('tab(reward-tab)', function(o) {
|
||||
var key = o.index === 0 ? 'normalGiftList' : o.index === 1 ? 'luxuryGiftList' : 'supremeGiftList';
|
||||
var list = rewardCtx[key];
|
||||
var ph = layero.find('.gift-placeholder[data-key="' + key + '"]');
|
||||
ph.html($('#gift-editor-tpl').html());
|
||||
var propOpts = '<option value="">请选择道具</option>';
|
||||
propList.forEach(function(p) { propOpts += '<option value="'+p.number+'">'+p.number+' - '+p.name+'</option>'; });
|
||||
ph.find('#giftProductNumber').html(propOpts);
|
||||
form.render();
|
||||
bindGiftEvents(ph, list);
|
||||
});
|
||||
},
|
||||
end: function() { renderLevelTable(); renderAdvanceTable(); }
|
||||
});
|
||||
}
|
||||
|
||||
function initGiftEditor(layero, giftList) {
|
||||
var ph = layero.find('.gift-placeholder[data-key="normalGiftList"]');
|
||||
ph.html($('#gift-editor-tpl').html());
|
||||
var propOpts = '<option value="">请选择道具</option>';
|
||||
propList.forEach(function(p) { propOpts += '<option value="'+p.number+'">'+p.number+' - '+p.name+'</option>'; });
|
||||
ph.find('#giftProductNumber').html(propOpts);
|
||||
form.render();
|
||||
bindGiftEvents(ph, giftList);
|
||||
}
|
||||
|
||||
function bindGiftEvents(container, giftList) {
|
||||
var $c = $(container);
|
||||
currentGiftIndex = -1;
|
||||
renderGiftTable($c, giftList);
|
||||
|
||||
$c.find('#btn-add-gift').on('click', function() {
|
||||
giftList.push({ type:1, count:100, isRandom:false, minCount:0, maxCount:0, otherId:'' });
|
||||
currentGiftIndex = giftList.length - 1;
|
||||
renderGiftTable($c, giftList, currentGiftIndex);
|
||||
loadGiftForm(giftList[giftList.length-1], $c);
|
||||
});
|
||||
$c.find('#btn-delete-gift').on('click', function() {
|
||||
if (currentGiftIndex < 0) return layer.msg('请先选择要删除的项');
|
||||
giftList.splice(currentGiftIndex, 1);
|
||||
currentGiftIndex = -1; clearGiftForm($c);
|
||||
renderGiftTable($c, giftList, -1);
|
||||
});
|
||||
$c.find('#btn-save-gift').on('click', function() {
|
||||
if (currentGiftIndex < 0) return layer.msg('请先选择要编辑的项');
|
||||
var t = parseInt($c.find('#giftType').val()) || 1;
|
||||
var oid = t === 3 ? ($c.find('#giftProductNumber').val()||'') : '';
|
||||
giftList[currentGiftIndex] = {
|
||||
type: t, count: parseInt($c.find('#giftCount').val()) || 0,
|
||||
isRandom: $c.find('#giftIsRandom')[0].checked,
|
||||
minCount: parseInt($c.find('#giftMinCount').val()) || 0,
|
||||
maxCount: parseInt($c.find('#giftMaxCount').val()) || 0,
|
||||
otherId: oid
|
||||
};
|
||||
renderGiftTable($c, giftList, currentGiftIndex);
|
||||
layer.msg('保存成功');
|
||||
});
|
||||
|
||||
form.on('select(giftType)', function(o) {
|
||||
$c.find('.gift-prop-select').toggle(o.value === '3');
|
||||
$c.find('#giftCount').val(0); $c.find('#giftIsRandom')[0].checked = false; form.render('checkbox');
|
||||
});
|
||||
$c.find('#giftCount').on('input', function() { $c.find('#giftIsRandom')[0].checked = false; form.render('checkbox'); });
|
||||
$c.find('#giftIsRandom').on('click', function() {
|
||||
if (this.checked) setTimeout(function() { $c.find('#giftCount').val(0); }, 10);
|
||||
});
|
||||
}
|
||||
|
||||
var currentGiftIndex = -1;
|
||||
|
||||
function renderGiftTable(container, giftList, selectIndex) {
|
||||
table.render({ elem: container.find('#table-gift-list'), data: giftList, page: false, height: 380,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'type', title: '类型', width: 80, templet: function(d) { return ({1:'金币',2:'钻石',3:'道具'})[d.type]||'金币'; }},
|
||||
{ field: 'count', title: '数量', width: 80 },
|
||||
{ field: 'minCount', title: '最小值', width: 80 },
|
||||
{ field: 'maxCount', title: '最大值', width: 80 },
|
||||
{ field: 'isRandom', title: '随机', width: 70, templet: function(d) { return d.isRandom ? '是' : '否'; }},
|
||||
{ field: 'otherId', title: '道具Id', width: 120 }
|
||||
]],
|
||||
done: function() {
|
||||
if (selectIndex === undefined) selectIndex = giftList.length > 0 ? 0 : -1;
|
||||
if (selectIndex >= 0 && selectIndex < giftList.length) {
|
||||
currentGiftIndex = selectIndex;
|
||||
var tr = container.find('#table-gift-list + .layui-table-view tr[data-index="'+selectIndex+'"]');
|
||||
if (tr.length) { tr.addClass('layui-table-click'); loadGiftForm(giftList[selectIndex], container); }
|
||||
}
|
||||
}
|
||||
});
|
||||
container.find('#table-gift-list + .layui-table-view').off('click').on('click', 'tr[data-index]', function() {
|
||||
var idx = parseInt($(this).attr('data-index'));
|
||||
if (idx >= 0 && idx < giftList.length) {
|
||||
currentGiftIndex = idx;
|
||||
container.find('tr[data-index]').removeClass('layui-table-click');
|
||||
$(this).addClass('layui-table-click');
|
||||
loadGiftForm(giftList[idx], container);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadGiftForm(data, container) {
|
||||
container.find('#giftType').val(data.type || 1);
|
||||
container.find('#giftCount').val(data.count || 0);
|
||||
container.find('#giftIsRandom')[0].checked = data.isRandom || false;
|
||||
container.find('#giftMinCount').val(data.minCount || 0);
|
||||
container.find('#giftMaxCount').val(data.maxCount || 0);
|
||||
var oid = data.otherId || '';
|
||||
container.find('#giftProductNumber').val(oid);
|
||||
container.find('.gift-prop-select').toggle(data.type === 3);
|
||||
form.render('checkbox'); form.render('select');
|
||||
}
|
||||
|
||||
function clearGiftForm(container) {
|
||||
container.find('#giftType').val('1');
|
||||
container.find('#giftCount').val('0');
|
||||
container.find('#giftIsRandom')[0].checked = false;
|
||||
container.find('#giftMinCount').val('0');
|
||||
container.find('#giftMaxCount').val('0');
|
||||
container.find('#giftProductNumber').val('');
|
||||
container.find('.gift-prop-select').hide();
|
||||
form.render('checkbox'); form.render('select');
|
||||
}
|
||||
|
||||
// ==================== 初始化按钮(从 JSON 还原) ====================
|
||||
$(document).on('click', '[lay-filter="init-level"],[lay-filter="init-advance"]', function() {
|
||||
layer.confirm('确定要从配置文件还原战令数据吗?', function(i) {
|
||||
layer.close(i);
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/GameConfig/InitActivitySection/BattleOrderConfig',
|
||||
done: function(r) {
|
||||
if (r.code === 0 || r.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(r.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$(document).on('click', '[lay-filter="add-level"]', function() {
|
||||
var b = bo(), levels = b.levelConfig || [];
|
||||
var max = levels.length ? Math.max.apply(null, levels.map(function(l){return l.level;})) : 0;
|
||||
showLevelEdit({ level:max+1, exp:(max+1)*100, normalGiftList:[], luxuryGiftList:[], supremeGiftList:[], payType:1, payCount:(max+1)*100 }, true);
|
||||
});
|
||||
$(document).on('click', '[lay-filter="add-advance"]', function() {
|
||||
var b = bo(), list = b.advanceGift || [];
|
||||
var used = list.map(function(a){return a.type;});
|
||||
var nt = 1; while (used.indexOf(nt) > -1) nt++;
|
||||
showAdvanceEdit({ type:nt, name:({1:'豪华',2:'至尊',3:'豪华+至尊'})[nt]||'进阶', count:100, payType:1, payCount:10000, giftList:[] }, true);
|
||||
});
|
||||
$(document).on('click', '[lay-filter="save-levels"],[lay-filter="save-advances"]', function() { save('保存成功'); });
|
||||
|
||||
// ==================== 表格操作事件 ====================
|
||||
table.on('tool(table-level)', function(obj) {
|
||||
var d = obj.data, b = bo(), i = b.levelConfig.findIndex(function(x){return x.level===d.level;});
|
||||
if (i < 0) return;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除等级'+d.level+'?', function(idx) { b.levelConfig.splice(i,1); layer.close(idx); save('删除成功'); });
|
||||
} else if (obj.event === 'edit') {
|
||||
showLevelEdit(d, false);
|
||||
}
|
||||
});
|
||||
|
||||
table.on('tool(table-advance)', function(obj) {
|
||||
var d = obj.data, b = bo(), i = b.advanceGift.findIndex(function(x){return String(x.type)===String(d.type);});
|
||||
if (i < 0) return;
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除进阶'+d.name+'?', function(idx) { b.advanceGift.splice(i,1); layer.close(idx); save('删除成功'); });
|
||||
} else if (obj.event === 'edit') {
|
||||
showAdvanceEdit(d);
|
||||
} else if (obj.event === 'reward') {
|
||||
if (!b.advanceGift[i].giftList) b.advanceGift[i].giftList = [];
|
||||
var html = '<div class="gift-placeholder">'+$('#gift-editor-tpl').html()+'</div>';
|
||||
layer.open({
|
||||
type:1, title:'进阶 - '+d.name+' 奖励列表', area:['1000px','620px'],
|
||||
content: html, shade: 0.1, shadeClose: true,
|
||||
success: function(layero) {
|
||||
// 奖励类型下拉与道具编号输入是两个不同字段,不能把道具选项塞进类型下拉。
|
||||
form.render();
|
||||
bindGiftEvents(layero.find('.gift-placeholder'), b.advanceGift[i].giftList);
|
||||
},
|
||||
end: function() { renderLevelTable(); renderAdvanceTable(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
window.saveAct=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/ActivityConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gift-container { display: flex; height: 460px; padding: 10px; }
|
||||
.gift-left { flex: 1; margin-right: 15px; }
|
||||
.gift-table-wrap { height: 380px; overflow: auto; }
|
||||
.gift-right { width: 280px; border-left: 1px solid #e6e6e6; padding-left: 15px; }
|
||||
.gift-right h4 { margin-bottom: 12px; color: #333; font-size: 15px; padding-bottom: 8px; border-bottom: 1px solid #eee; }
|
||||
.gift-toolbar { margin-bottom: 8px; }
|
||||
.gift-toolbar .layui-btn { margin-right: 5px; }
|
||||
.gift-right .layui-form-item { margin-bottom: 10px; }
|
||||
.gift-right .layui-form-label { padding: 9px 0; width: 60px; }
|
||||
.gift-right .layui-input-block { margin-left: 70px; }
|
||||
.reward-tabs .layui-tab-title { height: 42px; }
|
||||
.reward-tabs .layui-tab-title li { line-height: 42px; }
|
||||
.reward-tabs .layui-tab-content { padding: 10px 0; }
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,179 @@
|
||||
<title>Boss道具掉落配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>Boss道具掉落配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-bossdrop"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-bossdrop"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-bossdrop"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('BossDropConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" lay-filter="bd-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">不掉落权重</label>
|
||||
<div class="layui-input-inline" style="width:200px;">
|
||||
<input type="number" name="noDropWeight" class="layui-input" placeholder="不掉落权重(值越大越难掉落)">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">总权重 = 不掉落权重 + 各掉落项权重之和</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="save-base">保存基础配置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">掉落道具列表(所有Boss通用)</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-container" style="margin-bottom:10px;">
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-item"><i class="layui-icon layui-icon-add-1"></i> 添加掉落项</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-items"><i class="layui-icon layui-icon-ok"></i> 保存</button>
|
||||
</div>
|
||||
<table id="table-items" lay-filter="table-items"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="bar-item">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$, admin = layui.admin, table = layui.table, form = layui.form, layer = layui.layer, setter = layui.setter;
|
||||
var gameConfig = null, propList = [];
|
||||
|
||||
setTimeout(function() { $('.layui-layer-shade').remove(); layer.closeAll(); }, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
if (!gameConfig.bossDropConfig) gameConfig.bossDropConfig = { noDropWeight: 5000, dropItems: [] };
|
||||
propList = (gameConfig.propConfig || []).filter(function(p){ return p.isSale; }).map(function(p){ return { number: p.number, name: p.name }; });
|
||||
initForm();
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bd() { return gameConfig.bossDropConfig; }
|
||||
|
||||
function initForm() {
|
||||
var cfg = bd();
|
||||
$('input[name="noDropWeight"]').val(cfg.noDropWeight || 5000);
|
||||
form.render();
|
||||
}
|
||||
|
||||
function saveBase() {
|
||||
var cfg = bd();
|
||||
cfg.noDropWeight = parseInt($('input[name="noDropWeight"]').val()) || 5000;
|
||||
save();
|
||||
}
|
||||
|
||||
function save() {
|
||||
admin.req({
|
||||
method: "post", contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/UpdateBossDrop",
|
||||
data: JSON.stringify(bd()),
|
||||
done: function (r) {
|
||||
r.code === 0 ? (layer.msg('保存成功'), loadConfig()) : layer.msg(r.info || '保存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
var items = bd().dropItems || [];
|
||||
table.render({ elem: '#table-items', data: items, page: false,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'propName', title: '道具名称', width: 150 },
|
||||
{ field: 'count', title: '数量', width: 80 },
|
||||
{ field: 'weight', title: '权重', width: 80 },
|
||||
{ title: '操作', width: 160, fixed: 'right', toolbar: '#bar-item' }
|
||||
]]
|
||||
});
|
||||
}
|
||||
|
||||
form.on('submit(save-base)', function() { saveBase(); return false; });
|
||||
|
||||
function showItemEdit(data, idx) {
|
||||
var items = bd().dropItems || [];
|
||||
var opts = '<option value="">请选择道具</option>';
|
||||
(gameConfig.propConfig || []).forEach(function(p) { opts += '<option value="'+p.number+'"'+(p.number===data.propNumber?' selected':'')+'>'+p.number+' - '+p.name+'</option>'; });
|
||||
var html = '<div style="padding:20px;"><form class="layui-form">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">道具</label><div class="layui-input-block"><select id="dlg-prop" lay-search>'+opts+'</select></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">数量</label><div class="layui-input-block"><input type="number" id="dlg-count" value="'+(data.count||1)+'" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">权重</label><div class="layui-input-block"><input type="number" id="dlg-weight" value="'+(data.weight||100)+'" class="layui-input"></div></div>' +
|
||||
'</form></div>';
|
||||
layer.open({ type:1, title: idx < 0 ? '添加掉落项' : '编辑掉落项', area:['420px','320px'], content:html, btn:['保存','取消'],
|
||||
success:function(l){ form.render('select'); },
|
||||
yes:function(i,l){
|
||||
var item = {
|
||||
propNumber: l.find('#dlg-prop').val() || '',
|
||||
propName: l.find('#dlg-prop option:selected').text().replace(/^[^-]+ - /, ''),
|
||||
count: parseInt(l.find('#dlg-count').val()) || 1,
|
||||
weight: parseInt(l.find('#dlg-weight').val()) || 0
|
||||
};
|
||||
if (idx < 0) items.push(item); else items[idx] = item;
|
||||
layer.close(i); renderTable(); save();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-item"]', function() { showItemEdit({ propNumber:'', propName:'', count:1, weight:100 }, -1); });
|
||||
$(document).on('click', '[lay-filter="save-items"]', function() { save(); });
|
||||
|
||||
table.on('tool(table-items)', function(obj) {
|
||||
var items = bd().dropItems || [];
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除?', function(i) { items.splice(items.indexOf(obj.data), 1); layer.close(i); renderTable(); save(); });
|
||||
} else if (obj.event === 'edit') {
|
||||
var idx = items.indexOf(obj.data);
|
||||
showItemEdit(obj.data, idx);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="init-bossdrop"]', function() {
|
||||
layer.confirm('确定要从配置文件还原Boss掉落配置吗?', function(i) {
|
||||
layer.close(i);
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/GameConfig/InitSection/BossDropConfig',
|
||||
done: function(r) {
|
||||
if (r.code === 0 || r.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(r.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-bossdrop"]', function() { loadConfig(); layer.msg('刷新成功'); });
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,393 @@
|
||||
|
||||
<title>机器人AI配置</title>
|
||||
|
||||
<style>
|
||||
.layui-form-label { width: 200px; }
|
||||
.bot-row { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.bot-row .layui-form-item { display: flex; align-items: center; margin: 0; white-space: nowrap; flex: 1; min-width: 300px; }
|
||||
.bot-row .layui-form-label { width: auto; text-align: right; padding-right: 6px; font-size: 13px; }
|
||||
.bot-row .layui-input-inline { width: 70px; }
|
||||
.bot-row .layui-form-mid { font-size: 11px; color: #999; margin-left: 4px; }
|
||||
</style>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>机器人AI配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-botai"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-botai"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-botai"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('BotConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" id="form-botai" style="padding: 20px;">
|
||||
|
||||
<fieldset class="layui-elem-field"><legend>全局设置</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="layui-form-item"><label class="layui-form-label">总开关</label><div class="layui-input-inline"><input type="checkbox" name="enabled" lay-skin="switch" lay-text="开启|关闭"></div><div class="layui-form-mid">机器人总开关</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">AI状态</label><div class="layui-input-inline"><input type="text" name="aiState" class="layui-input" style="width:120px;"></div><div class="layui-form-mid">active=正常 | idle=待机 | aggressive=激进</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">爆率因子</label><div class="layui-input-inline"><input type="number" name="luckFactor" class="layui-input" step="0.1"></div><div class="layui-form-mid">1.0=正常, >1容易杀, <1难杀</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">状态刷新间隔(秒)</label><div class="layui-input-inline"><input type="number" name="stateRefreshInterval" class="layui-input" step="0.1"></div><div class="layui-form-mid">0=不自动刷新</div></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="layui-elem-field"><legend>技能配置</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="layui-form-item"><label class="layui-form-label">技能刷新间隔(秒)</label><div class="layui-input-inline"><input type="number" name="skillRefreshInterval" class="layui-input" step="0.1"></div><div class="layui-form-mid">每隔多少秒重新掷骰子决定技能组合</div></div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">锁定概率</label><div class="layui-input-inline"><input type="number" name="lockProb" class="layui-input" step="0.01"></div><div class="layui-form-mid">自动瞄准最近鱼</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">锁定Min</label><div class="layui-input-inline"><input type="number" name="lockMinTime" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">锁定Max</label><div class="layui-input-inline"><input type="number" name="lockMaxTime" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">狂暴概率</label><div class="layui-input-inline"><input type="number" name="frenzyProb" class="layui-input" step="0.01"></div><div class="layui-form-mid">开火速度翻倍</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">狂暴Min</label><div class="layui-input-inline"><input type="number" name="frenzyMinTime" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">狂暴Max</label><div class="layui-input-inline"><input type="number" name="frenzyMaxTime" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">三发散弹概率</label><div class="layui-input-inline"><input type="number" name="tripleProb" class="layui-input" step="0.01"></div><div class="layui-form-mid">一次3发</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">三发Min</label><div class="layui-input-inline"><input type="number" name="tripleMinTime" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">三发Max</label><div class="layui-input-inline"><input type="number" name="tripleMaxTime" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">双倍炮概率</label><div class="layui-input-inline"><input type="number" name="doubleProb" class="layui-input" step="0.01"></div><div class="layui-form-mid">消耗翻倍</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">双倍Min</label><div class="layui-input-inline"><input type="number" name="doubleMinTime" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">双倍Max</label><div class="layui-input-inline"><input type="number" name="doubleMaxTime" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- 行为模板 -->
|
||||
<!-- 三个行为模式共用同一套字段,使用前缀区分 -->
|
||||
<fieldset class="layui-elem-field"><legend>Active 行为参数</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火间隔Min(秒)</label><div class="layui-input-inline"><input type="number" name="activeFireIntervalMin" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火间隔Max(秒)</label><div class="layui-input-inline"><input type="number" name="activeFireIntervalMax" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火概率</label><div class="layui-input-inline"><input type="number" name="activeFireProb" class="layui-input" step="0.01"></div><div class="layui-form-mid">0.9=经常开火偶尔停顿</div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">旋转速度(度/秒)</label><div class="layui-input-inline"><input type="number" name="activeRotateSpeed" class="layui-input" step="1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">目标保持Min(秒)</label><div class="layui-input-inline"><input type="number" name="activeTargetHoldTimeMin" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">目标保持Max(秒)</label><div class="layui-input-inline"><input type="number" name="activeTargetHoldTimeMax" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">切换目标概率</label><div class="layui-input-inline"><input type="number" name="activeTargetSwitchChance" class="layui-input" step="0.01"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">高分偏好</label><div class="layui-input-inline"><input type="number" name="activeTargetPreferHighScore" class="layui-input" step="0.1"></div><div class="layui-form-mid">0=纯距离, 1=纯分数</div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">允许打Boss</label><div class="layui-input-inline"><input type="checkbox" name="activeCanTargetBoss" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">允许打特殊鱼</label><div class="layui-input-inline"><input type="checkbox" name="activeCanTargetSpecial" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="layui-elem-field"><legend>Idle 行为参数</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火间隔Min(秒)</label><div class="layui-input-inline"><input type="number" name="idleFireIntervalMin" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火间隔Max(秒)</label><div class="layui-input-inline"><input type="number" name="idleFireIntervalMax" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火概率</label><div class="layui-input-inline"><input type="number" name="idleFireProb" class="layui-input" step="0.01"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">旋转速度(度/秒)</label><div class="layui-input-inline"><input type="number" name="idleRotateSpeed" class="layui-input" step="1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">目标保持Min(秒)</label><div class="layui-input-inline"><input type="number" name="idleTargetHoldTimeMin" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">目标保持Max(秒)</label><div class="layui-input-inline"><input type="number" name="idleTargetHoldTimeMax" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">切换目标概率</label><div class="layui-input-inline"><input type="number" name="idleTargetSwitchChance" class="layui-input" step="0.01"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">高分偏好</label><div class="layui-input-inline"><input type="number" name="idleTargetPreferHighScore" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">允许打Boss</label><div class="layui-input-inline"><input type="checkbox" name="idleCanTargetBoss" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">允许打特殊鱼</label><div class="layui-input-inline"><input type="checkbox" name="idleCanTargetSpecial" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="layui-elem-field"><legend>Aggressive 行为参数</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火间隔Min(秒)</label><div class="layui-input-inline"><input type="number" name="aggFireIntervalMin" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火间隔Max(秒)</label><div class="layui-input-inline"><input type="number" name="aggFireIntervalMax" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">开火概率</label><div class="layui-input-inline"><input type="number" name="aggFireProb" class="layui-input" step="0.01"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">旋转速度(度/秒)</label><div class="layui-input-inline"><input type="number" name="aggRotateSpeed" class="layui-input" step="1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">目标保持Min(秒)</label><div class="layui-input-inline"><input type="number" name="aggTargetHoldTimeMin" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">目标保持Max(秒)</label><div class="layui-input-inline"><input type="number" name="aggTargetHoldTimeMax" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">切换目标概率</label><div class="layui-input-inline"><input type="number" name="aggTargetSwitchChance" class="layui-input" step="0.01"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">高分偏好</label><div class="layui-input-inline"><input type="number" name="aggTargetPreferHighScore" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">允许打Boss</label><div class="layui-input-inline"><input type="checkbox" name="aggCanTargetBoss" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">允许打特殊鱼</label><div class="layui-input-inline"><input type="checkbox" name="aggCanTargetSpecial" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="layui-elem-field"><legend>倍数策略</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">初始档位索引</label><div class="layui-input-inline"><input type="number" name="multiplierInitialLevelIndex" class="layui-input"></div><div class="layui-form-mid">对应炮倍列表下标,0=最低档</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">降档阈值</label><div class="layui-input-inline"><input type="number" name="multiplierDecreaseThreshold" class="layui-input" step="0.1"></div><div class="layui-form-mid">当前金币/进场金币 < 此值</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">升档阈值</label><div class="layui-input-inline"><input type="number" name="multiplierIncreaseThreshold" class="layui-input" step="0.1"></div><div class="layui-form-mid">当前金币/进场金币 > 此值</div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">调整档位步数</label><div class="layui-input-inline"><input type="number" name="multiplierStep" class="layui-input"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">检查间隔(秒)</label><div class="layui-input-inline"><input type="number" name="multiplierCheckInterval" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">最低档位</label><div class="layui-input-inline"><input type="number" name="multiplierMinLevelIndex" class="layui-input"></div><div class="layui-form-mid">不会降到低于此值</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">最高档位(-1不限)</label><div class="layui-input-inline"><input type="number" name="multiplierMaxLevelIndex" class="layui-input"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="layui-elem-field"><legend>Boss策略</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">Boss鱼类型</label><div class="layui-input-inline"><input type="text" name="bossFishTypes" class="layui-input" style="width:120px;" placeholder="2,5"></div><div class="layui-form-mid">FishTypeEnum 的 int 值,逗号分隔</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">无Boss散射</label><div class="layui-input-inline"><input type="checkbox" name="scatterWhenNoBoss" lay-skin="switch" lay-text="开启|关闭"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">三发概率</label><div class="layui-input-inline"><input type="number" name="tripleShotProb" class="layui-input" step="0.01"></div><div class="layui-form-mid">无Boss时定点三发概率</div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">优先最大倍率Boss</label><div class="layui-input-inline"><input type="checkbox" name="preferMaxMultiplierBoss" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">散射阈值</label><div class="layui-input-inline"><input type="number" name="scatterModeThreshold" class="layui-input"></div><div class="layui-form-mid">Boss数 > 此值开启散射</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">狂暴概率</label><div class="layui-input-inline"><input type="number" name="bossFrenzyProb" class="layui-input" step="0.01"></div><div class="layui-form-mid">Boss数 ≤ 散射阈值时的概率</div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">狂暴Min</label><div class="layui-input-inline"><input type="number" name="bossFrenzyMinTime" class="layui-input" step="0.1"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">狂暴Max</label><div class="layui-input-inline"><input type="number" name="bossFrenzyMaxTime" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="layui-elem-field"><legend>退出条件</legend>
|
||||
<div class="layui-field-box">
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">盈利退出(金币)</label><div class="layui-input-inline"><input type="number" name="exitWhenGoldAbove" class="layui-input"></div><div class="layui-form-mid">超过此值时退出(盈利离场),0=不检测</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">亏损退出(金币)</label><div class="layui-input-inline"><input type="number" name="exitWhenGoldBelow" class="layui-input"></div><div class="layui-form-mid">低于此值时退出(输完离场)</div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">检查间隔(秒)</label><div class="layui-input-inline"><input type="number" name="exitCheckInterval" class="layui-input" step="0.1"></div></div>
|
||||
</div>
|
||||
<div class="bot-row">
|
||||
<div class="layui-form-item"><label class="layui-form-label">发送离房消息</label><div class="layui-input-inline"><input type="checkbox" name="sendLeaveRoom" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
<div class="layui-form-item"><label class="layui-form-label">退出后显示等待</label><div class="layui-input-inline"><input type="checkbox" name="showWaitingAfterExit" lay-skin="switch" lay-text="是|否"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})};
|
||||
</script>
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
setTimeout(function() { $('.layui-layer-shade').remove(); layer.closeAll(); }, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) { gameConfig = res.data; fillForm(); }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bc() { if (!gameConfig.botConfig) gameConfig.botConfig = {}; return gameConfig.botConfig; }
|
||||
|
||||
function val(name, def) { var v = $('#form-botai input[name="'+name+'"]').val(); return v !== undefined && v !== '' ? v : def; }
|
||||
function chk(name) { return $('#form-botai input[name="'+name+'"]').prop('checked'); }
|
||||
function num(name, def) { return parseFloat(val(name, def)) || def; }
|
||||
function intv(name, def) { return parseInt(val(name, def)) || def; }
|
||||
|
||||
function fillBehavior(prefix, data) {
|
||||
if (!data) return;
|
||||
$('#form-botai input[name="'+prefix+'FireIntervalMin"]').val(data.fireIntervalMin ?? 0.3);
|
||||
$('#form-botai input[name="'+prefix+'FireIntervalMax"]').val(data.fireIntervalMax ?? 1.2);
|
||||
$('#form-botai input[name="'+prefix+'FireProb"]').val(data.fireProb ?? 0.9);
|
||||
$('#form-botai input[name="'+prefix+'RotateSpeed"]').val(data.rotateSpeed ?? 80);
|
||||
$('#form-botai input[name="'+prefix+'TargetHoldTimeMin"]').val(data.targetHoldTimeMin ?? 2);
|
||||
$('#form-botai input[name="'+prefix+'TargetHoldTimeMax"]').val(data.targetHoldTimeMax ?? 5);
|
||||
$('#form-botai input[name="'+prefix+'TargetSwitchChance"]').val(data.targetSwitchChance ?? 0.7);
|
||||
$('#form-botai input[name="'+prefix+'TargetPreferHighScore"]').val(data.targetPreferHighScore ?? 0);
|
||||
$('#form-botai input[name="'+prefix+'CanTargetBoss"]').prop('checked', data.canTargetBoss !== false);
|
||||
$('#form-botai input[name="'+prefix+'CanTargetSpecial"]').prop('checked', data.canTargetSpecial !== false);
|
||||
}
|
||||
|
||||
function readBehavior(prefix) {
|
||||
return {
|
||||
fireIntervalMin: num(prefix+'FireIntervalMin', 0.3),
|
||||
fireIntervalMax: num(prefix+'FireIntervalMax', 1.2),
|
||||
fireProb: num(prefix+'FireProb', 0.9),
|
||||
rotateSpeed: num(prefix+'RotateSpeed', 80),
|
||||
targetHoldTimeMin: num(prefix+'TargetHoldTimeMin', 2),
|
||||
targetHoldTimeMax: num(prefix+'TargetHoldTimeMax', 5),
|
||||
targetSwitchChance: num(prefix+'TargetSwitchChance', 0.7),
|
||||
targetPreferHighScore: num(prefix+'TargetPreferHighScore', 0),
|
||||
canTargetBoss: chk(prefix+'CanTargetBoss'),
|
||||
canTargetSpecial: chk(prefix+'CanTargetSpecial')
|
||||
};
|
||||
}
|
||||
|
||||
function fillForm() {
|
||||
var c = bc();
|
||||
$('#form-botai input[name="enabled"]').prop('checked', c.enabled !== false);
|
||||
$('#form-botai input[name="aiState"]').val(c.aiState || 'active');
|
||||
$('#form-botai input[name="luckFactor"]').val(c.luckFactor ?? 1);
|
||||
$('#form-botai input[name="stateRefreshInterval"]').val(c.stateRefreshInterval ?? 0);
|
||||
|
||||
var sk = c.skills || {};
|
||||
$('#form-botai input[name="skillRefreshInterval"]').val(sk.skillRefreshInterval ?? 10);
|
||||
$('#form-botai input[name="lockProb"]').val(sk.lockProb ?? 0);
|
||||
$('#form-botai input[name="lockMinTime"]').val(sk.lockMinTime ?? 5);
|
||||
$('#form-botai input[name="lockMaxTime"]').val(sk.lockMaxTime ?? 20);
|
||||
$('#form-botai input[name="frenzyProb"]').val(sk.frenzyProb ?? 0.3);
|
||||
$('#form-botai input[name="frenzyMinTime"]').val(sk.frenzyMinTime ?? 3);
|
||||
$('#form-botai input[name="frenzyMaxTime"]').val(sk.frenzyMaxTime ?? 8);
|
||||
$('#form-botai input[name="tripleProb"]').val(sk.tripleProb ?? 0.5);
|
||||
$('#form-botai input[name="tripleMinTime"]').val(sk.tripleMinTime ?? 4);
|
||||
$('#form-botai input[name="tripleMaxTime"]').val(sk.tripleMaxTime ?? 12);
|
||||
$('#form-botai input[name="doubleProb"]').val(sk.doubleProb ?? 0);
|
||||
$('#form-botai input[name="doubleMinTime"]').val(sk.doubleMinTime ?? 3);
|
||||
$('#form-botai input[name="doubleMaxTime"]').val(sk.doubleMaxTime ?? 6);
|
||||
|
||||
var mp = c.multiplier || {};
|
||||
$('#form-botai input[name="multiplierInitialLevelIndex"]').val(mp.initialLevelIndex ?? 0);
|
||||
$('#form-botai input[name="multiplierDecreaseThreshold"]').val(mp.decreaseThreshold ?? 0.5);
|
||||
$('#form-botai input[name="multiplierIncreaseThreshold"]').val(mp.increaseThreshold ?? 1.5);
|
||||
$('#form-botai input[name="multiplierStep"]').val(mp.step ?? 1);
|
||||
$('#form-botai input[name="multiplierCheckInterval"]').val(mp.checkInterval ?? 3);
|
||||
$('#form-botai input[name="multiplierMinLevelIndex"]').val(mp.minLevelIndex ?? 0);
|
||||
$('#form-botai input[name="multiplierMaxLevelIndex"]').val(mp.maxLevelIndex ?? -1);
|
||||
|
||||
var bs = c.bossStrategy || {};
|
||||
$('#form-botai input[name="bossFishTypes"]').val((bs.bossFishTypes || [2,5]).join(','));
|
||||
$('#form-botai input[name="scatterWhenNoBoss"]').prop('checked', bs.scatterWhenNoBoss !== false);
|
||||
$('#form-botai input[name="tripleShotProb"]').val(bs.tripleShotProb ?? 0.5);
|
||||
$('#form-botai input[name="preferMaxMultiplierBoss"]').prop('checked', bs.preferMaxMultiplierBoss !== false);
|
||||
$('#form-botai input[name="scatterModeThreshold"]').val(bs.scatterModeThreshold ?? 3);
|
||||
$('#form-botai input[name="bossFrenzyProb"]').val(bs.frenzyProb ?? 0.6);
|
||||
$('#form-botai input[name="bossFrenzyMinTime"]').val(bs.frenzyMinTime ?? 3);
|
||||
$('#form-botai input[name="bossFrenzyMaxTime"]').val(bs.frenzyMaxTime ?? 8);
|
||||
|
||||
var ex = c.exitCondition || {};
|
||||
$('#form-botai input[name="exitWhenGoldAbove"]').val(ex.exitWhenGoldAbove ?? 0);
|
||||
$('#form-botai input[name="exitWhenGoldBelow"]').val(ex.exitWhenGoldBelow ?? 100);
|
||||
$('#form-botai input[name="exitCheckInterval"]').val(ex.checkInterval ?? 5);
|
||||
$('#form-botai input[name="sendLeaveRoom"]').prop('checked', ex.sendLeaveRoom !== false);
|
||||
$('#form-botai input[name="showWaitingAfterExit"]').prop('checked', ex.showWaitingAfterExit !== false);
|
||||
|
||||
fillBehavior('active', c.activeBehavior);
|
||||
fillBehavior('idle', c.idleBehavior);
|
||||
fillBehavior('agg', c.aggressiveBehavior);
|
||||
|
||||
form.render();
|
||||
}
|
||||
|
||||
function collectConfig() {
|
||||
var c = bc();
|
||||
c.enabled = chk('enabled');
|
||||
c.aiState = val('aiState', 'active');
|
||||
c.luckFactor = num('luckFactor', 1);
|
||||
c.stateRefreshInterval = num('stateRefreshInterval', 0);
|
||||
|
||||
c.skills = {
|
||||
skillRefreshInterval: num('skillRefreshInterval', 10),
|
||||
lockProb: num('lockProb', 0), lockMinTime: num('lockMinTime', 5), lockMaxTime: num('lockMaxTime', 20),
|
||||
frenzyProb: num('frenzyProb', 0.3), frenzyMinTime: num('frenzyMinTime', 3), frenzyMaxTime: num('frenzyMaxTime', 8),
|
||||
tripleProb: num('tripleProb', 0.5), tripleMinTime: num('tripleMinTime', 4), tripleMaxTime: num('tripleMaxTime', 12),
|
||||
doubleProb: num('doubleProb', 0), doubleMinTime: num('doubleMinTime', 3), doubleMaxTime: num('doubleMaxTime', 6)
|
||||
};
|
||||
|
||||
c.multiplier = {
|
||||
initialLevelIndex: intv('multiplierInitialLevelIndex', 0),
|
||||
decreaseThreshold: num('multiplierDecreaseThreshold', 0.5),
|
||||
increaseThreshold: num('multiplierIncreaseThreshold', 1.5),
|
||||
step: intv('multiplierStep', 1),
|
||||
checkInterval: num('multiplierCheckInterval', 3),
|
||||
minLevelIndex: intv('multiplierMinLevelIndex', 0),
|
||||
maxLevelIndex: intv('multiplierMaxLevelIndex', -1)
|
||||
};
|
||||
|
||||
var bft = val('bossFishTypes', '2,5').split(',').map(function(s) { return parseInt(s.trim()) || 2; }).filter(function(n) { return n > 0; });
|
||||
c.bossStrategy = {
|
||||
bossFishTypes: bft.length > 0 ? bft : [2, 5],
|
||||
scatterWhenNoBoss: chk('scatterWhenNoBoss'),
|
||||
tripleShotProb: num('tripleShotProb', 0.5),
|
||||
preferMaxMultiplierBoss: chk('preferMaxMultiplierBoss'),
|
||||
scatterModeThreshold: intv('scatterModeThreshold', 3),
|
||||
frenzyProb: num('bossFrenzyProb', 0.6),
|
||||
frenzyMinTime: num('bossFrenzyMinTime', 3),
|
||||
frenzyMaxTime: num('bossFrenzyMaxTime', 8)
|
||||
};
|
||||
|
||||
c.exitCondition = {
|
||||
exitWhenGoldAbove: intv('exitWhenGoldAbove', 0),
|
||||
exitWhenGoldBelow: intv('exitWhenGoldBelow', 100),
|
||||
checkInterval: num('exitCheckInterval', 5),
|
||||
sendLeaveRoom: chk('sendLeaveRoom'),
|
||||
showWaitingAfterExit: chk('showWaitingAfterExit')
|
||||
};
|
||||
|
||||
c.activeBehavior = readBehavior('active');
|
||||
c.idleBehavior = readBehavior('idle');
|
||||
c.aggressiveBehavior = readBehavior('agg');
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-botai"]', function () {
|
||||
layer.confirm('确定要初始化机器人AI配置吗?此操作将覆盖现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/BotConfig",
|
||||
done: function (res) {
|
||||
layer.msg(res.info || (res.code === 0 ? '初始化成功' : '初始化失败'));
|
||||
if (res.code === 0 || res.code === 200) loadConfig();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-botai"]', function () { loadConfig(); layer.msg('刷新成功'); });
|
||||
|
||||
$(document).on('click', '[lay-filter="save-botai"]', function () {
|
||||
collectConfig();
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) { layer.msg('保存成功'); loadConfig(); }
|
||||
else { layer.msg(res.info || '保存失败'); }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,313 @@
|
||||
<title>机器人头像配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>机器人头像配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-bot" lay-filter="table-bot"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 头像预览列模板 -->
|
||||
<script type="text/html" id="tpl-avatar">
|
||||
{{# if(d.avatar){ }}
|
||||
<img src="{{d.avatar}}" style="width:40px;height:40px;border-radius:50%;object-fit:cover;vertical-align:middle;" onerror="this.src='../../../images/face/0.png'">
|
||||
{{# } else { }}
|
||||
<span style="color:#aaa;">无</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="toolbar-bot">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-bot"><i class="layui-icon layui-icon-add-1"></i> 添加机器人</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-bot"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="bot-bar">
|
||||
<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>
|
||||
</script>
|
||||
|
||||
<!-- 添加/编辑弹窗内嵌表单(隐藏,动态使用) -->
|
||||
<div id="bot-form-tpl" style="display:none;">
|
||||
<div style="padding:24px 20px 10px;">
|
||||
<form class="layui-form" id="bot-edit-form">
|
||||
<input type="hidden" name="id" id="bot-id">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称 <span style="color:red">*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" id="bot-name" class="layui-input" placeholder="请输入机器人昵称" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-block">
|
||||
<div style="display:flex;align-items:center;gap:12px;">
|
||||
<!-- 预览框 -->
|
||||
<div id="avatar-preview-wrap" style="width:64px;height:64px;border:1px dashed #ccc;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#f8f8f8;flex-shrink:0;">
|
||||
<img id="avatar-preview" src="" style="width:100%;height:100%;object-fit:cover;display:none;" onerror="this.style.display='none';document.getElementById('avatar-placeholder').style.display='flex';">
|
||||
<span id="avatar-placeholder" style="font-size:12px;color:#aaa;text-align:center;display:flex;">点击上传</span>
|
||||
</div>
|
||||
<!-- 上传按钮 -->
|
||||
<div>
|
||||
<button type="button" class="layui-btn layui-btn-sm" id="btn-upload-avatar">
|
||||
<i class="layui-icon layui-icon-upload"></i> 上传图片
|
||||
</button>
|
||||
<input type="file" id="avatar-file-input" accept="image/*" style="display:none;">
|
||||
<div style="margin-top:6px;font-size:12px;color:#999;">支持 jpg/png/gif,建议正方形,≤2MB</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- URL 输入框(上传后自动填充,也可手动填写) -->
|
||||
<input type="text" name="avatar" id="bot-avatar" class="layui-input" placeholder="头像URL(上传后自动填充,或直接粘贴URL)" style="margin-top:10px;">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer', 'upload'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
upload = layui.upload,
|
||||
setter = layui.setter;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadData() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/BotConfig/GetAll",
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
table.reload('table-bot', { data: res.data || [] });
|
||||
} else {
|
||||
layer.msg(res.info || '加载失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
table.render({
|
||||
elem: '#table-bot',
|
||||
url: setter.baseurl + 'adminapi/BotConfig/GetAll',
|
||||
method: 'get',
|
||||
page: false,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "avatar", title: "头像", width: 80, templet: '#tpl-avatar', align: 'center' },
|
||||
{ field: "name", title: "昵称", minWidth: 200 },
|
||||
{ field: "avatar", title: "头像URL", minWidth: 280 },
|
||||
{ title: "操作", width: 150, fixed: 'right', toolbar: '#bot-bar' }
|
||||
]],
|
||||
toolbar: '#toolbar-bot',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="add-bot"]', function () {
|
||||
showEditDialog(null, true);
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-bot"]', function () {
|
||||
loadData();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
table.on('tool(table-bot)', function (obj) {
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除「' + obj.data.name + '」吗?', function (idx) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
url: setter.baseurl + "adminapi/BotConfig/Delete?id=" + encodeURIComponent(obj.data.id || obj.data.Id || ''),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
obj.del();
|
||||
layer.msg('删除成功');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
layer.close(idx);
|
||||
});
|
||||
} else if (obj.event === 'edit') {
|
||||
showEditDialog(obj.data, false);
|
||||
}
|
||||
});
|
||||
|
||||
// =========== 上传逻辑 ===========
|
||||
var currentLayer = null; // 当前弹窗 DOM 引用
|
||||
|
||||
// 判断是否后台相对路径,自动补全当前域名
|
||||
function fixUrl(path) {
|
||||
if (!path) return '';
|
||||
// 已是完整URL直接返回
|
||||
if (/^https?:\/\//i.test(path)) return path;
|
||||
// 相对路径补全域名
|
||||
if (path.indexOf('/') === 0) {
|
||||
return window.location.origin + path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function initUpload(layero) {
|
||||
currentLayer = layero;
|
||||
|
||||
// 点击上传按钮触发文件选择
|
||||
layero.find('#btn-upload-avatar').off('click').on('click', function () {
|
||||
$('#avatar-file-input').val('').trigger('click');
|
||||
});
|
||||
|
||||
// 文件选择后立即上传
|
||||
$('#avatar-file-input').off('change').on('change', function () {
|
||||
var file = this.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// 大小校验 2MB
|
||||
if (file.size > 2 * 1024 * 1024) {
|
||||
layer.msg('图片大小不能超过 2MB');
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
// 显示上传中状态
|
||||
var loadIdx = layer.load(2, { shade: [0.3, '#fff'] });
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/temp',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + (setter.token || layui.data(setter.tableName || 'layuiAdmin')[setter.tokenName || 'token'] || '')
|
||||
},
|
||||
success: function (res) {
|
||||
layer.close(loadIdx);
|
||||
if (res.code === 0 && res.data && res.data.path) {
|
||||
// 后台返回相对路径,自动拼接当前域名
|
||||
var url = fixUrl(res.data.path);
|
||||
// 填充弹窗内 URL 输入框
|
||||
currentLayer.find('#bot-avatar').val(url);
|
||||
// 更新弹窗内预览
|
||||
setAvatarPreview(url);
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || res.msg || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.close(loadIdx);
|
||||
layer.msg('上传请求失败,请稍后重试');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// URL 输入框变化时同步预览
|
||||
layero.find('#bot-avatar').off('input').on('input', function () {
|
||||
setAvatarPreview($(this).val().trim());
|
||||
});
|
||||
}
|
||||
|
||||
function setAvatarPreview(url) {
|
||||
if (!currentLayer) return;
|
||||
if (url) {
|
||||
currentLayer.find('#avatar-preview').attr('src', url).show();
|
||||
currentLayer.find('#avatar-placeholder').hide();
|
||||
} else {
|
||||
currentLayer.find('#avatar-preview').attr('src', '').hide();
|
||||
currentLayer.find('#avatar-placeholder').show();
|
||||
}
|
||||
}
|
||||
|
||||
// =========== 弹窗 ===========
|
||||
function showEditDialog(data, isAdd) {
|
||||
var title = isAdd ? '添加机器人' : '编辑机器人';
|
||||
var formHtml = $('#bot-form-tpl').html();
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['520px', '380px'],
|
||||
content: formHtml,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function (layero) {
|
||||
form.render();
|
||||
|
||||
// 回填数据
|
||||
if (data) {
|
||||
layero.find('#bot-id').val(data.id || '');
|
||||
layero.find('#bot-name').val(data.name || '');
|
||||
layero.find('#bot-avatar').val(data.avatar || '');
|
||||
setAvatarPreview(data.avatar || '');
|
||||
} else {
|
||||
layero.find('#bot-id').val('');
|
||||
layero.find('#bot-name').val('');
|
||||
layero.find('#bot-avatar').val('');
|
||||
setAvatarPreview('');
|
||||
}
|
||||
|
||||
// 初始化上传事件(传入弹窗DOM引用)
|
||||
initUpload(layero);
|
||||
},
|
||||
yes: function (idx, layero) {
|
||||
var name = layero.find('#bot-name').val().trim();
|
||||
var avatar = layero.find('#bot-avatar').val().trim();
|
||||
var id = layero.find('#bot-id').val();
|
||||
|
||||
if (!name) {
|
||||
layer.msg('昵称不能为空');
|
||||
return;
|
||||
}
|
||||
|
||||
var url, sendData;
|
||||
if (isAdd) {
|
||||
url = setter.baseurl + 'adminapi/BotConfig/Add';
|
||||
sendData = { name: name, avatar: avatar };
|
||||
} else {
|
||||
url = setter.baseurl + 'adminapi/BotConfig/Update';
|
||||
sendData = { id: id, name: name, avatar: avatar };
|
||||
}
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: url,
|
||||
data: JSON.stringify(sendData),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(idx);
|
||||
layer.msg(isAdd ? '添加成功' : '更新成功');
|
||||
loadData();
|
||||
} else {
|
||||
layer.msg(res.info || '操作失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,220 @@
|
||||
|
||||
<title>游戏房间配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>游戏房间配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header" style="font-weight:bold;">中国象棋 - 开房权限</div>
|
||||
<div class="layui-card-body" style="padding-top:10px;">
|
||||
<form class="layui-form" lay-filter="chess-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">开房权限</label>
|
||||
<div class="layui-input-block" id="createRoomLimit">
|
||||
<input type="checkbox" name="createRoomLimit" value="1" title="VIP" lay-filter="createRoomLimitVip">
|
||||
<input type="checkbox" name="createRoomLimit" value="2" title="代理商">
|
||||
<input type="checkbox" name="createRoomLimit" value="3" title="普通用户">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="createRoomVipLevelsRow" style="display:none;">
|
||||
<label class="layui-form-label">VIP等级范围</label>
|
||||
<div class="layui-input-block" id="createRoomVipLevels">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最小下注</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="minBetGold" class="layui-input" style="width:300px">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">下注档位</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="betGoldLimits" placeholder="多个值用逗号分隔" class="layui-input" style="width:300px">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header" style="font-weight:bold;">捕鱼 - 手动选座权限</div>
|
||||
<div class="layui-card-body" style="padding-top:10px;">
|
||||
<form class="layui-form" lay-filter="fish-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手动选座</label>
|
||||
<div class="layui-input-block" id="seatSelectLimit">
|
||||
<input type="checkbox" name="seatSelectLimit" value="1" title="VIP" lay-filter="seatSelectLimitVip">
|
||||
<input type="checkbox" name="seatSelectLimit" value="2" title="代理商">
|
||||
<input type="checkbox" name="seatSelectLimit" value="3" title="普通用户">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" id="seatSelectVipLevelsRow" style="display:none;">
|
||||
<label class="layui-form-label">VIP等级范围</label>
|
||||
<div class="layui-input-block" id="seatSelectVipLevels">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body" style="padding-top:10px;">
|
||||
<button class="layui-btn" lay-submit lay-filter="save-all"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-warm" type="button" lay-filter="reload-all"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('ChessConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
setter = layui.setter;
|
||||
|
||||
setTimeout(function() {
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function buildVipCheckboxHtml(selectedVipLevels) {
|
||||
var html = '';
|
||||
for (var i = 1; i <= 10; i++) {
|
||||
var checked = selectedVipLevels && selectedVipLevels.indexOf(i) !== -1 ? 'checked' : '';
|
||||
html += '<input type="checkbox" name="vipLevels" value="' + i + '" title="VIP' + i + '" ' + checked + ' lay-skin="primary">';
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
function toggleVipLevelsRow() {
|
||||
var createVipChecked = $('input[name="createRoomLimit"][value="1"]').is(':checked');
|
||||
$('#createRoomVipLevelsRow').toggle(createVipChecked);
|
||||
|
||||
var seatVipChecked = $('input[name="seatSelectLimit"][value="1"]').is(':checked');
|
||||
$('#seatSelectVipLevelsRow').toggle(seatVipChecked);
|
||||
}
|
||||
|
||||
form.on('checkbox(createRoomLimitVip)', function() {
|
||||
toggleVipLevelsRow();
|
||||
});
|
||||
form.on('checkbox(seatSelectLimitVip)', function() {
|
||||
toggleVipLevelsRow();
|
||||
});
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
var cc = res.data.chessConfig || {};
|
||||
var fc = res.data.fishRoomConfig || {};
|
||||
|
||||
$('#createRoomVipLevels').html(buildVipCheckboxHtml(cc.createRoomVipLevels || []));
|
||||
$('#seatSelectVipLevels').html(buildVipCheckboxHtml(fc.seatSelectVipLevels || []));
|
||||
|
||||
$('input[name="createRoomLimit"]').prop('checked', false);
|
||||
if (cc.createRoomLimit && Array.isArray(cc.createRoomLimit)) {
|
||||
cc.createRoomLimit.forEach(function(v) {
|
||||
$('input[name="createRoomLimit"][value="' + v + '"]').prop('checked', true);
|
||||
});
|
||||
}
|
||||
$('input[name="seatSelectLimit"]').prop('checked', false);
|
||||
if (fc.seatSelectLimit && Array.isArray(fc.seatSelectLimit)) {
|
||||
fc.seatSelectLimit.forEach(function(v) {
|
||||
$('input[name="seatSelectLimit"][value="' + v + '"]').prop('checked', true);
|
||||
});
|
||||
}
|
||||
|
||||
$('input[name="minBetGold"]').val(cc.minBetGold || 0);
|
||||
var betStr = '';
|
||||
if (cc.betGoldLimits && Array.isArray(cc.betGoldLimits)) {
|
||||
betStr = cc.betGoldLimits.join(',');
|
||||
}
|
||||
$('input[name="betGoldLimits"]').val(betStr);
|
||||
|
||||
form.render('checkbox');
|
||||
|
||||
toggleVipLevelsRow();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function collectVipLevels(containerId) {
|
||||
var levels = [];
|
||||
$('#' + containerId + ' input[name="vipLevels"]:checked').each(function() {
|
||||
levels.push(parseInt($(this).val()));
|
||||
});
|
||||
return levels;
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="save-all"]', function() {
|
||||
var createRoomChecked = [];
|
||||
$('input[name="createRoomLimit"]:checked').each(function() {
|
||||
createRoomChecked.push(parseInt($(this).val()));
|
||||
});
|
||||
|
||||
var seatChecked = [];
|
||||
$('input[name="seatSelectLimit"]:checked').each(function() {
|
||||
seatChecked.push(parseInt($(this).val()));
|
||||
});
|
||||
|
||||
var betStr = $('input[name="betGoldLimits"]').val() || '';
|
||||
var betList = [];
|
||||
if (betStr.trim()) {
|
||||
betList = betStr.split(',').map(function(x) { return parseInt(x.trim()); }).filter(function(x) { return !isNaN(x); });
|
||||
}
|
||||
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
res.data.chessConfig = {
|
||||
createRoomLimit: createRoomChecked,
|
||||
createRoomVipLevels: collectVipLevels('createRoomVipLevels'),
|
||||
minBetGold: parseInt($('input[name="minBetGold"]').val()) || 0,
|
||||
betGoldLimits: betList
|
||||
};
|
||||
res.data.fishRoomConfig = {
|
||||
seatSelectLimit: seatChecked,
|
||||
seatSelectVipLevels: collectVipLevels('seatSelectVipLevels')
|
||||
};
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(res.data),
|
||||
done: function (r) {
|
||||
if (r.code === 0 || r.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
} else {
|
||||
layer.msg(r.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-all"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,111 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>象棋 Hub 流程测试</title>
|
||||
<style>
|
||||
body { font-family: Consolas, monospace; font-size: 13px; background: #111; color: #ddd; padding: 12px; }
|
||||
button { cursor: pointer; padding: 6px 12px; margin: 3px; }
|
||||
.log { background: #000; border: 1px solid #333; height: 50vh; overflow-y: auto; margin-top: 10px; padding: 8px; white-space: pre-wrap; font-size: 12px; }
|
||||
.ok { color: #0f0; } .bad { color: #f55; } .info { color: #9ad; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>象棋 Hub 流程测试</h3>
|
||||
<div>
|
||||
<label>Hub地址: <input id="hub" value="" placeholder="请输入测试环境 Hub 地址" style="width:260px"></label>
|
||||
<button onclick="connAll()">1. 连接 L1/A/B</button>
|
||||
<button onclick="createRoom()">2. A 建房</button>
|
||||
<button onclick="joinRoom()">3. B 加入</button>
|
||||
<button onclick="readyAll()">4. 双方Ready</button>
|
||||
<button onclick="bExit()">5. B退出</button>
|
||||
<button onclick="bJoin()">6. B重新加入</button>
|
||||
<button onclick="afkA()">7. A挂起</button>
|
||||
<button onclick="afkB()">8. B挂起(等5s)</button>
|
||||
<br>
|
||||
<label>RoomID: <input id="room" name="room" value="" style="width:200px"></label>
|
||||
<label>密码: <input id="password" name="password" value="" placeholder="请输入测试房间密码" style="width:180px"></label>
|
||||
<label>UID-A: <input id="a" name="a" value="" style="width:280px"></label>
|
||||
<label>UID-B: <input id="b" name="b" value="" style="width:280px"></label>
|
||||
<button onclick="clearLog()">清空日志</button>
|
||||
</div>
|
||||
<div class="log" id="log"></div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/@microsoft/signalr@8.0.7/dist/browser/signalr.min.js"></script>
|
||||
<script>
|
||||
const logEl = document.getElementById('log');
|
||||
function log(msg) { logEl.innerHTML += msg + '\n'; logEl.scrollTop = logEl.scrollHeight; }
|
||||
function ok(m) { log('<span class="ok">[OK]</span> ' + m); }
|
||||
function bad(m) { log('<span class="bad">[FAIL]</span> ' + m); }
|
||||
function info(m) { log('<span class="info">[INFO]</span> ' + m); }
|
||||
|
||||
let L1, A, B;
|
||||
const roomQ = () => document.getElementById('room').value;
|
||||
const passwordQ = () => document.getElementById('password').value;
|
||||
const uidA = () => document.getElementById('a').value;
|
||||
const uidB = () => document.getElementById('b').value;
|
||||
const hubUrl = () => document.getElementById('hub').value;
|
||||
|
||||
function newTestId(prefix) {
|
||||
const value = window.crypto && crypto.randomUUID ? crypto.randomUUID().replace(/-/g, '') : Date.now() + Math.random().toString(16).slice(2);
|
||||
return prefix + value;
|
||||
}
|
||||
|
||||
document.getElementById('hub').value = /^https?:$/.test(location.protocol) ? location.origin + '/chessgamehub' : '';
|
||||
document.getElementById('room').value = 'TEST_' + Date.now();
|
||||
document.getElementById('a').value = newTestId('A_');
|
||||
document.getElementById('b').value = newTestId('B_');
|
||||
|
||||
function evt(conn, name, cb) { conn.on(name, cb); }
|
||||
|
||||
function make(id, uid, tag) {
|
||||
const c = new signalR.HubConnectionBuilder()
|
||||
.withUrl(hubUrl() + '?userId=' + uid)
|
||||
.withAutomaticReconnect()
|
||||
.build();
|
||||
const events = ['GameError','BeginGame','CreateRoomNotice','JoinRoomNotice','ExitRoomNotice',
|
||||
'JoinRoom','Reconnect','ReadyNotice','AllBeginTime','GoldConfigRequired','ExitRoomSuccess',
|
||||
'GameEnd','Disconnect','PlayerAfkNotice','PlayerCancelAfkNotice','OpponentRequestEnd','EndGameRequestSent','RestartRoomNotice'];
|
||||
events.forEach(e => c.on(e, (arg) => {
|
||||
let s = typeof arg === 'object' ? JSON.stringify(arg) : arg;
|
||||
if (s && s.length > 140) s = s.substr(0, 140) + '…';
|
||||
log(`<span class="info">[${tag}]</span> 推送 <b>${e}</b>: ${s}`);
|
||||
}));
|
||||
c.onreconnected(() => log(`<span class="bad">[${tag}] 重连</span>`));
|
||||
return c;
|
||||
}
|
||||
|
||||
async function connAll() {
|
||||
L1 = make('L1', 'L1_' + uidA().substr(0,8), 'L1'); A = make('A', uidA(), 'A'); B = make('B', uidB(), 'B');
|
||||
for (const [tag, c] of [['L1', L1], ['A', A], ['B', B]]) {
|
||||
try { await c.start(); ok(`${tag} 连接成功 ${c.connectionId}`); }
|
||||
catch (e) { bad(`${tag} 连接失败: ${e}`); log(e.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
async function createRoom() {
|
||||
try {
|
||||
await A.invoke('CreateRoom', { roomId: roomQ(), userId: uidA(), gameType: 1, password: passwordQ(), gold: 100 });
|
||||
ok('A invoke CreateRoom 已发送');
|
||||
} catch (e) { bad('CreateRoom 异常: ' + e); }
|
||||
}
|
||||
|
||||
async function joinRoom() {
|
||||
try { await B.invoke('JoinGame', roomQ(), passwordQ(), uidB()); ok('B invoke JoinGame 已发送'); }
|
||||
catch (e) { bad('JoinGame 异常: ' + e); }
|
||||
}
|
||||
|
||||
async function readyAll() {
|
||||
try { await A.invoke('GameReady', roomQ(), uidA()); await B.invoke('GameReady', roomQ(), uidB()); ok('双方 Ready 已发送'); }
|
||||
catch (e) { bad('Ready 异常: ' + e); }
|
||||
}
|
||||
|
||||
async function bExit() { try { await B.invoke('ExitRoom', roomQ(), uidB()); ok('B ExitRoom 已发送'); } catch (e) { bad('ExitRoom: ' + e); } }
|
||||
async function bJoin() { try { await B.invoke('JoinGame', roomQ(), passwordQ(), uidB()); ok('B 重新加入已发送'); } catch (e) { bad(e); } }
|
||||
async function afkA() { try { await A.invoke('SetPlayerAfk', roomQ(), uidA()); ok('A SetPlayerAfk 已发送'); } catch (e) { bad('afkA: ' + e); } }
|
||||
async function afkB() { try { await B.invoke('SetPlayerAfk', roomQ(), uidB()); ok('B SetPlayerAfk 已发送'); } catch (e) { bad('afkB: ' + e); } }
|
||||
|
||||
function clearLog(){ logEl.innerHTML=''; }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,359 @@
|
||||
|
||||
<title>钻石商城配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>钻石商城配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-diamondshop" lay-filter="table-diamondshop"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-diamondshop">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-diamondshop"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-diamondshop"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-diamondshop"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-diamondshop" lay-event="add">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-diamondshop" lay-event="batchdel">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveAct('DiamondShopConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-icon">
|
||||
{{# if(d.icon){ }}
|
||||
<img src="{{d.icon}}" style="width:40px;height:40px;object-fit:cover;cursor:pointer;border-radius:4px;" onclick="previewImage('{{d.icon}}')" alt="图标">
|
||||
{{# } else { }}
|
||||
<span style="color:#999;">无</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-upload-box { position: relative; display: inline-block; }
|
||||
.icon-upload-box .upload-btn { position: absolute; top: 0; left: 0; width: 80px; height: 80px; opacity: 0; cursor: pointer; }
|
||||
.icon-upload-preview { width: 80px; height: 80px; border: 1px dashed #ddd; border-radius: 4px; display: flex; align-items: center; justify-content: center; background: #fafafa; cursor: pointer; }
|
||||
.icon-upload-preview:hover { border-color: #009688; }
|
||||
.icon-upload-preview img { max-width: 100%; max-height: 100%; }
|
||||
.icon-upload-preview .placeholder { color: #999; font-size: 12px; text-align: center; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var activityConfig = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/Get",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
activityConfig = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-diamondshop',
|
||||
data: activityConfig ? activityConfig.diamondShopConfigs || [] : [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "number", title: "商品编号", width: 100 },
|
||||
{ field: "name", title: "商品名称", width: 120 },
|
||||
{ field: "icon", title: "图标", width: 100, templet: '#tpl-icon' },
|
||||
{ field: "diamond", title: "钻石数量", width: 100 },
|
||||
{ field: "money", title: "现金价格", width: 100 },
|
||||
{ field: "dealerMoney", title: "经销商价格", width: 120 },
|
||||
{ title: "操作", width: 180, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-diamondshop',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
window.previewImage = function(url) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '图片预览',
|
||||
area: ['auto', 'auto'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:20px;text-align:center;"><img src="' + url + '" style="max-width:400px;max-height:400px;border-radius:8px;"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要从配置文件还原钻石商城配置吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitActivitySection/DiamondShopConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-diamondshop"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-diamondshop"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-diamondshop"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/UpdateDiamondShop",
|
||||
data: JSON.stringify(activityConfig.diamondShopConfigs || []),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-diamondshop)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = activityConfig.diamondShopConfigs.findIndex(function(x) { return x.number === data.number; });
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(trIndex > -1 ? activityConfig.diamondShopConfigs[trIndex] : data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) activityConfig.diamondShopConfigs.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
table.on('toolbar(table-diamondshop)', function(obj) {
|
||||
if (obj.event === 'add') {
|
||||
showAddDialog();
|
||||
} else if (obj.event === 'batchdel') {
|
||||
var checkStatus = table.checkStatus('table-diamondshop');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.number; });
|
||||
activityConfig.diamondShopConfigs = activityConfig.diamondShopConfigs.filter(function(item) {
|
||||
return !ids.includes(item.number);
|
||||
});
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
showEditDialog({
|
||||
number: '',
|
||||
name: '',
|
||||
icon: '',
|
||||
diamond: 0,
|
||||
money: 0,
|
||||
dealerMoney: 0
|
||||
}, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-diamondshop"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var isNewAdd = isAdd === true;
|
||||
var dialogTitle = isNewAdd ? '添加商品' : '编辑商品';
|
||||
|
||||
var imagePreviewHtml = data.icon
|
||||
? '<img src="' + data.icon + '" style="max-width:100%;max-height:100%;">'
|
||||
: '<div class="placeholder">点击上传</div>';
|
||||
|
||||
var html = '<div class="edit-dialog" style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">商品编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="number" value="' + (data.number || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">商品名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">图标</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="icon-upload-box">' +
|
||||
'<div class="icon-upload-preview" id="iconPreview">' + imagePreviewHtml + '</div>' +
|
||||
'<input type="file" class="upload-btn" accept="image/png" id="iconUpload">' +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="icon" id="iconInput" value="' + (data.icon || '') + '">' +
|
||||
'<div style="margin-top:8px;color:#999;font-size:12px;">点击图片可预览,仅支持 PNG 格式</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">钻石数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="diamond" value="' + (data.diamond || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">现金价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="money" value="' + (data.money || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经销商价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="dealerMoney" value="' + (data.dealerMoney || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['600px', '600px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
var $preview = layero.find('#iconPreview');
|
||||
var $input = layero.find('#iconInput');
|
||||
var $fileInput = layero.find('#iconUpload');
|
||||
|
||||
$preview.on('click', function() {
|
||||
var url = $input.val();
|
||||
if (url) previewImage(url);
|
||||
});
|
||||
|
||||
$fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (file) {
|
||||
var number = layero.find('input[name="number"]').val();
|
||||
if (!number) {
|
||||
layer.msg('请先填写商品编号');
|
||||
$(this).val('');
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('number', number);
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/config',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
success: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
var path = res.data.path;
|
||||
$input.val(path);
|
||||
$preview.html('<img src="' + path + '" style="max-width:100%;max-height:100%;">');
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('上传失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
number: layero.find('input[name="number"]').val(),
|
||||
name: layero.find('input[name="name"]').val(),
|
||||
icon: layero.find('#iconInput').val(),
|
||||
diamond: parseInt(layero.find('input[name="diamond"]').val()) || 0,
|
||||
money: parseFloat(layero.find('input[name="money"]').val()) || 0,
|
||||
dealerMoney: parseFloat(layero.find('input[name="dealerMoney"]').val()) || 0
|
||||
};
|
||||
activityConfig.diamondShopConfigs.unshift(newItem);
|
||||
} else if (rowIndex > -1) {
|
||||
var original = activityConfig.diamondShopConfigs[rowIndex];
|
||||
original.number = layero.find('input[name="number"]').val();
|
||||
original.name = layero.find('input[name="name"]').val();
|
||||
original.icon = layero.find('#iconInput').val();
|
||||
original.diamond = parseInt(layero.find('input[name="diamond"]').val()) || 0;
|
||||
original.money = parseFloat(layero.find('input[name="money"]').val()) || 0;
|
||||
original.dealerMoney = parseFloat(layero.find('input[name="dealerMoney"]').val()) || 0;
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-diamondshop', {
|
||||
data: activityConfig.diamondShopConfigs
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveAct=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/ActivityConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,211 @@
|
||||
<title>空房率配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>空房率配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body" style="padding-top:10px;">
|
||||
<table id="table-rate" lay-filter="table-rate"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-rate">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-rate"><i class="layui-icon layui-icon-add-1"></i> 添加配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-rate"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate-rate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
// 页面加载时清理可能残留的遮罩
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
var typeMap = {0:'无', 1:'风雷之渊', 2:'永夜尸城', 3:'中国象棋', 4:'星际迷航', 5:'黑神话悟空'};
|
||||
|
||||
function loadData() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/EmptyRoomRateConfig/list?page=1&size=100",
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
table.reload('table-rate', { data: res.data || [] });
|
||||
} else {
|
||||
layer.msg(res.info || '加载失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
table.render({
|
||||
elem: '#table-rate',
|
||||
data: [],
|
||||
page: true,
|
||||
limit: 20,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "gameTypeName", title: "游戏类型", width: 130 },
|
||||
{ field: "gameType", title: "游戏类型值", width: 100 },
|
||||
{ field: "roomLevel", title: "房间等级", width: 100, templet: function(d) { return d.gameType === 3 ? '-' : d.roomLevel; } },
|
||||
{ field: "emptyRoomRate", title: "空房率(%)", width: 120 },
|
||||
{ title: "操作", width: 150, fixed: 'right', toolbar: '#table-operate-rate' }
|
||||
]],
|
||||
toolbar: '#toolbar-rate',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="add-rate"]', function () {
|
||||
showEditDialog(null, true);
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-rate"]', function () {
|
||||
loadData();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
table.on('tool(table-rate)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(data, false);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除「' + data.gameTypeName + ' Lv.' + data.roomLevel + '」的空房率配置吗?', function (idx) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/EmptyRoomRateConfig/delete",
|
||||
data: JSON.stringify({ id: data.id }),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
obj.del();
|
||||
layer.msg('删除成功');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd) {
|
||||
var dialogTitle = isAdd ? '添加空房率配置' : '编辑空房率配置';
|
||||
|
||||
var typeHtml = '';
|
||||
for (var key in typeMap) {
|
||||
var val = parseInt(key);
|
||||
typeHtml += '<option value="' + val + '"' + (data && data.gameType === val ? ' selected' : '') + '>' + typeMap[key] + '</option>';
|
||||
}
|
||||
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">游戏类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="gameType"' + (isAdd ? '' : ' disabled') + '>' + typeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">房间等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="roomLevel" value="' + (data ? data.roomLevel : 0) + '" class="layui-input"' + (isAdd ? '' : ' readonly') + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">空房率(%)</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="emptyRoomRate" value="' + (data ? data.emptyRoomRate : 30) + '" class="layui-input" placeholder="0-100,0或负数=不启用">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label"></label>' +
|
||||
'<div class="layui-input-block" style="color:#999;font-size:12px;">空房率低于该值时暂停补充机器人;0或负数表示不启用</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['480px', '360px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function (layero) {
|
||||
form.render('select');
|
||||
},
|
||||
yes: function (index, layero) {
|
||||
var gameType = parseInt(layero.find('select[name="gameType"]').val());
|
||||
var roomLevel = parseInt(layero.find('input[name="roomLevel"]').val()) || 0;
|
||||
if (gameType === 3) roomLevel = 0; // 象棋无房间等级
|
||||
var emptyRoomRate = parseInt(layero.find('input[name="emptyRoomRate"]').val());
|
||||
if (isNaN(emptyRoomRate)) {
|
||||
layer.msg('请输入有效的空房率');
|
||||
return;
|
||||
}
|
||||
if (!isAdd) {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/EmptyRoomRateConfig/update",
|
||||
data: JSON.stringify({ id: data.id, emptyRoomRate: emptyRoomRate }),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
layer.msg('更新成功');
|
||||
loadData();
|
||||
} else {
|
||||
layer.msg(res.info || '更新失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/EmptyRoomRateConfig/add",
|
||||
data: JSON.stringify({ gameType: gameType, roomLevel: roomLevel, emptyRoomRate: emptyRoomRate }),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
layer.msg('添加成功');
|
||||
loadData();
|
||||
} else {
|
||||
layer.msg(res.info || '添加失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,458 @@
|
||||
<title>鱼种配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>鱼种配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body" style="padding:10px 10px 0 10px;">
|
||||
<div class="layui-btn-container" id="game-type-btns">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="0">全部游戏</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="1">风雷之渊</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="2">永夜尸城</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="3">黑化悟空</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="4">星际迷航</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body" style="padding-top:10px;">
|
||||
<table id="table-fish" lay-filter="table-fish"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-fish">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-fish"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-fish"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-fish"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-fish">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-fish">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('FishTypeConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
<select name="filterType" lay-filter="filter-type" lay-search="true" style="width:120px;">
|
||||
<option value="">全部类型</option>
|
||||
<option value="1">普通鱼</option>
|
||||
<option value="2">Boss鱼</option>
|
||||
<option value="3">黄金鱼</option>
|
||||
<option value="4">特殊鱼</option>
|
||||
<option value="5">特殊Boss</option>
|
||||
</select>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<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>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form'], function () {
|
||||
if (window._fishInitialized) return;
|
||||
window._fishInitialized = true;
|
||||
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var currentGameType = 0;
|
||||
var currentFilterType = '';
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.data) {
|
||||
gameConfig = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getFishForGameType(gameType) {
|
||||
var allFish = (gameConfig ? gameConfig.fishTypeConfigs : []) || [];
|
||||
if (gameType === 0) return allFish;
|
||||
|
||||
var minNum = 0, maxNum = 0;
|
||||
switch (gameType) {
|
||||
case 1: minNum = 11000; maxNum = 11999; break; // 风雷之渊
|
||||
case 2: minNum = 15000; maxNum = 15999; break; // 丧尸/永夜尸城
|
||||
case 3: minNum = 13000; maxNum = 13999; break; // 黑化悟空
|
||||
case 4: minNum = 12000; maxNum = 12999; break; // 星际迷航
|
||||
case 5: minNum = 14000; maxNum = 14999; break; // 黑神话悟空 (备用)
|
||||
default: return allFish;
|
||||
}
|
||||
|
||||
return allFish.filter(function(f) {
|
||||
var num = parseInt(f.fishNumber) || 0;
|
||||
return num >= minNum && num <= maxNum;
|
||||
});
|
||||
}
|
||||
|
||||
function switchGameType(gameType) {
|
||||
currentGameType = gameType;
|
||||
$('#game-type-btns .layui-btn').removeClass('layui-btn-primary');
|
||||
$('#game-type-btns .layui-btn[data-type="' + gameType + '"]').addClass('layui-btn-primary');
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function getFilteredTableData() {
|
||||
var data = getFishForGameType(currentGameType);
|
||||
if (currentFilterType && currentFilterType !== '') {
|
||||
data = data.filter(function(item) { return item.fishType === parseInt(currentFilterType); });
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function reloadFilteredTable() {
|
||||
table.reload('table-fish', {
|
||||
data: getFilteredTableData()
|
||||
});
|
||||
}
|
||||
|
||||
// 删除鱼种时同步清理所有精确引用。Boss 概率配置允许多个鱼共用,
|
||||
// 因此只移除目标编号,不能因为命中一个编号就删除整条配置。
|
||||
function removeFishReferences(fishNumbers) {
|
||||
var deletedNumbers = (fishNumbers || []).map(function(n) { return String(n); });
|
||||
var isDeleted = function(n) { return deletedNumbers.includes(String(n)); };
|
||||
|
||||
var roomConfigs = gameConfig.roomFishConfigs || [];
|
||||
if (!Array.isArray(roomConfigs)) roomConfigs = [roomConfigs];
|
||||
roomConfigs.forEach(function(roomConfig) {
|
||||
if (Array.isArray(roomConfig.roomFishLevelList)) {
|
||||
roomConfig.roomFishLevelList = roomConfig.roomFishLevelList.filter(function(x) {
|
||||
return !isDeleted(x.fishNumber);
|
||||
});
|
||||
}
|
||||
if (Array.isArray(roomConfig.normalFishList)) {
|
||||
roomConfig.normalFishList = roomConfig.normalFishList.filter(function(x) {
|
||||
return !isDeleted(x.fishNumber);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var probability = gameConfig.bossConfigs && gameConfig.bossConfigs.probability;
|
||||
if (Array.isArray(probability)) {
|
||||
gameConfig.bossConfigs.probability = probability.filter(function(p) {
|
||||
if (!Array.isArray(p.fishNumber)) return true;
|
||||
p.fishNumber = p.fishNumber.filter(function(n) { return !isDeleted(n); });
|
||||
return p.fishNumber.length > 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var tableInitialized = false;
|
||||
|
||||
function renderTable() {
|
||||
var data = getFilteredTableData();
|
||||
if (tableInitialized) {
|
||||
table.reload('table-fish', { data: data });
|
||||
return;
|
||||
}
|
||||
tableInitialized = true;
|
||||
table.render({
|
||||
elem: '#table-fish',
|
||||
data: data,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "fishNumber", title: "鱼编号", width: 80 },
|
||||
{ field: "fishName", title: "名称", width: 100 },
|
||||
{ field: "fishBrief", title: "简介", width: 150 },
|
||||
{ field: "fishType", title: "类型", width: 100, templet: function(d) { return getFishTypeName(d.fishType); } },
|
||||
{ field: "fishImage", title: "图标", width: 100, templet: function(d) { return d.fishImage ? '<img src="' + d.fishImage + '" style="width:36px;height:36px;object-fit:cover;border-radius:4px;">' : '-'; } },
|
||||
{ field: "fishScore", title: "击杀金币倍数", width: 140 },
|
||||
{ field: "fishMultipleDesc", title: "倍数描述", width: 120 },
|
||||
{ field: "killWeight", title: "击杀概率(1/10000)", width: 150 },
|
||||
{ field: "pathList", title: "路径列表", minWidth: 200, templet: function(d) { return formatPathList(d.pathList); } },
|
||||
{ title: "操作", width: 150, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-fish',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
done: function() {
|
||||
form.render('select');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getFishTypeName(type) {
|
||||
var map = {1: '普通鱼', 2: 'Boss鱼', 3: '黄金鱼', 4: '特殊鱼', 5: '特殊Boss'};
|
||||
return map[type] || '普通鱼';
|
||||
}
|
||||
|
||||
function formatPathList(pathList) {
|
||||
if (!pathList) return '';
|
||||
if (Array.isArray(pathList)) {
|
||||
return pathList.join(',');
|
||||
}
|
||||
return String(pathList);
|
||||
}
|
||||
|
||||
function parsePathList(pathStr) {
|
||||
if (!pathStr) return [];
|
||||
if (Array.isArray(pathStr)) return pathStr;
|
||||
if (typeof pathStr === 'string') {
|
||||
return pathStr.split(',').map(function(x) { return parseInt(x.trim()); }).filter(function(x) { return !isNaN(x); });
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function saveConfig() {
|
||||
var saveData = JSON.stringify(gameConfig);
|
||||
console.log('保存数据 pathList:', gameConfig.fishTypeConfigs.map(function(f) { return { fishNumber: f.fishNumber, pathList: f.pathList }; }));
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: saveData,
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/FishTypeConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 游戏类型切换
|
||||
$('#game-type-btns').off().on('click', '.layui-btn', function() {
|
||||
var gameType = parseInt($(this).data('type'));
|
||||
switchGameType(gameType);
|
||||
});
|
||||
|
||||
// 类型筛选事件
|
||||
form.on('select(filter-type)', function(data) {
|
||||
currentFilterType = data.value;
|
||||
renderTable();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="init-fish"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-fish"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-fish"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
saveConfig();
|
||||
});
|
||||
|
||||
table.on('tool(table-fish)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = gameConfig.fishTypeConfigs.findIndex(function(x) { return x.fishNumber === data.fishNumber; });
|
||||
console.log('编辑行 index:', trIndex, '数据:', data);
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
var delNum = data.fishNumber;
|
||||
gameConfig.fishTypeConfigs.splice(trIndex, 1);
|
||||
removeFishReferences([delNum]);
|
||||
obj.del();
|
||||
reloadFilteredTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
var newData = {
|
||||
fishNumber: '',
|
||||
fishName: '',
|
||||
fishBrief: '',
|
||||
fishType: 1,
|
||||
fishScore: 0,
|
||||
killWeight: 0,
|
||||
fishImage: '',
|
||||
fishMultipleDesc: '',
|
||||
pathList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
};
|
||||
if (!gameConfig.fishTypeConfigs) gameConfig.fishTypeConfigs = [];
|
||||
showEditDialog(newData, true, -1);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-fish"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-fish"]', function() {
|
||||
var checkStatus = table.checkStatus('table-fish');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.fishNumber; });
|
||||
gameConfig.fishTypeConfigs = gameConfig.fishTypeConfigs.filter(function(item) {
|
||||
return !ids.includes(item.fishNumber);
|
||||
});
|
||||
removeFishReferences(ids);
|
||||
reloadFilteredTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, itemIndex) {
|
||||
var dialogTitle = isAdd ? '添加鱼种' : '编辑鱼种';
|
||||
var typeOptions = [
|
||||
{value: 1, text: '普通鱼'},
|
||||
{value: 2, text: 'Boss鱼'},
|
||||
{value: 3, text: '黄金鱼'},
|
||||
{value: 4, text: '特殊鱼'},
|
||||
{value: 5, text: '特殊Boss'}
|
||||
];
|
||||
|
||||
var typeHtml = '';
|
||||
typeOptions.forEach(function(opt) {
|
||||
typeHtml += '<option value="' + opt.value + '"' + (data.fishType === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var currentPathStr = formatPathList(data.pathList);
|
||||
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">鱼号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="fishNumber" value="' + (data.fishNumber || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="fishName" value="' + (data.fishName || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">简介</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="fishBrief" value="' + (data.fishBrief || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="fishType">' + typeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">击杀金币倍数</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="fishScore" value="' + (data.fishScore || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">击杀概率(1/10000)</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="killWeight" value="' + (data.killWeight || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">图标URL</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="fishImage" value="' + (data.fishImage || '') + '" placeholder="图片地址" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">倍数描述</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="fishMultipleDesc" value="' + (data.fishMultipleDesc || '') + '" placeholder="如: 最高500倍" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">路径列表</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="pathList" value="' + currentPathStr + '" placeholder="多个值用逗号分隔" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['800px', '750px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
layui.form.render('select');
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
console.log('保存 isAdd:', isAdd, 'itemIndex:', itemIndex);
|
||||
var pathStr = layero.find('input[name="pathList"]').val();
|
||||
var pathList = parsePathList(pathStr);
|
||||
var updatedItem = {
|
||||
fishNumber: layero.find('input[name="fishNumber"]').val(),
|
||||
fishName: layero.find('input[name="fishName"]').val(),
|
||||
fishBrief: layero.find('input[name="fishBrief"]').val(),
|
||||
fishType: parseInt(layero.find('select[name="fishType"]').val()),
|
||||
fishScore: parseFloat(layero.find('input[name="fishScore"]').val()) || 0,
|
||||
killWeight: parseFloat(layero.find('input[name="killWeight"]').val()) || 0,
|
||||
fishImage: layero.find('input[name="fishImage"]').val(),
|
||||
fishMultipleDesc: layero.find('input[name="fishMultipleDesc"]').val(),
|
||||
pathList: pathList
|
||||
};
|
||||
if (isAdd) {
|
||||
gameConfig.fishTypeConfigs.unshift(updatedItem);
|
||||
} else {
|
||||
if (itemIndex >= 0 && itemIndex < gameConfig.fishTypeConfigs.length) {
|
||||
gameConfig.fishTypeConfigs[itemIndex] = updatedItem;
|
||||
console.log('更新后 gameConfig:', JSON.parse(JSON.stringify(gameConfig.fishTypeConfigs)));
|
||||
} else {
|
||||
console.log('条件不满足: itemIndex=', itemIndex, 'length=', gameConfig.fishTypeConfigs.length);
|
||||
}
|
||||
}
|
||||
layer.close(index);
|
||||
reloadFilteredTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,384 @@
|
||||
|
||||
<title>鱼阵配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>鱼阵配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body" style="padding:10px 10px 0 10px;">
|
||||
<div class="layui-btn-container" id="game-type-btns">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="0">全部游戏</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="1">风雷之渊</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="2">永夜尸城</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="3">黑化悟空</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="4">星际迷航</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body" style="padding-top:10px;">
|
||||
<table id="table-fisharray" lay-filter="table-fisharray"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-fisharray">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-fisharray"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-fisharray"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-fisharray"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-fisharray">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-fisharray">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('FishArrayConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var currentGameType = 0;
|
||||
var fishList = [];
|
||||
var bossFishList = [];
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
var fishConfigs = gameConfig.fishTypeConfigs || [];
|
||||
fishList = fishConfigs.filter(function(f) { return f.fishType === 1 || f.fishType === 3; });
|
||||
bossFishList = fishConfigs.filter(function(f) { return f.fishType === 2 || f.fishType === 5; });
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getArrayForGameType(gameType) {
|
||||
var allArrays = (gameConfig ? gameConfig.fishArrayConfigs : []) || [];
|
||||
if (gameType === 0) return allArrays;
|
||||
|
||||
var prefix = '';
|
||||
switch (gameType) {
|
||||
case 1: prefix = '32'; break; // 风雷之渊
|
||||
case 2: prefix = '33'; break; // 永夜尸城
|
||||
case 3: prefix = '31'; break; // 黑化悟空
|
||||
case 4: prefix = '30'; break; // 星际迷航
|
||||
default: return allArrays;
|
||||
}
|
||||
|
||||
return allArrays.filter(function(f) {
|
||||
var numStr = String(f.fishArrayNumber || '');
|
||||
return numStr.indexOf(prefix) === 0;
|
||||
});
|
||||
}
|
||||
|
||||
function switchGameType(gameType) {
|
||||
currentGameType = gameType;
|
||||
$('#game-type-btns .layui-btn').removeClass('layui-btn-primary');
|
||||
$('#game-type-btns .layui-btn[data-type="' + gameType + '"]').addClass('layui-btn-primary');
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function formatList(list) {
|
||||
if (!list) return '';
|
||||
if (Array.isArray(list)) return list.join(',');
|
||||
return String(list);
|
||||
}
|
||||
|
||||
function parseList(str) {
|
||||
if (!str) return [];
|
||||
if (Array.isArray(str)) return str;
|
||||
if (typeof str === 'string') {
|
||||
return str.split(',').map(function(x) { return parseInt(x.trim()); }).filter(function(x) { return !isNaN(x); });
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// 删除鱼阵时同步移除房间出鱼配置中的鱼阵引用(type=2)。
|
||||
function removeFishArrayReferences(arrayNumbers) {
|
||||
var deleted = new Set((arrayNumbers || []).map(function(x) { return String(x); }));
|
||||
var roomConfigs = gameConfig && gameConfig.roomFishConfigs;
|
||||
if (!deleted.size || !roomConfigs) return;
|
||||
|
||||
var configs = Array.isArray(roomConfigs) ? roomConfigs : [roomConfigs];
|
||||
configs.forEach(function(roomConfig) {
|
||||
if (!roomConfig) return;
|
||||
['normalFishList', 'roomFishLevelList'].forEach(function(field) {
|
||||
if (!Array.isArray(roomConfig[field])) return;
|
||||
roomConfig[field] = roomConfig[field].filter(function(item) {
|
||||
return !item || Number(item.type) !== 2 || !deleted.has(String(item.fishNumber));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var tableInitialized = false;
|
||||
|
||||
function renderTable() {
|
||||
var tableData = getArrayForGameType(currentGameType);
|
||||
if (tableInitialized) {
|
||||
table.reload('table-fisharray', { data: tableData });
|
||||
return;
|
||||
}
|
||||
tableInitialized = true;
|
||||
table.render({
|
||||
elem: '#table-fisharray',
|
||||
data: tableData,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "fishArrayNumber", title: "鱼阵编号", width: 100 },
|
||||
{ field: "name", title: "名称", width: 120 },
|
||||
{ field: "fishNumber", title: "普通鱼编号", width: 100 },
|
||||
{ field: "fishCount", title: "普通鱼数量", width: 100 },
|
||||
{ field: "bossFishNumber", title: "Boss鱼编号", width: 100 },
|
||||
{ field: "boosCount", title: "Boss数量", width: 90 },
|
||||
{ field: "arrayNumber", title: "阵型编号", width: 100 },
|
||||
{
|
||||
field: "generateFrequency", title: "生成频率(影响阵容间距)", width: 100, templet: function(d) {
|
||||
return d.generateFrequency || 0.2;
|
||||
}},
|
||||
{ title: "操作", width: 150, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-fisharray',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
// 游戏类型切换
|
||||
$('#game-type-btns').off().on('click', '.layui-btn', function() {
|
||||
var gameType = parseInt($(this).data('type'));
|
||||
switchGameType(gameType);
|
||||
});
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/FishArrayConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-fisharray"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-fisharray"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-fisharray"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-fisharray)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = gameConfig.fishArrayConfigs.findIndex(function(x) { return x.fishArrayNumber === data.fishArrayNumber; });
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) {
|
||||
gameConfig.fishArrayConfigs.splice(trIndex, 1);
|
||||
removeFishArrayReferences([data.fishArrayNumber]);
|
||||
}
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
if (!gameConfig.fishArrayConfigs) gameConfig.fishArrayConfigs = [];
|
||||
var newData = {
|
||||
fishArrayNumber: '',
|
||||
name: '',
|
||||
fishNumber: '',
|
||||
fishCount: 0,
|
||||
bossFishNumber: '',
|
||||
boosCount: 0,
|
||||
arrayNumber: '',
|
||||
generateFrequency: 0.2
|
||||
};
|
||||
showEditDialog(newData, true, -1);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-fisharray"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-fisharray"]', function() {
|
||||
var checkStatus = table.checkStatus('table-fisharray');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.fishArrayNumber; });
|
||||
gameConfig.fishArrayConfigs = gameConfig.fishArrayConfigs.filter(function(item) {
|
||||
return !ids.includes(item.fishArrayNumber);
|
||||
});
|
||||
removeFishArrayReferences(ids);
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, itemIndex) {
|
||||
var dialogTitle = isAdd ? '添加鱼阵' : '编辑鱼阵';
|
||||
var fishOptions = '<option value="">请选择</option>';
|
||||
fishList.forEach(function(f) {
|
||||
fishOptions += '<option value="' + f.fishNumber + '"' + (data.fishNumber === f.fishNumber ? ' selected' : '') + '>' + f.fishNumber + ' - ' + f.fishName + '</option>';
|
||||
});
|
||||
|
||||
var bossOptions = '<option value="">请选择</option>';
|
||||
bossFishList.forEach(function(f) {
|
||||
bossOptions += '<option value="' + f.fishNumber + '"' + (data.bossFishNumber === f.fishNumber ? ' selected' : '') + '>' + f.fishNumber + ' - ' + f.fishName + '</option>';
|
||||
});
|
||||
|
||||
var html = '<div class="edit-dialog" style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">鱼阵编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="fishArrayNumber" value="' + (data.fishArrayNumber || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">普通鱼编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="fishNumber" lay-search="true">' + fishOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">普通鱼数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="fishCount" value="' + (data.fishCount || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">Boss鱼编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="bossFishNumber" lay-search="true">' + bossOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">Boss数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="boosCount" value="' + (data.boosCount || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">阵型编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="arrayNumber" value="' + (data.arrayNumber || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">生成频率</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="generateFrequency" value="' + (data.generateFrequency || 0.2) + '" step="0.01" class="layui-input" placeholder="如: 0.2">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['600px', '600px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
var updatedItem = {
|
||||
fishArrayNumber: layero.find('input[name="fishArrayNumber"]').val(),
|
||||
name: layero.find('input[name="name"]').val(),
|
||||
fishNumber: layero.find('select[name="fishNumber"]').val(),
|
||||
fishCount: parseInt(layero.find('input[name="fishCount"]').val()) || 0,
|
||||
bossFishNumber: layero.find('select[name="bossFishNumber"]').val(),
|
||||
boosCount: parseInt(layero.find('input[name="boosCount"]').val()) || 0,
|
||||
arrayNumber: layero.find('input[name="arrayNumber"]').val(),
|
||||
generateFrequency: parseFloat(layero.find('input[name="generateFrequency"]').val()) || 0.2
|
||||
};
|
||||
if (isAdd) {
|
||||
gameConfig.fishArrayConfigs.unshift(updatedItem);
|
||||
} else {
|
||||
if (itemIndex >= 0 && itemIndex < gameConfig.fishArrayConfigs.length) {
|
||||
gameConfig.fishArrayConfigs[itemIndex] = updatedItem;
|
||||
}
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-fisharray', {
|
||||
data: getArrayForGameType(currentGameType)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,164 @@
|
||||
|
||||
<title>捕鱼返金币活动配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>捕鱼返金币活动</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="reload-fishing-return"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-fishing-return"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveAct('FishingReturnConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<blockquote class="layui-elem-quote layui-quote-nm" style="margin-bottom: 15px;">
|
||||
<p><strong>活动说明:</strong></p>
|
||||
<p>1. 用户每天捕鱼消耗金币的千分之一,第二天可领取返还</p>
|
||||
<p>2. 例如:第一天捕鱼消耗 1000 万金币,第二天可领取 1 万金币</p>
|
||||
<p>3. 每日返利上限可配置,0 表示无上限</p>
|
||||
</blockquote>
|
||||
<form class="layui-form" id="form-fishing-return" style="padding: 20px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">是否开启</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="isEnabled" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">返利比例</label>
|
||||
<div class="layui-input-inline" style="width: 200px;">
|
||||
<input type="number" name="returnRate" class="layui-input" placeholder="返利比例" step="0.0001" min="0" max="1">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">千分之一 = 0.001(例如:消耗1000金币,返还1金币)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">每日上限</label>
|
||||
<div class="layui-input-inline" style="width: 200px;">
|
||||
<input type="number" name="dailyMaxReturn" class="layui-input" placeholder="每日返利上限" min="0">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">0 = 无上限</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">计算示例</label>
|
||||
<div class="layui-input-block">
|
||||
<table class="layui-table" style="width: 400px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>昨日消耗金币</th>
|
||||
<th>返利比例</th>
|
||||
<th>可领取金币</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="calc-example">
|
||||
<tr><td colspan="3" style="text-align: center; color: #999;">请输入返利比例查看示例</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var fishingReturnConfig = null;
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/GetFishingReturn",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
fishingReturnConfig = res.data;
|
||||
fillForms();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fillForms() {
|
||||
if (fishingReturnConfig) {
|
||||
var r = fishingReturnConfig;
|
||||
$('#form-fishing-return input[name="isEnabled"]').prop('checked', r.isEnabled);
|
||||
$('#form-fishing-return input[name="returnRate"]').val(r.returnRate || 0.001);
|
||||
$('#form-fishing-return input[name="dailyMaxReturn"]').val(r.dailyMaxReturn || 0);
|
||||
}
|
||||
form.render();
|
||||
updateCalcExample();
|
||||
}
|
||||
|
||||
function updateCalcExample() {
|
||||
var rate = parseFloat($('#form-fishing-return input[name="returnRate"]').val()) || 0.001;
|
||||
var max = parseInt($('#form-fishing-return input[name="dailyMaxReturn"]').val()) || 0;
|
||||
var examples = [100000, 1000000, 10000000, 100000000];
|
||||
var html = '';
|
||||
examples.forEach(function(consume) {
|
||||
var gold = Math.floor(consume * rate);
|
||||
if (max > 0 && gold > max) {
|
||||
gold = max;
|
||||
}
|
||||
html += '<tr><td>' + consume.toLocaleString() + '</td><td>' + rate + '</td><td>' + gold.toLocaleString() + '</td></tr>';
|
||||
});
|
||||
$('#calc-example').html(html);
|
||||
}
|
||||
|
||||
$(document).on('input', '#form-fishing-return input[name="returnRate"], #form-fishing-return input[name="dailyMaxReturn"]', function() {
|
||||
updateCalcExample();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-fishing-return"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-fishing-return"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
|
||||
var config = {
|
||||
isEnabled: $('#form-fishing-return input[name="isEnabled"]').prop('checked'),
|
||||
returnRate: parseFloat($('#form-fishing-return input[name="returnRate"]').val()) || 0.001,
|
||||
dailyMaxReturn: parseInt($('#form-fishing-return input[name="dailyMaxReturn"]').val()) || 0
|
||||
};
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/UpdateFishingReturn",
|
||||
data: JSON.stringify(config),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
window.saveAct=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/ActivityConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,354 @@
|
||||
|
||||
<title>金币商城配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>金币商城配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-goldshop" lay-filter="table-goldshop"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-goldshop">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-goldshop"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-goldshop"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-goldshop"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-goldshop">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-goldshop">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveAct('GoldShopConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-icon">
|
||||
{{# if(d.icon){ }}
|
||||
<img src="{{d.icon}}" style="width:40px;height:40px;object-fit:cover;cursor:pointer;border-radius:4px;" onclick="previewImage('{{d.icon}}')" alt="图标">
|
||||
{{# } else { }}
|
||||
<span style="color:#999;">无</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-upload-box { position: relative; display: inline-block; }
|
||||
.icon-upload-box .upload-btn { position: absolute; top: 0; left: 0; width: 80px; height: 80px; opacity: 0; cursor: pointer; }
|
||||
.icon-upload-preview { width: 80px; height: 80px; border: 1px dashed #ddd; border-radius: 4px; display: flex; align-items: center; justify-content: center; background: #fafafa; cursor: pointer; }
|
||||
.icon-upload-preview:hover { border-color: #009688; }
|
||||
.icon-upload-preview img { max-width: 100%; max-height: 100%; }
|
||||
.icon-upload-preview .placeholder { color: #999; font-size: 12px; text-align: center; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var activityConfig = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/Get",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
activityConfig = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-goldshop',
|
||||
data: activityConfig ? activityConfig.goldShopConfigs || [] : [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "number", title: "商品编号", width: 100 },
|
||||
{ field: "name", title: "商品名称", width: 120 },
|
||||
{ field: "icon", title: "图标", width: 100, templet: '#tpl-icon' },
|
||||
{ field: "gold", title: "金币数量", width: 100 },
|
||||
{ field: "diamond", title: "钻石数量", width: 100 },
|
||||
{ field: "dealerDiamond", title: "经销商钻石", width: 120 },
|
||||
{ title: "操作", width: 180, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-goldshop',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
window.previewImage = function(url) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '图片预览',
|
||||
area: ['auto', 'auto'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:20px;text-align:center;"><img src="' + url + '" style="max-width:400px;max-height:400px;border-radius:8px;"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要从配置文件还原金币商城配置吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitActivitySection/GoldShopConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-goldshop"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-goldshop"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-goldshop"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/UpdateGoldShop",
|
||||
data: JSON.stringify(activityConfig.goldShopConfigs || []),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-goldshop)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = activityConfig.goldShopConfigs.findIndex(function(x) { return x.number === data.number; });
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(trIndex > -1 ? activityConfig.goldShopConfigs[trIndex] : data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) activityConfig.goldShopConfigs.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
var newData = {
|
||||
number: '',
|
||||
name: '',
|
||||
icon: '',
|
||||
gold: 0,
|
||||
diamond: 0,
|
||||
dealerDiamond: 0
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-goldshop"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-goldshop"]', function() {
|
||||
var checkStatus = table.checkStatus('table-goldshop');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.number; });
|
||||
activityConfig.goldShopConfigs = activityConfig.goldShopConfigs.filter(function(item) {
|
||||
return !ids.includes(item.number);
|
||||
});
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加金币商城' : '编辑金币商城';
|
||||
var imagePreviewHtml = data.icon
|
||||
? '<img src="' + data.icon + '" style="max-width:100%;max-height:100%;">'
|
||||
: '<div class="placeholder">点击上传</div>';
|
||||
|
||||
var html = '<div class="edit-dialog" style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">商品编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="number" value="' + (data.number || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">商品名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">图标</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="icon-upload-box">' +
|
||||
'<div class="icon-upload-preview" id="iconPreview">' + imagePreviewHtml + '</div>' +
|
||||
'<input type="file" class="upload-btn" accept="image/png" id="iconUpload">' +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="icon" id="iconInput" value="' + (data.icon || '') + '">' +
|
||||
'<div style="margin-top:8px;color:#999;font-size:12px;">点击图片可预览,仅支持 PNG 格式</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">金币数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="gold" value="' + (data.gold || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">钻石数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="diamond" value="' + (data.diamond || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经销商钻石</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="dealerDiamond" value="' + (data.dealerDiamond || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['600px', '600px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
var $preview = layero.find('#iconPreview');
|
||||
var $input = layero.find('#iconInput');
|
||||
var $fileInput = layero.find('#iconUpload');
|
||||
|
||||
$preview.on('click', function() {
|
||||
var url = $input.val();
|
||||
if (url) previewImage(url);
|
||||
});
|
||||
|
||||
$fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (file) {
|
||||
var number = layero.find('input[name="number"]').val();
|
||||
if (!number) {
|
||||
layer.msg('请先填写商品编号');
|
||||
$(this).val('');
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('number', number);
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/config',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
success: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
var path = res.data.path;
|
||||
$input.val(path);
|
||||
$preview.html('<img src="' + path + '" style="max-width:100%;max-height:100%;">');
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('上传失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
number: layero.find('input[name="number"]').val(),
|
||||
name: layero.find('input[name="name"]').val(),
|
||||
icon: layero.find('#iconInput').val(),
|
||||
gold: parseInt(layero.find('input[name="gold"]').val()) || 0,
|
||||
diamond: parseInt(layero.find('input[name="diamond"]').val()) || 0,
|
||||
dealerDiamond: parseInt(layero.find('input[name="dealerDiamond"]').val()) || 0
|
||||
};
|
||||
activityConfig.goldShopConfigs.unshift(newItem);
|
||||
} else if (rowIndex > -1) {
|
||||
var original = activityConfig.goldShopConfigs[rowIndex];
|
||||
original.number = layero.find('input[name="number"]').val();
|
||||
original.name = layero.find('input[name="name"]').val();
|
||||
original.icon = layero.find('#iconInput').val();
|
||||
original.gold = parseInt(layero.find('input[name="gold"]').val()) || 0;
|
||||
original.diamond = parseInt(layero.find('input[name="diamond"]').val()) || 0;
|
||||
original.dealerDiamond = parseInt(layero.find('input[name="dealerDiamond"]').val()) || 0;
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-goldshop', {
|
||||
data: activityConfig.goldShopConfigs
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveAct=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/ActivityConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,335 @@
|
||||
|
||||
<title>击杀配置</title>
|
||||
|
||||
<style>
|
||||
.layui-form-label { width: 400px; }
|
||||
.kill-form legend { font-size: 14px; font-weight: normal; }
|
||||
.kill-form .layui-form-mid { font-size: 12px; color: #999; }
|
||||
.layui-elem-field { border-color: #666; }
|
||||
.kill-row { display: flex; flex-wrap: wrap; gap: 15px; margin: 10px 0; }
|
||||
.kill-row .layui-form-item { display: flex; align-items: center; margin: 0; white-space: nowrap; }
|
||||
.kill-row .layui-form-label { width: auto; text-align: right; padding-right: 8px; font-size: 14px; }
|
||||
.kill-row .layui-input-inline { width: 80px; }
|
||||
</style>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>击杀配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-kill"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-kill"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-kill"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('KillConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form kill-form" id="form-kill" style="padding: 20px;">
|
||||
<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-inline">
|
||||
<input type="number" name="normalizationFactorPlayer" class="layui-input" placeholder="用户盈亏调节灵敏度">
|
||||
</div>
|
||||
<div class="layui-form-mid">公式: 原始玩家值 = -(当前余额-累计充值-注册赠送) / 此值, 玩家因子 = 1+原始玩家值。值越大调节越平缓。</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">击杀率下限</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="minPlayerModifier" class="layui-input" placeholder="击杀率下限倍数">
|
||||
</div>
|
||||
<div class="layui-form-mid">玩家因子最小值(下限)。<br>默认0.3=盈利再多也保持30%击杀率; 改为0=可能完全打不死鱼; 改为1=盈利再高也不压鱼</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">击杀率上限</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="maxPlayerModifier" class="layui-input" placeholder="击杀率上限倍数">
|
||||
</div>
|
||||
<div class="layui-form-mid">玩家因子最大值(上限)。<br>默认2.0=亏损再多最高200%击杀率; 改为1=亏损再多也不补偿; 改为5=亏损玩家可获5倍击杀率(易刷钱)</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-inline">
|
||||
<input type="number" name="targetSystemProfit" class="layui-input" placeholder="系统期望累计盈利目标">
|
||||
</div>
|
||||
<div class="layui-form-mid">已弃用,实际由下方系统日收益替代。保留仅作参考</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">系统平滑系数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="normalizationFactorSystem" class="layui-input" placeholder="系统调节平滑系数">
|
||||
</div>
|
||||
<div class="layui-form-mid">公式: 系统差值=(当日盈利-日目标)/此值, 系统因子=1+系统差值。值越大调节越平缓。</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">系统击杀下限</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="minSystemModifier" class="layui-input" placeholder="系统整体击杀率下限">
|
||||
</div>
|
||||
<div class="layui-form-mid">系统因子最小值(下限)。<br>默认0.95=系统亏损再大最低95%击杀率; 改为0.5=系统亏损时可以压到50%; 改为0=系统亏损时可完全禁止击杀(危险)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">系统击杀上限</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="maxSystemModifier" class="layui-input" placeholder="系统整体击杀率上限">
|
||||
</div>
|
||||
<div class="layui-form-mid">系统因子最大值(上限)。<br>默认1.05=盈利再多最高105%; 改为1.2=系统可上调20%击杀率刺激消费; 改为1=关闭系统调节(永远固定1.0)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">系统日收益</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="daySystemGold" class="layui-input" placeholder="系统每日收益金额">
|
||||
</div>
|
||||
<div class="layui-form-mid">当日系统净盈利的锚点值。实际盈利高于此→调高击杀率鼓励消费;低于此→调低击杀率回收金币。</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">全局播报最低金币</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="globalAnnounceMinGold" class="layui-input" placeholder="全局击杀播报最低金币">
|
||||
</div>
|
||||
<div class="layui-form-mid">击杀获得金币 ≥ 此值时才触发全局播报,0=全部播报</div>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>限制设置</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">IP限制</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="ipCount" class="layui-input" placeholder="IP关联用户数限制">
|
||||
</div>
|
||||
<div class="layui-form-mid">相同IP关联超过此数量的用户会被屏蔽</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">违规值限制</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="violateValue" class="layui-input" placeholder="违规值限制" step="0.01">
|
||||
</div>
|
||||
<div class="layui-form-mid">公式: 被屏蔽用户直接使用此值作为玩家因子(跳过盈亏调节)。正常用户使用各自因子配置中的系统因子(默认1=不调节)。默认0.2=黑名单击杀率16%左右(KillWeight=8000时)。值越大击杀率越高(无限制范围,注意风险)</div>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>补偿系数 (CompensateQuota > 0 时生效)</legend>
|
||||
</fieldset>
|
||||
<div class="kill-row">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Boss鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="compensateBossRate" class="layui-input" placeholder="Boss鱼补偿系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">黄金鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="compensateGoldRate" class="layui-input" placeholder="黄金鱼补偿系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">特殊鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="compensateSpecialRate" class="layui-input" placeholder="特殊鱼补偿系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">普通鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="compensateOrdinary" class="layui-input" placeholder="普通鱼补偿系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-mid">在用户因子基础上按鱼种额外乘以系数(提升击杀率)。公式: 最终用户因子 = 限制范围(玩家因子 × 鱼种系数, 下限, 上限)</div>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>罚款系数 (PenaltyQuota > 0 时生效)</legend>
|
||||
</fieldset>
|
||||
<div class="kill-row">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Boss鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="penaltyBossRate" class="layui-input" placeholder="Boss鱼罚款系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">黄金鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="penaltyGoldRate" class="layui-input" placeholder="黄金鱼罚款系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">特殊鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="penaltySpecialRate" class="layui-input" placeholder="特殊鱼罚款系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">普通鱼</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="penaltyOrdinary" class="layui-input" placeholder="普通鱼罚款系数" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-mid">在用户因子基础上按鱼种额外乘以系数(降低击杀率)。公式: 最终用户因子 = 限制范围(玩家因子 × 鱼种系数, 下限, 上限)</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
fillForms();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fillForms() {
|
||||
if (gameConfig.killConfig) {
|
||||
var k = gameConfig.killConfig;
|
||||
$('#form-kill input[name="normalizationFactorPlayer"]').val(k.normalizationFactorPlayer || 50000);
|
||||
$('#form-kill input[name="minPlayerModifier"]').val(k.minPlayerModifier || 0.3);
|
||||
$('#form-kill input[name="maxPlayerModifier"]').val(k.maxPlayerModifier || 2.0);
|
||||
$('#form-kill input[name="targetSystemProfit"]').val(k.targetSystemProfit || 1000000);
|
||||
$('#form-kill input[name="normalizationFactorSystem"]').val(k.normalizationFactorSystem || 10000000);
|
||||
$('#form-kill input[name="minSystemModifier"]').val(k.minSystemModifier || 0.95);
|
||||
$('#form-kill input[name="maxSystemModifier"]').val(k.maxSystemModifier || 1.05);
|
||||
$('#form-kill input[name="daySystemGold"]').val(k.daySystemGold || 100000);
|
||||
$('#form-kill input[name="globalAnnounceMinGold"]').val(k.globalAnnounceMinGold || 0);
|
||||
$('#form-kill input[name="ipCount"]').val(k.ipCount || 5);
|
||||
$('#form-kill input[name="violateValue"]').val(k.violateValue || 0.2);
|
||||
if (k.compensateRate) {
|
||||
$('#form-kill input[name="compensateBossRate"]').val(k.compensateRate.bossRate || 1);
|
||||
$('#form-kill input[name="compensateGoldRate"]').val(k.compensateRate.goldRate || 1);
|
||||
$('#form-kill input[name="compensateSpecialRate"]').val(k.compensateRate.specialRate || 1);
|
||||
$('#form-kill input[name="compensateOrdinary"]').val(k.compensateRate.ordinary || 1);
|
||||
}
|
||||
if (k.penaltyRate) {
|
||||
$('#form-kill input[name="penaltyBossRate"]').val(k.penaltyRate.bossRate || 1);
|
||||
$('#form-kill input[name="penaltyGoldRate"]').val(k.penaltyRate.goldRate || 1);
|
||||
$('#form-kill input[name="penaltySpecialRate"]').val(k.penaltyRate.specialRate || 1);
|
||||
$('#form-kill input[name="penaltyOrdinary"]').val(k.penaltyRate.ordinary || 1);
|
||||
}
|
||||
}
|
||||
form.render();
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/KillConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-kill"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-kill"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-kill"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
if (!gameConfig.killConfig) {
|
||||
gameConfig.killConfig = {};
|
||||
}
|
||||
var k = gameConfig.killConfig;
|
||||
k.normalizationFactorPlayer = parseInt($('#form-kill input[name="normalizationFactorPlayer"]').val()) || 50000;
|
||||
k.minPlayerModifier = parseFloat($('#form-kill input[name="minPlayerModifier"]').val()) || 0.3;
|
||||
k.maxPlayerModifier = parseFloat($('#form-kill input[name="maxPlayerModifier"]').val()) || 2.0;
|
||||
k.targetSystemProfit = parseInt($('#form-kill input[name="targetSystemProfit"]').val()) || 1000000;
|
||||
k.normalizationFactorSystem = parseInt($('#form-kill input[name="normalizationFactorSystem"]').val()) || 10000000;
|
||||
k.minSystemModifier = parseFloat($('#form-kill input[name="minSystemModifier"]').val()) || 0.95;
|
||||
k.maxSystemModifier = parseFloat($('#form-kill input[name="maxSystemModifier"]').val()) || 1.05;
|
||||
k.daySystemGold = parseInt($('#form-kill input[name="daySystemGold"]').val()) || 100000;
|
||||
k.globalAnnounceMinGold = parseInt($('#form-kill input[name="globalAnnounceMinGold"]').val()) || 0;
|
||||
k.ipCount = parseInt($('#form-kill input[name="ipCount"]').val()) || 5;
|
||||
k.violateValue = parseFloat($('#form-kill input[name="violateValue"]').val()) || 0.2;
|
||||
k.compensateRate = {
|
||||
bossRate: parseFloat($('#form-kill input[name="compensateBossRate"]').val()) || 1,
|
||||
goldRate: parseFloat($('#form-kill input[name="compensateGoldRate"]').val()) || 1,
|
||||
specialRate: parseFloat($('#form-kill input[name="compensateSpecialRate"]').val()) || 1,
|
||||
ordinary: parseFloat($('#form-kill input[name="compensateOrdinary"]').val()) || 1
|
||||
};
|
||||
k.penaltyRate = {
|
||||
bossRate: parseFloat($('#form-kill input[name="penaltyBossRate"]').val()) || 1,
|
||||
goldRate: parseFloat($('#form-kill input[name="penaltyGoldRate"]').val()) || 1,
|
||||
specialRate: parseFloat($('#form-kill input[name="penaltySpecialRate"]').val()) || 1,
|
||||
ordinary: parseFloat($('#form-kill input[name="penaltyOrdinary"]').val()) || 1
|
||||
};
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,574 @@
|
||||
|
||||
<title>月卡配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>月卡配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-monthcard" lay-filter="table-monthcard"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-monthcard">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-monthcard"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-monthcard"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-monthcard"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-monthcard">添加月卡</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="monthcard-bar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="gift">礼包</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="daily">每日</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="gift-dialog-tpl">
|
||||
<div class="gift-container">
|
||||
<div class="gift-left">
|
||||
<div class="gift-toolbar">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add-gift"><i class="layui-icon layui-icon-add-1"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete-gift"><i class="layui-icon layui-icon-delete"></i> 删除</button>
|
||||
</div>
|
||||
<div class="gift-table-wrap">
|
||||
<table id="table-gift-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift-right">
|
||||
<h4>礼包项详情</h4>
|
||||
<div class="layui-form" id="gift-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="giftType" id="giftType" lay-filter="giftType">
|
||||
<option value="1">金币</option>
|
||||
<option value="2">钻石</option>
|
||||
<option value="3">道具</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="giftCount" id="giftCount" class="layui-input" placeholder="请输入数量">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">随机</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="giftIsRandom" lay-skin="switch" lay-text="是|否" id="giftIsRandom">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最小值</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="giftMinCount" id="giftMinCount" class="layui-input" placeholder="最小值">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最大值</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="giftMaxCount" id="giftMaxCount" class="layui-input" placeholder="最大值">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item gift-prop-select" style="display:none;">
|
||||
<label class="layui-form-label">道具</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="giftProductNumber" id="giftProductNumber" lay-search>
|
||||
<option value="">请选择道具</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-top:20px;">
|
||||
<button class="layui-btn layui-btn-normal" id="btn-save-gift" style="width:100%;">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var currentMcIndex = -1;
|
||||
var currentGiftIndex = -1;
|
||||
var currentGiftType = 'gift';
|
||||
var propList = [];
|
||||
var currentDialogData = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
propList = (gameConfig.propConfig || []).map(function(p) {
|
||||
return { number: p.number, name: p.name, type: p.type };
|
||||
});
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-monthcard',
|
||||
data: gameConfig ? (gameConfig.monthCardConfigs || []) : [],
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "type", title: "类型", width: 80, templet: function(d) {
|
||||
var map = {1: '周卡', 2: '月卡', 3: '年卡'};
|
||||
return map[d.type] || '月卡';
|
||||
}},
|
||||
{ field: "name", title: "名称", width: 120 },
|
||||
{ field: "remark", title: "备注", minWidth: 150 },
|
||||
{ field: "signInAdd", title: "签到加成", width: 100 },
|
||||
{ field: "gold", title: "金币", width: 100 },
|
||||
{ field: "money", title: "现金价格", width: 100 },
|
||||
{ field: "giftList", title: "礼包", width: 80, templet: function(d) {
|
||||
return (d.giftList && d.giftList.length) ? d.giftList.length + '项' : '无';
|
||||
}},
|
||||
{ field: "dailyGift", title: "每日", width: 80, templet: function(d) {
|
||||
return (d.dailyGift && d.dailyGift.length) ? d.dailyGift.length + '项' : '无';
|
||||
}},
|
||||
{ title: "操作", width: 250, fixed: 'right', toolbar: '#monthcard-bar' }
|
||||
]],
|
||||
toolbar: '#toolbar-monthcard',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/init-game",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-monthcard"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-monthcard"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-monthcard"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-monthcard)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = obj.tr.index();
|
||||
if (trIndex < 0) trIndex = gameConfig.monthCardConfigs.findIndex(function(x) { return x.cardId === data.cardId; });
|
||||
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) gameConfig.monthCardConfigs.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
} else if (obj.event === 'edit') {
|
||||
showEditDialog(data, false, trIndex);
|
||||
} else if (obj.event === 'gift') {
|
||||
currentMcIndex = trIndex;
|
||||
currentGiftType = 'gift';
|
||||
showGiftDialog(data, '月卡礼包');
|
||||
} else if (obj.event === 'daily') {
|
||||
currentMcIndex = trIndex;
|
||||
currentGiftType = 'daily';
|
||||
showGiftDialog(data, '月卡每日');
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
if (!gameConfig.monthCardConfigs) gameConfig.monthCardConfigs = [];
|
||||
var newData = {
|
||||
type: 2,
|
||||
name: '',
|
||||
remark: '',
|
||||
signInAdd: 0,
|
||||
gold: 0,
|
||||
money: 0,
|
||||
giftList: [],
|
||||
dailyGift: []
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-monthcard"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加月卡' : '编辑月卡';
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="type">' +
|
||||
'<option value="1"' + (data.type === 1 ? ' selected' : '') + '>周卡</option>' +
|
||||
'<option value="2"' + (data.type === 2 ? ' selected' : '') + '>月卡</option>' +
|
||||
'<option value="3"' + (data.type === 3 ? ' selected' : '') + '>年卡</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">备注</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="remark" value="' + (data.remark || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">签到加成</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="signInAdd" value="' + (data.signInAdd || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">金币</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="gold" value="' + (data.gold || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">现金价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="money" value="' + (data.money || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['500px', '450px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
},
|
||||
yes: function(idx, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
type: parseInt(layero.find('select[name="type"]').val()),
|
||||
name: layero.find('input[name="name"]').val(),
|
||||
remark: layero.find('input[name="remark"]').val(),
|
||||
signInAdd: parseFloat(layero.find('input[name="signInAdd"]').val()) || 0,
|
||||
gold: parseInt(layero.find('input[name="gold"]').val()) || 0,
|
||||
money: parseFloat(layero.find('input[name="money"]').val()) || 0,
|
||||
giftList: [],
|
||||
dailyGift: []
|
||||
};
|
||||
gameConfig.monthCardConfigs.unshift(newItem);
|
||||
} else {
|
||||
var original = gameConfig.monthCardConfigs[rowIndex];
|
||||
if (!original) {
|
||||
original = gameConfig.monthCardConfigs.find(function(x) { return x.cardId === data.cardId; });
|
||||
}
|
||||
if (!original) { layer.msg('数据异常,请刷新后重试'); return; }
|
||||
original.type = parseInt(layero.find('select[name="type"]').val());
|
||||
original.name = layero.find('input[name="name"]').val();
|
||||
original.remark = layero.find('input[name="remark"]').val();
|
||||
original.signInAdd = parseFloat(layero.find('input[name="signInAdd"]').val()) || 0;
|
||||
original.gold = parseInt(layero.find('input[name="gold"]').val()) || 0;
|
||||
original.money = parseFloat(layero.find('input[name="money"]').val()) || 0;
|
||||
}
|
||||
layer.close(idx);
|
||||
table.reload('table-monthcard', {
|
||||
data: gameConfig.monthCardConfigs
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showGiftDialog(data, title) {
|
||||
currentDialogData = data;
|
||||
currentGiftIndex = -1;
|
||||
|
||||
var dialogContent = $('#gift-dialog-tpl').html();
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title + ' - ' + data.name,
|
||||
area: ['1000px', '620px'],
|
||||
content: dialogContent,
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
var propOptions = '<option value="">请选择道具</option>';
|
||||
propList.forEach(function(p) {
|
||||
propOptions += '<option value="' + p.number + '">' + p.number + ' - ' + p.name + '</option>';
|
||||
});
|
||||
layero.find('#giftProductNumber').html(propOptions);
|
||||
form.render();
|
||||
|
||||
renderGiftTable(layero);
|
||||
|
||||
layero.find('#btn-add-gift').on('click', function() {
|
||||
addGiftItem(layero);
|
||||
});
|
||||
|
||||
layero.find('#btn-delete-gift').on('click', function() {
|
||||
deleteGiftItem(layero);
|
||||
});
|
||||
|
||||
layero.find('#btn-save-gift').on('click', function() {
|
||||
saveGiftItem(layero);
|
||||
});
|
||||
|
||||
form.on('select(giftType)', function(obj) {
|
||||
if (obj.value === '3') {
|
||||
layero.find('.gift-prop-select').show();
|
||||
} else {
|
||||
layero.find('.gift-prop-select').hide();
|
||||
}
|
||||
layero.find('#giftCount').val(0);
|
||||
layero.find('#giftIsRandom')[0].checked = false;
|
||||
form.render('checkbox');
|
||||
});
|
||||
|
||||
layero.find('#giftCount').on('input', function() {
|
||||
layero.find('#giftIsRandom')[0].checked = false;
|
||||
layero.find('#giftIsRandom').prop('checked', false);
|
||||
form.render('checkbox');
|
||||
});
|
||||
|
||||
layero.on('click', '#giftIsRandom + .layui-form-switch', function() {
|
||||
var checkbox = layero.find('#giftIsRandom')[0];
|
||||
setTimeout(function() {
|
||||
if (checkbox.checked) {
|
||||
layero.find('#giftCount').val(0);
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
|
||||
form.on('switch(giftIsRandom)', function(data) {
|
||||
if (data.elem.checked) {
|
||||
layero.find('#giftCount').val(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getGiftList() {
|
||||
if (!currentDialogData) return [];
|
||||
if (currentGiftType === 'gift') {
|
||||
return currentDialogData.giftList || [];
|
||||
} else {
|
||||
return currentDialogData.dailyGift || [];
|
||||
}
|
||||
}
|
||||
|
||||
function addGiftItem(layero) {
|
||||
var list = getGiftList();
|
||||
list.push({ type: 1, count: 100, isRandom: false, minCount: 0, maxCount: 0, otherId: '' });
|
||||
currentGiftIndex = list.length - 1;
|
||||
renderGiftTable(layero, currentGiftIndex);
|
||||
loadFormData(list[list.length - 1], layero);
|
||||
}
|
||||
|
||||
function deleteGiftItem(layero) {
|
||||
if (currentGiftIndex < 0) {
|
||||
return layer.msg('请先选择要删除的项');
|
||||
}
|
||||
var list = getGiftList();
|
||||
if (list.length > currentGiftIndex) {
|
||||
list.splice(currentGiftIndex, 1);
|
||||
currentGiftIndex = -1;
|
||||
clearForm(layero);
|
||||
renderGiftTable(layero, -1);
|
||||
}
|
||||
}
|
||||
|
||||
function saveGiftItem(layero) {
|
||||
if (currentGiftIndex < 0) {
|
||||
return layer.msg('请先选择要编辑的项');
|
||||
}
|
||||
var list = getGiftList();
|
||||
var giftType = parseInt(layero.find('#giftType').val()) || 1;
|
||||
list[currentGiftIndex] = {
|
||||
type: giftType,
|
||||
count: parseInt(layero.find('#giftCount').val()) || 0,
|
||||
isRandom: layero.find('#giftIsRandom')[0].checked,
|
||||
minCount: parseInt(layero.find('#giftMinCount').val()) || 0,
|
||||
maxCount: parseInt(layero.find('#giftMaxCount').val()) || 0,
|
||||
otherId: giftType === 3 ? layero.find('#giftProductNumber').val() : ''
|
||||
};
|
||||
renderGiftTable(layero, currentGiftIndex);
|
||||
layer.msg('保存成功');
|
||||
}
|
||||
|
||||
function clearForm(layero) {
|
||||
layero.find('#giftType').val('1');
|
||||
layero.find('#giftCount').val('0');
|
||||
layero.find('#giftIsRandom')[0].checked = false;
|
||||
layero.find('#giftMinCount').val('0');
|
||||
layero.find('#giftMaxCount').val('0');
|
||||
layero.find('#giftProductNumber').val('');
|
||||
layero.find('.gift-prop-select').hide();
|
||||
form.render('checkbox');
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
function loadFormData(data, layero) {
|
||||
layero.find('#giftType').val(data.type || 1);
|
||||
layero.find('#giftCount').val(data.count || 0);
|
||||
layero.find('#giftIsRandom')[0].checked = data.isRandom || false;
|
||||
layero.find('#giftMinCount').val(data.minCount || 0);
|
||||
layero.find('#giftMaxCount').val(data.maxCount || 0);
|
||||
layero.find('#giftProductNumber').val(data.otherId || '');
|
||||
|
||||
if (data.type === 3) {
|
||||
layero.find('.gift-prop-select').show();
|
||||
} else {
|
||||
layero.find('.gift-prop-select').hide();
|
||||
}
|
||||
form.render('checkbox');
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
function getPropName(number) {
|
||||
var prop = propList.find(function(p) { return p.number === number; });
|
||||
return prop ? prop.number + ' - ' + prop.name : number || '';
|
||||
}
|
||||
|
||||
function renderGiftTable(layero, selectIndex) {
|
||||
var list = getGiftList();
|
||||
|
||||
table.render({
|
||||
elem: layero.find('#table-gift-list'),
|
||||
data: list,
|
||||
page: false,
|
||||
height: 380,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "type", title: "类型", width: 80, templet: function(d) {
|
||||
var map = {1: '金币', 2: '钻石', 3: '道具'};
|
||||
return map[d.type] || '金币';
|
||||
}},
|
||||
{ field: "count", title: "数量", width: 80 },
|
||||
{ field: "minCount", title: "最小值", width: 80 },
|
||||
{ field: "maxCount", title: "最大值", width: 80 },
|
||||
{ field: "isRandom", title: "随机", width: 70, templet: function(d) {
|
||||
return d.isRandom ? '是' : '否';
|
||||
}},
|
||||
{ field: "otherId", title: "道具编号", minWidth: 150, templet: function(d) {
|
||||
return d.type === 3 ? getPropName(d.otherId || '') : '';
|
||||
}}
|
||||
]],
|
||||
done: function() {
|
||||
if (list.length > 0 && selectIndex < 0) {
|
||||
selectIndex = 0;
|
||||
}
|
||||
if (selectIndex >= 0 && selectIndex < list.length) {
|
||||
currentGiftIndex = selectIndex;
|
||||
var $tr = layero.find('#table-gift-list + .layui-table-view tr[data-index="' + selectIndex + '"]');
|
||||
if ($tr.length) {
|
||||
$tr.addClass('layui-table-click');
|
||||
loadFormData(list[selectIndex], layero);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
layero.find('#table-gift-list + .layui-table-view').on('click', 'tr[data-index]', function() {
|
||||
var index = parseInt($(this).attr('data-index'));
|
||||
if (index >= 0 && index < list.length) {
|
||||
currentGiftIndex = index;
|
||||
layero.find('tr[data-index]').removeClass('layui-table-click');
|
||||
$(this).addClass('layui-table-click');
|
||||
loadFormData(list[index], layero);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gift-container { display: flex; height: 480px; padding: 10px; }
|
||||
.gift-left { flex: 1; margin-right: 15px; }
|
||||
.gift-table-wrap { height: 400px; overflow: auto; }
|
||||
.gift-right { width: 280px; border-left: 1px solid #e6e6e6; padding-left: 15px; }
|
||||
.gift-right h4 { margin-bottom: 15px; color: #333; font-size: 16px; padding-bottom: 10px; border-bottom: 1px solid #eee; }
|
||||
.gift-toolbar { margin-bottom: 10px; }
|
||||
.gift-toolbar .layui-btn { margin-right: 5px; }
|
||||
.gift-right .layui-form-item { margin-bottom: 12px; }
|
||||
.gift-right .layui-form-label { padding: 9px 0; width: 60px; }
|
||||
.gift-right .layui-input-block { margin-left: 70px; }
|
||||
</style>
|
||||
@@ -0,0 +1,532 @@
|
||||
|
||||
<title>道具配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>道具配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-prop" lay-filter="table-prop"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-prop">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-prop"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-prop"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-prop"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-prop">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-prop">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('PropConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-type">
|
||||
{{# var typeMap = {1:'炮台',2:'翅膀',3:'炮塔碎片',4:'翅膀碎片',5:'战神',6:'战神碎片',7:'刮刮卡',8:'改名卡',9:'大喇叭',10:'技能',11:'召唤卡',12:'VIP经验',13:'鱼雷'}; }}
|
||||
{{= typeMap[d.type] || '未知' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-saleType">
|
||||
{{# var saleTypeMap = {1:'金币',2:'钻石'}; }}
|
||||
{{= saleTypeMap[d.saleType] || '金币' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-isEnable">
|
||||
<input type="checkbox" name="isEnable" value="{{d.isEnable}}" lay-skin="switch" lay-text="启用|禁用" {{ d.isEnable ? 'checked' : '' }} lay-filter="isEnable-switch" data-field="isEnable">
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-isSale">
|
||||
<input type="checkbox" name="isSale" value="{{d.isSale}}" lay-skin="switch" lay-text="销售|停售" {{ d.isSale ? 'checked' : '' }} lay-filter="isSale-switch" data-field="isSale">
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-image">
|
||||
{{# if(d.imageUrl){ }}
|
||||
<img src="{{d.imageUrl}}" style="width:40px;height:40px;object-fit:cover;cursor:pointer;border-radius:4px;" onclick="previewImage('{{d.imageUrl}}')" alt="图标">
|
||||
{{# } else { }}
|
||||
<span style="color:#999;">无</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="preview"><i class="layui-icon layui-icon-search"></i>预览</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-upload-box { position: relative; display: inline-block; }
|
||||
.icon-upload-box .upload-btn { position: absolute; top: 0; left: 0; width: 80px; height: 80px; opacity: 0; cursor: pointer; }
|
||||
.icon-upload-preview { width: 80px; height: 80px; border: 1px dashed #ddd; border-radius: 4px; display: flex; align-items: center; justify-content: center; background: #fafafa; cursor: pointer; }
|
||||
.icon-upload-preview:hover { border-color: #009688; }
|
||||
.icon-upload-preview img { max-width: 100%; max-height: 100%; }
|
||||
.icon-upload-preview .placeholder { color: #999; font-size: 12px; text-align: center; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var currentEditIndex = -1;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-prop',
|
||||
data: gameConfig ? gameConfig.propConfig || [] : [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "number", title: "编号", width: 80 },
|
||||
{ field: "name", title: "名称", width: 100 },
|
||||
{ field: "type", title: "类型", width: 90, templet: '#tpl-type' },
|
||||
{ field: "desc", title: "描述", width: 150 },
|
||||
{ field: "imageUrl", title: "图标", width: 100, templet: '#tpl-image' },
|
||||
{ field: "saleType", title: "售卖方式", width: 90, templet: '#tpl-saleType' },
|
||||
{ field: "price", title: "价格", width: 80 },
|
||||
{ field: "vipPrice", title: "VIP价格", width: 90 },
|
||||
{ field: "dealerPrice", title: "经销商价", width: 100 },
|
||||
{ field: "saleCount", title: "售卖数量", width: 90 },
|
||||
{ field: "day", title: "有效期(天)", width: 100 },
|
||||
{ field: "isEnable", title: "启用", width: 80, templet: '#tpl-isEnable' },
|
||||
{ field: "isSale", title: "销售", width: 80, templet: '#tpl-isSale' },
|
||||
{ title: "操作", width: 180, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-prop',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
window.previewImage = function(url) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '图片预览',
|
||||
area: ['auto', 'auto'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:20px;text-align:center;"><img src="' + url + '" style="max-width:400px;max-height:400px;border-radius:8px;"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/PropConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-prop"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-prop"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-prop"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 启用开关
|
||||
form.on('switch(isEnable-switch)', function(obj) {
|
||||
var tr = $(obj.elem).closest('tr');
|
||||
var dataIndex = tr.attr('data-index');
|
||||
var tableData = gameConfig.propConfig;
|
||||
if (tableData && tableData[dataIndex]) {
|
||||
tableData[dataIndex].isEnable = obj.elem.checked;
|
||||
}
|
||||
});
|
||||
|
||||
// 销售开关
|
||||
form.on('switch(isSale-switch)', function(obj) {
|
||||
var tr = $(obj.elem).closest('tr');
|
||||
var dataIndex = tr.attr('data-index');
|
||||
var tableData = gameConfig.propConfig;
|
||||
if (tableData && tableData[dataIndex]) {
|
||||
tableData[dataIndex].isSale = obj.elem.checked;
|
||||
}
|
||||
});
|
||||
|
||||
// 表格行工具栏
|
||||
table.on('tool(table-prop)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = obj.tr.index();
|
||||
if (trIndex < 0) trIndex = gameConfig.propConfig.findIndex(function(x) { return x.propId === data.propId; });
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) gameConfig.propConfig.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
} else if (obj.event === 'preview') {
|
||||
if (data.imageUrl) {
|
||||
previewImage(data.imageUrl);
|
||||
} else {
|
||||
layer.msg('暂无图片');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 使用按钮点击事件
|
||||
$(document).on('click', '[lay-filter="add-prop"]', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-prop"]', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var checkStatus = table.checkStatus('table-prop');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.number; });
|
||||
gameConfig.propConfig = gameConfig.propConfig.filter(function(item) {
|
||||
return !ids.includes(item.number);
|
||||
});
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-prop"]', function() {
|
||||
var checkStatus = table.checkStatus('table-prop');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.number; });
|
||||
gameConfig.propConfig = gameConfig.propConfig.filter(function(item) {
|
||||
return !ids.includes(item.number);
|
||||
});
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
var newData = {
|
||||
number: '',
|
||||
name: '',
|
||||
type: 1,
|
||||
desc: '',
|
||||
imageUrl: '',
|
||||
saleType: 1,
|
||||
price: 0,
|
||||
saleCount: 1,
|
||||
vipPrice: 0,
|
||||
dealerPrice: 0,
|
||||
isEnable: true,
|
||||
isSale: true,
|
||||
gameNumber: [],
|
||||
day: 0
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加道具' : '编辑道具';
|
||||
var typeOptions = [
|
||||
{value: 1, text: '炮台'},
|
||||
{value: 2, text: '翅膀'},
|
||||
{value: 3, text: '炮塔碎片'},
|
||||
{value: 4, text: '翅膀碎片'},
|
||||
{value: 5, text: '战神'},
|
||||
{value: 6, text: '战神碎片'},
|
||||
{value: 7, text: '刮刮卡'},
|
||||
{value: 8, text: '改名卡'},
|
||||
{value: 9, text: '大喇叭'},
|
||||
{value: 10, text: '技能'},
|
||||
{value: 11, text: '召唤卡'},
|
||||
{value: 12, text: 'VIP经验'},
|
||||
{value: 13, text: '鱼雷'}
|
||||
];
|
||||
var saleTypeOptions = [
|
||||
{value: 1, text: '金币'},
|
||||
{value: 2, text: '钻石'}
|
||||
];
|
||||
|
||||
var typeHtml = '';
|
||||
typeOptions.forEach(function(opt) {
|
||||
typeHtml += '<option value="' + opt.value + '"' + (data.type === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var saleTypeHtml = '';
|
||||
saleTypeOptions.forEach(function(opt) {
|
||||
saleTypeHtml += '<option value="' + opt.value + '"' + (data.saleType === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var imagePreviewHtml = data.imageUrl
|
||||
? '<img src="' + data.imageUrl + '" style="max-width:100%;max-height:100%;">'
|
||||
: '<div class="placeholder">点击上传图片</div>';
|
||||
var uploadBtnHtml = '<input type="file" name="file" class="upload-btn" accept="image/png" id="propIconUpload">';
|
||||
|
||||
var html = '<div class="edit-dialog" style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="number" value="' + (data.number || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="type">' + typeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">描述</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="desc" value="' + (data.desc || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">图标</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="icon-upload-box">' +
|
||||
'<div class="icon-upload-preview" id="iconPreview">' + imagePreviewHtml + '</div>' +
|
||||
uploadBtnHtml +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="imageUrl" id="imageUrlInput" value="' + (data.imageUrl || '') + '">' +
|
||||
'<div style="margin-top:8px;color:#999;font-size:12px;">点击图片可预览,支持jpg、png、gif格式</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">售卖方式</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="saleType">' + saleTypeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="price" value="' + (data.price || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">VIP价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="vipPrice" value="' + (data.vipPrice || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经销商价</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="dealerPrice" value="' + (data.dealerPrice || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">售卖数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="saleCount" value="' + (data.saleCount || 1) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">有效期(天)</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="day" value="' + (data.day || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">启用</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="isEnable" lay-skin="switch" lay-text="启用|禁用" ' + (data.isEnable ? 'checked' : '') + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">销售</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="isSale" lay-skin="switch" lay-text="销售|停售" ' + (data.isSale ? 'checked' : '') + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['650px', '700px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
var $preview = layero.find('#iconPreview');
|
||||
var $input = layero.find('#imageUrlInput');
|
||||
var $fileInput = layero.find('#propIconUpload');
|
||||
|
||||
$preview.on('click', function() {
|
||||
var url = $input.val();
|
||||
if (url) {
|
||||
previewImage(url);
|
||||
}
|
||||
});
|
||||
|
||||
$fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (file) {
|
||||
var number = layero.find('input[name="number"]').val();
|
||||
if (!number) {
|
||||
layer.msg('请先填写道具编号');
|
||||
$(this).val('');
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('number', number);
|
||||
|
||||
$.ajax({
|
||||
// 配置图片按道具编号覆盖,并通过 timespan 参数刷新浏览器缓存。
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/config',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
success: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
var path = res.data.path;
|
||||
$input.val(path);
|
||||
$preview.html('<img src="' + path + '" style="max-width:100%;max-height:100%;">');
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('上传失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
number: layero.find('input[name="number"]').val(),
|
||||
name: layero.find('input[name="name"]').val(),
|
||||
type: parseInt(layero.find('select[name="type"]').val()),
|
||||
desc: layero.find('input[name="desc"]').val(),
|
||||
imageUrl: layero.find('input[name="imageUrl"]').val(),
|
||||
saleType: parseInt(layero.find('select[name="saleType"]').val()),
|
||||
price: parseFloat(layero.find('input[name="price"]').val()) || 0,
|
||||
vipPrice: parseFloat(layero.find('input[name="vipPrice"]').val()) || 0,
|
||||
dealerPrice: parseFloat(layero.find('input[name="dealerPrice"]').val()) || 0,
|
||||
saleCount: parseInt(layero.find('input[name="saleCount"]').val()) || 1,
|
||||
day: parseInt(layero.find('input[name="day"]').val()) || 0,
|
||||
isEnable: layero.find('input[name="isEnable"]').prop('checked'),
|
||||
isSale: layero.find('input[name="isSale"]').prop('checked'),
|
||||
gameNumber: [],
|
||||
id: data.id
|
||||
};
|
||||
gameConfig.propConfig.unshift(newItem);
|
||||
} else {
|
||||
var number = layero.find('input[name="number"]').val();
|
||||
var idx = gameConfig.propConfig.findIndex(function(x) { return x.number === data.number; });
|
||||
if (idx < 0) idx = rowIndex;
|
||||
if (idx < 0) { layer.msg('数据异常'); return; }
|
||||
gameConfig.propConfig[idx].number = number;
|
||||
gameConfig.propConfig[idx].name = layero.find('input[name="name"]').val();
|
||||
gameConfig.propConfig[idx].type = parseInt(layero.find('select[name="type"]').val());
|
||||
gameConfig.propConfig[idx].desc = layero.find('input[name="desc"]').val();
|
||||
gameConfig.propConfig[idx].imageUrl = layero.find('input[name="imageUrl"]').val();
|
||||
gameConfig.propConfig[idx].saleType = parseInt(layero.find('select[name="saleType"]').val());
|
||||
gameConfig.propConfig[idx].price = parseFloat(layero.find('input[name="price"]').val()) || 0;
|
||||
gameConfig.propConfig[idx].vipPrice = parseFloat(layero.find('input[name="vipPrice"]').val()) || 0;
|
||||
gameConfig.propConfig[idx].dealerPrice = parseFloat(layero.find('input[name="dealerPrice"]').val()) || 0;
|
||||
gameConfig.propConfig[idx].saleCount = parseInt(layero.find('input[name="saleCount"]').val()) || 1;
|
||||
gameConfig.propConfig[idx].day = parseInt(layero.find('input[name="day"]').val()) || 0;
|
||||
gameConfig.propConfig[idx].isEnable = layero.find('input[name="isEnable"]').prop('checked');
|
||||
gameConfig.propConfig[idx].isSale = layero.find('input[name="isSale"]').prop('checked');
|
||||
}
|
||||
layer.close(index);
|
||||
renderTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,526 @@
|
||||
|
||||
<title>道具碎片配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>道具碎片配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-propfragment" lay-filter="table-propfragment"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-propfragment">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-propfragment"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-propfragment"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-propfragment"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-propfragment">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-propfragment">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('PropFragments')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-type">
|
||||
{{# var t = d.type + ''; }}
|
||||
{{# if(t === '3') { }}
|
||||
炮塔碎片
|
||||
{{# } else if(t === '4') { }}
|
||||
翅膀碎片
|
||||
{{# } else if(t === '6') { }}
|
||||
战神碎片
|
||||
{{# } else { }}
|
||||
未知({{= t}})
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-saleType">
|
||||
{{# var saleTypeMap = {'1':'金币','2':'钻石'}; }}
|
||||
{{= saleTypeMap[d.saleType] || '金币' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-isEnable">
|
||||
<input type="checkbox" name="isEnable" lay-skin="switch" lay-text="启用|禁用" {{ d.isEnable ? 'checked' : '' }} lay-filter="isEnable-switch">
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-isSale">
|
||||
<input type="checkbox" name="isSale" lay-skin="switch" lay-text="销售|停售" {{ d.isSale ? 'checked' : '' }} lay-filter="isSale-switch">
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-image">
|
||||
{{# if(d.imageUrl){ }}
|
||||
<img src="{{d.imageUrl}}" style="width:40px;height:40px;object-fit:cover;cursor:pointer;border-radius:4px;" onclick="previewImage('{{d.imageUrl}}')" alt="图标">
|
||||
{{# } else { }}
|
||||
<span style="color:#999;">无</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-upload-box { position: relative; display: inline-block; }
|
||||
.icon-upload-box .upload-btn { position: absolute; top: 0; left: 0; width: 80px; height: 80px; opacity: 0; cursor: pointer; }
|
||||
.icon-upload-preview { width: 80px; height: 80px; border: 1px dashed #ddd; border-radius: 4px; display: flex; align-items: center; justify-content: center; background: #fafafa; cursor: pointer; }
|
||||
.icon-upload-preview:hover { border-color: #009688; }
|
||||
.icon-upload-preview img { max-width: 100%; max-height: 100%; }
|
||||
.icon-upload-preview .placeholder { color: #999; font-size: 12px; text-align: center; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var propList = [];
|
||||
|
||||
function getProductName(number) {
|
||||
if (!number) return '-';
|
||||
var prop = propList.find(function(p) { return String(p.number) === String(number); });
|
||||
return prop ? prop.name : number;
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
propList = gameConfig.propConfig || [];
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-propfragment',
|
||||
data: gameConfig ? gameConfig.propFragments || [] : [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "number", title: "编号", width: 80 },
|
||||
{ field: "name", title: "名称", width: 100 },
|
||||
{ field: "type", title: "类型", width: 100, templet: '#tpl-type' },
|
||||
{ field: "desc", title: "描述", width: 150 },
|
||||
{ field: "imageUrl", title: "图标", width: 100, templet: '#tpl-image' },
|
||||
{ field: "saleType", title: "售卖方式", width: 100, templet: '#tpl-saleType' },
|
||||
{ field: "price", title: "价格", width: 80 },
|
||||
{ field: "vipPrice", title: "VIP价格", width: 90 },
|
||||
{ field: "dealerPrice", title: "经销商价", width: 100 },
|
||||
{ field: "saleCount", title: "每日限购", width: 90 },
|
||||
{ field: "fragmentCount", title: "合成数量", width: 90 },
|
||||
{ field: "productNumber", title: "成品编号", width: 120, templet: function(d) { return getProductName(d.productNumber); }},
|
||||
{ field: "isEnable", title: "启用", width: 80, templet: '#tpl-isEnable' },
|
||||
{ field: "isSale", title: "销售", width: 80, templet: '#tpl-isSale' },
|
||||
{ title: "操作", width: 180, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-propfragment',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
window.previewImage = function(url) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '图片预览',
|
||||
area: ['auto', 'auto'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:20px;text-align:center;"><img src="' + url + '" style="max-width:400px;max-height:400px;border-radius:8px;"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/PropFragments",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-propfragment"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-propfragment"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-propfragment"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
form.on('switch(isEnable-switch)', function(obj) {
|
||||
var tr = $(obj.elem).closest('tr');
|
||||
var dataIndex = tr.attr('data-index');
|
||||
var tableData = gameConfig.propFragments;
|
||||
if (tableData && tableData[dataIndex]) {
|
||||
tableData[dataIndex].isEnable = obj.elem.checked;
|
||||
}
|
||||
});
|
||||
|
||||
form.on('switch(isSale-switch)', function(obj) {
|
||||
var tr = $(obj.elem).closest('tr');
|
||||
var dataIndex = tr.attr('data-index');
|
||||
var tableData = gameConfig.propFragments;
|
||||
if (tableData && tableData[dataIndex]) {
|
||||
tableData[dataIndex].isSale = obj.elem.checked;
|
||||
}
|
||||
});
|
||||
|
||||
table.on('tool(table-propfragment)', function(obj) {
|
||||
var data = obj.data;
|
||||
// Layui 返回的是行副本,按碎片编号定位原始配置。
|
||||
var trIndex = gameConfig.propFragments.findIndex(function(x) {
|
||||
return String(x.number) === String(data.number);
|
||||
});
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(trIndex > -1 ? gameConfig.propFragments[trIndex] : data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) gameConfig.propFragments.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
} else if (obj.event === 'preview') {
|
||||
if (data.imageUrl) {
|
||||
previewImage(data.imageUrl);
|
||||
} else {
|
||||
layer.msg('暂无图片');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
if (!gameConfig.propFragments) gameConfig.propFragments = [];
|
||||
var newData = {
|
||||
number: '',
|
||||
name: '',
|
||||
type: 7,
|
||||
desc: '',
|
||||
imageUrl: '/uploads/',
|
||||
saleType: 1,
|
||||
price: 0,
|
||||
saleCount: 1,
|
||||
vipPrice: 0,
|
||||
dealerPrice: 0,
|
||||
fragmentCount: 60,
|
||||
productNumber: '',
|
||||
isEnable: true,
|
||||
isSale: true
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-propfragment"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-propfragment"]', function() {
|
||||
var checkStatus = table.checkStatus('table-propfragment');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.number; });
|
||||
gameConfig.propFragments = gameConfig.propFragments.filter(function(item) {
|
||||
return !ids.includes(item.number);
|
||||
});
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加道具碎片' : '编辑道具碎片';
|
||||
var typeOptions = [
|
||||
{value: '3', text: '炮塔碎片'},
|
||||
{value: '4', text: '翅膀碎片'},
|
||||
{value: '6', text: '战神碎片'}
|
||||
];
|
||||
var saleTypeOptions = [
|
||||
{value: '1', text: '金币'},
|
||||
{value: '2', text: '钻石'}
|
||||
];
|
||||
|
||||
var typeHtml = '';
|
||||
typeOptions.forEach(function(opt) {
|
||||
typeHtml += '<option value="' + opt.value + '"' + (String(data.type) === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var saleTypeHtml = '';
|
||||
saleTypeOptions.forEach(function(opt) {
|
||||
saleTypeHtml += '<option value="' + opt.value + '"' + (String(data.saleType) === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var productOptions = '<option value="">请选择成品</option>';
|
||||
propList.forEach(function(p) {
|
||||
productOptions += '<option value="' + p.number + '"' + (String(data.productNumber) === String(p.number) ? ' selected' : '') + '>' + p.number + ' - ' + p.name + '</option>';
|
||||
});
|
||||
|
||||
var imagePreviewHtml = data.imageUrl
|
||||
? '<img src="' + data.imageUrl + '" style="max-width:100%;max-height:100%;">'
|
||||
: '<div class="placeholder">点击上传图片</div>';
|
||||
|
||||
var html = '<div class="edit-dialog" style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="number" value="' + (data.number || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="type">' + typeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">描述</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="desc" value="' + (data.desc || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">图标</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="icon-upload-box">' +
|
||||
'<div class="icon-upload-preview" id="iconPreview">' + imagePreviewHtml + '</div>' +
|
||||
'<input type="file" name="file" class="upload-btn" accept="image/png" id="propIconUpload">' +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="imageUrl" id="imageUrlInput" value="' + (data.imageUrl || '') + '">' +
|
||||
'<div style="margin-top:8px;color:#999;font-size:12px;">点击图片可预览,仅支持 PNG 格式</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">售卖方式</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="saleType">' + saleTypeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="price" value="' + (data.price || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">VIP价格</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="vipPrice" value="' + (data.vipPrice || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经销商价</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="dealerPrice" value="' + (data.dealerPrice || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">每日限购</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="saleCount" value="' + (data.saleCount || 1) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">合成数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="fragmentCount" value="' + (data.fragmentCount || 60) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">成品编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="productNumber">' + productOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">启用</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="isEnable" lay-skin="switch" lay-text="启用|禁用" ' + (data.isEnable ? 'checked' : '') + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">销售</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="isSale" lay-skin="switch" lay-text="销售|停售" ' + (data.isSale ? 'checked' : '') + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['520px', '650px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
var $preview = layero.find('#iconPreview');
|
||||
var $input = layero.find('#imageUrlInput');
|
||||
var $fileInput = layero.find('#propIconUpload');
|
||||
|
||||
$preview.on('click', function() {
|
||||
var url = $input.val();
|
||||
if (url) {
|
||||
previewImage(url);
|
||||
}
|
||||
});
|
||||
|
||||
$fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (file) {
|
||||
var number = layero.find('input[name="number"]').val();
|
||||
if (!number) {
|
||||
layer.msg('请先填写碎片编号');
|
||||
$(this).val('');
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('number', number);
|
||||
|
||||
$.ajax({
|
||||
// 配置图片按碎片编号覆盖,并通过 timespan 参数刷新浏览器缓存。
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/config',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
success: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
var path = res.data.path;
|
||||
$input.val(path);
|
||||
$preview.html('<img src="' + path + '" style="max-width:100%;max-height:100%;">');
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('上传失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
number: layero.find('input[name="number"]').val(),
|
||||
name: layero.find('input[name="name"]').val(),
|
||||
type: parseInt(layero.find('select[name="type"]').val()),
|
||||
desc: layero.find('input[name="desc"]').val(),
|
||||
imageUrl: layero.find('input[name="imageUrl"]').val(),
|
||||
saleType: parseInt(layero.find('select[name="saleType"]').val()),
|
||||
price: parseFloat(layero.find('input[name="price"]').val()) || 0,
|
||||
vipPrice: parseFloat(layero.find('input[name="vipPrice"]').val()) || 0,
|
||||
dealerPrice: parseFloat(layero.find('input[name="dealerPrice"]').val()) || 0,
|
||||
saleCount: parseInt(layero.find('input[name="saleCount"]').val()) || 1,
|
||||
fragmentCount: parseInt(layero.find('input[name="fragmentCount"]').val()) || 60,
|
||||
productNumber: layero.find('select[name="productNumber"]').val(),
|
||||
isEnable: layero.find('input[name="isEnable"]').prop('checked'),
|
||||
isSale: layero.find('input[name="isSale"]').prop('checked')
|
||||
};
|
||||
gameConfig.propFragments.unshift(newItem);
|
||||
} else if (rowIndex > -1) {
|
||||
// 上传后的 imageUrl 必须写回原数组,否则表格重载仍会使用旧图片。
|
||||
var original = gameConfig.propFragments[rowIndex];
|
||||
original.number = layero.find('input[name="number"]').val();
|
||||
original.name = layero.find('input[name="name"]').val();
|
||||
original.type = parseInt(layero.find('select[name="type"]').val());
|
||||
original.desc = layero.find('input[name="desc"]').val();
|
||||
original.imageUrl = layero.find('input[name="imageUrl"]').val();
|
||||
original.saleType = parseInt(layero.find('select[name="saleType"]').val());
|
||||
original.price = parseFloat(layero.find('input[name="price"]').val()) || 0;
|
||||
original.vipPrice = parseFloat(layero.find('input[name="vipPrice"]').val()) || 0;
|
||||
original.dealerPrice = parseFloat(layero.find('input[name="dealerPrice"]').val()) || 0;
|
||||
original.saleCount = parseInt(layero.find('input[name="saleCount"]').val()) || 1;
|
||||
original.fragmentCount = parseInt(layero.find('input[name="fragmentCount"]').val()) || 60;
|
||||
original.productNumber = layero.find('select[name="productNumber"]').val();
|
||||
original.isEnable = layero.find('input[name="isEnable"]').prop('checked');
|
||||
original.isSale = layero.find('input[name="isSale"]').prop('checked');
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-propfragment', {
|
||||
data: gameConfig.propFragments
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,432 @@
|
||||
|
||||
<title>排行榜奖励配置</title>
|
||||
|
||||
<style>
|
||||
.layui-form-label { width: 200px; }
|
||||
.rank-table { width: 100%; border-collapse: collapse; margin: 10px 0; }
|
||||
.rank-table th, .rank-table td { border: 1px solid #e6e6e6; padding: 6px 8px; text-align: center; font-size: 13px; }
|
||||
.rank-table th { background: #f2f2f2; font-weight: bold; }
|
||||
.rank-table input { text-align: center; height: 32px; }
|
||||
.rank-table .del-row { color: #ff5722; cursor: pointer; }
|
||||
.item-btn { cursor: pointer; color: #1e9fff; text-decoration: underline; }
|
||||
.prop-row { display: flex; align-items: center; gap: 6px; margin: 4px 0; }
|
||||
.prop-row select { flex: 1; }
|
||||
.prop-row input { width: 60px; }
|
||||
</style>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>排行榜奖励配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="save-ranking"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-ranking"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="init-ranking"><i class="layui-icon layui-icon-refresh-3"></i> 初始化</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" id="form-ranking" style="padding: 20px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">总开关</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="isEnabled" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
<div class="layui-form-mid">关闭后所有排行榜奖励将不发放</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">维护中</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="isMaintaining" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
<div class="layui-form-mid">开启后前端请求排行榜将提示维护中</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">维护提示文案</label>
|
||||
<div class="layui-input-inline" style="width: 400px;">
|
||||
<input type="text" name="maintainingMessage" class="layui-input" placeholder="当前排行榜正在维护中,请稍后再试">
|
||||
</div>
|
||||
</div>
|
||||
<div id="groups-container"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var activityConfig = null;
|
||||
var propList = [];
|
||||
var RANKING_NAMES = { 1: '金币达人榜', 2: '等级达人榜', 3: '当日积分榜' };
|
||||
var ITEMS_CTX = null; // { gi, ri } 当前编辑的单元格
|
||||
|
||||
function loadPropList() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/PropList",
|
||||
async: false,
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) propList = res.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getPropInfo(otherId) {
|
||||
return propList.find(function(p) { return p.number === otherId; });
|
||||
}
|
||||
|
||||
function getTypeName(type) {
|
||||
var typeNames = {
|
||||
1: '炮台', 2: '翅膀', 3: '炮塔碎片', 4: '翅膀碎片', 5: '战神',
|
||||
6: '战神碎片', 7: '刮刮卡', 8: '改名卡', 9: '大喇叭', 10: '技能',
|
||||
11: '召唤卡', 12: 'VIP经验', 13: '鱼雷'
|
||||
};
|
||||
return typeNames[type] || '其他';
|
||||
}
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig",
|
||||
done: function (res) {
|
||||
activityConfig = (res.code === 0 && res.data) ? res.data : {};
|
||||
renderGroups();
|
||||
},
|
||||
fail: function () { activityConfig = {}; renderGroups(); }
|
||||
});
|
||||
}
|
||||
|
||||
function renderGroups() {
|
||||
if (!activityConfig) activityConfig = {};
|
||||
var cfg = activityConfig.rankingRewardConfig || { isEnabled: false, isMaintaining: false, maintainingMessage: '', groups: [] };
|
||||
$('#form-ranking input[name="isEnabled"]').prop('checked', cfg.isEnabled);
|
||||
$('#form-ranking input[name="isMaintaining"]').prop('checked', cfg.isMaintaining);
|
||||
$('#form-ranking input[name="maintainingMessage"]').val(cfg.maintainingMessage || '当前排行榜正在维护中,请稍后再试');
|
||||
form.render();
|
||||
|
||||
var html = '';
|
||||
var groups = cfg.groups && cfg.groups.length > 0 ? cfg.groups : getDefaultGroups();
|
||||
for (var gi = 0; gi < groups.length; gi++) {
|
||||
var g = groups[gi];
|
||||
html += '<fieldset class="layui-elem-field"><legend>' + (g.name || RANKING_NAMES[g.rankingType] || '排行榜') + '</legend>';
|
||||
html += '<div class="layui-field-box">';
|
||||
html += '<table class="rank-table"><thead><tr>';
|
||||
html += '<th style="width:40px">启用</th><th>排名</th><th>金币</th><th>钻石</th><th>道具</th><th style="width:40px">操作</th>';
|
||||
html += '</tr></thead><tbody id="tbody-' + gi + '">';
|
||||
var rewards = g.rewards && g.rewards.length > 0 ? g.rewards : [];
|
||||
for (var ri = 0; ri < rewards.length; ri++) {
|
||||
html += renderRow(gi, ri, rewards[ri]);
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
html += '<button class="layui-btn layui-btn-xs layui-btn-normal" onclick="addRow(' + gi + ')"><i class="layui-icon layui-icon-add-1"></i> 新增排名</button>';
|
||||
html += '</div></fieldset><br>';
|
||||
}
|
||||
$('#groups-container').html(html);
|
||||
}
|
||||
|
||||
function renderRow(gi, ri, r) {
|
||||
if (!r) r = { rankMin: ri + 1, rankMax: ri + 1, gold: 0, diamond: 0, items: [], enabled: true };
|
||||
var rankLabel = r.rankMin === r.rankMax ? '第' + r.rankMin + '名' : '第' + r.rankMin + '-' + r.rankMax + '名';
|
||||
var itemsStr = '';
|
||||
if (r.items) {
|
||||
itemsStr = r.items.map(function (it) {
|
||||
var prop = getPropInfo(it.otherId);
|
||||
var imgHtml = prop ? '<img src="' + (prop.imageUrl || '/uploads/' + prop.number + '.png') + '" style="width:20px;height:20px;vertical-align:middle;margin-right:3px;">' : '';
|
||||
var name = prop ? prop.name : (it.otherId || '');
|
||||
return imgHtml + name + 'x' + (it.count || 0);
|
||||
}).join(' ');
|
||||
}
|
||||
var checked = r.enabled !== false ? 'checked' : '';
|
||||
return '<tr>' +
|
||||
'<td><input type="checkbox" lay-filter="row-switch" data-gi="' + gi + '" data-ri="' + ri + '" ' + checked + ' lay-skin="switch" lay-text="开|关"></td>' +
|
||||
'<td><input type="text" class="layui-input" style="width:70px" data-gi="' + gi + '" data-ri="' + ri + '" data-field="rankLabel" value="' + rankLabel + '"></td>' +
|
||||
'<td><input type="number" class="layui-input" style="width:80px" data-gi="' + gi + '" data-ri="' + ri + '" data-field="gold" value="' + (r.gold || 0) + '"></td>' +
|
||||
'<td><input type="number" class="layui-input" style="width:80px" data-gi="' + gi + '" data-ri="' + ri + '" data-field="diamond" value="' + (r.diamond || 0) + '"></td>' +
|
||||
'<td><span class="item-btn" onclick="openItemsDialog(' + gi + ',' + ri + ')">' + (itemsStr || '点击设置') + '</span></td>' +
|
||||
'<td><span class="del-row" onclick="removeRow(' + gi + ',' + ri + ')"><i class="layui-icon layui-icon-delete"></i></span></td>' +
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
// 每次操作前, 将 DOM 中的 gold/diamond/rankLabel 同步回 config 缓存
|
||||
function syncDomToConfig() {
|
||||
var cfg = activityConfig.rankingRewardConfig || { groups: [] };
|
||||
$('#groups-container fieldset').each(function (gi) {
|
||||
if (!cfg.groups[gi]) return;
|
||||
$(this).find('table tbody tr').each(function (ri) {
|
||||
if (!cfg.groups[gi].rewards[ri]) return;
|
||||
var rankLabel = $(this).find('input[data-field="rankLabel"]').val() || ('第' + (ri + 1) + '名');
|
||||
var parsed = parseRankLabel(rankLabel);
|
||||
cfg.groups[gi].rewards[ri].rankMin = parsed.rankMin;
|
||||
cfg.groups[gi].rewards[ri].rankMax = parsed.rankMax;
|
||||
cfg.groups[gi].rewards[ri].gold = parseInt($(this).find('input[data-field="gold"]').val()) || 0;
|
||||
cfg.groups[gi].rewards[ri].diamond = parseInt($(this).find('input[data-field="diamond"]').val()) || 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
window.addRow = function (gi) {
|
||||
syncDomToConfig();
|
||||
var cfg = activityConfig.rankingRewardConfig || { groups: [] };
|
||||
if (!cfg.groups[gi]) cfg.groups[gi] = { rankingType: gi + 1, name: RANKING_NAMES[gi + 1] || '', rewards: [] };
|
||||
var ri = cfg.groups[gi].rewards.length;
|
||||
cfg.groups[gi].rewards.push({ rankMin: ri + 1, rankMax: ri + 1, gold: 0, diamond: 0, items: [], enabled: true });
|
||||
renderGroups();
|
||||
};
|
||||
|
||||
window.removeRow = function (gi, ri) {
|
||||
layer.confirm('确定删除该排名奖励?', function (idx) {
|
||||
layer.close(idx);
|
||||
syncDomToConfig();
|
||||
var cfg = activityConfig.rankingRewardConfig || { groups: [] };
|
||||
if (cfg.groups[gi] && cfg.groups[gi].rewards) {
|
||||
cfg.groups[gi].rewards.splice(ri, 1);
|
||||
renderGroups();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.openItemsDialog = function (gi, ri) {
|
||||
ITEMS_CTX = { gi: gi, ri: ri };
|
||||
var tr = document.querySelector('#tbody-' + gi + ' tr:nth-child(' + (ri + 1) + ')');
|
||||
var rewards = getGroupRewards(gi);
|
||||
var items = (rewards[ri] && rewards[ri].items) ? JSON.parse(JSON.stringify(rewards[ri].items)) : [];
|
||||
|
||||
var html = '<div style="padding:15px;max-height:400px;overflow-y:auto;">';
|
||||
html += '<div id="items-list">';
|
||||
if (items.length === 0) {
|
||||
html += '<div class="items-empty" style="color:#999;">暂无道具,点击下方按钮添加</div>';
|
||||
} else {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
html += renderItemRow(i, items[i]);
|
||||
}
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<button type="button" class="layui-btn layui-btn-xs layui-btn-normal btn-add-item-row" style="margin-top:10px;"><i class="layui-icon layui-icon-add-1"></i> 添加道具</button>';
|
||||
html += '</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '编辑道具',
|
||||
area: ['500px', '450px'],
|
||||
content: html,
|
||||
btn: ['确定', '取消'],
|
||||
success: function (layero) {
|
||||
layero.on('click', '.btn-add-item-row', function () {
|
||||
addItemRow(layero);
|
||||
});
|
||||
layero.on('click', '.btn-remove-item-row', function () {
|
||||
$(this).closest('.prop-row').remove();
|
||||
if (layero.find('#items-list .prop-row').length === 0) {
|
||||
layero.find('#items-list').html('<div class="items-empty" style="color:#999;">暂无道具,点击下方按钮添加</div>');
|
||||
}
|
||||
});
|
||||
form.render('select');
|
||||
},
|
||||
yes: function (idx, layero) {
|
||||
var newItems = collectItems(layero);
|
||||
saveItemsToReward(gi, ri, newItems);
|
||||
layer.close(idx);
|
||||
renderGroups();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function renderItemRow(i, item) {
|
||||
var selectHtml = '<select class="layui-input item-prop" style="width:140px;height:32px;">';
|
||||
selectHtml += '<option value="">无</option>';
|
||||
var groups = {};
|
||||
propList.forEach(function(p) {
|
||||
var typeName = getTypeName(p.type);
|
||||
if (!groups[typeName]) groups[typeName] = [];
|
||||
groups[typeName].push(p);
|
||||
});
|
||||
for (var typeName in groups) {
|
||||
selectHtml += '<optgroup label="' + typeName + '">';
|
||||
groups[typeName].forEach(function(p) {
|
||||
var selected = p.number === item.otherId ? ' selected' : '';
|
||||
selectHtml += '<option value="' + p.number + '"' + selected + '>' + p.name + '</option>';
|
||||
});
|
||||
selectHtml += '</optgroup>';
|
||||
}
|
||||
selectHtml += '</select>';
|
||||
var prop = getPropInfo(item.otherId);
|
||||
var imgSrc = prop ? (prop.imageUrl || '/uploads/' + prop.number + '.png') : '';
|
||||
var imgHtml = '<img class="prop-preview" src="' + imgSrc + '" style="width:32px;height:32px;vertical-align:middle;margin:0 4px;' + (prop ? '' : 'display:none;') + '">';
|
||||
return '<div class="prop-row">' +
|
||||
selectHtml +
|
||||
imgHtml +
|
||||
'<span>x</span>' +
|
||||
'<input class="layui-input item-count" type="number" value="' + (item.count || 1) + '" style="width:60px;height:32px;">' +
|
||||
'<span class="del-row btn-remove-item-row" style="margin-left:6px;"><i class="layui-icon layui-icon-delete"></i></span>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function addItemRow(layero) {
|
||||
var list = layero.find('#items-list')[0];
|
||||
layero.find('#items-list .items-empty').remove();
|
||||
var i = layero.find('#items-list .prop-row').length;
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = renderItemRow(i, { otherId: '', count: 1 });
|
||||
list.appendChild(div.firstElementChild);
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
function collectItems(layero) {
|
||||
var items = [];
|
||||
layero.find('#items-list .prop-row').each(function () {
|
||||
var row = this;
|
||||
var otherId = row.querySelector('.item-prop').value.trim();
|
||||
var count = parseInt(row.querySelector('.item-count').value) || 1;
|
||||
if (otherId) items.push({ otherId: otherId, count: count });
|
||||
});
|
||||
return items;
|
||||
}
|
||||
|
||||
function saveItemsToReward(gi, ri, items) {
|
||||
var cfg = activityConfig.rankingRewardConfig || { groups: [] };
|
||||
if (!cfg.groups[gi]) cfg.groups[gi] = { rankingType: gi + 1, name: RANKING_NAMES[gi + 1] || '', rewards: [] };
|
||||
if (!cfg.groups[gi].rewards[ri]) cfg.groups[gi].rewards[ri] = { rankMin: ri + 1, rankMax: ri + 1, gold: 0, diamond: 0, items: [] };
|
||||
cfg.groups[gi].rewards[ri].items = items;
|
||||
}
|
||||
|
||||
// 道具选择变更时更新图片预览
|
||||
$(document).on('change', '.item-prop', function() {
|
||||
var val = $(this).val();
|
||||
var $img = $(this).next('.prop-preview');
|
||||
if (val) {
|
||||
var prop = getPropInfo(val);
|
||||
if (prop) {
|
||||
$img.attr('src', prop.imageUrl || '/uploads/' + prop.number + '.png').show();
|
||||
}
|
||||
} else {
|
||||
$img.hide();
|
||||
}
|
||||
});
|
||||
|
||||
function getGroupRewards(gi) {
|
||||
var cfg = activityConfig.rankingRewardConfig || { groups: [] };
|
||||
if (!cfg.groups[gi]) cfg.groups[gi] = { rankingType: gi + 1, name: RANKING_NAMES[gi + 1] || '', rewards: [] };
|
||||
return cfg.groups[gi].rewards;
|
||||
}
|
||||
|
||||
function parseRankLabel(str) {
|
||||
// "第1名" / "第1-3名" / "第1名" → { rankMin, rankMax }
|
||||
str = str.replace(/[第名\s]/g, '');
|
||||
var parts = str.split('-');
|
||||
return { rankMin: parseInt(parts[0]) || 1, rankMax: parseInt(parts[1]) || parseInt(parts[0]) || 1 };
|
||||
}
|
||||
|
||||
function getDefaultGroups() {
|
||||
return [
|
||||
{ rankingType: 1, name: '金币达人榜', rewards: getDefaultRewards() },
|
||||
{ rankingType: 2, name: '等级达人榜', rewards: getDefaultRewards() },
|
||||
{ rankingType: 3, name: '当日积分榜', rewards: getDefaultRewards() }
|
||||
];
|
||||
}
|
||||
|
||||
function getDefaultRewards() {
|
||||
return [
|
||||
{ rankMin: 1, rankMax: 1, gold: 65000, diamond: 50, items: [{ otherId: '40004', count: 10 }, { otherId: '40003', count: 10 }], enabled: true },
|
||||
{ rankMin: 2, rankMax: 2, gold: 45000, diamond: 50, items: [{ otherId: '40004', count: 10 }, { otherId: '40003', count: 10 }], enabled: true },
|
||||
{ rankMin: 3, rankMax: 3, gold: 30000, diamond: 50, items: [{ otherId: '40004', count: 10 }, { otherId: '40003', count: 10 }], enabled: true },
|
||||
{ rankMin: 4, rankMax: 4, gold: 20000, diamond: 50, items: [{ otherId: '40004', count: 8 }, { otherId: '40003', count: 8 }], enabled: true },
|
||||
{ rankMin: 5, rankMax: 5, gold: 15000, diamond: 50, items: [{ otherId: '40004', count: 8 }, { otherId: '40003', count: 8 }], enabled: true },
|
||||
{ rankMin: 6, rankMax: 6, gold: 12000, diamond: 30, items: [{ otherId: '40004', count: 8 }, { otherId: '40003', count: 8 }], enabled: true },
|
||||
{ rankMin: 7, rankMax: 7, gold: 10000, diamond: 30, items: [{ otherId: '40004', count: 6 }, { otherId: '40003', count: 6 }], enabled: true },
|
||||
{ rankMin: 8, rankMax: 8, gold: 8000, diamond: 30, items: [{ otherId: '40004', count: 6 }, { otherId: '40003', count: 6 }], enabled: true },
|
||||
{ rankMin: 9, rankMax: 9, gold: 6000, diamond: 30, items: [{ otherId: '40004', count: 6 }, { otherId: '40003', count: 6 }], enabled: true },
|
||||
{ rankMin: 10, rankMax: 10, gold: 5000, diamond: 30, items: [{ otherId: '40004', count: 5 }, { otherId: '40003', count: 5 }], enabled: true },
|
||||
{ rankMin: 11, rankMax: 11, gold: 3000, diamond: 20, items: [{ otherId: '40004', count: 5 }, { otherId: '40003', count: 5 }], enabled: true },
|
||||
{ rankMin: 12, rankMax: 12, gold: 2000, diamond: 20, items: [{ otherId: '40004', count: 5 }, { otherId: '40003', count: 5 }], enabled: true },
|
||||
{ rankMin: 13, rankMax: 13, gold: 1500, diamond: 20, items: [{ otherId: '40004', count: 3 }, { otherId: '40003', count: 3 }], enabled: true },
|
||||
{ rankMin: 14, rankMax: 14, gold: 1200, diamond: 20, items: [{ otherId: '40004', count: 3 }, { otherId: '40003', count: 3 }], enabled: true },
|
||||
{ rankMin: 15, rankMax: 15, gold: 1000, diamond: 20, items: [{ otherId: '40004', count: 3 }, { otherId: '40003', count: 3 }], enabled: true }
|
||||
];
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-ranking"]', function () { loadConfig(); layer.msg('刷新成功'); });
|
||||
|
||||
$(document).on('click', '[lay-filter="init-ranking"]', function () {
|
||||
layer.confirm('确定要初始化排行榜奖励配置吗?', function (idx) {
|
||||
layer.close(idx);
|
||||
if (!activityConfig.rankingRewardConfig) activityConfig.rankingRewardConfig = {};
|
||||
var cfg = activityConfig.rankingRewardConfig;
|
||||
cfg.isEnabled = true;
|
||||
cfg.isMaintaining = false;
|
||||
cfg.maintainingMessage = '当前排行榜正在维护中,请稍后再试';
|
||||
cfg.groups = [
|
||||
{ rankingType: 1, name: '金币达人榜', rewards: getDefaultRewards() },
|
||||
{ rankingType: 2, name: '等级达人榜', rewards: getDefaultRewards() },
|
||||
{ rankingType: 3, name: '当日积分榜', rewards: getDefaultRewards() }
|
||||
];
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/Update",
|
||||
data: JSON.stringify(activityConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) { layer.msg('初始化成功'); loadConfig(); }
|
||||
else { layer.msg(res.info || '初始化失败'); }
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-ranking"]', function () {
|
||||
if (!activityConfig.rankingRewardConfig) activityConfig.rankingRewardConfig = {};
|
||||
var cfg = activityConfig.rankingRewardConfig;
|
||||
cfg.isEnabled = $('#form-ranking input[name="isEnabled"]').prop('checked');
|
||||
cfg.isMaintaining = $('#form-ranking input[name="isMaintaining"]').prop('checked');
|
||||
cfg.maintainingMessage = $('#form-ranking input[name="maintainingMessage"]').val() || '当前排行榜正在维护中,请稍后再试';
|
||||
|
||||
var groups = [];
|
||||
$('#groups-container fieldset').each(function (gi) {
|
||||
var name = $(this).find('legend').text();
|
||||
var rewards = [];
|
||||
$(this).find('table tbody tr').each(function (ri) {
|
||||
var enabled = $(this).find('input[type="checkbox"]').first().prop('checked');
|
||||
if (!enabled) return;
|
||||
|
||||
var rankLabel = $(this).find('input[data-field="rankLabel"]').val() || ('第' + (ri + 1) + '名');
|
||||
var parsed = parseRankLabel(rankLabel);
|
||||
var gold = parseInt($(this).find('input[data-field="gold"]').val()) || 0;
|
||||
var diamond = parseInt($(this).find('input[data-field="diamond"]').val()) || 0;
|
||||
// 从 config 缓存取道具数据
|
||||
var items = [];
|
||||
if (cfg.groups && cfg.groups[gi] && cfg.groups[gi].rewards && cfg.groups[gi].rewards[ri]) {
|
||||
items = cfg.groups[gi].rewards[ri].items || [];
|
||||
}
|
||||
rewards.push({ rankMin: parsed.rankMin, rankMax: parsed.rankMax, gold: gold, diamond: diamond, items: items, enabled: true });
|
||||
});
|
||||
groups.push({ rankingType: gi + 1, name: name, rewards: rewards });
|
||||
});
|
||||
cfg.groups = groups;
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/Update",
|
||||
data: JSON.stringify(activityConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) { layer.msg('保存成功'); loadConfig(); }
|
||||
else { layer.msg(res.info || '保存失败'); }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
loadPropList();
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,431 @@
|
||||
|
||||
<title>注册配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>注册配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-register"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-register"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-register"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveAct('RegisterConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form" style="max-width: 800px; padding: 20px;">
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>基础配置</legend>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">初始金币</label>
|
||||
<div class="layui-input-inline" style="width: 200px;">
|
||||
<input type="number" name="initGold" class="layui-input" placeholder="初始金币">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">初始钻石</label>
|
||||
<div class="layui-input-inline" style="width: 200px;">
|
||||
<input type="number" name="initDiamond" class="layui-input" placeholder="初始钻石">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>初始道具</legend>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-edit-gifts">编辑初始道具</button>
|
||||
<span id="gift-count" style="margin-left: 10px; color: #666;"></span>
|
||||
</div>
|
||||
<table id="table-init-gift" lay-filter="table-init-gift"></table>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="gift-toolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-register">添加道具</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-register">批量删除</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-productType">
|
||||
{{# var typeMap = {1:'炮台',2:'翅膀',3:'炮塔碎片',4:'翅膀碎片',5:'战神',6:'战神碎片',7:'刮刮卡',8:'改名卡',9:'大喇叭',10:'技能',11:'召唤卡',12:'VIP经验',13:'鱼雷'}; }}
|
||||
{{= typeMap[d.type] || '道具' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="gift-bar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gift-type-selector { margin-bottom: 15px; }
|
||||
.gift-type-selector .layui-form-label { width: 80px; }
|
||||
.gift-type-selector .layui-input-block { margin-left: 100px; }
|
||||
.gift-type-row { display: flex; gap: 10px; align-items: center; }
|
||||
.gift-type-row select { flex: 1; }
|
||||
.gift-type-row input { flex: 1; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var activityConfig = null;
|
||||
var propList = [];
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
var loaded = { activity: false, props: false };
|
||||
function tryFill() {
|
||||
if (loaded.activity && loaded.props) {
|
||||
fillForms();
|
||||
}
|
||||
}
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/Get",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
activityConfig = res.data;
|
||||
} else {
|
||||
activityConfig = {};
|
||||
}
|
||||
if (!activityConfig.registerConfig) activityConfig.registerConfig = {};
|
||||
loaded.activity = true;
|
||||
tryFill();
|
||||
}
|
||||
});
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
propList = (res.data.propConfig || []).map(function(p) {
|
||||
return { number: p.number, name: p.name, type: p.type, imageUrl: p.imageUrl };
|
||||
});
|
||||
}
|
||||
loaded.props = true;
|
||||
tryFill();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getPropsByType(type) {
|
||||
return propList.filter(function(p) { return p.type === type; });
|
||||
}
|
||||
|
||||
function buildPropSelectOptions(type, currentNumber) {
|
||||
var props = getPropsByType(type);
|
||||
var html = '<option value="">请选择道具</option>';
|
||||
props.forEach(function(p) {
|
||||
var selected = p.number === currentNumber ? ' selected' : '';
|
||||
html += '<option value="' + p.number + '"' + selected + '>' + p.number + ' - ' + p.name + '</option>';
|
||||
});
|
||||
return html;
|
||||
}
|
||||
|
||||
function fillForms() {
|
||||
var config = activityConfig.registerConfig || {};
|
||||
$('input[name="initGold"]').val(config.initGold ?? 0);
|
||||
$('input[name="initDiamond"]').val(config.initDiamond ?? 0);
|
||||
renderGiftTable();
|
||||
updateGiftCount();
|
||||
form.render();
|
||||
}
|
||||
|
||||
function updateGiftCount() {
|
||||
var count = (activityConfig.registerConfig && activityConfig.registerConfig.initProductList)
|
||||
? activityConfig.registerConfig.initProductList.length : 0;
|
||||
$('#gift-count').text('共 ' + count + ' 个道具');
|
||||
}
|
||||
|
||||
function renderGiftTable() {
|
||||
var data = (activityConfig.registerConfig && activityConfig.registerConfig.initProductList)
|
||||
? activityConfig.registerConfig.initProductList : [];
|
||||
table.render({
|
||||
elem: '#table-init-gift',
|
||||
data: data,
|
||||
cols: [[
|
||||
{ type: 'checkbox' },
|
||||
{ field: "number", title: "道具编号", width: 120 },
|
||||
{ field: "name", title: "道具名称", width: 100 },
|
||||
{ field: "count", title: "数量", width: 80 },
|
||||
{ field: "image", title: "图标", width: 60, templet: function(d) {
|
||||
var imgUrl = d.imageUrl || '';
|
||||
if (!imgUrl && d.number) imgUrl = '/uploads/' + d.number + '.png';
|
||||
return imgUrl ? '<img src="' + imgUrl + '" style="width:28px;height:28px;vertical-align:middle;">' : '';
|
||||
}},
|
||||
{ field: "type", title: "类型", width: 100, templet: '#tpl-productType' },
|
||||
{ title: "操作", width: 150, toolbar: '#gift-bar' }
|
||||
]],
|
||||
toolbar: '#gift-toolbar',
|
||||
page: false
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要从配置文件还原注册配置吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitActivitySection/RegisterConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-register"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-register"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-register"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
if (!activityConfig.registerConfig) {
|
||||
activityConfig.registerConfig = {};
|
||||
}
|
||||
activityConfig.registerConfig.initGold = parseInt($('input[name="initGold"]').val()) || 0;
|
||||
activityConfig.registerConfig.initDiamond = parseInt($('input[name="initDiamond"]').val()) || 0;
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/UpdateRegister",
|
||||
data: JSON.stringify(activityConfig.registerConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-init-gift)', function(obj) {
|
||||
var config = activityConfig.registerConfig;
|
||||
var rowIndex = obj.tr.index();
|
||||
if (rowIndex < 0 && config && config.initProductList) {
|
||||
rowIndex = config.initProductList.findIndex(function(x) { return x.number === obj.data.number; });
|
||||
}
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(obj.data, false, rowIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该道具吗?', function(idx) {
|
||||
if (config && config.initProductList) {
|
||||
if (rowIndex > -1) config.initProductList.splice(rowIndex, 1);
|
||||
}
|
||||
obj.del();
|
||||
updateGiftCount();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
if (!activityConfig.registerConfig) activityConfig.registerConfig = {};
|
||||
if (!activityConfig.registerConfig.initProductList) {
|
||||
activityConfig.registerConfig.initProductList = [];
|
||||
}
|
||||
var newItem = { number: '', count: 1, name: '', type: 1, imageUrl: '' };
|
||||
showEditDialog(newItem, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-register"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-register"]', function() {
|
||||
var checkStatus = table.checkStatus('table-init-gift');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var config = activityConfig.registerConfig;
|
||||
if (config && config.initProductList) {
|
||||
checkData.forEach(function(item) {
|
||||
var index = config.initProductList.indexOf(item);
|
||||
if (index > -1) config.initProductList.splice(index, 1);
|
||||
});
|
||||
}
|
||||
renderGiftTable();
|
||||
updateGiftCount();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加初始道具' : '编辑初始道具';
|
||||
var typeOptions = [
|
||||
{value: 1, text: '炮台'},
|
||||
{value: 2, text: '翅膀'},
|
||||
{value: 3, text: '炮塔碎片'},
|
||||
{value: 4, text: '翅膀碎片'},
|
||||
{value: 5, text: '战神'},
|
||||
{value: 6, text: '战神碎片'},
|
||||
{value: 7, text: '刮刮卡'},
|
||||
{value: 8, text: '改名卡'},
|
||||
{value: 9, text: '大喇叭'},
|
||||
{value: 10, text: '技能'},
|
||||
{value: 11, text: '召唤卡'},
|
||||
{value: 12, text: 'VIP经验'},
|
||||
{value: 13, text: '鱼雷'}
|
||||
];
|
||||
|
||||
var currentType = data.type || 1;
|
||||
var currentNumber = data.number || '';
|
||||
var currentImg = data.imageUrl || '';
|
||||
if (!currentImg && currentNumber) {
|
||||
var cp = propList.find(function(p) { return p.number === currentNumber; });
|
||||
if (cp) currentImg = cp.imageUrl || '/uploads/' + cp.number + '.png';
|
||||
}
|
||||
|
||||
var typeHtml = '';
|
||||
typeOptions.forEach(function(opt) {
|
||||
typeHtml += '<option value="' + opt.value + '"' + (currentType === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var propOptionsHtml = buildPropSelectOptions(currentType, currentNumber);
|
||||
|
||||
var imgStyle = currentImg ? '' : 'display:none;';
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="giftType" id="giftType" lay-filter="giftType">' + typeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">道具</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="number" id="giftNumber" lay-search style="width:280px;">' + propOptionsHtml + '</select>' +
|
||||
'<img class="prop-preview" src="' + currentImg + '" style="width:36px;height:36px;vertical-align:middle;margin-left:8px;' + imgStyle + '">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="count" id="giftCount" value="' + (data.count || 1) + '" class="layui-input" style="width:200px;">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['600px', '400px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
|
||||
form.on('select(giftType)', function(obj) {
|
||||
var type = parseInt(obj.value) || 1;
|
||||
var propHtml = buildPropSelectOptions(type, '');
|
||||
layero.find('#giftNumber').html(propHtml);
|
||||
form.render('select');
|
||||
layero.find('.prop-preview').hide();
|
||||
});
|
||||
|
||||
form.on('select(giftNumber)', function(obj) {
|
||||
var val = obj.value;
|
||||
var $img = layero.find('.prop-preview');
|
||||
if (val) {
|
||||
var p = propList.find(function(x) { return x.number === val; });
|
||||
if (p) {
|
||||
$img.attr('src', p.imageUrl || '/uploads/' + p.number + '.png').show();
|
||||
}
|
||||
} else {
|
||||
$img.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
var number = layero.find('#giftNumber').val();
|
||||
var type = parseInt(layero.find('#giftType').val()) || 1;
|
||||
var prop = propList.find(function(p) { return p.number === number; });
|
||||
var name = prop ? prop.name : '';
|
||||
var imgUrl = prop ? (prop.imageUrl || '/uploads/' + prop.number + '.png') : '';
|
||||
var count = parseInt(layero.find('#giftCount').val()) || 1;
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
number: number,
|
||||
name: name,
|
||||
type: type,
|
||||
count: count,
|
||||
imageUrl: imgUrl
|
||||
};
|
||||
activityConfig.registerConfig.initProductList.unshift(newItem);
|
||||
} else {
|
||||
var original = activityConfig.registerConfig.initProductList[rowIndex];
|
||||
if (!original) {
|
||||
original = activityConfig.registerConfig.initProductList.find(function(x) { return x.number === data.number; });
|
||||
}
|
||||
if (!original) { layer.msg('数据异常,请刷新后重试'); return; }
|
||||
original.number = number;
|
||||
original.name = name;
|
||||
original.type = type;
|
||||
original.count = count;
|
||||
original.imageUrl = imgUrl;
|
||||
}
|
||||
layer.close(index);
|
||||
renderGiftTable();
|
||||
updateGiftCount();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveAct=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/ActivityConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,161 @@
|
||||
|
||||
<title>救济金配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>救济金配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-relief"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-relief"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-relief"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveAct('ReliefConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" id="form-relief" style="padding: 20px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">是否开启</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="isOpen" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">金币数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="gold" class="layui-input" placeholder="金币数量">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">每天次数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="count" class="layui-input" placeholder="每天可领取次数">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">金币限制</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="limit" class="layui-input" placeholder="领取金币的限制">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var activityConfig = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/Get",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
activityConfig = res.data;
|
||||
fillForms();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fillForms() {
|
||||
if (activityConfig.reliefConfig) {
|
||||
var r = activityConfig.reliefConfig;
|
||||
$('#form-relief input[name="isOpen"]').prop('checked', r.isOpen);
|
||||
$('#form-relief input[name="gold"]').val(r.gold || 10000);
|
||||
$('#form-relief input[name="count"]').val(r.count || 3);
|
||||
$('#form-relief input[name="limit"]').val(r.limit || 10000);
|
||||
}
|
||||
form.render();
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要从配置文件还原救济金配置吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitActivitySection/ReliefConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-relief"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-relief"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-relief"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
var reliefData = {
|
||||
isOpen: $('#form-relief input[name="isOpen"]').prop('checked'),
|
||||
gold: parseInt($('#form-relief input[name="gold"]').val()) || 10000,
|
||||
count: parseInt($('#form-relief input[name="count"]').val()) || 3,
|
||||
limit: parseInt($('#form-relief input[name="limit"]').val()) || 10000
|
||||
};
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/UpdateRelief",
|
||||
data: JSON.stringify(reliefData),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
window.saveAct=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/ActivityConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,317 @@
|
||||
|
||||
<title>机器人击杀播报配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>机器人击杀播报配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-robotkill"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-robotkill"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="add-robotkill"><i class="layui-icon layui-icon-add-1"></i> 添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="init-robotkill"><i class="layui-icon layui-icon-refresh"></i> 初始化</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('RobotKillConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form" style="padding: 10px 0;">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width:80px;">总开关</label>
|
||||
<div class="layui-input-inline" style="width:80px;">
|
||||
<input type="checkbox" id="isEnabled" lay-skin="switch" lay-text="开启|关闭">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label" style="width:100px;">播报间隔(秒)</label>
|
||||
<div class="layui-input-inline" style="width:80px;">
|
||||
<input type="number" id="intervalSeconds" class="layui-input" value="5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="table-robotkill" lay-filter="table-robotkill"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-gameType">
|
||||
{{# var map = {1:'风雷之渊',4:'星际迷航',5:'黑神话悟空'}; }}
|
||||
{{= map[d.gameType] || d.gameName || '未知' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-level">
|
||||
{{# var map = {1:'初级场',2:'中级场',3:'高级场'}; }}
|
||||
{{= map[d.roomLevel] || d.levelName || '未知' }}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var GAME_TYPES = [
|
||||
{ value: 1, name: '风雷之渊' },
|
||||
{ value: 4, name: '星际迷航' },
|
||||
{ value: 5, name: '黑神话悟空' }
|
||||
];
|
||||
var LEVELS = [
|
||||
{ value: 1, name: '初级场' },
|
||||
{ value: 2, name: '中级场' },
|
||||
{ value: 3, name: '高级场' }
|
||||
];
|
||||
var fishOptions = ''; // 鱼种下拉选项
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
buildFishOptions();
|
||||
fillForm();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildFishOptions() {
|
||||
fishOptions = '<option value="">-- 选择鱼种 --</option>';
|
||||
var list = gameConfig.fishTypeConfigs || [];
|
||||
// 只保留 Boss鱼(2)、特殊鱼(4)、特殊Boss(5)
|
||||
list = list.filter(function(f) {
|
||||
var ft = f.fishType || f.fishType || 0;
|
||||
return ft === 2 || ft === 4 || ft === 5;
|
||||
});
|
||||
list.sort(function(a, b) { return (a.fishNumber || '').localeCompare(b.fishNumber || ''); });
|
||||
list.forEach(function(f) {
|
||||
fishOptions += '<option value="' + (f.fishNumber || '') + '" data-name="' + (f.fishName || '') + '">' + (f.fishName || '') + ' (' + (f.fishNumber || '') + ')</option>';
|
||||
});
|
||||
}
|
||||
|
||||
function fillForm() {
|
||||
if (!gameConfig.robotKillConfig) gameConfig.robotKillConfig = {};
|
||||
var cfg = gameConfig.robotKillConfig;
|
||||
$('#isEnabled').prop('checked', cfg.isEnabled === true);
|
||||
$('#intervalSeconds').val(cfg.intervalSeconds || 5);
|
||||
form.render();
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function getScenes() {
|
||||
if (!gameConfig.robotKillConfig) gameConfig.robotKillConfig = {};
|
||||
return gameConfig.robotKillConfig.scenes || [];
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
var data = getScenes();
|
||||
table.render({
|
||||
elem: '#table-robotkill',
|
||||
data: data,
|
||||
page: { limit: 50 },
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'gameName', title: '场次', width: 120, templet: '#tpl-gameType' },
|
||||
{ field: 'levelName', title: '等级', width: 80, templet: '#tpl-level' },
|
||||
{ field: 'weight', title: '权重', width: 70 },
|
||||
{ field: 'fishName', title: '鱼种', width: 120, templet: function(d) { return d.fishName || d.fishNumber || '-'; } },
|
||||
{ field: 'fishNumber', title: '鱼编号', width: 90 },
|
||||
{ field: 'multiplierMin', title: '倍数Min', width: 90 },
|
||||
{ field: 'multiplierMax', title: '倍数Max', width: 90 },
|
||||
{ field: 'jackpotMin', title: '爆奖Min', width: 120 },
|
||||
{ field: 'jackpotMax', title: '爆奖Max', width: 120 },
|
||||
{ title: '操作', width: 120, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
done: function() { form.render(); }
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-robotkill"]', function () {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="init-robotkill"]', function () {
|
||||
layer.confirm('确定要从 gameconfig 初始化机器人击杀播报配置吗?', function (idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/RobotKillConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function () { layer.msg('初始化失败'); }
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="add-robotkill"]', function () {
|
||||
var scenes = getScenes();
|
||||
scenes.push({
|
||||
gameName: '', levelName: '', gameType: 1, roomLevel: 1, weight: 1,
|
||||
fishName: '', fishNumber: '',
|
||||
multiplierMin: 500, multiplierMax: 2000,
|
||||
jackpotMin: 5000000, jackpotMax: 200000000
|
||||
});
|
||||
renderTable();
|
||||
});
|
||||
|
||||
var currentEditIndex = -1;
|
||||
|
||||
function openEditDialog(data, idx) {
|
||||
currentEditIndex = idx;
|
||||
var gtOpts = '';
|
||||
GAME_TYPES.forEach(function(g) {
|
||||
gtOpts += '<option value="' + g.value + '"' + (data.gameType === g.value ? ' selected' : '') + '>' + g.name + '</option>';
|
||||
});
|
||||
var lvOpts = '';
|
||||
LEVELS.forEach(function(l) {
|
||||
lvOpts += '<option value="' + l.value + '"' + (data.roomLevel === l.value ? ' selected' : '') + '>' + l.name + '</option>';
|
||||
});
|
||||
var html = '<div style="padding:20px;"><form class="layui-form">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">场次</label><div class="layui-input-block"><select id="edit-gameType">' + gtOpts + '</select></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">等级</label><div class="layui-input-block"><select id="edit-roomLevel">' + lvOpts + '</select></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">权重</label><div class="layui-input-block"><input type="number" id="edit-weight" value="' + (data.weight||1) + '" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">鱼种</label><div class="layui-input-block"><select id="edit-fishNumber" lay-search>' + fishOptions + '</select></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">倍数Min</label><div class="layui-input-block"><input type="number" id="edit-multiplierMin" value="' + (data.multiplierMin||500) + '" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">倍数Max</label><div class="layui-input-block"><input type="number" id="edit-multiplierMax" value="' + (data.multiplierMax||2000) + '" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">爆奖Min</label><div class="layui-input-block"><input type="number" id="edit-jackpotMin" value="' + (data.jackpotMin||5000000) + '" class="layui-input"></div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">爆奖Max</label><div class="layui-input-block"><input type="number" id="edit-jackpotMax" value="' + (data.jackpotMax||200000000) + '" class="layui-input"></div></div>' +
|
||||
'</form></div>';
|
||||
layer.open({
|
||||
type: 1, title: '编辑播报配置', area: ['500px', '500px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
success: function(layero) {
|
||||
// 设置鱼种下拉的选中值
|
||||
if (data.fishNumber) {
|
||||
layero.find('#edit-fishNumber').val(data.fishNumber);
|
||||
}
|
||||
form.render();
|
||||
},
|
||||
yes: function (ei) {
|
||||
var fishNum = $('#edit-fishNumber').val();
|
||||
var fishName = '';
|
||||
if (fishNum) {
|
||||
var opt = $('#edit-fishNumber option[value="' + fishNum + '"]');
|
||||
fishName = opt.attr('data-name') || opt.text().split(' (')[0] || '';
|
||||
}
|
||||
var update = {
|
||||
gameType: parseInt($('#edit-gameType').val()) || 1,
|
||||
roomLevel: parseInt($('#edit-roomLevel').val()) || 1,
|
||||
weight: parseInt($('#edit-weight').val()) || 1,
|
||||
fishNumber: fishNum || '',
|
||||
fishName: fishName,
|
||||
multiplierMin: parseInt($('#edit-multiplierMin').val()) || 500,
|
||||
multiplierMax: parseInt($('#edit-multiplierMax').val()) || 2000,
|
||||
jackpotMin: parseInt($('#edit-jackpotMin').val()) || 5000000,
|
||||
jackpotMax: parseInt($('#edit-jackpotMax').val()) || 200000000
|
||||
};
|
||||
update.gameName = GAME_TYPES.find(function(g) { return g.value === update.gameType; })?.name || '';
|
||||
update.levelName = LEVELS.find(function(l) { return l.value === update.roomLevel; })?.name || '';
|
||||
// 写回原始数据
|
||||
var scenes = getScenes();
|
||||
if (currentEditIndex >= 0 && currentEditIndex < scenes.length) {
|
||||
scenes[currentEditIndex] = update;
|
||||
}
|
||||
layer.close(ei);
|
||||
renderTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
table.on('tool(table-robotkill)', function (obj) {
|
||||
var data = obj.data;
|
||||
var scenes = getScenes();
|
||||
|
||||
// 通过对比所有字段在原始数组中找真实索引
|
||||
var realIndex = -1;
|
||||
for (var i = 0; i < scenes.length; i++) {
|
||||
if (scenes[i].fishNumber === data.fishNumber &&
|
||||
scenes[i].gameType === data.gameType &&
|
||||
scenes[i].roomLevel === data.roomLevel) {
|
||||
realIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 如果找不到(新增行无 fishNumber),用行 data-index + 页码计算
|
||||
if (realIndex < 0) {
|
||||
var pageIndex = $('.layui-laypage-em').next().length > 0
|
||||
? parseInt($('.layui-laypage-em').next().text()) || 1
|
||||
: 1;
|
||||
var trIdx = obj.tr ? $(obj.tr).data('index') : -1;
|
||||
if (trIdx < 0) trIdx = $(obj.tr).index();
|
||||
realIndex = (pageIndex - 1) * 50 + trIdx;
|
||||
}
|
||||
if (realIndex < 0 || realIndex >= scenes.length) realIndex = 0;
|
||||
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定要删除该配置吗?', function (idx) {
|
||||
if (realIndex >= 0 && realIndex < scenes.length) {
|
||||
scenes.splice(realIndex, 1);
|
||||
}
|
||||
layer.close(idx);
|
||||
renderTable();
|
||||
});
|
||||
}
|
||||
if (obj.event === 'edit') {
|
||||
openEditDialog(data, realIndex);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-robotkill"]', function () {
|
||||
if (!gameConfig.robotKillConfig) gameConfig.robotKillConfig = {};
|
||||
var cfg = gameConfig.robotKillConfig;
|
||||
cfg.isEnabled = $('#isEnabled').prop('checked');
|
||||
cfg.intervalSeconds = parseInt($('#intervalSeconds').val()) || 5;
|
||||
// 数据已直接存储在 gameConfig.robotKillConfig.scenes 中
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
<script>window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}</script>
|
||||
@@ -0,0 +1,330 @@
|
||||
|
||||
<title>房间配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>房间配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
|
||||
<div class="layui-card-body" style="padding-top:10px;">
|
||||
<table id="table-room" lay-filter="table-room"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-room">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-room"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-room"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-room"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-room">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-room">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('RoomConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-gameType">
|
||||
{{# var typeMap = {0:'无',1:'风雷之渊',2:'永夜尸城',3:'中国象棋',4:'星际迷航',5:'黑神话悟空'}; }}
|
||||
{{= typeMap[d.gameType] || '无' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
|
||||
// 页面加载时清理可能残留的遮罩
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function formatList(list) {
|
||||
if (!list) return '';
|
||||
if (Array.isArray(list)) return list.join(',');
|
||||
return String(list);
|
||||
}
|
||||
|
||||
function parseList(str) {
|
||||
if (!str) return [];
|
||||
if (Array.isArray(str)) return str;
|
||||
if (typeof str === 'string') {
|
||||
return str.split(',').map(function(x) { return parseInt(x.trim()); }).filter(function(x) { return !isNaN(x); });
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-room',
|
||||
data: gameConfig ? gameConfig.roomConfigs || [] : [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "roomNumber", title: "编号", width: 80 },
|
||||
{ field: "roomName", title: "名称", width: 120 },
|
||||
{ field: "gameType", title: "游戏类型", width: 100, templet: '#tpl-gameType' },
|
||||
{ field: "roomLevel", title: "等级", width: 70 },
|
||||
{ field: "roomPartitionNum", title: "分区数", width: 80 },
|
||||
{ field: "roomCount", title: "房间数", width: 80 },
|
||||
{ field: "roomGoldLimit", title: "金币限制", width: 100 },
|
||||
{ field: "cannonMultipleList", title: "炮倍列表", width: 150, templet: function(d) {
|
||||
return formatList(d.cannonMultipleList);
|
||||
}},
|
||||
{ title: "操作", width: 150, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-room',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/RoomConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-room"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-room"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-room"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-room)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = obj.tr.index();
|
||||
if (trIndex < 0) trIndex = gameConfig.roomConfigs.findIndex(function(x) { return x.roomNumber === data.roomNumber; });
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) gameConfig.roomConfigs.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
var newData = {
|
||||
roomNumber: '',
|
||||
roomName: '',
|
||||
gameType: 0,
|
||||
roomLevel: 0,
|
||||
roomPartitionNum: 0,
|
||||
roomCount: 0,
|
||||
roomGoldLimit: 0,
|
||||
cannonMultipleList: []
|
||||
};
|
||||
showEditDialog(newData, true, -1);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-room"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-room"]', function() {
|
||||
var checkStatus = table.checkStatus('table-room');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.roomNumber; });
|
||||
gameConfig.roomConfigs = gameConfig.roomConfigs.filter(function(item) {
|
||||
return !ids.includes(item.roomNumber);
|
||||
});
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, itemIndex) {
|
||||
var dialogTitle = isAdd ? '添加房间' : '编辑房间';
|
||||
var typeOptions = [
|
||||
{value: 0, text: '无'},
|
||||
{value: 1, text: '风雷之渊'},
|
||||
{value: 2, text: '永夜尸城'},
|
||||
{value: 3, text: '中国象棋'},
|
||||
{value: 4, text: '星际迷航'},
|
||||
{value: 5, text: '黑神话悟空'}
|
||||
];
|
||||
|
||||
var typeHtml = '';
|
||||
typeOptions.forEach(function(opt) {
|
||||
typeHtml += '<option value="' + opt.value + '"' + (data.gameType === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var cannonStr = formatList(data.cannonMultipleList);
|
||||
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="roomNumber" value="' + (data.roomNumber || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="roomName" value="' + (data.roomName || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">游戏类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="gameType">' + typeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="roomLevel" value="' + (data.roomLevel || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">分区数</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="roomPartitionNum" value="' + (data.roomPartitionNum || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">房间数</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="roomCount" value="' + (data.roomCount || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">金币限制</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="roomGoldLimit" value="' + (data.roomGoldLimit || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">炮倍列表</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="cannonMultipleList" value="' + cannonStr + '" placeholder="多个值用逗号分隔" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['600px', '550px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
var cannonStr = layero.find('input[name="cannonMultipleList"]').val();
|
||||
var cannonList = parseList(cannonStr);
|
||||
var updatedItem = {
|
||||
roomNumber: layero.find('input[name="roomNumber"]').val(),
|
||||
roomName: layero.find('input[name="roomName"]').val(),
|
||||
gameType: parseInt(layero.find('select[name="gameType"]').val()),
|
||||
roomLevel: parseInt(layero.find('input[name="roomLevel"]').val()) || 0,
|
||||
roomPartitionNum: parseInt(layero.find('input[name="roomPartitionNum"]').val()) || 0,
|
||||
roomCount: parseInt(layero.find('input[name="roomCount"]').val()) || 0,
|
||||
roomGoldLimit: parseInt(layero.find('input[name="roomGoldLimit"]').val()) || 0,
|
||||
cannonMultipleList: cannonList
|
||||
};
|
||||
if (isAdd) {
|
||||
gameConfig.roomConfigs.unshift(updatedItem);
|
||||
} else {
|
||||
if (itemIndex >= 0 && itemIndex < gameConfig.roomConfigs.length) {
|
||||
gameConfig.roomConfigs[itemIndex] = updatedItem;
|
||||
}
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-room', {
|
||||
data: gameConfig.roomConfigs
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,680 @@
|
||||
|
||||
<title>出鱼配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>出鱼配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="roomfish-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this" lay-id="normal">出鱼配置</li>
|
||||
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="padding: 10px 0 0 0;">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<table id="table-roomfish" lay-filter="table-roomfish"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">游戏类型选择</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-container" id="game-type-btns">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="1">风雷之渊</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="2">永夜尸城</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="5">黑神话悟空</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md9">
|
||||
<table id="table-probability" lay-filter="table-probability"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-roomfish">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-roomfish"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-roomfish"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-roomfish"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('RoomFishConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-gameType">
|
||||
{{# var typeMap = {1:'风雷之渊',2:'永夜尸城',3:'中国象棋',4:'星际迷航',5:'黑神话悟空'}; }}
|
||||
{{= typeMap[d.gameType] || '未知(' + d.gameType + ')' }}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
buildFishNameMap();
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var fishNameMap = {};
|
||||
var fishArrayNameMap = {};
|
||||
|
||||
function buildFishNameMap() {
|
||||
if (!gameConfig) return;
|
||||
fishNameMap = {};
|
||||
fishArrayNameMap = {};
|
||||
|
||||
var fishConfigs = gameConfig.fishTypeConfigs || [];
|
||||
fishConfigs.forEach(function(f) {
|
||||
fishNameMap[f.fishNumber] = f.fishName || f.fishNumber;
|
||||
});
|
||||
|
||||
var fishArrayConfigs = gameConfig.fishArrayConfigs || [];
|
||||
fishArrayConfigs.forEach(function(f) {
|
||||
fishArrayNameMap[f.fishArrayNumber] = f.name || f.fishArrayNumber;
|
||||
});
|
||||
}
|
||||
|
||||
function buildRoomLevelNameMap(gameType) {
|
||||
var map = {};
|
||||
if (!gameConfig) return map;
|
||||
var roomConfigs = gameConfig.roomConfigs || [];
|
||||
roomConfigs.forEach(function(r) {
|
||||
if (r.gameType === gameType) {
|
||||
map[r.roomLevel] = r.roomLevel + ' ' + r.roomName;
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
function getRoomLevelDisplay(roomLevel, gameType) {
|
||||
var map = buildRoomLevelNameMap(gameType);
|
||||
return map[roomLevel] || roomLevel.toString();
|
||||
}
|
||||
|
||||
function getFishDisplayName(fishNumber, type) {
|
||||
if (type === 2) {
|
||||
var name = fishArrayNameMap[fishNumber] || fishNumber;
|
||||
return name + ' (' + fishNumber + ')';
|
||||
} else {
|
||||
var name = fishNameMap[fishNumber] || fishNumber;
|
||||
return name + ' (' + fishNumber + ')';
|
||||
}
|
||||
}
|
||||
|
||||
function saveConfig() {
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/RoomFishConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
var data = (gameConfig ? gameConfig.roomFishConfigs : []) || [];
|
||||
table.render({
|
||||
elem: '#table-roomfish',
|
||||
data: data,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "gameType", title: "游戏类型", width: 150, templet: '#tpl-gameType' },
|
||||
{ field: "normalFishList", title: "普通鱼配置", width: 120, templet: function(d) { return (d.normalFishList || []).length + ' 条'; } },
|
||||
{ field: "roomFishLevelList", title: "等级配置", width: 120, templet: function(d) { return (d.roomFishLevelList || []).length + ' 条'; } },
|
||||
{ title: "操作", width: 100, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-roomfish',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-roomfish"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-roomfish"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-roomfish"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
saveConfig();
|
||||
});
|
||||
|
||||
table.on('tool(table-roomfish)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = obj.tr.index();
|
||||
if (trIndex < 0) trIndex = gameConfig.roomFishConfigs.findIndex(function(x) { return x.gameType === data.gameType; });
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(data, trIndex);
|
||||
}
|
||||
});
|
||||
|
||||
function showEditDialog(data, itemIndex) {
|
||||
var typeMap = {1:'风雷之渊',2:'永夜尸城',3:'中国象棋',4:'星际迷航',5:'黑神话悟空'};
|
||||
var gameTypeName = typeMap[data.gameType] || '未知';
|
||||
|
||||
var html = '<div style="padding:15px;">' +
|
||||
'<div style="margin-bottom:10px;">' +
|
||||
'<span style="font-weight:bold;font-size:14px;">游戏类型:</span>' +
|
||||
'<span style="color:#1e88e5;">' + gameTypeName + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="layui-tab layui-tab-brief" lay-filter="fish-config-tab">' +
|
||||
'<ul class="layui-tab-title">' +
|
||||
'<li class="layui-this" lay-id="normal">普通鱼配置 (' + ((data.normalFishList || []).length) + '条)</li>' +
|
||||
'<li lay-id="level1">初级房间配置 (' + ((data.roomFishLevelList || []).filter(function(x){return x.roomLevel===1;}).length) + '条)</li>' +
|
||||
'<li lay-id="level2">中级房间配置 (' + ((data.roomFishLevelList || []).filter(function(x){return x.roomLevel===2;}).length) + '条)</li>' +
|
||||
'<li lay-id="level3">高级房间配置 (' + ((data.roomFishLevelList || []).filter(function(x){return x.roomLevel===3;}).length) + '条)</li>' +
|
||||
'</ul>' +
|
||||
'<div class="layui-tab-content" style="padding:10px 0 0 0;">' +
|
||||
'<div class="layui-tab-item layui-show">' +
|
||||
'<div style="margin-bottom:10px;">' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm" id="add-normal-fish-btn"><i class="layui-icon layui-icon-add-1"></i> 添加</button>' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="del-normal-fish-btn"><i class="layui-icon layui-icon-delete"></i> 批量删除</button>' +
|
||||
'</div>' +
|
||||
'<table id="table-normal-detail" lay-filter="table-normal-detail"></table>' +
|
||||
'</div>' +
|
||||
'<div class="layui-tab-item">' +
|
||||
'<div style="margin-bottom:10px;">' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm" id="add-level1-fish-btn"><i class="layui-icon layui-icon-add-1"></i> 添加</button>' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="del-level1-fish-btn"><i class="layui-icon layui-icon-delete"></i> 批量删除</button>' +
|
||||
'</div>' +
|
||||
'<table id="table-level1-detail" lay-filter="table-level1-detail"></table>' +
|
||||
'</div>' +
|
||||
'<div class="layui-tab-item">' +
|
||||
'<div style="margin-bottom:10px;">' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm" id="add-level2-fish-btn"><i class="layui-icon layui-icon-add-1"></i> 添加</button>' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="del-level2-fish-btn"><i class="layui-icon layui-icon-delete"></i> 批量删除</button>' +
|
||||
'</div>' +
|
||||
'<table id="table-level2-detail" lay-filter="table-level2-detail"></table>' +
|
||||
'</div>' +
|
||||
'<div class="layui-tab-item">' +
|
||||
'<div style="margin-bottom:10px;">' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm" id="add-level3-fish-btn"><i class="layui-icon layui-icon-add-1"></i> 添加</button>' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="del-level3-fish-btn"><i class="layui-icon layui-icon-delete"></i> 批量删除</button>' +
|
||||
'</div>' +
|
||||
'<table id="table-level3-detail" lay-filter="table-level3-detail"></table>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '编辑出鱼配置 - ' + gameTypeName,
|
||||
area: ['1000px', '600px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
layui.element.init();
|
||||
|
||||
var normalTable = layui.table.render({
|
||||
elem: '#table-normal-detail',
|
||||
data: data.normalFishList || [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "type", title: "类型", width: 80, templet: function(d) { return d.type === 1 ? '鱼' : '鱼阵'; } },
|
||||
{ field: "fishNumber", title: "鱼/鱼阵", minWidth: 180, templet: function(d) { return getFishDisplayName(d.fishNumber, d.type); } },
|
||||
{ field: "fishWeight", title: "权重", width: 80 },
|
||||
{ field: "fishFrequency", title: "频率(秒)", width: 100 },
|
||||
{ field: "maxCount", title: "最大数量", width: 100 },
|
||||
{ field: "times", title: "出场秒数", width: 100 },
|
||||
{ title: "操作", width: 80, fixed: 'right', toolbar: '#table-normal-operate' }
|
||||
]]
|
||||
});
|
||||
|
||||
var level1Data = (data.roomFishLevelList || []).filter(function(x){return x.roomLevel===1;});
|
||||
var level2Data = (data.roomFishLevelList || []).filter(function(x){return x.roomLevel===2;});
|
||||
var level3Data = (data.roomFishLevelList || []).filter(function(x){return x.roomLevel===3;});
|
||||
|
||||
layui.table.render({
|
||||
elem: '#table-level1-detail',
|
||||
data: level1Data,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "roomLevel", title: "房间等级", width: 120, templet: function(d) { return getRoomLevelDisplay(d.roomLevel, data.gameType); } },
|
||||
{ field: "type", title: "类型", width: 80, templet: function(d) { return d.type === 1 ? '鱼' : '鱼阵'; } },
|
||||
{ field: "fishNumber", title: "鱼/鱼阵", minWidth: 180, templet: function(d) { return getFishDisplayName(d.fishNumber, d.type); } },
|
||||
{ field: "fishWeight", title: "权重", width: 80 },
|
||||
{ field: "fishFrequency", title: "频率(秒)", width: 100 },
|
||||
{ field: "maxCount", title: "最大数量", width: 100 },
|
||||
{ field: "times", title: "出场秒数", width: 100 },
|
||||
{ title: "操作", width: 80, fixed: 'right', toolbar: '#table-level-operate' }
|
||||
]]
|
||||
});
|
||||
|
||||
layui.table.render({
|
||||
elem: '#table-level2-detail',
|
||||
data: level2Data,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "roomLevel", title: "房间等级", width: 120, templet: function(d) { return getRoomLevelDisplay(d.roomLevel, data.gameType); } },
|
||||
{ field: "type", title: "类型", width: 80, templet: function(d) { return d.type === 1 ? '鱼' : '鱼阵'; } },
|
||||
{ field: "fishNumber", title: "鱼/鱼阵", minWidth: 180, templet: function(d) { return getFishDisplayName(d.fishNumber, d.type); } },
|
||||
{ field: "fishWeight", title: "权重", width: 80 },
|
||||
{ field: "fishFrequency", title: "频率(秒)", width: 100 },
|
||||
{ field: "maxCount", title: "最大数量", width: 100 },
|
||||
{ field: "times", title: "出场秒数", width: 100 },
|
||||
{ title: "操作", width: 80, fixed: 'right', toolbar: '#table-level-operate' }
|
||||
]]
|
||||
});
|
||||
|
||||
layui.table.render({
|
||||
elem: '#table-level3-detail',
|
||||
data: level3Data,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "roomLevel", title: "房间等级", width: 120, templet: function(d) { return getRoomLevelDisplay(d.roomLevel, data.gameType); } },
|
||||
{ field: "type", title: "类型", width: 80, templet: function(d) { return d.type === 1 ? '鱼' : '鱼阵'; } },
|
||||
{ field: "fishNumber", title: "鱼/鱼阵", minWidth: 180, templet: function(d) { return getFishDisplayName(d.fishNumber, d.type); } },
|
||||
{ field: "fishWeight", title: "权重", width: 80 },
|
||||
{ field: "fishFrequency", title: "频率(秒)", width: 100 },
|
||||
{ field: "maxCount", title: "最大数量", width: 100 },
|
||||
{ field: "times", title: "出场秒数", width: 100 },
|
||||
{ title: "操作", width: 80, fixed: 'right', toolbar: '#table-level-operate' }
|
||||
]]
|
||||
});
|
||||
|
||||
layui.table.on('tool(table-normal-detail)', function(obj) {
|
||||
var d = obj.data;
|
||||
var idx = obj.tr.index();
|
||||
if (obj.event === 'edit') {
|
||||
showFishEditDialog(d, 'normal', data, idx, function(updated) {
|
||||
obj.update(updated);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
layui.table.on('tool(table-level1-detail)', function(obj) {
|
||||
var d = obj.data;
|
||||
var idx = obj.tr.index();
|
||||
if (obj.event === 'edit') {
|
||||
showFishEditDialog(d, 'level', data, idx, 1, function(updated) {
|
||||
obj.update(updated);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
layui.table.on('tool(table-level2-detail)', function(obj) {
|
||||
var d = obj.data;
|
||||
var idx = obj.tr.index();
|
||||
if (obj.event === 'edit') {
|
||||
showFishEditDialog(d, 'level', data, idx, 2, function(updated) {
|
||||
obj.update(updated);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
layui.table.on('tool(table-level3-detail)', function(obj) {
|
||||
var d = obj.data;
|
||||
var idx = obj.tr.index();
|
||||
if (obj.event === 'edit') {
|
||||
showFishEditDialog(d, 'level', data, idx, 3, function(updated) {
|
||||
obj.update(updated);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#add-normal-fish-btn').on('click', function() {
|
||||
var newData = {type: 1, fishNumber: '', fishWeight: 0, fishFrequency: 5, maxCount: 1, times: 10};
|
||||
showFishEditDialog(newData, 'normal', data, -1, function(updated) {
|
||||
data.normalFishList = data.normalFishList || [];
|
||||
data.normalFishList.unshift(updated);
|
||||
layui.table.reload('table-normal-detail', { data: data.normalFishList });
|
||||
$('.layui-tab-title li[lay-id="normal"]').text('普通鱼配置 (' + data.normalFishList.length + '条)');
|
||||
});
|
||||
});
|
||||
|
||||
$('#add-level1-fish-btn').on('click', function() {
|
||||
var newData = {roomLevel: 1, type: 1, fishNumber: '', fishWeight: 0, fishFrequency: 5, maxCount: 1, times: 10};
|
||||
showFishEditDialog(newData, 'level', data, -1, 1, function(updated) {
|
||||
data.roomFishLevelList = data.roomFishLevelList || [];
|
||||
data.roomFishLevelList.unshift(updated);
|
||||
layui.table.reload('table-level1-detail', { data: (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===1;}) });
|
||||
$('.layui-tab-title li[lay-id="level1"]').text('初级房间配置 (' + (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===1;}).length + '条)');
|
||||
});
|
||||
});
|
||||
|
||||
$('#add-level2-fish-btn').on('click', function() {
|
||||
var newData = {roomLevel: 2, type: 1, fishNumber: '', fishWeight: 0, fishFrequency: 5, maxCount: 1, times: 10};
|
||||
showFishEditDialog(newData, 'level', data, -1, 2, function(updated) {
|
||||
data.roomFishLevelList = data.roomFishLevelList || [];
|
||||
data.roomFishLevelList.unshift(updated);
|
||||
layui.table.reload('table-level2-detail', { data: (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===2;}) });
|
||||
$('.layui-tab-title li[lay-id="level2"]').text('中级房间配置 (' + (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===2;}).length + '条)');
|
||||
});
|
||||
});
|
||||
|
||||
$('#add-level3-fish-btn').on('click', function() {
|
||||
var newData = {roomLevel: 3, type: 1, fishNumber: '', fishWeight: 0, fishFrequency: 5, maxCount: 1, times: 10};
|
||||
showFishEditDialog(newData, 'level', data, -1, 3, function(updated) {
|
||||
data.roomFishLevelList = data.roomFishLevelList || [];
|
||||
data.roomFishLevelList.unshift(updated);
|
||||
layui.table.reload('table-level3-detail', { data: (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===3;}) });
|
||||
$('.layui-tab-title li[lay-id="level3"]').text('高级房间配置 (' + (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===3;}).length + '条)');
|
||||
});
|
||||
});
|
||||
|
||||
$('#del-normal-fish-btn').on('click', function() {
|
||||
var checkStatus = layui.table.checkStatus('table-normal-detail');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
layer.msg('请选择要删除的数据');
|
||||
return;
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.fishNumber + '_' + item.type; });
|
||||
data.normalFishList = (data.normalFishList || []).filter(function(item) {
|
||||
return !ids.includes(item.fishNumber + '_' + item.type);
|
||||
});
|
||||
layui.table.reload('table-normal-detail', { data: data.normalFishList });
|
||||
$('.layui-tab-title li[lay-id="normal"]').text('普通鱼配置 (' + data.normalFishList.length + '条)');
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
$('#del-level1-fish-btn').on('click', function() {
|
||||
var checkStatus = layui.table.checkStatus('table-level1-detail');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
layer.msg('请选择要删除的数据');
|
||||
return;
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.roomLevel + '_' + item.fishNumber + '_' + item.type; });
|
||||
data.roomFishLevelList = (data.roomFishLevelList || []).filter(function(item) {
|
||||
return !ids.includes(item.roomLevel + '_' + item.fishNumber + '_' + item.type);
|
||||
});
|
||||
layui.table.reload('table-level1-detail', { data: (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===1;}) });
|
||||
$('.layui-tab-title li[lay-id="level1"]').text('初级房间配置 (' + (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===1;}).length + '条)');
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
$('#del-level2-fish-btn').on('click', function() {
|
||||
var checkStatus = layui.table.checkStatus('table-level2-detail');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
layer.msg('请选择要删除的数据');
|
||||
return;
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.roomLevel + '_' + item.fishNumber + '_' + item.type; });
|
||||
data.roomFishLevelList = (data.roomFishLevelList || []).filter(function(item) {
|
||||
return !ids.includes(item.roomLevel + '_' + item.fishNumber + '_' + item.type);
|
||||
});
|
||||
layui.table.reload('table-level2-detail', { data: (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===2;}) });
|
||||
$('.layui-tab-title li[lay-id="level2"]').text('中级房间配置 (' + (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===2;}).length + '条)');
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
$('#del-level3-fish-btn').on('click', function() {
|
||||
var checkStatus = layui.table.checkStatus('table-level3-detail');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
layer.msg('请选择要删除的数据');
|
||||
return;
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.roomLevel + '_' + item.fishNumber + '_' + item.type; });
|
||||
data.roomFishLevelList = (data.roomFishLevelList || []).filter(function(item) {
|
||||
return !ids.includes(item.roomLevel + '_' + item.fishNumber + '_' + item.type);
|
||||
});
|
||||
layui.table.reload('table-level3-detail', { data: (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===3;}) });
|
||||
$('.layui-tab-title li[lay-id="level3"]').text('高级房间配置 (' + (data.roomFishLevelList||[]).filter(function(x){return x.roomLevel===3;}).length + '条)');
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
},
|
||||
yes: function(idx, layero) {
|
||||
if (itemIndex >= 0 && itemIndex < gameConfig.roomFishConfigs.length) {
|
||||
gameConfig.roomFishConfigs[itemIndex] = data;
|
||||
}
|
||||
layer.close(idx);
|
||||
renderTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showFishEditDialog(data, type, configData, itemIndex, roomLevel, callback) {
|
||||
// 兼容普通鱼调用(不传 roomLevel,callback 在第5位)
|
||||
if (type !== 'level' && typeof roomLevel === 'function') {
|
||||
callback = roomLevel;
|
||||
roomLevel = undefined;
|
||||
}
|
||||
var isLevel = type === 'level';
|
||||
var title = isLevel ? '编辑房间等级出鱼配置' : '编辑普通鱼出鱼配置';
|
||||
var gameType = configData.gameType || data.gameType || 0;
|
||||
|
||||
var typeOptions = '<option value="1"' + (data.type === 1 ? ' selected' : '') + '>鱼</option>' +
|
||||
'<option value="2"' + (data.type === 2 ? ' selected' : '') + '>鱼阵</option>';
|
||||
|
||||
var fishConfigs = gameConfig.fishTypeConfigs || [];
|
||||
var fishArrayConfigs = gameConfig.fishArrayConfigs || [];
|
||||
var roomConfigs = gameConfig.roomConfigs || [];
|
||||
|
||||
var roomLevelOptions = '<option value="">请选择</option>';
|
||||
roomConfigs.forEach(function(r) {
|
||||
if (r.gameType === gameType) {
|
||||
roomLevelOptions += '<option value="' + r.roomLevel + '"' + (data.roomLevel === r.roomLevel ? ' selected' : '') + '>' + r.roomLevel + ' ' + r.roomName + '</option>';
|
||||
}
|
||||
});
|
||||
|
||||
var fishOptions = '<option value="">请选择</option>';
|
||||
fishConfigs.forEach(function(f) {
|
||||
fishOptions += '<option value="' + f.fishNumber + '"' + (data.fishNumber === f.fishNumber ? ' selected' : '') + '>' + (f.fishName || f.fishNumber) + ' (' + f.fishNumber + ')</option>';
|
||||
});
|
||||
|
||||
var fishArrayOptions = '<option value="">请选择</option>';
|
||||
fishArrayConfigs.forEach(function(f) {
|
||||
fishArrayOptions += '<option value="' + f.fishArrayNumber + '"' + (data.fishNumber === f.fishArrayNumber ? ' selected' : '') + '>' + (f.name || f.fishArrayNumber) + ' (' + f.fishArrayNumber + ')</option>';
|
||||
});
|
||||
|
||||
var html = '<div style="padding:15px 15px 5px 15px;">' +
|
||||
'<form class="layui-form" style="margin:0;">' +
|
||||
(isLevel ? '<div class="layui-form-item" style="margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">房间等级</label>' +
|
||||
'<div class="layui-input-inline" style="width:160px;">' +
|
||||
'<select name="roomLevel" id="room-level-select" lay-search>' + roomLevelOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' : '') +
|
||||
'<div class="layui-form-item" style="margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">类型</label>' +
|
||||
'<div class="layui-input-inline" style="width:100px;">' +
|
||||
'<select name="type" id="fish-type-select" lay-filter="fish-type-select">' + typeOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item" id="fish-select-item" style="margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">选择鱼</label>' +
|
||||
'<div class="layui-input-inline" style="width:280px;">' +
|
||||
'<select name="fishSelect" id="fish-select" lay-filter="fish-select" lay-search>' + fishOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item" id="fish-array-select-item" style="display:none;margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">选择鱼阵</label>' +
|
||||
'<div class="layui-input-inline" style="width:280px;">' +
|
||||
'<select name="fishArraySelect" id="fish-array-select" lay-filter="fish-array-select" lay-search>' + fishArrayOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="fishNumber" value="' + (data.fishNumber || '') + '">' +
|
||||
'<div class="layui-form-item" style="margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">权重</label>' +
|
||||
'<div class="layui-input-inline" style="width:100px;">' +
|
||||
'<input type="number" name="fishWeight" value="' + (data.fishWeight || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-mid" style="color:#999;font-size:12px;">权重值越大,出鱼概率越高</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item" style="margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">频率(秒)</label>' +
|
||||
'<div class="layui-input-inline" style="width:100px;">' +
|
||||
'<input type="number" name="fishFrequency" value="' + (data.fishFrequency || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-mid" style="color:#999;font-size:12px;">下次出鱼间隔时间</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item" style="margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">最大数量</label>' +
|
||||
'<div class="layui-input-inline" style="width:100px;">' +
|
||||
'<input type="number" name="maxCount" value="' + (data.maxCount || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-mid" style="color:#999;font-size:12px;">屏幕中该鱼最大数量</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item" style="margin-bottom:10px;">' +
|
||||
'<label class="layui-form-label" style="width:80px;">出场秒数</label>' +
|
||||
'<div class="layui-input-inline" style="width:100px;">' +
|
||||
'<input type="number" name="times" value="' + (data.times || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-mid" style="color:#999;font-size:12px;">出场时间(秒)</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['800px', '500px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
layui.form.render('select');
|
||||
|
||||
function updateFishSelect(type) {
|
||||
if (type === 1) {
|
||||
$('#fish-select-item', layero).show();
|
||||
$('#fish-array-select-item', layero).hide();
|
||||
} else {
|
||||
$('#fish-select-item', layero).hide();
|
||||
$('#fish-array-select-item', layero).show();
|
||||
}
|
||||
}
|
||||
|
||||
updateFishSelect(data.type);
|
||||
|
||||
layui.form.on('select(fish-type-select)', function(fdata) {
|
||||
var t = parseInt(fdata.value);
|
||||
updateFishSelect(t);
|
||||
});
|
||||
|
||||
layui.form.on('select(fish-select)', function(fdata) {
|
||||
$('input[name="fishNumber"]', layero).val(fdata.value);
|
||||
});
|
||||
|
||||
layui.form.on('select(fish-array-select)', function(fdata) {
|
||||
$('input[name="fishNumber"]', layero).val(fdata.value);
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
var updatedItem = {
|
||||
type: parseInt(layero.find('select[name="type"]').val()) || 1,
|
||||
fishNumber: layero.find('input[name="fishNumber"]').val(),
|
||||
fishWeight: parseInt(layero.find('input[name="fishWeight"]').val()) || 0,
|
||||
fishFrequency: parseInt(layero.find('input[name="fishFrequency"]').val()) || 0,
|
||||
maxCount: parseInt(layero.find('input[name="maxCount"]').val()) || 0,
|
||||
times: parseInt(layero.find('input[name="times"]').val()) || 0
|
||||
};
|
||||
|
||||
if (isLevel) {
|
||||
updatedItem.roomLevel = parseInt(layero.find('select[name="roomLevel"]').val()) || 0;
|
||||
}
|
||||
|
||||
callback(updatedItem);
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-normal-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-level-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
</script>
|
||||
+531
@@ -0,0 +1,531 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>出鱼概率配置</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>出鱼概率配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-roomfishprobability"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-roomfishprobability"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-roomfishprobability"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('RoomFishProbabilityList')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">游戏类型选择</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-container" id="game-type-btns">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-type="1">风雷之渊</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="2">永夜尸城</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="4">星际迷航</button>
|
||||
<button class="layui-btn layui-btn-sm" data-type="5">黑神话悟空</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card" style="margin-top: 15px;">
|
||||
<div class="layui-card-header">房间等级筛选</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-btn-container" id="room-level-btns">
|
||||
<button class="layui-btn layui-btn-sm" data-level="all">全部房间</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-level="1">初级房间</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-level="2">中级房间</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" data-level="3">高级房间</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md9">
|
||||
<table id="table-roomfishprobability" lay-filter="table-roomfishprobability"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-roomfishprobability">
|
||||
<div class="layui-btn-container">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-type">
|
||||
{{# var typeMap = {1:'鱼',2:'鱼阵'}; }}
|
||||
{{= typeMap[d.type] || '未知(' + d.type + ')' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-fishType">
|
||||
{{# var typeMap = {0:'不限',1:'普通鱼',2:'Boss鱼',3:'黄金鱼',4:'特殊鱼',5:'特殊Boss'}; }}
|
||||
{{= typeMap[d.fishType] || '未知(' + d.fishType + ')' }}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
if (window._roomFishProbabilityInitialized) return;
|
||||
window._roomFishProbabilityInitialized = true;
|
||||
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var TABLE_ID = 'table-roomfishprobability';
|
||||
var gameConfig = null;
|
||||
var probabilityCache = [];
|
||||
var currentGameType = 1;
|
||||
var currentRoomLevel = 'all';
|
||||
var tableRendered = false;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
// 格式化 range 字段用于显示
|
||||
function formatRange(val) {
|
||||
if (Array.isArray(val)) return val.join('-');
|
||||
if (val !== undefined && val !== null) return String(val);
|
||||
return '';
|
||||
}
|
||||
|
||||
// 从任意值解析为数组
|
||||
function parseIntOrDefault(val, defaultValue) {
|
||||
var parsed = parseInt(val);
|
||||
return Number.isNaN(parsed) ? defaultValue : parsed;
|
||||
}
|
||||
|
||||
function parseRange(val, defaultMin, defaultMax) {
|
||||
if (Array.isArray(val) && val.length >= 2) {
|
||||
return [parseIntOrDefault(val[0], defaultMin), parseIntOrDefault(val[1], defaultMax)];
|
||||
}
|
||||
if (typeof val === 'string' && val.indexOf('-') > -1) {
|
||||
var parts = val.split('-');
|
||||
return [parseIntOrDefault(parts[0], defaultMin), parseIntOrDefault(parts[1], defaultMax)];
|
||||
}
|
||||
return [defaultMin, defaultMax];
|
||||
}
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
buildFishNameMap();
|
||||
switchGameType(currentGameType);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var fishNameMap = {};
|
||||
var fishArrayNameMap = {};
|
||||
|
||||
function buildFishNameMap() {
|
||||
if (!gameConfig) return;
|
||||
fishNameMap = {};
|
||||
fishArrayNameMap = {};
|
||||
|
||||
var fishConfigs = gameConfig.fishTypeConfigs || [];
|
||||
fishConfigs.forEach(function(f) {
|
||||
fishNameMap[f.fishNumber] = f.fishName || f.fishNumber;
|
||||
});
|
||||
|
||||
var fishArrayConfigs = gameConfig.fishArrayConfigs || [];
|
||||
fishArrayConfigs.forEach(function(f) {
|
||||
fishArrayNameMap[f.fishArrayNumber] = f.name || f.fishArrayNumber;
|
||||
});
|
||||
}
|
||||
|
||||
function switchGameType(gameType) {
|
||||
currentGameType = gameType;
|
||||
|
||||
$('#game-type-btns .layui-btn').removeClass('layui-btn-primary');
|
||||
$('#game-type-btns .layui-btn[data-type="' + gameType + '"]').addClass('layui-btn-primary');
|
||||
|
||||
var roomFishConfig = null;
|
||||
if (gameConfig && gameConfig.roomFishConfigs) {
|
||||
roomFishConfig = gameConfig.roomFishConfigs.find(function(r) {
|
||||
var gt = r.gameType !== undefined ? r.gameType : r.GameType;
|
||||
return gt === gameType;
|
||||
});
|
||||
}
|
||||
|
||||
// 深拷贝,切断与 gameConfig 的引用关系
|
||||
probabilityCache = roomFishConfig
|
||||
? JSON.parse(JSON.stringify(roomFishConfig.roomFishProbabilityList || roomFishConfig.RoomFishProbabilityList || []))
|
||||
: [];
|
||||
// 确保所有 range 字段都是数组,并给每条数据加唯一标识
|
||||
probabilityCache.forEach(function(item, index) {
|
||||
item.firstFishCountRange = parseRange(item.firstFishCountRange || item.FirstFishCountRange, 1, 5);
|
||||
item.timeRange = parseRange(item.timeRange || item.TimeRange, 5, 10);
|
||||
item.countRange = parseRange(item.countRange || item.CountRange, 5, 10);
|
||||
item.maxCountRange = parseRange(item.maxCountRange || item.MaxCountRange, 10, 20);
|
||||
// 给每条数据添加唯一标识(用于编辑时精确匹配)
|
||||
if (!item._uid) {
|
||||
item._uid = 'prob_' + Date.now() + '_' + index;
|
||||
}
|
||||
});
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
var filteredData = probabilityCache;
|
||||
if (currentRoomLevel !== 'all') {
|
||||
var levelNum = parseInt(currentRoomLevel);
|
||||
filteredData = probabilityCache.filter(function(item) {
|
||||
return item.roomLevel === levelNum;
|
||||
});
|
||||
}
|
||||
|
||||
var cols = [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "roomLevel", title: "房间等级", width: 100 },
|
||||
{ field: "type", title: "类型", width: 80, templet: '#tpl-type' },
|
||||
{ field: "fishType", title: "鱼类型", width: 100, templet: '#tpl-fishType' },
|
||||
{ field: "firstFishCountRange", title: "首次出鱼数量", width: 140, templet: function(d) { return formatRange(d.firstFishCountRange); } },
|
||||
{ field: "timeRange", title: "出鱼时间频率(秒)", width: 170, templet: function(d) { return formatRange(d.timeRange); } },
|
||||
{ field: "countRange", title: "出鱼数量频率", width: 140, templet: function(d) { return formatRange(d.countRange); } },
|
||||
{ field: "maxCountRange", title: "场内允许数量", width: 140, templet: function(d) { return formatRange(d.maxCountRange); } },
|
||||
{ title: "操作", width: 150, fixed: 'right', toolbar: '#table-operate' }
|
||||
]];
|
||||
|
||||
if (tableRendered) {
|
||||
table.reload(TABLE_ID, {
|
||||
data: JSON.parse(JSON.stringify(filteredData)),
|
||||
cols: cols
|
||||
});
|
||||
} else {
|
||||
table.render({
|
||||
id: TABLE_ID,
|
||||
elem: '#' + TABLE_ID,
|
||||
data: JSON.parse(JSON.stringify(filteredData)),
|
||||
cols: cols,
|
||||
toolbar: '#toolbar-roomfishprobability',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
tableRendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
function saveConfig() {
|
||||
if (!gameConfig) return;
|
||||
if (!gameConfig.roomFishConfigs) gameConfig.roomFishConfigs = [];
|
||||
|
||||
var roomFishConfig = gameConfig.roomFishConfigs.find(function(r) {
|
||||
return r.gameType === currentGameType;
|
||||
});
|
||||
|
||||
if (!roomFishConfig) {
|
||||
roomFishConfig = { gameType: currentGameType, roomFishProbabilityList: [] };
|
||||
gameConfig.roomFishConfigs.push(roomFishConfig);
|
||||
}
|
||||
|
||||
// 深拷贝写入,防止引用污染
|
||||
roomFishConfig.roomFishProbabilityList = JSON.parse(JSON.stringify(probabilityCache));
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/RoomFishProbabilityList",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-roomfishprobability"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-roomfishprobability"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-roomfishprobability"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
saveConfig();
|
||||
});
|
||||
|
||||
$('#game-type-btns').off().on('click', '.layui-btn', function() {
|
||||
var gameType = parseInt($(this).data('type'));
|
||||
switchGameType(gameType);
|
||||
});
|
||||
|
||||
$('#room-level-btns').off().on('click', '.layui-btn', function() {
|
||||
var level = $(this).data('level');
|
||||
switchRoomLevel(level);
|
||||
});
|
||||
|
||||
function switchRoomLevel(level) {
|
||||
currentRoomLevel = level;
|
||||
|
||||
$('#room-level-btns .layui-btn').removeClass('layui-btn-primary');
|
||||
if (level === 'all') {
|
||||
$('#room-level-btns .layui-btn[data-level="all"]').addClass('layui-btn-primary');
|
||||
} else {
|
||||
$('#room-level-btns .layui-btn[data-level="' + level + '"]').addClass('layui-btn-primary');
|
||||
}
|
||||
|
||||
renderTable();
|
||||
}
|
||||
|
||||
table.on('tool(' + TABLE_ID + ')', function(obj) {
|
||||
if (obj.event === 'edit') {
|
||||
// 使用唯一标识匹配,而不是行号(行号在分页/筛选后会不准)
|
||||
var data = null;
|
||||
if (obj.data._uid) {
|
||||
// 优先通过唯一ID匹配
|
||||
data = probabilityCache.find(function(item) { return item._uid === obj.data._uid; });
|
||||
}
|
||||
if (!data) {
|
||||
// 兜底:通过字段组合匹配
|
||||
var roomLevel = obj.data.roomLevel;
|
||||
var type = obj.data.type;
|
||||
var fishType = obj.data.fishType;
|
||||
data = probabilityCache.find(function(item) {
|
||||
return item.roomLevel === roomLevel && item.type === type && item.fishType === fishType;
|
||||
});
|
||||
}
|
||||
if (!data) data = obj.data;
|
||||
showEditDialog(data);
|
||||
}
|
||||
});
|
||||
|
||||
function showEditDialog(data) {
|
||||
var d = JSON.parse(JSON.stringify(data));
|
||||
|
||||
// 统一解析 range 为数组
|
||||
d.firstFishCountRange = parseRange(d.firstFishCountRange, 1, 5);
|
||||
d.timeRange = parseRange(d.timeRange, 5, 10);
|
||||
d.countRange = parseRange(d.countRange, 5, 10);
|
||||
d.maxCountRange = parseRange(d.maxCountRange, 10, 20);
|
||||
|
||||
var html = '<form class="layui-form" lay-filter="probability-form" style="padding:20px;">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">房间等级</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="roomLevel" value="' + (d.roomLevel || 1) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">类型</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<select name="type">' +
|
||||
'<option value="1" ' + (d.type === 1 ? 'selected' : '') + '>鱼</option>' +
|
||||
'<option value="2" ' + (d.type === 2 ? 'selected' : '') + '>鱼阵</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">鱼类型</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<select name="fishType">' +
|
||||
'<option value="0" ' + (d.fishType === 0 ? 'selected' : '') + '>不限</option>' +
|
||||
'<option value="1" ' + (d.fishType === 1 ? 'selected' : '') + '>普通鱼</option>' +
|
||||
'<option value="2" ' + (d.fishType === 2 ? 'selected' : '') + '>Boss鱼</option>' +
|
||||
'<option value="3" ' + (d.fishType === 3 ? 'selected' : '') + '>黄金鱼</option>' +
|
||||
'<option value="4" ' + (d.fishType === 4 ? 'selected' : '') + '>特殊鱼</option>' +
|
||||
'<option value="5" ' + (d.fishType === 5 ? 'selected' : '') + '>特殊Boss</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-mid">鱼阵时此参数无效</div>' +
|
||||
'</div>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>首次出鱼数量区间</legend>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最小值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="firstFishCountMin" value="' + d.firstFishCountRange[0] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最大值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="firstFishCountMax" value="' + d.firstFishCountRange[1] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>出鱼时间频率区间(秒)</legend>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最小值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="timeRangeMin" value="' + d.timeRange[0] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最大值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="timeRangeMax" value="' + d.timeRange[1] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>出鱼数量频率区间</legend>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最小值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="countRangeMin" value="' + d.countRange[0] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最大值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="countRangeMax" value="' + d.countRange[1] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>场内允许数量区间</legend>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最小值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="maxCountRangeMin" value="' + d.maxCountRange[0] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-inline">' +
|
||||
'<label class="layui-form-label">最大值</label>' +
|
||||
'<div class="layui-input-inline">' +
|
||||
'<input type="number" name="maxCountRangeMax" value="' + d.maxCountRange[1] + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="probability-save">保存</button>' +
|
||||
'<button type="button" class="layui-btn layui-btn-primary" id="probability-cancel">取消</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '编辑出鱼概率配置',
|
||||
area: ['600px', '550px'],
|
||||
content: html,
|
||||
success: function(layero) {
|
||||
form.render();
|
||||
|
||||
form.on('submit(probability-save)', function(formData) {
|
||||
var newData = {
|
||||
roomLevel: parseIntOrDefault(formData.field.roomLevel, 1),
|
||||
type: parseIntOrDefault(formData.field.type, 1),
|
||||
fishType: parseIntOrDefault(formData.field.fishType, 0),
|
||||
firstFishCountRange: [
|
||||
parseIntOrDefault(formData.field.firstFishCountMin, 1),
|
||||
parseIntOrDefault(formData.field.firstFishCountMax, 5)
|
||||
],
|
||||
timeRange: [
|
||||
parseIntOrDefault(formData.field.timeRangeMin, 5),
|
||||
parseIntOrDefault(formData.field.timeRangeMax, 10)
|
||||
],
|
||||
countRange: [
|
||||
parseIntOrDefault(formData.field.countRangeMin, 5),
|
||||
parseIntOrDefault(formData.field.countRangeMax, 10)
|
||||
],
|
||||
maxCountRange: [
|
||||
parseIntOrDefault(formData.field.maxCountRangeMin, 10),
|
||||
parseIntOrDefault(formData.field.maxCountRangeMax, 20)
|
||||
]
|
||||
};
|
||||
|
||||
// 通过 roomLevel + type + fishType 匹配找到对应行并更新
|
||||
var found = false;
|
||||
for (var i = 0; i < probabilityCache.length; i++) {
|
||||
if (probabilityCache[i].roomLevel === data.roomLevel &&
|
||||
probabilityCache[i].type === data.type &&
|
||||
probabilityCache[i].fishType === data.fishType) {
|
||||
probabilityCache[i] = newData;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
probabilityCache.push(newData);
|
||||
}
|
||||
|
||||
layer.closeAll();
|
||||
renderTable();
|
||||
layer.msg('保存成功');
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#probability-cancel').off().on('click', function() {
|
||||
layer.closeAll();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,349 @@
|
||||
|
||||
<title>刮刮卡配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>刮刮卡配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-scratchcard" lay-filter="table-scratchcard"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-scratchcard">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-scratchcard"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-scratchcard"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-scratchcard"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-scratchcard">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-scratchcard">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('ScratchCardConfig')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-type">
|
||||
{{# var typeMap = {1:'金币',2:'钻石',3:'道具'}; }}
|
||||
{{= typeMap[d.type] || '金币' }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
var data = gameConfig ? gameConfig.scratchCardConfig || [] : [];
|
||||
table.render({
|
||||
elem: '#table-scratchcard',
|
||||
data: data,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "type", title: "奖励类型", width: 100, templet: '#tpl-type' },
|
||||
{ field: "count", title: "奖励数量", width: 100 },
|
||||
{ field: "weight", title: "权重", width: 100 },
|
||||
{ field: "baseProduct", title: "道具编号", width: 120, templet: function(d) { return d.baseProduct ? d.baseProduct.number : ''; } },
|
||||
{ field: "baseProduct", title: "道具名称", width: 120, templet: function(d) { return d.baseProduct ? d.baseProduct.name : ''; } },
|
||||
{ title: "操作", width: 150, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-scratchcard',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/ScratchCardConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-scratchcard"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-scratchcard"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-scratchcard"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
var configs = gameConfig.scratchCardConfig || [];
|
||||
if (configs.length === 0) return layer.msg('至少保留一条刮刮卡配置');
|
||||
for (var i = 0; i < configs.length; i++) {
|
||||
if (configs[i].count <= 0) return layer.msg('第 ' + (i + 1) + ' 项奖励数量必须大于0');
|
||||
if (configs[i].weight <= 0) return layer.msg('第 ' + (i + 1) + ' 项权重必须大于0');
|
||||
if (configs[i].type === 3 && (!configs[i].baseProduct || !configs[i].baseProduct.number))
|
||||
return layer.msg('第 ' + (i + 1) + ' 项道具编号不能为空');
|
||||
}
|
||||
if (configs.length > 0) {
|
||||
configs.forEach(function(item) {
|
||||
if (!item.baseProduct) {
|
||||
item.baseProduct = { type: 1, number: '', name: '', desc: '', imageUrl: '', level: 0 };
|
||||
}
|
||||
});
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/UpdateScratchCard",
|
||||
data: JSON.stringify(configs),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-scratchcard)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = gameConfig.scratchCardConfig.findIndex(function(x) {
|
||||
return x.type === data.type && x.count === data.count && x.weight === data.weight;
|
||||
});
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(trIndex > -1 ? gameConfig.scratchCardConfig[trIndex] : data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) gameConfig.scratchCardConfig.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
if (!gameConfig.scratchCardConfig) {
|
||||
gameConfig.scratchCardConfig = [];
|
||||
}
|
||||
var newData = {
|
||||
type: 1,
|
||||
count: 100,
|
||||
weight: 10,
|
||||
baseProduct: { type: 1, number: '', name: '', desc: '' },
|
||||
propNumber: '',
|
||||
propName: ''
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-scratchcard"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-scratchcard"]', function() {
|
||||
var checkStatus = table.checkStatus('table-scratchcard');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var ids = checkData.map(function(item) { return item.baseProduct ? item.baseProduct.number : ''; });
|
||||
gameConfig.scratchCardConfig = gameConfig.scratchCardConfig.filter(function(item) {
|
||||
return !ids.includes(item.baseProduct ? item.baseProduct.number : '');
|
||||
});
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加刮刮卡' : '编辑刮刮卡';
|
||||
if (!data.baseProduct) {
|
||||
data.baseProduct = { type: 1, number: '', name: '', desc: '' };
|
||||
}
|
||||
var typeOptions = [
|
||||
{value: 1, text: '金币'},
|
||||
{value: 2, text: '钻石'},
|
||||
{value: 3, text: '道具'}
|
||||
];
|
||||
|
||||
var typeHtml = '';
|
||||
typeOptions.forEach(function(opt) {
|
||||
typeHtml += '<option value="' + opt.value + '"' + (data.type === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var propTypeOptions = [
|
||||
{value: 1, text: '道具'},
|
||||
{value: 2, text: '技能'},
|
||||
{value: 5, text: '炮台'},
|
||||
{value: 6, text: '翅膀'},
|
||||
{value: 7, text: '战神'}
|
||||
];
|
||||
|
||||
var propTypeHtml = '';
|
||||
var currentPropType = data.baseProduct ? data.baseProduct.type : 1;
|
||||
propTypeOptions.forEach(function(opt) {
|
||||
propTypeHtml += '<option value="' + opt.value + '"' + (currentPropType === opt.value ? ' selected' : '') + '>' + opt.text + '</option>';
|
||||
});
|
||||
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">奖励类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="type">' + typeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">奖励数量</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="count" value="' + (data.count || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">权重</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="weight" value="' + (data.weight || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">道具编号</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="propNumber" value="' + ((data.baseProduct && data.baseProduct.number) || data.propNumber || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">道具名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="propName" value="' + ((data.baseProduct && data.baseProduct.name) || data.propName || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">道具类型</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="propType">' + propTypeHtml + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['500px', '450px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
var rewardType = parseInt(layero.find('select[name="type"]').val());
|
||||
var rewardCount = parseInt(layero.find('input[name="count"]').val()) || 0;
|
||||
var rewardWeight = parseInt(layero.find('input[name="weight"]').val()) || 0;
|
||||
var propNumber = layero.find('input[name="propNumber"]').val();
|
||||
var propName = layero.find('input[name="propName"]').val();
|
||||
var propType = parseInt(layero.find('select[name="propType"]').val());
|
||||
|
||||
if (rewardCount <= 0) return layer.msg('奖励数量必须大于0');
|
||||
if (rewardWeight <= 0) return layer.msg('权重必须大于0');
|
||||
if (rewardType === 3 && !propNumber) return layer.msg('道具奖励必须填写道具编号');
|
||||
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
type: rewardType,
|
||||
count: rewardCount,
|
||||
weight: rewardWeight,
|
||||
propNumber: propNumber,
|
||||
propName: propName,
|
||||
baseProduct: {
|
||||
type: propType,
|
||||
number: propNumber,
|
||||
name: propName,
|
||||
desc: ''
|
||||
}
|
||||
};
|
||||
gameConfig.scratchCardConfig.unshift(newItem);
|
||||
} else if (rowIndex > -1) {
|
||||
// Layui 行对象是副本,编辑结果必须写回原始数组。
|
||||
var original = gameConfig.scratchCardConfig[rowIndex];
|
||||
original.type = rewardType;
|
||||
original.count = rewardCount;
|
||||
original.weight = rewardWeight;
|
||||
original.propNumber = propNumber;
|
||||
original.propName = propName;
|
||||
original.baseProduct = {
|
||||
type: propType,
|
||||
number: propNumber,
|
||||
name: propName,
|
||||
desc: original.baseProduct ? (original.baseProduct.desc || '') : ''
|
||||
};
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-scratchcard', {
|
||||
data: gameConfig.scratchCardConfig
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,378 @@
|
||||
|
||||
<title>签到配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>签到配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-sign" lay-filter="table-sign"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-sign">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-sign"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-sign"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-sign"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-sign">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-sign">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveAct('SignConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="preview"><i class="layui-icon layui-icon-search"></i>预览</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tpl-icon">
|
||||
{{# if(d.icon){ }}
|
||||
<img src="{{d.icon}}" style="width:40px;height:40px;object-fit:cover;cursor:pointer;border-radius:4px;" onclick="previewImage('{{d.icon}}')" alt="图标">
|
||||
{{# } else { }}
|
||||
<span style="color:#999;">无图标</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-upload-box { position: relative; display: inline-block; }
|
||||
.icon-upload-box .upload-btn { position: absolute; top: 0; left: 0; width: 80px; height: 80px; opacity: 0; cursor: pointer; }
|
||||
.icon-upload-preview { width: 80px; height: 80px; border: 1px dashed #ddd; border-radius: 4px; display: flex; align-items: center; justify-content: center; background: #fafafa; cursor: pointer; }
|
||||
.icon-upload-preview:hover { border-color: #009688; }
|
||||
.icon-upload-preview img { max-width: 100%; max-height: 100%; }
|
||||
.icon-upload-preview .placeholder { color: #999; font-size: 12px; text-align: center; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var activityConfig = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/Get",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
activityConfig = res.data;
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-sign',
|
||||
data: activityConfig ? activityConfig.signConfigs || [] : [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "order", title: "排序", width: 70, edit: 'text' },
|
||||
{ field: "name", title: "名称", width: 100, edit: 'text' },
|
||||
{ field: "gold", title: "金币", width: 100, edit: 'text' },
|
||||
{ field: "probability", title: "概率", width: 100, edit: 'text' },
|
||||
{ field: "icon", title: "图标", width: 100, templet: '#tpl-icon' },
|
||||
{ title: "操作", width: 180, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-sign',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要从配置文件还原签到配置吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitActivitySection/SignConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-sign"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-sign"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-sign"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/ActivityConfig/UpdateSign",
|
||||
data: JSON.stringify(activityConfig.signConfigs || []),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
window.previewImage = function(url) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '图片预览',
|
||||
area: ['auto', 'auto'],
|
||||
shadeClose: true,
|
||||
content: '<div style="padding:20px;text-align:center;"><img src="' + url + '" style="max-width:400px;max-height:400px;border-radius:8px;"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
function updateDataByTable(obj) {
|
||||
var field = obj.field;
|
||||
var value = obj.value;
|
||||
var data = obj.data;
|
||||
|
||||
if (field === 'gold') {
|
||||
data[field] = parseInt(value) || 0;
|
||||
} else if (field === 'probability') {
|
||||
data[field] = parseFloat(value) || 0;
|
||||
} else {
|
||||
data[field] = value;
|
||||
}
|
||||
}
|
||||
|
||||
table.on('edit(table-sign)', function(obj){
|
||||
updateDataByTable(obj);
|
||||
});
|
||||
|
||||
table.on('tool(table-sign)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = activityConfig && activityConfig.signConfigs
|
||||
? activityConfig.signConfigs.findIndex(function(x) { return x.order === data.order; }) : -1;
|
||||
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(trIndex > -1 ? activityConfig.signConfigs[trIndex] : data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex >= 0 && activityConfig && activityConfig.signConfigs) {
|
||||
activityConfig.signConfigs.splice(trIndex, 1);
|
||||
}
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
} else if (obj.event === 'preview') {
|
||||
if (data.icon) {
|
||||
previewImage(data.icon);
|
||||
} else {
|
||||
layer.msg('暂无图片');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
var newData = {
|
||||
order: 0,
|
||||
name: '',
|
||||
gold: 0,
|
||||
probability: 0,
|
||||
icon: ''
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-sign"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加签到配置' : '编辑签到配置';
|
||||
var imagePreviewHtml = data.icon
|
||||
? '<img src="' + data.icon + '" style="max-width:100%;max-height:100%;">'
|
||||
: '<div class="placeholder">点击上传</div>';
|
||||
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">排序</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="order" value="' + (data.order || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">金币</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="gold" value="' + (data.gold || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">概率</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="probability" value="' + (data.probability || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">图标</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="icon-upload-box">' +
|
||||
'<div class="icon-upload-preview" id="iconPreview">' + imagePreviewHtml + '</div>' +
|
||||
'<input type="file" class="upload-btn" accept="image/png" id="iconUpload">' +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="icon" id="iconInput" value="' + (data.icon || '') + '">' +
|
||||
'<div style="margin-top:8px;color:#999;font-size:12px;">点击图片可预览,仅支持 PNG 格式</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['600px', '500px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
var $preview = layero.find('#iconPreview');
|
||||
var $input = layero.find('#iconInput');
|
||||
var $fileInput = layero.find('#iconUpload');
|
||||
|
||||
$preview.on('click', function() {
|
||||
var url = $input.val();
|
||||
if (url) {
|
||||
previewImage(url);
|
||||
}
|
||||
});
|
||||
|
||||
$fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (file) {
|
||||
var order = layero.find('input[name="order"]').val();
|
||||
if (!order && isAdd) {
|
||||
layer.msg('请先填写排序编号');
|
||||
$(this).val('');
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('number', order);
|
||||
|
||||
$.ajax({
|
||||
url: setter.baseurl + 'adminapi/ImageUpload/upload/config',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
success: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
var path = res.data.path;
|
||||
$input.val(path);
|
||||
$preview.html('<img src="' + path + '" style="max-width:100%;max-height:100%;">');
|
||||
layer.msg('上传成功');
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('上传失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
order: parseInt(layero.find('input[name="order"]').val()) || 0,
|
||||
name: layero.find('input[name="name"]').val(),
|
||||
gold: parseInt(layero.find('input[name="gold"]').val()) || 0,
|
||||
probability: parseFloat(layero.find('input[name="probability"]').val()) || 0,
|
||||
icon: layero.find('input[name="icon"]').val()
|
||||
};
|
||||
if (!activityConfig.signConfigs) activityConfig.signConfigs = [];
|
||||
activityConfig.signConfigs.unshift(newItem);
|
||||
} else if (rowIndex > -1) {
|
||||
var original = activityConfig.signConfigs[rowIndex];
|
||||
original.order = parseInt(layero.find('input[name="order"]').val()) || 0;
|
||||
original.name = layero.find('input[name="name"]').val();
|
||||
original.gold = parseInt(layero.find('input[name="gold"]').val()) || 0;
|
||||
original.probability = parseFloat(layero.find('input[name="probability"]').val()) || 0;
|
||||
original.icon = layero.find('input[name="icon"]').val();
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-sign', {
|
||||
data: activityConfig.signConfigs || []
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-sign"]', function() {
|
||||
var checkStatus = table.checkStatus('table-sign');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var orders = checkData.map(function(item) { return item.order; });
|
||||
if (activityConfig && activityConfig.signConfigs) {
|
||||
activityConfig.signConfigs = activityConfig.signConfigs.filter(function(item) {
|
||||
return !orders.includes(item.order);
|
||||
});
|
||||
}
|
||||
renderTable();
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
window.saveAct=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/ActivityConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,111 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>象棋 Hub 流程测试</title>
|
||||
<style>
|
||||
body { font-family: Consolas, monospace; font-size: 13px; background: #111; color: #ddd; padding: 12px; }
|
||||
button { cursor: pointer; padding: 6px 12px; margin: 3px; }
|
||||
.log { background: #000; border: 1px solid #333; height: 50vh; overflow-y: auto; margin-top: 10px; padding: 8px; white-space: pre-wrap; font-size: 12px; }
|
||||
.ok { color: #0f0; } .bad { color: #f55; } .info { color: #9ad; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>象棋 Hub 流程测试</h3>
|
||||
<div>
|
||||
<label>Hub地址: <input id="hub" value="" placeholder="请输入测试环境 Hub 地址" style="width:260px"></label>
|
||||
<button onclick="connAll()">1. 连接 L1/A/B</button>
|
||||
<button onclick="createRoom()">2. A 建房</button>
|
||||
<button onclick="joinRoom()">3. B 加入</button>
|
||||
<button onclick="readyAll()">4. 双方Ready</button>
|
||||
<button onclick="bExit()">5. B退出</button>
|
||||
<button onclick="bJoin()">6. B重新加入</button>
|
||||
<button onclick="afkA()">7. A挂起</button>
|
||||
<button onclick="afkB()">8. B挂起(等5s)</button>
|
||||
<br>
|
||||
<label>RoomID: <input id="room" name="room" value="" style="width:200px"></label>
|
||||
<label>密码: <input id="password" name="password" value="" placeholder="请输入测试房间密码" style="width:180px"></label>
|
||||
<label>UID-A: <input id="a" name="a" value="" style="width:280px"></label>
|
||||
<label>UID-B: <input id="b" name="b" value="" style="width:280px"></label>
|
||||
<button onclick="clearLog()">清空日志</button>
|
||||
</div>
|
||||
<div class="log" id="log"></div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/@microsoft/signalr@8.0.7/dist/browser/signalr.min.js"></script>
|
||||
<script>
|
||||
const logEl = document.getElementById('log');
|
||||
function log(msg) { logEl.innerHTML += msg + '\n'; logEl.scrollTop = logEl.scrollHeight; }
|
||||
function ok(m) { log('<span class="ok">[OK]</span> ' + m); }
|
||||
function bad(m) { log('<span class="bad">[FAIL]</span> ' + m); }
|
||||
function info(m) { log('<span class="info">[INFO]</span> ' + m); }
|
||||
|
||||
let L1, A, B;
|
||||
const roomQ = () => document.getElementById('room').value;
|
||||
const passwordQ = () => document.getElementById('password').value;
|
||||
const uidA = () => document.getElementById('a').value;
|
||||
const uidB = () => document.getElementById('b').value;
|
||||
const hubUrl = () => document.getElementById('hub').value;
|
||||
|
||||
function newTestId(prefix) {
|
||||
const value = window.crypto && crypto.randomUUID ? crypto.randomUUID().replace(/-/g, '') : Date.now() + Math.random().toString(16).slice(2);
|
||||
return prefix + value;
|
||||
}
|
||||
|
||||
document.getElementById('hub').value = /^https?:$/.test(location.protocol) ? location.origin + '/chessgamehub' : '';
|
||||
document.getElementById('room').value = 'TEST_' + Date.now();
|
||||
document.getElementById('a').value = newTestId('A_');
|
||||
document.getElementById('b').value = newTestId('B_');
|
||||
|
||||
function evt(conn, name, cb) { conn.on(name, cb); }
|
||||
|
||||
function make(id, uid, tag) {
|
||||
const c = new signalR.HubConnectionBuilder()
|
||||
.withUrl(hubUrl() + '?userId=' + uid)
|
||||
.withAutomaticReconnect()
|
||||
.build();
|
||||
const events = ['GameError','BeginGame','CreateRoomNotice','JoinRoomNotice','ExitRoomNotice',
|
||||
'JoinRoom','Reconnect','ReadyNotice','AllBeginTime','GoldConfigRequired','ExitRoomSuccess',
|
||||
'GameEnd','Disconnect','PlayerAfkNotice','PlayerCancelAfkNotice','OpponentRequestEnd','EndGameRequestSent','RestartRoomNotice'];
|
||||
events.forEach(e => c.on(e, (arg) => {
|
||||
let s = typeof arg === 'object' ? JSON.stringify(arg) : arg;
|
||||
if (s && s.length > 140) s = s.substr(0, 140) + '…';
|
||||
log(`<span class="info">[${tag}]</span> 推送 <b>${e}</b>: ${s}`);
|
||||
}));
|
||||
c.onreconnected(() => log(`<span class="bad">[${tag}] 重连</span>`));
|
||||
return c;
|
||||
}
|
||||
|
||||
async function connAll() {
|
||||
L1 = make('L1', 'L1_' + uidA().substr(0,8), 'L1'); A = make('A', uidA(), 'A'); B = make('B', uidB(), 'B');
|
||||
for (const [tag, c] of [['L1', L1], ['A', A], ['B', B]]) {
|
||||
try { await c.start(); ok(`${tag} 连接成功 ${c.connectionId}`); }
|
||||
catch (e) { bad(`${tag} 连接失败: ${e}`); log(e.stack); }
|
||||
}
|
||||
}
|
||||
|
||||
async function createRoom() {
|
||||
try {
|
||||
await A.invoke('CreateRoom', { roomId: roomQ(), userId: uidA(), gameType: 1, password: passwordQ(), gold: 100 });
|
||||
ok('A invoke CreateRoom 已发送');
|
||||
} catch (e) { bad('CreateRoom 异常: ' + e); }
|
||||
}
|
||||
|
||||
async function joinRoom() {
|
||||
try { await B.invoke('JoinGame', roomQ(), passwordQ(), uidB()); ok('B invoke JoinGame 已发送'); }
|
||||
catch (e) { bad('JoinGame 异常: ' + e); }
|
||||
}
|
||||
|
||||
async function readyAll() {
|
||||
try { await A.invoke('GameReady', roomQ(), uidA()); await B.invoke('GameReady', roomQ(), uidB()); ok('双方 Ready 已发送'); }
|
||||
catch (e) { bad('Ready 异常: ' + e); }
|
||||
}
|
||||
|
||||
async function bExit() { try { await B.invoke('ExitRoom', roomQ(), uidB()); ok('B ExitRoom 已发送'); } catch (e) { bad('ExitRoom: ' + e); } }
|
||||
async function bJoin() { try { await B.invoke('JoinGame', roomQ(), passwordQ(), uidB()); ok('B 重新加入已发送'); } catch (e) { bad(e); } }
|
||||
async function afkA() { try { await A.invoke('SetPlayerAfk', roomQ(), uidA()); ok('A SetPlayerAfk 已发送'); } catch (e) { bad('afkA: ' + e); } }
|
||||
async function afkB() { try { await B.invoke('SetPlayerAfk', roomQ(), uidB()); ok('B SetPlayerAfk 已发送'); } catch (e) { bad('afkB: ' + e); } }
|
||||
|
||||
function clearLog(){ logEl.innerHTML=''; }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,197 @@
|
||||
|
||||
<title>鱼雷配置</title>
|
||||
|
||||
<style>
|
||||
.torpedo-item { border: 1px solid #ddd; padding: 15px; margin: 15px 0; border-radius: 4px; background: #fafafa; }
|
||||
.torpedo-item .item-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
||||
.torpedo-item .item-header .item-title { font-weight: bold; font-size: 14px; }
|
||||
.torpedo-item table { width: 100%; border-collapse: collapse; margin-top: 10px; }
|
||||
.torpedo-item table th, .torpedo-item table td { border: 1px solid #ddd; padding: 8px; text-align: center; }
|
||||
.torpedo-item table th { background: #e6e6e6; font-weight: bold; }
|
||||
.torpedo-item .param-row input { width: 100px; text-align: center; }
|
||||
</style>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>鱼雷配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-torpedo"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-torpedo"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="add-torpedo"><i class="layui-icon layui-icon-addition"></i> 添加鱼雷</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div id="torpedo-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form'], function() {
|
||||
var $ = layui.$;
|
||||
var admin = layui.admin;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var setter = layui.setter;
|
||||
var gameConfig = {};
|
||||
var torpedoListCache = [];
|
||||
var propList = [];
|
||||
|
||||
function escapeHtml(value) {
|
||||
return $('<div>').text(value == null ? '' : String(value)).html();
|
||||
}
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/GameConfig',
|
||||
done: function(res) {
|
||||
if ((res.code !== 0 && res.code !== 200) || !res.data) {
|
||||
layer.msg(res.info || '鱼雷配置加载失败');
|
||||
return;
|
||||
}
|
||||
gameConfig = res.data;
|
||||
torpedoListCache = gameConfig.torpedoConfigs || [];
|
||||
propList = (gameConfig.propConfig || []).filter(function(prop) {
|
||||
return Number(prop.type) === 13;
|
||||
});
|
||||
renderTorpedoList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTorpedoList() {
|
||||
var html = '';
|
||||
torpedoListCache.forEach(function(item, index) {
|
||||
item.rewardRanges = item.rewardRanges || [];
|
||||
var options = '<option value="">请选择鱼雷道具</option>';
|
||||
var found = false;
|
||||
propList.forEach(function(prop) {
|
||||
var selected = String(prop.number) === String(item.number);
|
||||
if (selected) found = true;
|
||||
options += '<option value="' + escapeHtml(prop.number) + '"' + (selected ? ' selected' : '') + '>' +
|
||||
escapeHtml(prop.number + ' - ' + prop.name) + '</option>';
|
||||
});
|
||||
if (item.number && !found) {
|
||||
options += '<option value="' + escapeHtml(item.number) + '" selected>' +
|
||||
escapeHtml(item.number + ' - ' + (item.name || '道具表未找到')) + '</option>';
|
||||
}
|
||||
|
||||
html += '<div class="torpedo-item" data-index="' + index + '">';
|
||||
html += '<div class="item-header">';
|
||||
html += '<span class="item-title">' + escapeHtml(item.name || '未选择鱼雷') + ' (' + escapeHtml(item.number || '') + ')</span>';
|
||||
html += '<button type="button" class="layui-btn layui-btn-xs layui-btn-danger js-remove-torpedo" data-index="' + index + '"><i class="layui-icon layui-icon-delete"></i> 删除</button>';
|
||||
html += '</div>';
|
||||
html += '<div class="layui-form" style="margin-bottom:10px;max-width:460px">';
|
||||
html += '<label style="display:inline-block;margin-right:10px">鱼雷道具:</label>';
|
||||
html += '<div style="display:inline-block;width:320px;vertical-align:middle"><select class="js-torpedo-prop" data-index="' + index + '" lay-search>' + options + '</select></div>';
|
||||
html += '</div>';
|
||||
html += '<table><thead><tr><th>最小金币</th><th>最大金币</th><th>权重</th><th>操作</th></tr></thead><tbody>';
|
||||
item.rewardRanges.forEach(function(range, ri) {
|
||||
html += '<tr>';
|
||||
html += '<td><input type="number" class="layui-input param-row js-reward-field" value="' + (range.minGold || 0) + '" data-index="' + index + '" data-ri="' + ri + '" data-field="minGold" /></td>';
|
||||
html += '<td><input type="number" class="layui-input param-row js-reward-field" value="' + (range.maxGold || 0) + '" data-index="' + index + '" data-ri="' + ri + '" data-field="maxGold" /></td>';
|
||||
html += '<td><input type="number" class="layui-input param-row js-reward-field" value="' + (range.weight || 0) + '" data-index="' + index + '" data-ri="' + ri + '" data-field="weight" /></td>';
|
||||
html += '<td><button type="button" class="layui-btn layui-btn-xs layui-btn-danger js-remove-reward" data-index="' + index + '" data-ri="' + ri + '">删除</button></td>';
|
||||
html += '</tr>';
|
||||
});
|
||||
html += '</tbody></table>';
|
||||
html += '<button type="button" class="layui-btn layui-btn-xs layui-btn-warm js-add-reward" data-index="' + index + '" style="margin-top:8px"><i class="layui-icon layui-icon-addition"></i> 添加奖励区间</button>';
|
||||
html += '</div>';
|
||||
});
|
||||
if (torpedoListCache.length === 0) {
|
||||
html = '<div style="text-align:center;color:#999;padding:40px">暂无鱼雷配置,点击“添加鱼雷”开始配置</div>';
|
||||
}
|
||||
$('#torpedo-list').html(html);
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
$(document).off('.torpedoConfig');
|
||||
|
||||
$(document).on('change.torpedoConfig', '.js-torpedo-prop', function() {
|
||||
var index = Number($(this).data('index'));
|
||||
var number = String($(this).val() || '');
|
||||
var prop = propList.find(function(p) { return String(p.number) === number; });
|
||||
torpedoListCache[index].number = number;
|
||||
torpedoListCache[index].name = prop ? prop.name : '';
|
||||
renderTorpedoList();
|
||||
});
|
||||
|
||||
$(document).on('change.torpedoConfig', '.js-reward-field', function() {
|
||||
var index = Number($(this).data('index'));
|
||||
var rewardIndex = Number($(this).data('ri'));
|
||||
var field = $(this).data('field');
|
||||
torpedoListCache[index].rewardRanges[rewardIndex][field] = parseInt($(this).val(), 10) || 0;
|
||||
});
|
||||
|
||||
$(document).on('click.torpedoConfig', '.js-add-reward', function() {
|
||||
var index = Number($(this).data('index'));
|
||||
torpedoListCache[index].rewardRanges.push({ minGold: 0, maxGold: 0, weight: 1 });
|
||||
renderTorpedoList();
|
||||
});
|
||||
|
||||
$(document).on('click.torpedoConfig', '.js-remove-reward', function() {
|
||||
var index = Number($(this).data('index'));
|
||||
var rewardIndex = Number($(this).data('ri'));
|
||||
torpedoListCache[index].rewardRanges.splice(rewardIndex, 1);
|
||||
renderTorpedoList();
|
||||
});
|
||||
|
||||
$(document).on('click.torpedoConfig', '.js-remove-torpedo', function() {
|
||||
torpedoListCache.splice(Number($(this).data('index')), 1);
|
||||
renderTorpedoList();
|
||||
});
|
||||
|
||||
loadConfig();
|
||||
|
||||
$(document).on('click.torpedoConfig', '[lay-filter="init-torpedo"]', function() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/TorpedoConfigs",
|
||||
done: function(res) {
|
||||
layer.msg(res.info || '初始化成功');
|
||||
loadConfig();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click.torpedoConfig', '[lay-filter="save-torpedo"]', function() {
|
||||
gameConfig.torpedoConfigs = torpedoListCache;
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click.torpedoConfig', '[lay-filter="add-torpedo"]', function() {
|
||||
torpedoListCache.push({
|
||||
number: '',
|
||||
name: '',
|
||||
color: '',
|
||||
rewardRanges: [
|
||||
{ minGold: 10000, maxGold: 30000, weight: 100 },
|
||||
{ minGold: 30001, maxGold: 100000, weight: 20 }
|
||||
]
|
||||
});
|
||||
renderTorpedoList();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,443 @@
|
||||
<title>用户等级配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>用户等级配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="table-userlevel" lay-filter="table-userlevel"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-userlevel">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-userlevel"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-userlevel"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-userlevel"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-userlevel">添加</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-filter="batchdel-userlevel">批量删除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('UserLevelConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
<script>window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="product"><i class="layui-icon layui-icon-gift"></i>道具</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="product-dialog-tpl">
|
||||
<div style="padding:20px;">
|
||||
<div class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择道具</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="productNumber" id="productNumber" lay-search>
|
||||
<option value="">请选择道具</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="productCount" id="productCount" class="layui-input" placeholder="请输入数量" value="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var currentLevelIndex = -1;
|
||||
var currentProductIndex = -1;
|
||||
var propList = [];
|
||||
var currentDialogData = null;
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
propList = (gameConfig.propConfig || []).map(function(p) {
|
||||
return { number: p.number, name: p.name, type: p.type };
|
||||
});
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-userlevel',
|
||||
data: gameConfig ? gameConfig.userLevelConfigs || [] : [],
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ field: "level", title: "等级", width: 70, edit: 'text' },
|
||||
{ field: "expMin", title: "经验下限", width: 100, edit: 'text' },
|
||||
{ field: "expMax", title: "经验上限", width: 100, edit: 'text' },
|
||||
{ field: "gold", title: "金币", width: 120, edit: 'text' },
|
||||
{ field: "diamond", title: "钻石", width: 100, edit: 'text' },
|
||||
{ field: "productList", title: "升级道具", width: 100, templet: function(d) {
|
||||
return (d.productList && d.productList.length) ? d.productList.length + '项' : '无';
|
||||
}},
|
||||
{ title: "操作", width: 220, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-userlevel',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/UserLevelConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-userlevel"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-userlevel"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-userlevel"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/Update",
|
||||
data: JSON.stringify(gameConfig),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function updateDataByTable(obj) {
|
||||
var field = obj.field;
|
||||
var value = obj.value;
|
||||
var data = obj.data;
|
||||
|
||||
if (!isNaN(value) && value !== '') {
|
||||
var num = parseFloat(value);
|
||||
data[field] = num;
|
||||
}
|
||||
}
|
||||
|
||||
table.on('edit(table-userlevel)', function(obj){
|
||||
updateDataByTable(obj);
|
||||
});
|
||||
|
||||
table.on('tool(table-userlevel)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = obj.tr.index();
|
||||
if (trIndex < 0) trIndex = gameConfig.userLevelConfigs.findIndex(function(x) { return x.level === data.level; });
|
||||
|
||||
if (obj.event === 'edit') {
|
||||
showEditDialog(data, false, trIndex);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex >= 0) gameConfig.userLevelConfigs.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
} else if (obj.event === 'product') {
|
||||
currentLevelIndex = trIndex;
|
||||
showProductDialog(data);
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
var newData = {
|
||||
level: 0,
|
||||
expMin: 0,
|
||||
expMax: 0,
|
||||
gold: 0,
|
||||
diamond: 0,
|
||||
productList: []
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-userlevel"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加用户等级' : '编辑用户等级';
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="level" value="' + (data.level || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经验下限</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="expMin" value="' + (data.expMin || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经验上限</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="expMax" value="' + (data.expMax || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">金币</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="gold" value="' + (data.gold || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">钻石</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="diamond" value="' + (data.diamond || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['550px', '450px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
yes: function(index, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
level: parseInt(layero.find('input[name="level"]').val()) || 0,
|
||||
expMin: parseInt(layero.find('input[name="expMin"]').val()) || 0,
|
||||
expMax: parseInt(layero.find('input[name="expMax"]').val()) || 0,
|
||||
gold: parseInt(layero.find('input[name="gold"]').val()) || 0,
|
||||
diamond: parseInt(layero.find('input[name="diamond"]').val()) || 0,
|
||||
productList: []
|
||||
};
|
||||
gameConfig.userLevelConfigs.unshift(newItem);
|
||||
} else {
|
||||
var original = gameConfig.userLevelConfigs[rowIndex];
|
||||
if (!original) {
|
||||
original = gameConfig.userLevelConfigs.find(function(x) { return x.level === data.level; });
|
||||
}
|
||||
if (!original) { layer.msg('数据异常,请刷新后重试'); return; }
|
||||
original.level = parseInt(layero.find('input[name="level"]').val()) || 0;
|
||||
original.expMin = parseInt(layero.find('input[name="expMin"]').val()) || 0;
|
||||
original.expMax = parseInt(layero.find('input[name="expMax"]').val()) || 0;
|
||||
original.gold = parseInt(layero.find('input[name="gold"]').val()) || 0;
|
||||
original.diamond = parseInt(layero.find('input[name="diamond"]').val()) || 0;
|
||||
}
|
||||
layer.close(index);
|
||||
table.reload('table-userlevel', {
|
||||
data: gameConfig.userLevelConfigs
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="batchdel-userlevel"]', function() {
|
||||
var checkStatus = table.checkStatus('table-userlevel');
|
||||
var checkData = checkStatus.data;
|
||||
if (checkData.length === 0) {
|
||||
return layer.msg('请选择要删除的数据');
|
||||
}
|
||||
layer.confirm('确定删除选中的 ' + checkData.length + ' 条数据吗?', function(idx) {
|
||||
var levels = checkData.map(function(item) { return item.level; });
|
||||
gameConfig.userLevelConfigs = gameConfig.userLevelConfigs.filter(function(item) {
|
||||
return !levels.includes(item.level);
|
||||
});
|
||||
table.reload('table-userlevel', {
|
||||
data: gameConfig.userLevelConfigs
|
||||
});
|
||||
layer.close(idx);
|
||||
});
|
||||
});
|
||||
|
||||
function showProductDialog(data) {
|
||||
currentDialogData = data;
|
||||
currentProductIndex = -1;
|
||||
|
||||
var dialogContent = $('#product-dialog-tpl').html();
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '等级' + data.level + ' - 升级道具',
|
||||
area: ['600px', '400px'],
|
||||
content: dialogContent,
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
var propOptions = '<option value="">请选择道具</option>';
|
||||
propList.forEach(function(p) {
|
||||
propOptions += '<option value="' + p.number + '">' + p.number + ' - ' + p.name + '</option>';
|
||||
});
|
||||
layero.find('#productNumber').html(propOptions);
|
||||
form.render();
|
||||
|
||||
renderProductTable(layero);
|
||||
|
||||
layero.find('#productNumber').on('change', function() {
|
||||
var selected = $(this).val();
|
||||
if (selected) {
|
||||
var prop = propList.find(function(p) { return p.number === selected; });
|
||||
if (prop) {
|
||||
layero.find('#productCount').val(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
btn: ['添加', '关闭'],
|
||||
yes: function(index, layero) {
|
||||
var number = layero.find('#productNumber').val();
|
||||
var count = parseInt(layero.find('#productCount').val()) || 1;
|
||||
if (!number) {
|
||||
layer.msg('请选择道具');
|
||||
return;
|
||||
}
|
||||
var prop = propList.find(function(p) { return p.number === number; });
|
||||
var list = getProductList();
|
||||
var existing = list.find(function(p) { return p.number === number; });
|
||||
if (existing) {
|
||||
existing.count += count;
|
||||
} else {
|
||||
list.push({
|
||||
number: number,
|
||||
name: prop ? prop.name : '',
|
||||
type: prop ? prop.type : 0,
|
||||
count: count
|
||||
});
|
||||
}
|
||||
renderProductTable(layero);
|
||||
layer.msg('添加成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getProductList() {
|
||||
if (!currentDialogData) return [];
|
||||
if (!currentDialogData.productList) {
|
||||
currentDialogData.productList = [];
|
||||
}
|
||||
return currentDialogData.productList;
|
||||
}
|
||||
|
||||
function getPropName(number) {
|
||||
var prop = propList.find(function(p) { return p.number === number; });
|
||||
return prop ? prop.number + ' - ' + prop.name : number || '';
|
||||
}
|
||||
|
||||
function getPropType(number) {
|
||||
var prop = propList.find(function(p) { return p.number === number; });
|
||||
return prop ? prop.type : 0;
|
||||
}
|
||||
|
||||
function renderProductTable(layero) {
|
||||
var list = getProductList();
|
||||
|
||||
if (layero.find('#table-product-list').length === 0) {
|
||||
layero.find('.layui-layer-content').append(
|
||||
'<div style="padding:0 20px 20px;"><table id="table-product-list" lay-filter="table-product-list"></table></div>'
|
||||
);
|
||||
}
|
||||
|
||||
table.render({
|
||||
elem: layero.find('#table-product-list'),
|
||||
data: list,
|
||||
page: false,
|
||||
height: 260,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "number", title: "道具编号", width: 120 },
|
||||
{ field: "name", title: "道具名称", width: 120 },
|
||||
{ field: "count", title: "数量", width: 80, edit: 'text' },
|
||||
{ title: "操作", width: 100, templet: function(d) {
|
||||
return '<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>';
|
||||
}}
|
||||
]]
|
||||
});
|
||||
|
||||
layero.off('click', '.layui-btn-danger').on('click', '.layui-btn-danger', function() {
|
||||
var tr = $(this).closest('tr[data-index]');
|
||||
var index = parseInt(tr.attr('data-index'));
|
||||
var list = getProductList();
|
||||
if (index >= 0 && index < list.length) {
|
||||
list.splice(index, 1);
|
||||
renderProductTable(layero);
|
||||
}
|
||||
});
|
||||
|
||||
table.on('edit(table-product-list)', function(obj) {
|
||||
var list = getProductList();
|
||||
var index = layero.find('#table-product-list + .layui-table-view tr[data-index]').index(obj.tr);
|
||||
if (index >= 0 && index < list.length) {
|
||||
list[index].count = parseInt(obj.value) || 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -0,0 +1,604 @@
|
||||
|
||||
<title>VIP等级配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>VIP等级配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-bg-gray" style="padding:12px 16px;margin-bottom:12px;line-height:24px;">
|
||||
<strong>VIP经验计算规则:</strong>
|
||||
VIP经验 = 实际现金充值金额 × 10 + VIP经验包经验。
|
||||
金币、钻石余额、象棋或捕鱼输赢以及“累计充值金币”均不参与VIP经验计算。
|
||||
</div>
|
||||
<table id="table-vip" lay-filter="table-vip"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-vip">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-filter="init-vip"><i class="layui-icon layui-icon-refresh"></i> 初始化配置</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="save-vip"><i class="layui-icon layui-icon-ok"></i> 保存配置</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-filter="reload-vip"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm" lay-filter="add-vip">添加VIP等级</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="saveSection('VipLevelConfigs')"><i class="layui-icon layui-icon-export"></i> 保存到初始化文件</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="vip-bar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="gift">礼包</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="daily">每日</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="gift-dialog-tpl">
|
||||
<div class="gift-container">
|
||||
<div class="gift-left">
|
||||
<div class="gift-toolbar">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add-gift"><i class="layui-icon layui-icon-add-1"></i> 新增</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete-gift"><i class="layui-icon layui-icon-delete"></i> 删除</button>
|
||||
</div>
|
||||
<div class="gift-table-wrap">
|
||||
<table id="table-gift-list"></table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gift-right">
|
||||
<h4>礼包项详情</h4>
|
||||
<div class="layui-form" id="gift-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="giftType" id="giftType" lay-filter="giftType">
|
||||
<option value="1">金币</option>
|
||||
<option value="2">钻石</option>
|
||||
<option value="3">道具</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="giftCount" id="giftCount" class="layui-input" placeholder="请输入数量">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">随机</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="giftIsRandom" lay-skin="switch" lay-text="是|否" id="giftIsRandom">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最小值</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="giftMinCount" id="giftMinCount" class="layui-input" placeholder="最小值">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最大值</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="giftMaxCount" id="giftMaxCount" class="layui-input" placeholder="最大值">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item gift-prop-select" style="display:none;">
|
||||
<label class="layui-form-label">道具编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="giftProductNumber" id="giftProductNumber" class="layui-input" placeholder="输入道具编号">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="margin-top:20px;">
|
||||
<button class="layui-btn layui-btn-normal" id="btn-save-gift" style="width:100%;">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var gameConfig = null;
|
||||
var propList = [];
|
||||
var currentVipIndex = -1;
|
||||
var currentGiftIndex = -1;
|
||||
var currentGiftType = 'gift';
|
||||
var currentDialogData = null;
|
||||
|
||||
function getPropName(number) {
|
||||
var prop = propList.find(function(p) { return p.number === number; });
|
||||
return prop ? prop.number + ' - ' + prop.name : number || '';
|
||||
}
|
||||
|
||||
function getOid(data) {
|
||||
return data.otherId || data.OtherId || '';
|
||||
}
|
||||
|
||||
function getType(data) {
|
||||
return data.type || data.Type || 1;
|
||||
}
|
||||
|
||||
function enrichProduct(gift) {
|
||||
var oid = getOid(gift);
|
||||
if (getType(gift) === 3 && oid) {
|
||||
var prop = propList.find(function(p) { return p.number === oid; });
|
||||
gift.product = prop ? { number: prop.number, name: prop.name } : { number: oid, name: '' };
|
||||
} else {
|
||||
gift.product = null;
|
||||
}
|
||||
return gift;
|
||||
}
|
||||
|
||||
function enrichGiftList(list) {
|
||||
if (list) list.forEach(enrichProduct);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
$('.layui-layer-shade').remove();
|
||||
layer.closeAll();
|
||||
}, 100);
|
||||
|
||||
function loadConfig() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
gameConfig = res.data;
|
||||
propList = gameConfig.propConfig || [];
|
||||
renderTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable() {
|
||||
table.render({
|
||||
elem: '#table-vip',
|
||||
data: gameConfig ? (gameConfig.vipLevelConfigs || []) : [],
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "level", title: "等级", width: 80 },
|
||||
{ field: "expMin", title: "经验下限", width: 100 },
|
||||
{ field: "expMax", title: "经验上限", width: 100 },
|
||||
{ field: "signInAdd", title: "签到加成", width: 100 },
|
||||
{ field: "remark", title: "备注", minWidth: 150 },
|
||||
{ field: "giftList", title: "礼包", width: 80, templet: function(d) {
|
||||
return (d.giftList && d.giftList.length) ? d.giftList.length + '项' : '无';
|
||||
}},
|
||||
{ field: "dailyGift", title: "每日", width: 80, templet: function(d) {
|
||||
return (d.dailyGift && d.dailyGift.length) ? d.dailyGift.length + '项' : '无';
|
||||
}},
|
||||
{ title: "操作", width: 250, fixed: 'right', toolbar: '#vip-bar' }
|
||||
]],
|
||||
toolbar: '#toolbar-vip',
|
||||
defaultToolbar: ['filter', 'exports', 'print']
|
||||
});
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
layer.confirm('确定要初始化全部配置数据吗?此操作将清空现有数据!', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/GameConfig/InitSection/VipLevelConfigs",
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('初始化成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
},
|
||||
fail: function(res) {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="init-vip"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
initConfig();
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="reload-vip"]', function() {
|
||||
loadConfig();
|
||||
layer.msg('刷新成功');
|
||||
});
|
||||
|
||||
$(document).on('click', '[lay-filter="save-vip"]', function() {
|
||||
if (window.parent && window.parent.$ && window.parent.layer) {
|
||||
window.parent.$('.layui-layer-shade').remove();
|
||||
window.parent.layer.closeAll();
|
||||
}
|
||||
(gameConfig.vipLevelConfigs || []).forEach(function(v) {
|
||||
enrichGiftList(v.giftList);
|
||||
enrichGiftList(v.dailyGift);
|
||||
});
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
url: setter.baseurl + "adminapi/GameConfig/UpdateVipLevel",
|
||||
data: JSON.stringify(gameConfig.vipLevelConfigs || []),
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('保存成功');
|
||||
loadConfig();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
table.on('tool(table-vip)', function(obj) {
|
||||
var data = obj.data;
|
||||
var trIndex = gameConfig.vipLevelConfigs.findIndex(function(x) { return x.level === data.level; });
|
||||
var originalData = trIndex > -1 ? gameConfig.vipLevelConfigs[trIndex] : data;
|
||||
|
||||
if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该配置吗?', function(idx) {
|
||||
if (trIndex > -1) gameConfig.vipLevelConfigs.splice(trIndex, 1);
|
||||
obj.del();
|
||||
layer.close(idx);
|
||||
});
|
||||
} else if (obj.event === 'edit') {
|
||||
showEditDialog(originalData, false, trIndex);
|
||||
} else if (obj.event === 'gift') {
|
||||
currentVipIndex = trIndex;
|
||||
currentGiftType = 'gift';
|
||||
showGiftDialog(originalData, '等级礼包');
|
||||
} else if (obj.event === 'daily') {
|
||||
currentVipIndex = trIndex;
|
||||
currentGiftType = 'daily';
|
||||
showGiftDialog(originalData, '每日礼包');
|
||||
}
|
||||
});
|
||||
|
||||
function showAddDialog() {
|
||||
if (!gameConfig.vipLevelConfigs) gameConfig.vipLevelConfigs = [];
|
||||
var newData = {
|
||||
level: (gameConfig.vipLevelConfigs || []).length + 1,
|
||||
expMin: 0,
|
||||
expMax: 0,
|
||||
signInAdd: 0,
|
||||
remark: '',
|
||||
giftList: [],
|
||||
dailyGift: []
|
||||
};
|
||||
showEditDialog(newData, true);
|
||||
}
|
||||
|
||||
$(document).on('click', '[lay-filter="add-vip"]', function() {
|
||||
showAddDialog();
|
||||
});
|
||||
|
||||
function showEditDialog(data, isAdd, rowIndex) {
|
||||
var dialogTitle = isAdd ? '添加VIP等级' : '编辑VIP等级';
|
||||
var index = isAdd ? -1 : rowIndex;
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">等级</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="level" value="' + (data.level || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经验下限</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="expMin" value="' + (data.expMin || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">经验上限</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="expMax" value="' + (data.expMax || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">签到加成</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="signInAdd" value="' + (data.signInAdd || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">备注</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="remark" value="' + (data.remark || '') + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: dialogTitle,
|
||||
area: ['550px', '450px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render();
|
||||
},
|
||||
yes: function(idx, layero) {
|
||||
if (isAdd) {
|
||||
var newItem = {
|
||||
level: parseInt(layero.find('input[name="level"]').val()) || 0,
|
||||
expMin: parseInt(layero.find('input[name="expMin"]').val()) || 0,
|
||||
expMax: parseInt(layero.find('input[name="expMax"]').val()) || 0,
|
||||
signInAdd: parseFloat(layero.find('input[name="signInAdd"]').val()) || 0,
|
||||
remark: layero.find('input[name="remark"]').val(),
|
||||
giftList: [],
|
||||
dailyGift: []
|
||||
};
|
||||
gameConfig.vipLevelConfigs.unshift(newItem);
|
||||
} else if (index > -1) {
|
||||
// Layui 返回的是行数据副本,必须明确写回原配置数组。
|
||||
var original = gameConfig.vipLevelConfigs[index];
|
||||
original.level = parseInt(layero.find('input[name="level"]').val()) || 0;
|
||||
original.expMin = parseInt(layero.find('input[name="expMin"]').val()) || 0;
|
||||
original.expMax = parseInt(layero.find('input[name="expMax"]').val()) || 0;
|
||||
original.signInAdd = parseFloat(layero.find('input[name="signInAdd"]').val()) || 0;
|
||||
original.remark = layero.find('input[name="remark"]').val();
|
||||
}
|
||||
layer.close(idx);
|
||||
table.reload('table-vip', {
|
||||
data: gameConfig.vipLevelConfigs
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showGiftDialog(data, title) {
|
||||
currentDialogData = data;
|
||||
currentGiftIndex = -1;
|
||||
|
||||
var dialogContent = $('#gift-dialog-tpl').html();
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: 'VIP' + data.level + ' - ' + title,
|
||||
area: ['1000px', '620px'],
|
||||
content: dialogContent,
|
||||
shadeClose: true,
|
||||
success: function(layero) {
|
||||
form.render();
|
||||
|
||||
renderGiftTable(layero);
|
||||
|
||||
layero.find('#btn-add-gift').on('click', function() {
|
||||
addGiftItem(layero);
|
||||
});
|
||||
|
||||
layero.find('#btn-delete-gift').on('click', function() {
|
||||
deleteGiftItem(layero);
|
||||
});
|
||||
|
||||
layero.find('#btn-save-gift').on('click', function() {
|
||||
saveGiftItem(layero);
|
||||
});
|
||||
|
||||
form.on('select(giftType)', function(obj) {
|
||||
if (obj.value === '3') {
|
||||
layero.find('.gift-prop-select').show();
|
||||
} else {
|
||||
layero.find('.gift-prop-select').hide();
|
||||
}
|
||||
layero.find('#giftCount').val(0);
|
||||
layero.find('#giftIsRandom')[0].checked = false;
|
||||
form.render('checkbox');
|
||||
});
|
||||
|
||||
layero.find('#giftCount').on('input', function() {
|
||||
layero.find('#giftIsRandom')[0].checked = false;
|
||||
layero.find('#giftIsRandom').prop('checked', false);
|
||||
form.render('checkbox');
|
||||
});
|
||||
|
||||
layero.on('click', '#giftIsRandom + .layui-form-switch', function() {
|
||||
var checkbox = layero.find('#giftIsRandom')[0];
|
||||
setTimeout(function() {
|
||||
if (checkbox.checked) {
|
||||
layero.find('#giftCount').val(0);
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
|
||||
form.on('switch(giftIsRandom)', function(data) {
|
||||
if (data.elem.checked) {
|
||||
layero.find('#giftCount').val(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getGiftList() {
|
||||
if (!currentDialogData) return [];
|
||||
if (currentGiftType === 'gift') {
|
||||
return currentDialogData.giftList || (currentDialogData.giftList = []);
|
||||
} else {
|
||||
return currentDialogData.dailyGift || (currentDialogData.dailyGift = []);
|
||||
}
|
||||
}
|
||||
|
||||
function addGiftItem(layero) {
|
||||
var list = getGiftList();
|
||||
list.push({ type: 1, count: 100, isRandom: false, minCount: 0, maxCount: 0, otherId: '' });
|
||||
currentGiftIndex = list.length - 1;
|
||||
renderGiftTable(layero, currentGiftIndex);
|
||||
loadFormData(list[list.length - 1], layero);
|
||||
}
|
||||
|
||||
function deleteGiftItem(layero) {
|
||||
if (currentGiftIndex < 0) {
|
||||
return layer.msg('请先选择要删除的项');
|
||||
}
|
||||
var list = getGiftList();
|
||||
if (list.length > currentGiftIndex) {
|
||||
list.splice(currentGiftIndex, 1);
|
||||
currentGiftIndex = -1;
|
||||
clearForm(layero);
|
||||
renderGiftTable(layero, -1);
|
||||
}
|
||||
}
|
||||
|
||||
function saveGiftItem(layero) {
|
||||
if (currentGiftIndex < 0) {
|
||||
return layer.msg('请先选择要编辑的项');
|
||||
}
|
||||
var list = getGiftList();
|
||||
var giftType = parseInt(layero.find('#giftType').val()) || 1;
|
||||
var otherId = $.trim(layero.find('#giftProductNumber').val() || '');
|
||||
if (giftType === 3 && !propList.some(function(p) { return String(p.number) === otherId; })) {
|
||||
return layer.msg('请输入道具表中存在的道具编号');
|
||||
}
|
||||
list[currentGiftIndex] = {
|
||||
type: giftType,
|
||||
count: parseInt(layero.find('#giftCount').val()) || 0,
|
||||
isRandom: layero.find('#giftIsRandom')[0].checked,
|
||||
minCount: parseInt(layero.find('#giftMinCount').val()) || 0,
|
||||
maxCount: parseInt(layero.find('#giftMaxCount').val()) || 0,
|
||||
otherId: giftType === 3 ? otherId : ''
|
||||
};
|
||||
renderGiftTable(layero, currentGiftIndex);
|
||||
(gameConfig.vipLevelConfigs || []).forEach(function(v) {
|
||||
enrichGiftList(v.giftList);
|
||||
enrichGiftList(v.dailyGift);
|
||||
});
|
||||
var saveButton = layero.find('#btn-save-gift');
|
||||
if (saveButton.prop('disabled')) return;
|
||||
saveButton.prop('disabled', true).addClass('layui-btn-disabled');
|
||||
admin.req({
|
||||
method: 'post',
|
||||
contentType: 'application/json;charset=UTF-8',
|
||||
url: setter.baseurl + 'adminapi/GameConfig/UpdateVipLevel',
|
||||
data: JSON.stringify(gameConfig.vipLevelConfigs || []),
|
||||
done: function(res) {
|
||||
saveButton.prop('disabled', false).removeClass('layui-btn-disabled');
|
||||
layer.msg(res.code === 0 || res.code === 200 ? '保存成功' : (res.info || '保存失败,请重试'));
|
||||
},
|
||||
error: function() {
|
||||
saveButton.prop('disabled', false).removeClass('layui-btn-disabled');
|
||||
layer.msg('保存请求失败,请重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearForm(layero) {
|
||||
layero.find('#giftType').val('1');
|
||||
layero.find('#giftCount').val('0');
|
||||
layero.find('#giftIsRandom')[0].checked = false;
|
||||
layero.find('#giftMinCount').val('0');
|
||||
layero.find('#giftMaxCount').val('0');
|
||||
layero.find('#giftProductNumber').val('');
|
||||
layero.find('.gift-prop-select').hide();
|
||||
form.render('checkbox');
|
||||
form.render('select');
|
||||
}
|
||||
|
||||
function loadFormData(data, layero) {
|
||||
layero.find('#giftType').val(getType(data));
|
||||
layero.find('#giftCount').val(data.count || data.Count || 0);
|
||||
layero.find('#giftIsRandom')[0].checked = data.isRandom || data.IsRandom || false;
|
||||
layero.find('#giftMinCount').val(data.minCount || data.MinCount || 0);
|
||||
layero.find('#giftMaxCount').val(data.maxCount || data.MaxCount || 0);
|
||||
layero.find('#giftProductNumber').val(getOid(data));
|
||||
|
||||
if (getType(data) === 3) {
|
||||
layero.find('.gift-prop-select').show();
|
||||
} else {
|
||||
layero.find('.gift-prop-select').hide();
|
||||
}
|
||||
form.render('checkbox');
|
||||
form.render();
|
||||
}
|
||||
|
||||
function renderGiftTable(layero, selectIndex) {
|
||||
var list = getGiftList();
|
||||
if (typeof selectIndex !== 'number') selectIndex = list.length > 0 ? 0 : -1;
|
||||
|
||||
layero.find('.layui-table-view').remove();
|
||||
|
||||
table.render({
|
||||
elem: layero.find('#table-gift-list'),
|
||||
data: list,
|
||||
page: false,
|
||||
height: 380,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "type", title: "类型", width: 80, templet: function(d) {
|
||||
var map = {1: '金币', 2: '钻石', 3: '道具'};
|
||||
return map[d.type] || '金币';
|
||||
}},
|
||||
{ field: "count", title: "数量", width: 80 },
|
||||
{ field: "minCount", title: "最小值", width: 80 },
|
||||
{ field: "maxCount", title: "最大值", width: 80 },
|
||||
{ field: "isRandom", title: "随机", width: 70, templet: function(d) {
|
||||
return d.isRandom ? '是' : '否';
|
||||
}},
|
||||
{ field: "otherId", title: "道具编号", minWidth: 150, templet: function(d) {
|
||||
return getType(d) === 3 ? getPropName(getOid(d)) : '';
|
||||
}}
|
||||
]],
|
||||
done: function() {
|
||||
if (list.length > 0 && selectIndex < 0) {
|
||||
selectIndex = 0;
|
||||
}
|
||||
if (selectIndex >= 0 && selectIndex < list.length) {
|
||||
currentGiftIndex = selectIndex;
|
||||
loadFormData(list[selectIndex], layero);
|
||||
layero.find('.layui-table-view tr[data-index="' + selectIndex + '"]').addClass('layui-table-click');
|
||||
}
|
||||
layero.find('.layui-table-view').off('click', 'tr[data-index]').on('click', 'tr[data-index]', function() {
|
||||
var index = parseInt($(this).attr('data-index'));
|
||||
if (index >= 0 && index < list.length) {
|
||||
currentGiftIndex = index;
|
||||
layero.find('.layui-table-view tr[data-index]').removeClass('layui-table-click');
|
||||
$(this).addClass('layui-table-click');
|
||||
loadFormData(list[index], layero);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.saveSection=function(n){layui.admin.req({method:'get',url:(layui.setter.baseurl||'/')+'adminapi/GameConfig/SaveSection/'+n,done:function(r){layui.layer.msg(r.info||(r.code===0?'保存成功':'保存失败'))}})}
|
||||
|
||||
loadConfig();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gift-container { display: flex; height: 480px; padding: 10px; }
|
||||
.gift-left { flex: 1; margin-right: 15px; }
|
||||
.gift-table-wrap { height: 400px; overflow: auto; }
|
||||
.gift-right { width: 280px; border-left: 1px solid #e6e6e6; padding-left: 15px; }
|
||||
.gift-right h4 { margin-bottom: 15px; color: #333; font-size: 16px; padding-bottom: 10px; border-bottom: 1px solid #eee; }
|
||||
.gift-toolbar { margin-bottom: 10px; }
|
||||
.gift-toolbar .layui-btn { margin-right: 5px; }
|
||||
.gift-right .layui-form-item { margin-bottom: 12px; }
|
||||
.gift-right .layui-form-label { padding: 9px 0; width: 60px; }
|
||||
.gift-right .layui-input-block { margin-left: 70px; }
|
||||
</style>
|
||||
@@ -0,0 +1,180 @@
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md8">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">快捷方式111111111111</div>
|
||||
<div class="layui-card-body">
|
||||
|
||||
<div class="layui-carousel layadmin-carousel layadmin-shortcut">
|
||||
<div carousel-item>
|
||||
<ul class="layui-row layui-col-space10">
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="home/homepage1">
|
||||
<i class="layui-icon layui-icon-console"></i>
|
||||
<cite>主页一1111111111</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="home/homepage2">
|
||||
<i class="layui-icon layui-icon-chart"></i>
|
||||
<cite>主页二</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="component/layer/list">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
<cite>弹层</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="/senior/im/">
|
||||
<i class="layui-icon layui-icon-chat"></i>
|
||||
<cite>聊天</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="component/progress/index">
|
||||
<i class="layui-icon layui-icon-find-fill"></i>
|
||||
<cite>进度条</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="app/workorder/list">
|
||||
<i class="layui-icon layui-icon-survey"></i>
|
||||
<cite>工单</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="user/user/list">
|
||||
<i class="layui-icon layui-icon-user"></i>
|
||||
<cite>用户</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/system/website">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>设置</cite>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="layui-row layui-col-space10">
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
<li class="layui-col-xs3">
|
||||
<a lay-href="set/user/info">
|
||||
<i class="layui-icon layui-icon-set"></i>
|
||||
<cite>我的资料</cite>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">数据概览</div>
|
||||
<div class="layui-card-body">
|
||||
|
||||
<div class="layui-carousel layadmin-carousel layadmin-dataview" data-anim="fade" lay-filter="LAY-index-dataview">
|
||||
<div carousel-item id="LAY-index-dataview">
|
||||
<div><i class="layui-icon layui-icon-loading1 layadmin-loading"></i></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-tab layui-tab-brief layadmin-latestData">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">今日热搜</li>
|
||||
<li>今日热帖</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<table id="LAY-index-topSearch"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table id="LAY-index-topCard"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
//加载 controller 目录下的对应模块
|
||||
/*
|
||||
|
||||
小贴士:
|
||||
这里 console 模块对应 的 console.js 并不会重复加载,
|
||||
然而该页面的视图则是重新插入到容器,那如何保证能重新来控制视图?有两种方式:
|
||||
1): 借助 layui.factory 方法获取 console 模块的工厂(回调函数)给 layui.use
|
||||
2): 直接在 layui.use 方法的回调中书写业务代码,即:
|
||||
layui.use('console', function(){
|
||||
//同 console.js 中的 layui.define 回调中的代码
|
||||
});
|
||||
|
||||
这里我们采用的是方式1。其它很多视图中采用的其实都是方式2,因为更简单些,也减少了一个请求数。
|
||||
|
||||
*/
|
||||
layui.use('console', layui.factory('console'));
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
<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="note">
|
||||
<i class="layui-icon layui-icon-note"></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>
|
||||
<script type="text/html" template lay-url="{{layui.setter.baseurl}}adminapi/system/user/getuser"
|
||||
lay-done="layui.element.render('nav', 'layadmin-layout-right');">
|
||||
<a href="javascript:;">
|
||||
<cite>{{ (d.data && d.data.displayName) ? d.data.displayName : '用户' }}</cite>
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd layadmin-event="logout" style="text-align: center;"><a>退出</a></dd>
|
||||
</dl>
|
||||
</script>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 侧边菜单 -->
|
||||
<div class="layui-side layui-side-menu">
|
||||
<div class="layui-side-scroll">
|
||||
<script type="text/html" template lay-url="{{layui.setter.baseurl}}adminapi/System/user/nav"
|
||||
lay-done="layui.element.render('nav', 'layadmin-system-side-menu'); initMenuHighlight();" id="TPL_layout">
|
||||
|
||||
<div class="layui-logo" lay-href="">
|
||||
<span>{{ layui.setter.name || 'layuiAdmin' }}</span>
|
||||
</div>
|
||||
|
||||
<ul class="layui-nav layui-nav-tree" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
|
||||
{{#
|
||||
var path = layui.router().path
|
||||
,pathURL = layui.admin.correctRouter(path.join('/'))
|
||||
,dataName = layui.setter.response.dataName;
|
||||
|
||||
layui.each(d[dataName], function(index, item){
|
||||
var hasChildren = typeof item.children === 'object' && item.children.length > 0
|
||||
,url = (item.url && typeof item.url === 'string') ? item.url : item.name;
|
||||
}}
|
||||
<li data-name="{{ item.name || '' }}" data-jump="{{ item.url || '' }}" class="layui-nav-item">
|
||||
<a href="javascript:;" {{ hasChildren ? '' : 'lay-href='+ url }} lay-tips="{{ item.name }}" lay-direction="2">
|
||||
<i class="layui-icon {{ item.icon }}"></i>
|
||||
<cite>{{ item.name }}</cite>
|
||||
</a>
|
||||
{{# if(hasChildren){ }}
|
||||
<dl class="layui-nav-child">
|
||||
{{# layui.each(item.children, function(index2, item2){
|
||||
var hasChildren2 = typeof item2.children == 'object' && item2.children.length > 0
|
||||
,url2 = (item2.url && typeof item2.url === 'string')
|
||||
? item2.url
|
||||
: [item.name, item2.name, ''].join('/');
|
||||
}}
|
||||
<dd data-name="{{ item2.name || '' }}" data-jump="{{ item2.url || '' }}" class="layui-nav-item">
|
||||
<a href="javascript:;" {{ hasChildren2 ? '' : 'lay-href='+ url2 }}>{{ item2.name }}</a>
|
||||
{{# if(hasChildren2){ }}
|
||||
<dl class="layui-nav-child">
|
||||
{{# layui.each(item2.children, function(index3, item3){
|
||||
var url3 = (item3.url && typeof item3.url === 'string')
|
||||
? item3.url
|
||||
: [item.name, item2.name, item3.name].join('/')
|
||||
}}
|
||||
<dd data-name="{{ item3.name || '' }}" data-jump="{{ item3.url || '' }}">
|
||||
<a href="javascript:;" lay-href="{{ url3 }}" {{ item3.iframe ? 'lay-iframe="true"' : '' }}>{{ item3.name }}</a>
|
||||
</dd>
|
||||
{{# }); }}
|
||||
</dl>
|
||||
{{# } }}
|
||||
</dd>
|
||||
{{# }); }}
|
||||
</dl>
|
||||
{{# } }}
|
||||
</li>
|
||||
{{# }); }}
|
||||
</ul>
|
||||
</script>
|
||||
</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="/"><i class="layui-icon layui-icon-home"></i></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 - iframe模式 -->
|
||||
<div class="layui-body" id="LAY_app_body">
|
||||
<div class="layadmin-tabsbody-item layui-show" id="LAY_iframe_container">
|
||||
<iframe frameborder="0" src="" class="layadmin-iframe" id="LAY_admin_iframe"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 辅助元素 -->
|
||||
<div class="layadmin-body-shade" layadmin-event="shade"></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* iframe样式 */
|
||||
.layadmin-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 修复tabs位置 */
|
||||
.layadmin-pagetabs {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
left: 220px;
|
||||
z-index: 999;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 修复body位置 - 有tabs时 */
|
||||
.layui-layout-admin .layui-body {
|
||||
top: 90px !important;
|
||||
}
|
||||
|
||||
/* 修复body位置 - 无tabs时 */
|
||||
.layui-layout-admin .layui-body.no-tabs {
|
||||
top: 50px !important;
|
||||
}
|
||||
|
||||
/* 防止iframe容器被刷新时重新创建 */
|
||||
.layadmin-tabsbody-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// 菜单高亮函数
|
||||
function initMenuHighlight() {
|
||||
var $ = layui.$;
|
||||
var admin = layui.admin;
|
||||
|
||||
// 关闭所有layer弹窗和遮罩
|
||||
function closeAllLayers() {
|
||||
console.log('closeAllLayers 被调用');
|
||||
try {
|
||||
if (typeof layer !== 'undefined') {
|
||||
console.log('调用 layer.closeAll()');
|
||||
layer.closeAll();
|
||||
}
|
||||
} catch(e) {
|
||||
console.log('layer.closeAll 错误:', e);
|
||||
}
|
||||
console.log('移除 layui-layer-shade');
|
||||
$('.layui-layer-shade').remove();
|
||||
console.log('移除 layui-layer');
|
||||
$('.layui-layer').remove();
|
||||
// 关闭侧边栏遮罩
|
||||
console.log('隐藏 layadmin-body-shade');
|
||||
$('.layadmin-body-shade').hide();
|
||||
}
|
||||
|
||||
// 点击侧边栏链接时关闭弹窗
|
||||
$(document).on('click', '#LAY-system-side-menu a', function() {
|
||||
console.log('点击了侧边栏链接');
|
||||
closeAllLayers();
|
||||
});
|
||||
|
||||
// Tab切换时关闭弹窗
|
||||
layui.element.on('tab(layadmin-layout-tabs)', function() {
|
||||
console.log('Tab切换');
|
||||
closeAllLayers();
|
||||
});
|
||||
|
||||
// 监听iframe加载完成,关闭其他iframe上的弹窗
|
||||
window.addEventListener('message', function(e) {
|
||||
if (e.data === 'iframe-focused') {
|
||||
closeAllLayers();
|
||||
}
|
||||
});
|
||||
|
||||
// 暴露关闭函数到全局
|
||||
window.closeAllAdminLayers = closeAllLayers;
|
||||
|
||||
// 高亮当前菜单
|
||||
function highlightMenu(href) {
|
||||
var sideMenu = $('#LAY-system-side-menu');
|
||||
if (!sideMenu.length) return;
|
||||
|
||||
// 移除所有高亮
|
||||
sideMenu.find('.layui-this').removeClass('layui-this');
|
||||
|
||||
if (!href) {
|
||||
// 获取当前tab
|
||||
var $curTab = $('#LAY_app_tabsheader .layui-this');
|
||||
if ($curTab.length) {
|
||||
href = $curTab.attr('lay-id');
|
||||
}
|
||||
}
|
||||
|
||||
if (!href || href === '/') return;
|
||||
|
||||
// 标准化路径
|
||||
href = href.replace(/^\//, '');
|
||||
|
||||
// 查找匹配的菜单并高亮
|
||||
sideMenu.find('a[lay-href]').each(function() {
|
||||
var menuHref = $(this).attr('lay-href').replace(/^\//, '');
|
||||
if (menuHref === href) {
|
||||
var $dd = $(this).closest('dd');
|
||||
var $li = $(this).closest('li.layui-nav-item');
|
||||
|
||||
// 高亮当前
|
||||
$dd.addClass('layui-this');
|
||||
|
||||
// 展开父级
|
||||
$dd.parents('dd').each(function() {
|
||||
$(this).addClass('layui-nav-itemed');
|
||||
});
|
||||
$li.addClass('layui-nav-itemed');
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化高亮
|
||||
setTimeout(function() {
|
||||
highlightMenu();
|
||||
}, 100);
|
||||
|
||||
// Tab切换时高亮
|
||||
layui.element.on('tab(layadmin-layout-tabs)', function() {
|
||||
setTimeout(highlightMenu, 50);
|
||||
});
|
||||
|
||||
// Hash变化时高亮
|
||||
window.addEventListener('hashchange', function() {
|
||||
setTimeout(highlightMenu, 50);
|
||||
});
|
||||
}
|
||||
|
||||
// 暴露到全局
|
||||
window.initMenuHighlight = initMenuHighlight;
|
||||
</script>
|
||||
@@ -0,0 +1,346 @@
|
||||
<title>邮件列表</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>邮件管理</cite></a>
|
||||
<a><cite>发送邮件</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-admin" style="padding: 20px 30px 0 0;">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="title" value="" lay-verify="required" placeholder="发送标题" autocomplete="off" class="layui-input">
|
||||
|
||||
</div>
|
||||
|
||||
<label class="layui-form-label">内容</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="content" value="" lay-verify="required" placeholder="发送内容" autocomplete="off" class="layui-input">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">金币</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="gold" value="0" placeholder="金币数量" autocomplete="off" class="layui-input" style="width: 150px;">
|
||||
</div>
|
||||
|
||||
<label class="layui-form-label">钻石</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="diamond" value="0" placeholder="钻石数量" autocomplete="off" class="layui-input" style="width: 150px;">
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">玩家ID</label>
|
||||
|
||||
<div class="layui-input-inline">
|
||||
<textarea name="userIds" placeholder="请输入玩家ID,多个用逗号分隔,留空则发送给所有玩家" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">有效天数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="expireDays" value="30" placeholder="默认30天" class="layui-input" style="width: 150px;">
|
||||
</div>
|
||||
</div>
|
||||
<!-- 道具配置列表(初始1项,支持动态添加/删除) -->
|
||||
<div class="layui-form-item" id="rewardItems">
|
||||
<div class="layui-form-item layui-form-text" data-index="0">
|
||||
<!-- 道具选择(带搜索功能) -->
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">赠送道具</label>
|
||||
|
||||
<div class="layui-input-inline">
|
||||
<select name="itemNumber[0]" id="itemNumber[0]" lay-search class="layui-select">
|
||||
<option value=''>无</option>
|
||||
</select>
|
||||
<img class="prop-preview" src="" style="width:40px;height:40px;vertical-align:middle;margin-left:8px;display:none;">
|
||||
</div>
|
||||
<label class="layui-form-label">道具数量</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="itemCount[0]" min="1" value="1" class="layui-input" style="width: 200px;">
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加道具按钮(官方普通按钮样式) -->
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button type="button" class="layui-btn layui-btn-normal" onclick="addRewardItem()">
|
||||
<i class="layui-icon layui-icon-add-circle"></i> 添加新道具
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="sendEmail" value="确认发送" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form'], function(){
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, form = layui.form
|
||||
|
||||
, setter = layui.setter;
|
||||
|
||||
var propList = [];
|
||||
|
||||
// 从API获取道具列表
|
||||
function loadPropList() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
url: setter.baseurl + "adminapi/GameConfig/PropList",
|
||||
async: false,
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
propList = res.data;
|
||||
renderPropSelect(propList);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染道具下拉框
|
||||
function renderPropSelect(data) {
|
||||
var html = '<option value="">请选择道具</option>';
|
||||
|
||||
// 按类型分组
|
||||
var groups = {};
|
||||
data.forEach(function(item) {
|
||||
var typeName = getTypeName(item.type);
|
||||
if (!groups[typeName]) {
|
||||
groups[typeName] = [];
|
||||
}
|
||||
groups[typeName].push(item);
|
||||
});
|
||||
|
||||
// 生成optgroup
|
||||
for (var typeName in groups) {
|
||||
html += '<optgroup label="' + typeName + '">';
|
||||
groups[typeName].forEach(function(item) {
|
||||
html += '<option value="' + item.number + '">' + item.name + '</option>';
|
||||
});
|
||||
html += '</optgroup>';
|
||||
}
|
||||
|
||||
$('select[name^="itemNumber"]').each(function() {
|
||||
var $select = $(this);
|
||||
var prevVal = $select.val();
|
||||
$select.html(html);
|
||||
if (prevVal) $select.val(prevVal);
|
||||
});
|
||||
form.render('select');
|
||||
// 初始化已选道具的图片预览
|
||||
$('select[name^="itemNumber"]').each(function() {
|
||||
var val = $(this).val();
|
||||
if (val) {
|
||||
var prop = data.find(function(p) { return p.number === val; });
|
||||
if (prop) {
|
||||
var $img = $(this).closest('.layui-input-inline').find('.prop-preview');
|
||||
$img.attr('src', prop.imageUrl || '/uploads/' + prop.number + '.png').show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 道具选择变更时更新图片预览
|
||||
$(document).on('change', 'select[name^="itemNumber"]', function() {
|
||||
var val = $(this).val();
|
||||
var $img = $(this).closest('.layui-input-inline').find('.prop-preview');
|
||||
if (val) {
|
||||
var prop = propList.find(function(p) { return p.number === val; });
|
||||
if (prop) {
|
||||
$img.attr('src', prop.imageUrl || '/uploads/' + prop.number + '.png').show();
|
||||
}
|
||||
} else {
|
||||
$img.hide();
|
||||
}
|
||||
});
|
||||
|
||||
// 获取类型名称
|
||||
function getTypeName(type) {
|
||||
var typeNames = {
|
||||
1: '炮台',
|
||||
2: '翅膀',
|
||||
3: '炮塔碎片',
|
||||
4: '翅膀碎片',
|
||||
5: '战神',
|
||||
6: '战神碎片',
|
||||
7: '刮刮卡',
|
||||
8: '改名卡',
|
||||
9: '大喇叭',
|
||||
10: '技能',
|
||||
11: '召唤卡',
|
||||
12: 'VIP经验',
|
||||
13: '鱼雷'
|
||||
};
|
||||
return typeNames[type] || '其他';
|
||||
}
|
||||
|
||||
// 初始加载道具列表
|
||||
loadPropList();
|
||||
|
||||
form.render();
|
||||
|
||||
form.on('submit(sendEmail)', function (data) {
|
||||
var field = data.field;
|
||||
|
||||
// 处理用户ID列表
|
||||
var userIds = null;
|
||||
if (field.userIds && field.userIds.trim()) {
|
||||
userIds = field.userIds.split(',').map(function(id) {
|
||||
return id.trim();
|
||||
}).filter(function(id) {
|
||||
return id;
|
||||
});
|
||||
}
|
||||
|
||||
// 收集道具
|
||||
var props = [];
|
||||
$('[data-index]').each(function(idx) {
|
||||
var $item = $(this);
|
||||
var number = $item.find('select[name^="itemNumber"]').val();
|
||||
var count = parseInt($item.find('input[name^="itemCount"]').val()) || 1;
|
||||
|
||||
if (number) {
|
||||
var propInfo = propList.find(function(p) { return p.number === number; });
|
||||
props.push({
|
||||
number: number,
|
||||
name: propInfo ? propInfo.name : '',
|
||||
imageUrl: propInfo ? propInfo.imageUrl : '',
|
||||
type: propInfo ? propInfo.type : 0,
|
||||
count: count
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var param = {
|
||||
userIds: userIds,
|
||||
title: field.title,
|
||||
content: field.content,
|
||||
gold: parseInt(field.gold) || 0,
|
||||
diamond: parseInt(field.diamond) || 0,
|
||||
props: props,
|
||||
expireDays: parseInt(field.expireDays) || 30
|
||||
};
|
||||
|
||||
console.log('发送邮件参数:', param);
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/adminuser/BatchSendEmail",
|
||||
async: false,
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg("发送成功");
|
||||
} else {
|
||||
layer.msg(res.info || "发送失败");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// 记录当前道具配置项索引(用于动态生成唯一标识)
|
||||
var rewardItemIndex = 1;
|
||||
|
||||
/**
|
||||
* 动态添加道具配置项
|
||||
*/
|
||||
window.addRewardItem = function () {
|
||||
var targetContainer = $('#rewardItems');
|
||||
|
||||
var optionsHtml = '<option value="">请选择道具</option>';
|
||||
var groups = {};
|
||||
propList.forEach(function(item) {
|
||||
var typeName = getTypeName(item.type);
|
||||
if (!groups[typeName]) {
|
||||
groups[typeName] = [];
|
||||
}
|
||||
groups[typeName].push(item);
|
||||
});
|
||||
|
||||
for (var typeName in groups) {
|
||||
optionsHtml += '<optgroup label="' + typeName + '">';
|
||||
groups[typeName].forEach(function(item) {
|
||||
optionsHtml += '<option value="' + item.number + '">' + item.name + '</option>';
|
||||
});
|
||||
optionsHtml += '</optgroup>';
|
||||
}
|
||||
|
||||
var newItemHtml = `
|
||||
<div class="layui-form-item layui-form-text" data-index="${rewardItemIndex}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">赠送道具</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="itemNumber[${rewardItemIndex}]" lay-search class="layui-select">
|
||||
${optionsHtml}
|
||||
</select>
|
||||
<img class="prop-preview" src="" style="width:40px;height:40px;vertical-align:middle;margin-left:8px;display:none;">
|
||||
</div>
|
||||
<label class="layui-form-label">道具数量</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="number" name="itemCount[${rewardItemIndex}]" min="1" value="1" class="layui-input" style="width: 200px;">
|
||||
</div>
|
||||
<div class="layui-input-inline">
|
||||
<button type="button" class="layui-btn layui-btn-danger layui-btn-sm" onclick="removeRewardItem(${rewardItemIndex})">
|
||||
<i class="layui-icon layui-icon-close"></i> 删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
targetContainer.append(newItemHtml);
|
||||
form.render('select');
|
||||
form.render('input');
|
||||
rewardItemIndex++;
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除道具配置项
|
||||
*/
|
||||
window.removeRewardItem = function (index) {
|
||||
var allItems = $('.layui-form-item[data-index]');
|
||||
if (allItems.length <= 1) {
|
||||
layer.msg('至少保留1个道具配置项', { icon: 2, time: 1500 });
|
||||
return;
|
||||
}
|
||||
layer.confirm('确定要删除该道具配置吗?', {
|
||||
title: '删除确认',
|
||||
icon: 3
|
||||
}, function () {
|
||||
$(`.layui-form-item[data-index="${index}"]`).remove();
|
||||
layer.msg('删除成功', { icon: 1, time: 1200 });
|
||||
});
|
||||
};
|
||||
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,107 @@
|
||||
<title>邮件统计</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>邮件管理</cite></a>
|
||||
<a><cite>邮件统计</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm3">
|
||||
<div class="layuiadmin-card-elem">
|
||||
<div class="layuiadmin-stat-card bg-blue">
|
||||
<div class="stat-number" id="totalEmails">-</div>
|
||||
<div class="stat-desc">总邮件数</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm3">
|
||||
<div class="layuiadmin-card-elem">
|
||||
<div class="layuiadmin-stat-card bg-green">
|
||||
<div class="stat-number" id="todayEmails">-</div>
|
||||
<div class="stat-desc">今日发送</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm3">
|
||||
<div class="layuiadmin-card-elem">
|
||||
<div class="layuiadmin-stat-card bg-orange">
|
||||
<div class="stat-number" id="monthEmails">-</div>
|
||||
<div class="stat-desc">本月发送</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-sm3">
|
||||
<div class="layuiadmin-card-elem">
|
||||
<div class="layuiadmin-stat-card bg-red">
|
||||
<div class="stat-number" id="unclaimedEmails">-</div>
|
||||
<div class="stat-desc">未领取</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-row layui-col-space15" style="margin-top: 20px;">
|
||||
<div class="layui-col-sm3">
|
||||
<div class="layuiadmin-card-elem">
|
||||
<div class="layuiadmin-stat-card bg-cyan">
|
||||
<div class="stat-number" id="rewardEmails">-</div>
|
||||
<div class="stat-desc">已领取</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.layuiadmin-card-elem {
|
||||
padding: 15px;
|
||||
}
|
||||
.layuiadmin-stat-card {
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
}
|
||||
.bg-blue { background: #1E90FF; }
|
||||
.bg-green { background: #32CD32; }
|
||||
.bg-orange { background: #FF8C00; }
|
||||
.bg-red { background: #FF4500; }
|
||||
.bg-cyan { background: #00CED1; }
|
||||
.stat-number {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.stat-desc {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form'], function(){
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, setter = layui.setter;
|
||||
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/adminuser/GetEmailStatistics",
|
||||
dataType: "json",
|
||||
done: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
var data = res.data;
|
||||
$('#totalEmails').text(data.totalEmails || 0);
|
||||
$('#todayEmails').text(data.todayEmails || 0);
|
||||
$('#monthEmails').text(data.monthEmails || 0);
|
||||
$('#unclaimedEmails').text(data.unclaimedEmails || 0);
|
||||
$('#rewardEmails').text(data.rewardEmails || 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,408 @@
|
||||
<title>公告管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>系统</cite></a>
|
||||
<a><cite>公告管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/admin/lib/wangEditor/wangEditor.min.js"></script>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-notice-manage" lay-filter="LAY-notice-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-notice-toolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add"><i class="layui-icon layui-icon-add-1"></i> 发布公告</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="refresh"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-notice-bar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i> 编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete"><i class="layui-icon layui-icon-delete"></i> 删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var token = layui.data(setter.tableName)[setter.request.tokenName];
|
||||
var baseUrl = setter.baseurl + 'adminapi/Notice';
|
||||
var curPage = 1;
|
||||
var curLimit = 20;
|
||||
|
||||
function ajaxJson(url, data, done) {
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: 'post',
|
||||
contentType: 'application/json',
|
||||
headers: { 'token': token },
|
||||
data: JSON.stringify(data),
|
||||
success: done
|
||||
});
|
||||
}
|
||||
|
||||
function loadList(page, limit) {
|
||||
curPage = page || 1;
|
||||
curLimit = limit || 20;
|
||||
ajaxJson(baseUrl + '/list', { pageIndex: curPage, pageSize: curLimit }, function (res) {
|
||||
table.reload('LAY-notice-manage', {
|
||||
data: res.data || [],
|
||||
count: res.count || 0,
|
||||
page: { curr: curPage, limit: curLimit }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
table.render({
|
||||
elem: '#LAY-notice-manage',
|
||||
data: [],
|
||||
page: true,
|
||||
limit: 20,
|
||||
limits: [10, 20, 50, 100],
|
||||
toolbar: '#table-notice-toolbar',
|
||||
defaultToolbar: [],
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: 'title', title: '公告标题', minWidth: 200 },
|
||||
{ field: 'recommend', title: '简介', minWidth: 200 },
|
||||
{ field: 'topImage', title: '顶部图片', width: 120, templet: function(d) { return d.topImage ? '<img src="' + d.topImage + '" style="width:60px;height:36px;object-fit:cover;border-radius:3px;">' : '-'; } },
|
||||
{ field: 'createTime', title: '发布时间', width: 170, templet: function(d) {
|
||||
if (!d.createTime) return '-';
|
||||
var date = new Date(d.createTime * 1000);
|
||||
return date.getFullYear() + '-' +
|
||||
String(date.getMonth() + 1).padStart(2, '0') + '-' +
|
||||
String(date.getDate()).padStart(2, '0') + ' ' +
|
||||
String(date.getHours()).padStart(2, '0') + ':' +
|
||||
String(date.getMinutes()).padStart(2, '0') + ':' +
|
||||
String(date.getSeconds()).padStart(2, '0');
|
||||
}},
|
||||
{ width: 160, title: '操作', align: 'center', fixed: 'right', toolbar: '#table-notice-bar' }
|
||||
]]
|
||||
});
|
||||
|
||||
loadList(1, 20);
|
||||
|
||||
table.on('page(LAY-notice-manage)', function (obj) {
|
||||
loadList(obj.curr, obj.limit);
|
||||
});
|
||||
|
||||
table.on('toolbar(LAY-notice-manage)', function (obj) {
|
||||
if (obj.event === 'add') {
|
||||
showNoticeDialog('add', null);
|
||||
} else if (obj.event === 'refresh') {
|
||||
loadList(curPage, curLimit);
|
||||
}
|
||||
});
|
||||
|
||||
table.on('tool(LAY-notice-manage)', function (obj) {
|
||||
if (obj.event === 'edit') {
|
||||
$.ajax({
|
||||
url: baseUrl + '/get',
|
||||
method: 'get',
|
||||
headers: { 'token': token },
|
||||
data: { id: obj.data.id },
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
showNoticeDialog('edit', res.data);
|
||||
} else {
|
||||
layer.msg(res.info || '获取公告详情失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除公告「' + obj.data.title + '」吗?', function (idx) {
|
||||
$.ajax({
|
||||
url: baseUrl + '/delete',
|
||||
method: 'get',
|
||||
headers: { 'token': token },
|
||||
data: { id: obj.data.id },
|
||||
success: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.info || '删除成功');
|
||||
loadList(curPage, curLimit);
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showNoticeDialog(mode, data) {
|
||||
var isEdit = mode === 'edit';
|
||||
var title = isEdit ? '编辑公告' : '发布公告';
|
||||
// 公告图片先上传临时目录,公告保存成功后由服务端移动到 notice 目录。
|
||||
var uploadUrl = setter.baseurl + 'adminapi/ImageUpload/upload/temp';
|
||||
|
||||
var editor = null;
|
||||
var topImage = isEdit ? (data.topImage || data.TopImage || '') : '';
|
||||
var contentImages = isEdit ? ((data.contentImages || data.ContentImages || []).slice()) : [];
|
||||
|
||||
var html = '<div class="layui-form" lay-filter="notice-form" style="padding:20px 30px 0 0;">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">公告标题</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="title" lay-verify="required" placeholder="请输入公告标题" class="layui-input" value="' + (isEdit ? escHtml(data.title) : '') + '">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">简介</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="recommend" placeholder="请输入公告简介" class="layui-input" value="' + (isEdit ? escHtml(data.recommend || '') : '') + '">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">顶部图片</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="top-image-upload" style="display:flex;align-items:center;gap:10px;">' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="btn-upload-top">选择图片</button>' +
|
||||
'<div id="top-image-preview" style="max-width:200px;max-height:80px;' + (topImage ? '' : 'display:none') + '">' +
|
||||
(topImage ? '<img src="' + topImage + '" style="max-width:200px;max-height:80px;border-radius:4px;"><i class="layui-icon layui-icon-close-fill" style="position:relative;left:-16px;top:-30px;cursor:pointer;color:red;font-size:18px;" id="btn-remove-top"></i>' : '') +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="topImage" value="' + escHtml(topImage) + '">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">内容图片</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="btn-upload-content"><i class="layui-icon layui-icon-picture"></i> 添加图片</button>' +
|
||||
'<div id="content-images-list" style="margin-top:8px;display:flex;flex-wrap:wrap;gap:8px;">' +
|
||||
(contentImages.length ? contentImages.map(function(img, idx) {
|
||||
return '<div class="content-img-item" data-index="' + idx + '" style="position:relative;width:120px;height:80px;border:1px solid #e6e6e6;border-radius:4px;overflow:hidden;cursor:move;">' +
|
||||
'<img src="' + img + '" style="width:100%;height:100%;object-fit:cover;">' +
|
||||
'<i class="layui-icon layui-icon-close-fill btn-remove-img" style="position:absolute;top:2px;right:2px;cursor:pointer;color:red;font-size:18px;background:#fff;border-radius:50%;" title="删除"></i>' +
|
||||
'<div style="position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,0.5);color:#fff;font-size:11px;text-align:center;">第' + (idx+1) + '张</div>' +
|
||||
'</div>';
|
||||
}).join('') : '<div class="empty-tip" style="color:#999;font-size:13px;padding:8px 0;">尚未添加图片</div>') +
|
||||
'</div>' +
|
||||
'<input type="hidden" name="contentImages" id="content-images-input" value="' + escHtml(JSON.stringify(contentImages)) + '">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">内容</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div id="notice-content-editor" style="height:360px;border:1px solid #e6e6e6;border-radius:4px;"></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['850px', '780px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
yes: function (index) {
|
||||
var titleVal = $('input[name="title"]').val().trim();
|
||||
var recommendVal = $('input[name="recommend"]').val().trim();
|
||||
var contentVal = editor ? editor.txt.html().trim() : '';
|
||||
var topImageVal = $('input[name="topImage"]').val().trim();
|
||||
var contentImagesVal = [];
|
||||
|
||||
try {
|
||||
contentImagesVal = JSON.parse($('#content-images-input').val() || '[]');
|
||||
} catch(e) { contentImagesVal = []; }
|
||||
|
||||
if (!titleVal) { layer.msg('请输入公告标题'); return; }
|
||||
if (!contentVal) { layer.msg('请输入公告内容'); return; }
|
||||
|
||||
var reqData = isEdit
|
||||
? { id: data.id, title: titleVal, content: contentVal, recommend: recommendVal, topImage: topImageVal, contentImages: contentImagesVal }
|
||||
: { title: titleVal, content: contentVal, recommend: recommendVal, topImage: topImageVal, contentImages: contentImagesVal };
|
||||
|
||||
ajaxJson(baseUrl + (isEdit ? '/update' : '/add'), reqData, function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
layer.msg(res.info || (isEdit ? '修改成功' : '发布成功'));
|
||||
loadList(curPage, curLimit);
|
||||
} else {
|
||||
layer.msg(res.info || '操作失败');
|
||||
}
|
||||
});
|
||||
},
|
||||
success: function (layero) {
|
||||
form.render();
|
||||
|
||||
// 初始化 wangEditor 富文本编辑器
|
||||
editor = new window.wangEditor('#notice-content-editor');
|
||||
editor.config.placeholder = '请输入公告内容...';
|
||||
editor.config.zIndex = 2000;
|
||||
editor.config.excludeMenus = ['fontName', 'fontSize', 'code', 'codeBlock'];
|
||||
editor.config.customUploadImg = function (resultFiles, insertImgFn) {
|
||||
var fd = new FormData();
|
||||
fd.append('file', resultFiles[0]);
|
||||
$.ajax({
|
||||
url: uploadUrl,
|
||||
method: 'post',
|
||||
headers: { 'token': token },
|
||||
data: fd,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
insertImgFn(res.data.path || res.data);
|
||||
} else {
|
||||
layer.msg(res.info || '图片上传失败');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('图片上传失败');
|
||||
}
|
||||
});
|
||||
};
|
||||
editor.create();
|
||||
if (isEdit && data.content) {
|
||||
editor.txt.html(data.content);
|
||||
}
|
||||
|
||||
// 顶部图片上传
|
||||
var fileInput = $('<input type="file" accept="image/*" style="display:none">');
|
||||
layero.find('#btn-upload-top').after(fileInput);
|
||||
layero.find('#btn-upload-top').on('click', function() { fileInput.click(); });
|
||||
fileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (!file) return;
|
||||
var fd = new FormData();
|
||||
fd.append('file', file);
|
||||
$.ajax({
|
||||
url: uploadUrl,
|
||||
method: 'post',
|
||||
headers: { 'token': token },
|
||||
data: fd,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function(res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
var path = res.data.path || res.data;
|
||||
$('input[name="topImage"]').val(path);
|
||||
var preview = layero.find('#top-image-preview');
|
||||
preview.show().html('<img src="' + path + '" style="max-width:200px;max-height:80px;border-radius:4px;"><i class="layui-icon layui-icon-close-fill" style="position:relative;left:-16px;top:-30px;cursor:pointer;color:red;font-size:18px;" id="btn-remove-top"></i>');
|
||||
bindRemoveTop(layero);
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
this.value = '';
|
||||
});
|
||||
|
||||
bindRemoveTop(layero);
|
||||
|
||||
// 内容图片上传
|
||||
var contentFileInput = $('<input type="file" accept="image/*" style="display:none">');
|
||||
layero.find('#btn-upload-content').after(contentFileInput);
|
||||
layero.find('#btn-upload-content').on('click', function() { contentFileInput.click(); });
|
||||
contentFileInput.on('change', function() {
|
||||
var file = this.files[0];
|
||||
if (!file) return;
|
||||
var fd = new FormData();
|
||||
fd.append('file', file);
|
||||
$.ajax({
|
||||
url: uploadUrl,
|
||||
method: 'post',
|
||||
headers: { 'token': token },
|
||||
data: fd,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function(res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
var path = res.data.path || res.data;
|
||||
contentImages.push(path);
|
||||
renderContentImages(layero, contentImages);
|
||||
} else {
|
||||
layer.msg(res.info || '上传失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
this.value = '';
|
||||
});
|
||||
|
||||
// 内容图片拖拽排序
|
||||
var sortable = function(el) {
|
||||
var items = el.find('.content-img-item');
|
||||
var dragIdx = -1;
|
||||
items.each(function() {
|
||||
$(this).on('mousedown', function() {
|
||||
dragIdx = $(this).data('index');
|
||||
});
|
||||
});
|
||||
el.on('mouseup', '.content-img-item', function() {
|
||||
// 简单的点击交换:拖拽逻辑用 layui 自带的 sort 或简化版
|
||||
});
|
||||
};
|
||||
|
||||
// 启用拖拽排序(使用原生 drag API 简化实现)
|
||||
var contentListEl = layero.find('#content-images-list');
|
||||
contentListEl.on('dragstart', '.content-img-item', function(e) {
|
||||
e.originalEvent.dataTransfer.setData('text/plain', $(this).data('index'));
|
||||
});
|
||||
contentListEl.on('dragover', '.content-img-item', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
contentListEl.on('drop', '.content-img-item', function(e) {
|
||||
e.preventDefault();
|
||||
var fromIdx = parseInt(e.originalEvent.dataTransfer.getData('text/plain'));
|
||||
var toIdx = $(this).data('index');
|
||||
if (fromIdx !== toIdx && !isNaN(fromIdx) && !isNaN(toIdx)) {
|
||||
var item = contentImages.splice(fromIdx, 1)[0];
|
||||
contentImages.splice(toIdx, 0, item);
|
||||
renderContentImages(layero, contentImages);
|
||||
}
|
||||
});
|
||||
|
||||
// 内容图片删除
|
||||
contentListEl.on('click', '.btn-remove-img', function() {
|
||||
var idx = $(this).closest('.content-img-item').data('index');
|
||||
contentImages.splice(idx, 1);
|
||||
renderContentImages(layero, contentImages);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bindRemoveTop(layero) {
|
||||
layero.find('#btn-remove-top').off().on('click', function() {
|
||||
$('input[name="topImage"]').val('');
|
||||
layero.find('#top-image-preview').hide().empty();
|
||||
});
|
||||
}
|
||||
|
||||
function renderContentImages(layero, images) {
|
||||
var list = layero.find('#content-images-list');
|
||||
if (images.length === 0) {
|
||||
list.html('<div class="empty-tip" style="color:#999;font-size:13px;padding:8px 0;">尚未添加图片</div>');
|
||||
} else {
|
||||
list.html(images.map(function(img, idx) {
|
||||
return '<div class="content-img-item" data-index="' + idx + '" draggable="true" style="position:relative;width:120px;height:80px;border:1px solid #e6e6e6;border-radius:4px;overflow:hidden;cursor:move;display:inline-block;">' +
|
||||
'<img src="' + img + '" style="width:100%;height:100%;object-fit:cover;">' +
|
||||
'<i class="layui-icon layui-icon-close-fill btn-remove-img" style="position:absolute;top:2px;right:2px;cursor:pointer;color:red;font-size:18px;background:#fff;border-radius:50%;" title="删除"></i>' +
|
||||
'<div style="position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,0.5);color:#fff;font-size:11px;text-align:center;">第' + (idx+1) + '张</div>' +
|
||||
'</div>';
|
||||
}).join(''));
|
||||
}
|
||||
$('#content-images-input').val(JSON.stringify(images));
|
||||
}
|
||||
|
||||
function escHtml(str) {
|
||||
if (!str) return '';
|
||||
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,948 @@
|
||||
|
||||
<title>房间管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>游戏管理</cite></a>
|
||||
<a><cite>房间管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<!-- Tab切换 -->
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="room-tab-filter">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this" lay-id="fish">捕鱼房间</li>
|
||||
<li lay-id="chess">象棋房间</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<!-- 捕鱼房间 -->
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-room-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">房间等级</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="roomLevel" id="roomLevelFilter">
|
||||
<option value="">全部</option>
|
||||
<option value="1">初级场</option>
|
||||
<option value="2">中级场</option>
|
||||
<option value="3">高级场</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">游戏类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="gameType" id="gameTypeFilter">
|
||||
<option value="">全部</option>
|
||||
<option value="1">风雷之渊</option>
|
||||
<option value="2">永夜尸城</option>
|
||||
<option value="3">中国象棋</option>
|
||||
<option value="4">星际迷航</option>
|
||||
<option value="5">黑神话悟空</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">排序方式</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="sortField" id="sortFieldFilter">
|
||||
<option value="roomId" selected>按房间号</option>
|
||||
<option value="currentOnline">按当前在线</option>
|
||||
<option value="robotCount">按机器人数量</option>
|
||||
<option value="roomLevel">按房间等级</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">排序</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="sortOrder" id="sortOrderFilter">
|
||||
<option value="asc" selected>升序</option>
|
||||
<option value="desc">降序</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-room-search">
|
||||
<i class="layui-icon layui-icon-search"></i> 查询
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" id="LAY-room-refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-normal" id="LAY-room-auto-refresh">
|
||||
<i class="layui-icon layui-icon-loading"></i> 自动刷新:关
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-warm" id="LAY-room-init">
|
||||
<i class="layui-icon layui-icon-util"></i> 初始化房间
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总房间数</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="stat-total-rooms">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">在线玩家</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="stat-total-players" style="color: #5FB878;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">机器人</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="stat-total-robots" style="color: #FFB800;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总人数</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="stat-total-count" style="color: #1E9FFF;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<button class="layui-btn layui-btn-normal" id="btn-regenerate-bot-ids">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 一键刷新机器人编号
|
||||
</button>
|
||||
|
||||
<table id="LAY-room-manage" lay-filter="LAY-room-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-room-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">
|
||||
<i class="layui-icon layui-icon-about"></i> 详情
|
||||
</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="addRobot">
|
||||
<i class="layui-icon layui-icon-add-1"></i> 添加机器人
|
||||
</a>
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="setRobot">
|
||||
<i class="layui-icon layui-icon-set"></i> 设置机器人
|
||||
</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="clear">
|
||||
<i class="layui-icon layui-icon-close"></i> 清空玩家
|
||||
</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 象棋房间 -->
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-chess-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">房间状态</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="state" id="chessStateFilter">
|
||||
<option value="">全部</option>
|
||||
<option value="0">空房</option>
|
||||
<option value="1">待开始</option>
|
||||
<option value="2">进行中</option>
|
||||
<option value="3">已结束</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">游戏类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="gameType" id="chessGameTypeFilter">
|
||||
<option value="">全部</option>
|
||||
<option value="1">我方黑</option>
|
||||
<option value="2">我方红</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" lay-submit lay-filter="LAY-chess-search">
|
||||
<i class="layui-icon layui-icon-search"></i> 查询
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" id="LAY-chess-refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-normal" id="LAY-chess-auto-refresh">
|
||||
<i class="layui-icon layui-icon-loading"></i> 自动刷新:关
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-warm" id="LAY-chess-reinit">
|
||||
<i class="layui-icon layui-icon-util"></i> 重新初始化象棋房间
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<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 layui-text">
|
||||
<h3 id="chess-stat-total">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">空房率</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="chess-stat-waiting" style="color: #FFB800;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">进行中</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="chess-stat-playing" style="color: #5FB878;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">已结束</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="chess-stat-finished" style="color: #999;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">黑方玩家</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="chess-stat-black" style="color: #393939;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md2">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">红方玩家</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<h3 id="chess-stat-red" style="color: #FF5722;">0</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<table id="LAY-chess-room-manage" lay-filter="LAY-chess-room-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-chess-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="detail">
|
||||
<i class="layui-icon layui-icon-about"></i> 详情
|
||||
</a>
|
||||
<a class="layui-btn layui-btn-xs" lay-event="addRobot">
|
||||
<i class="layui-icon layui-icon-add-1"></i> 添加机器人
|
||||
</a>
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="setRobot">
|
||||
<i class="layui-icon layui-icon-edit"></i> 设置机器人
|
||||
</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="clear">
|
||||
<i class="layui-icon layui-icon-close"></i> 清空房间
|
||||
</a>
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="delete">
|
||||
<i class="layui-icon layui-icon-delete"></i> 删除
|
||||
</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'element'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
element = layui.element,
|
||||
setter = layui.setter,
|
||||
layer = layui.layer;
|
||||
|
||||
var autoRefreshFish = false;
|
||||
var refreshIntervalFish = null;
|
||||
var autoRefreshChess = false;
|
||||
var refreshIntervalChess = null;
|
||||
|
||||
form.render();
|
||||
|
||||
// ============ 捕鱼房间 ============
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-room-manage",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/GetAllRooms",
|
||||
method: "get",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: { curr: 1, limit: 20 },
|
||||
where: {
|
||||
roomLevel: "",
|
||||
gameType: "",
|
||||
sortField: "roomId",
|
||||
sortOrder: "asc"
|
||||
},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 20,
|
||||
cols: [[
|
||||
{ field: "roomId", title: "房间ID", width: 180, fixed: 'left' },
|
||||
{ field: "roomName", title: "房间名称", width: 120 },
|
||||
{ field: "roomLevel", title: "等级", width: 80 },
|
||||
{ field: "roomPartition", title: "分区", width: 70 },
|
||||
{ field: "roomNumber", title: "编号", width: 70 },
|
||||
{ field: "gameType", title: "游戏类型", width: 100 },
|
||||
{ field: "maxPlayerCount", title: "最大人数", width: 90 },
|
||||
{ field: "currentOnlinePlayerCount", title: "当前在线", width: 90, templet: function(d) {
|
||||
var count = d.currentOnlinePlayerCount || 0;
|
||||
return '<span class="layui-badge layui-bg-green">' + count + '</span>';
|
||||
}},
|
||||
{ field: "robotCount", title: "机器人", width: 90, templet: function(d) {
|
||||
var count = d.robotCount || 0;
|
||||
return '<span class="layui-badge layui-bg-orange">' + count + '</span>';
|
||||
}},
|
||||
{
|
||||
field: "players", title: "玩家列表", minWidth: 200, templet: function(d) {
|
||||
if (!d.players || d.players.length === 0) return '-';
|
||||
var names = d.players.map(p => p.userName || p.userId).slice(0, 3);
|
||||
var result = names.join(', ');
|
||||
if (d.players.length > 3) result += ' 等' + d.players.length + '人';
|
||||
return result;
|
||||
}
|
||||
},
|
||||
{ width: 260, title: "操作", align: "center", fixed: "right", toolbar: "#table-room-admin" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
},
|
||||
done: function(res) {
|
||||
loadStatistics();
|
||||
}
|
||||
});
|
||||
|
||||
function loadStatistics() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/GetRoomStatistics",
|
||||
done: function(res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
$('#stat-total-rooms').text(res.data.totalRooms || 0);
|
||||
$('#stat-total-players').text(res.data.totalPlayers || 0);
|
||||
$('#stat-total-robots').text(res.data.totalRobots || 0);
|
||||
$('#stat-total-count').text((res.data.totalPlayers || 0) + (res.data.totalRobots || 0));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
form.on('submit(LAY-room-search)', function (data) {
|
||||
table.reload('LAY-room-manage', {
|
||||
where: {
|
||||
roomLevel: data.field.roomLevel || '',
|
||||
gameType: data.field.gameType || '',
|
||||
sortField: data.field.sortField || 'roomId',
|
||||
sortOrder: data.field.sortOrder || 'desc'
|
||||
},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#LAY-room-refresh').on('click', function () {
|
||||
table.reload('LAY-room-manage');
|
||||
});
|
||||
|
||||
$('#btn-regenerate-bot-ids').on('click', function () {
|
||||
layer.confirm('确定要刷新所有机器人的编号吗?机器人将获得新的ID和编号。', function (index) {
|
||||
layer.close(index);
|
||||
var loadIndex = layer.load(2);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/RegenerateAllBotIds",
|
||||
done: function (res) {
|
||||
layer.close(loadIndex);
|
||||
layer.msg(res.info || '刷新成功');
|
||||
table.reload('LAY-room-manage');
|
||||
},
|
||||
error: function () {
|
||||
layer.close(loadIndex);
|
||||
layer.msg('操作失败');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#LAY-room-auto-refresh').on('click', function () {
|
||||
autoRefreshFish = !autoRefreshFish;
|
||||
var btn = $(this);
|
||||
if (autoRefreshFish) {
|
||||
btn.html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i> 自动刷新:开');
|
||||
btn.addClass('layui-btn-normal');
|
||||
refreshIntervalFish = setInterval(function () {
|
||||
table.reload('LAY-room-manage', { page: { curr: 1 } });
|
||||
}, 5000);
|
||||
} else {
|
||||
btn.html('<i class="layui-icon layui-icon-loading"></i> 自动刷新:关');
|
||||
btn.removeClass('layui-btn-normal');
|
||||
if (refreshIntervalFish) {
|
||||
clearInterval(refreshIntervalFish);
|
||||
refreshIntervalFish = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#LAY-room-init').on('click', function () {
|
||||
layer.confirm('确定要重新初始化所有房间吗?此操作将清空现有房间数据并重新生成。', function (index) {
|
||||
var btn = $(this);
|
||||
btn.html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i> 初始化中...');
|
||||
btn.attr('disabled', true);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/InitRooms",
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.info || '房间初始化成功', { icon: 1 });
|
||||
table.reload('LAY-room-manage');
|
||||
loadStatistics();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
$('#LAY-room-init').html('<i class="layui-icon layui-icon-util"></i> 初始化房间');
|
||||
$('#LAY-room-init').attr('disabled', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
table.on("tool(LAY-room-manage)", function (obj) {
|
||||
var data = obj.data;
|
||||
|
||||
if ("detail" === obj.event) {
|
||||
showFishRoomDetail(data);
|
||||
}
|
||||
|
||||
if ("addRobot" === obj.event) {
|
||||
layer.prompt({
|
||||
title: '添加机器人 - ' + data.roomName,
|
||||
formType: 0
|
||||
}, function (value, index, elem) {
|
||||
var count = parseInt(value) || 0;
|
||||
if (count <= 0) {
|
||||
layer.msg('请输入有效的数量');
|
||||
return;
|
||||
}
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/AddRobot",
|
||||
data: {
|
||||
roomId: data.roomId,
|
||||
count: count
|
||||
},
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg(res.info || '添加成功');
|
||||
table.reload('LAY-room-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ("setRobot" === obj.event) {
|
||||
layer.prompt({
|
||||
title: '设置机器人数量 - ' + data.roomName,
|
||||
formType: 0,
|
||||
value: data.robotCount || 0
|
||||
}, function (value, index, elem) {
|
||||
var count = parseInt(value) || 0;
|
||||
if (count < 0) {
|
||||
layer.msg('数量不能为负数');
|
||||
return;
|
||||
}
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/SetRobotCount",
|
||||
data: {
|
||||
roomId: data.roomId,
|
||||
count: count
|
||||
},
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg(res.info || '设置成功');
|
||||
table.reload('LAY-room-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ("clear" === obj.event) {
|
||||
layer.confirm('确定清空房间 ' + data.roomName + ' 的所有玩家吗?', function (index) {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/ClearRoom",
|
||||
data: {
|
||||
roomId: data.roomId
|
||||
},
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.info || '清空成功');
|
||||
} else {
|
||||
layer.msg(res.info || '清空失败');
|
||||
}
|
||||
table.reload('LAY-room-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showFishRoomDetail(room) {
|
||||
var playersHtml = '';
|
||||
if (room.players && room.players.length > 0) {
|
||||
playersHtml = '<table class="layui-table"><thead><tr><th>玩家ID</th><th>昵称</th><th>金币</th><th>炮倍</th><th>位置</th></tr></thead><tbody>';
|
||||
room.players.forEach(function (p) {
|
||||
playersHtml += '<tr><td>' + (p.userId || '-') + '</td><td>' + (p.userName || '-') + '</td><td>' + (p.gold || 0) + '</td><td>' + (p.cannonMultiple || 0) + '</td><td>' + (p.position || 0) + '</td></tr>';
|
||||
});
|
||||
playersHtml += '</tbody></table>';
|
||||
} else {
|
||||
playersHtml = '<p style="text-align:center;color:#999;">暂无玩家</p>';
|
||||
}
|
||||
|
||||
var content =
|
||||
'<div style="padding: 20px;">' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>房间信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p>房间ID:' + (room.roomId || '-') + '</p>' +
|
||||
'<p>房间名称:' + (room.roomName || '-') + '</p>' +
|
||||
'<p>游戏类型:' + (room.gameType || '-') + '</p>' +
|
||||
'<p>房间等级:' + (room.roomLevel || '-') + '</p>' +
|
||||
'<p>房间分区:' + (room.roomPartition || '-') + '</p>' +
|
||||
'<p>房间编号:' + (room.roomNumber || '-') + '</p>' +
|
||||
'<p>最大人数:' + (room.maxPlayerCount || 0) + '</p>' +
|
||||
'<p>当前在线:' + (room.currentOnlinePlayerCount || 0) + '</p>' +
|
||||
'<p>机器人数:' + (room.robotCount || 0) + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>玩家列表 (' + (room.players ? room.players.length : 0) + '人)</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
playersHtml +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '房间详情',
|
||||
area: ['700px', '600px'],
|
||||
content: content
|
||||
});
|
||||
}
|
||||
|
||||
// ============ 象棋房间 ============
|
||||
|
||||
function renderChessTable(state, gameType) {
|
||||
table.render({
|
||||
elem: "#LAY-chess-room-manage",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/GetAllChessRooms",
|
||||
method: "get",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
where: {
|
||||
state: state || "",
|
||||
gameType: gameType || ""
|
||||
},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 20,
|
||||
parseData: function(res) {
|
||||
console.log('象棋房间数据:', res);
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.info,
|
||||
"count": res.count,
|
||||
"data": res.data || []
|
||||
};
|
||||
},
|
||||
cols: [[
|
||||
{ field: "roomId", title: "房间ID", width: 200, fixed: 'left', templet: function(d) {
|
||||
return d.roomId || '-';
|
||||
}},
|
||||
{ field: "state", title: "状态", width: 100, templet: function(d) {
|
||||
var stateMap = {0: '<span class="layui-badge layui-bg-blue">空房</span>', 1: '<span class="layui-badge layui-bg-orange">待开始</span>', 2: '<span class="layui-badge layui-bg-green">进行中</span>', 3: '<span class="layui-badge layui-bg-gray">已结束</span>'};
|
||||
return stateMap[d.state] || '-';
|
||||
}},
|
||||
{ field: "gameType", title: "游戏类型", width: 100, templet: function(d) {
|
||||
return d.gameType === 1 ? '我方黑' : '我方红';
|
||||
}},
|
||||
{ field: "gold", title: "房间金币", width: 120 },
|
||||
{ field: "password", title: "密码", width: 100, templet: function(d) {
|
||||
return d.password ? '<span class="layui-badge">有密码</span>' : '<span class="layui-badge layui-bg-green">无</span>';
|
||||
}},
|
||||
{ field: "createTime", title: "创建时间", width: 170, templet: function(d) {
|
||||
var ct = d.createTime || d.CreateTime;
|
||||
if (!ct) return '-';
|
||||
var date = new Date(ct);
|
||||
return date.getFullYear() + '-' +
|
||||
String(date.getMonth() + 1).padStart(2, '0') + '-' +
|
||||
String(date.getDate()).padStart(2, '0') + ' ' +
|
||||
String(date.getHours()).padStart(2, '0') + ':' +
|
||||
String(date.getMinutes()).padStart(2, '0') + ':' +
|
||||
String(date.getSeconds()).padStart(2, '0');
|
||||
}},
|
||||
{ field: "userCount", title: "玩家数", width: 80, templet: function(d) {
|
||||
var count = (d.users && d.users.length) || 0;
|
||||
return '<span class="layui-badge">' + count + '/2</span>';
|
||||
}},
|
||||
{ field: "robotCount", title: "机器人", width: 80, templet: function(d) {
|
||||
var count = d.robotCount || 0;
|
||||
return '<span class="layui-badge layui-bg-orange">' + count + '</span>';
|
||||
}},
|
||||
{ field: "users", title: "玩家信息", minWidth: 250, templet: function(d) {
|
||||
if (!d.users || d.users.length === 0) return '<span style="color:#999;">暂无玩家</span>';
|
||||
var html = '<div style="display:flex;gap:10px;">';
|
||||
d.users.forEach(function(u) {
|
||||
var side = u.type === 1 ? '黑方' : '红方';
|
||||
var ready = u.isReady ? '<span class="layui-badge layui-bg-green">已准备</span>' : '<span class="layui-badge layui-bg-gray">未准备</span>';
|
||||
html += '<div style="background:#f5f5f5;padding:5px 10px;border-radius:3px;">' +
|
||||
'<div style="font-weight:bold;">' + (u.userName || u.userId) + '</div>' +
|
||||
'<div style="font-size:12px;color:#666;">' + side + '</div>' +
|
||||
'<div style="font-size:12px;">' + ready + '</div>' +
|
||||
'</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
return html;
|
||||
}},
|
||||
{ width: 220, title: "操作", align: "center", fixed: "right", toolbar: "#table-chess-admin" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
},
|
||||
done: function(res) {
|
||||
loadChessStatistics();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadChessStatistics() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/GetChessRoomStatistics",
|
||||
done: function(res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
$('#chess-stat-total').text(res.data.totalRooms || 0);
|
||||
$('#chess-stat-waiting').text((res.data.emptyRooms || 0) + ' (' + (res.data.emptyRoomRate || 0) + '%)');
|
||||
$('#chess-stat-playing').text(res.data.playingRooms || 0);
|
||||
$('#chess-stat-finished').text(res.data.finishedRooms || 0);
|
||||
$('#chess-stat-black').text(res.data.blackSidePlayers || 0);
|
||||
$('#chess-stat-red').text(res.data.redSidePlayers || 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
form.on('submit(LAY-chess-search)', function (data) {
|
||||
renderChessTable(data.field.state, data.field.gameType);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#LAY-chess-refresh').on('click', function () {
|
||||
table.reload('LAY-chess-room-manage');
|
||||
});
|
||||
|
||||
$('#LAY-chess-reinit').on('click', function () {
|
||||
layer.confirm('确定要清空所有象棋房间并重新初始化吗?此操作不可恢复!', function (index) {
|
||||
var btn = $(this);
|
||||
btn.html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i> 初始化中...');
|
||||
btn.attr('disabled', true);
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/ReInitChessRooms",
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg(res.info || '初始化成功', { icon: 1 });
|
||||
table.reload('LAY-chess-room-manage');
|
||||
loadChessStatistics();
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
$('#LAY-chess-reinit').html('<i class="layui-icon layui-icon-util"></i> 重新初始化象棋房间');
|
||||
$('#LAY-chess-reinit').attr('disabled', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#LAY-chess-auto-refresh').on('click', function () {
|
||||
autoRefreshChess = !autoRefreshChess;
|
||||
var btn = $(this);
|
||||
if (autoRefreshChess) {
|
||||
btn.html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i> 自动刷新:开');
|
||||
btn.addClass('layui-btn-normal');
|
||||
refreshIntervalChess = setInterval(function () {
|
||||
table.reload('LAY-chess-room-manage');
|
||||
}, 5000);
|
||||
} else {
|
||||
btn.html('<i class="layui-icon layui-icon-loading"></i> 自动刷新:关');
|
||||
btn.removeClass('layui-btn-normal');
|
||||
if (refreshIntervalChess) {
|
||||
clearInterval(refreshIntervalChess);
|
||||
refreshIntervalChess = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
table.on("tool(LAY-chess-room-manage)", function (obj) {
|
||||
var data = obj.data;
|
||||
|
||||
if ("detail" === obj.event) {
|
||||
showChessRoomDetail(data);
|
||||
}
|
||||
|
||||
if ("clear" === obj.event) {
|
||||
layer.confirm('确定清空房间 ' + data.roomId + ' 的所有玩家吗?', function (index) {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/ClearChessRoom",
|
||||
data: {
|
||||
roomId: data.roomId
|
||||
},
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.info || '清空成功');
|
||||
} else {
|
||||
layer.msg(res.info || '清空失败');
|
||||
}
|
||||
table.reload('LAY-chess-room-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if ("addRobot" === obj.event) {
|
||||
layer.prompt({
|
||||
title: '添加机器人 - ' + data.roomId,
|
||||
formType: 0
|
||||
}, function (value, index, elem) {
|
||||
var count = parseInt(value) || 0;
|
||||
if (count <= 0) {
|
||||
layer.msg('请输入有效的数量');
|
||||
return;
|
||||
}
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/AddChessRobot",
|
||||
data: {
|
||||
roomId: data.roomId,
|
||||
count: count
|
||||
},
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg(res.info || '添加成功');
|
||||
table.reload('LAY-chess-room-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ("setRobot" === obj.event) {
|
||||
var currentCount = data.robotCount || 0;
|
||||
layer.prompt({
|
||||
title: '设置机器人数量 - ' + data.roomId + ' (当前: ' + currentCount + ')',
|
||||
formType: 0,
|
||||
value: currentCount
|
||||
}, function (value, index, elem) {
|
||||
var count = parseInt(value);
|
||||
if (isNaN(count) || count < 0 || count > 2) {
|
||||
layer.msg('请输入0~2的整数');
|
||||
return;
|
||||
}
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/SetChessRobot",
|
||||
data: {
|
||||
roomId: data.roomId,
|
||||
count: count
|
||||
},
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg(res.info || '设置成功');
|
||||
table.reload('LAY-chess-room-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ("delete" === obj.event) {
|
||||
layer.confirm('确定删除房间 ' + data.roomId + ' 吗?此操作不可恢复!', function (index) {
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/Admin/Room/DeleteChessRoom",
|
||||
data: {
|
||||
roomId: data.roomId
|
||||
},
|
||||
done: function (res) {
|
||||
layer.close(index);
|
||||
layer.msg(res.info || '删除成功');
|
||||
table.reload('LAY-chess-room-manage');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showChessRoomDetail(room) {
|
||||
var stateMap = {0: '空房', 1: '待开始', 2: '进行中', 3: '已结束'};
|
||||
var typeMap = {1: '我方黑', 2: '我方红'};
|
||||
|
||||
var usersHtml = '';
|
||||
if (room.users && room.users.length > 0) {
|
||||
usersHtml = '<table class="layui-table"><thead><tr><th>玩家ID</th><th>昵称</th><th>阵营</th><th>状态</th><th>金币</th><th>操作</th></tr></thead><tbody>';
|
||||
room.users.forEach(function (u) {
|
||||
usersHtml += '<tr>' +
|
||||
'<td>' + (u.userId || '-') + '</td>' +
|
||||
'<td>' + (u.userName || '-') + '</td>' +
|
||||
'<td>' + (typeMap[u.type] || '-') + '</td>' +
|
||||
'<td>' + (u.isReady ? '已准备' : '未准备') + '</td>' +
|
||||
'<td>' + (u.gold || 0) + '</td>' +
|
||||
'<td><button type="button" class="layui-btn layui-btn-danger layui-btn-xs chess-kick-player" ' +
|
||||
'data-room-id="' + (room.roomId || room.RoomId || '') + '" data-user-id="' + (u.userId || '') + '" ' +
|
||||
(room.state === 2 ? 'disabled title="游戏进行中不能踢人"' : '') + '>踢出</button></td>' +
|
||||
'</tr>';
|
||||
});
|
||||
usersHtml += '</tbody></table>';
|
||||
} else {
|
||||
usersHtml = '<p style="text-align:center;color:#999;">暂无玩家</p>';
|
||||
}
|
||||
|
||||
var createTimeStr = '-';
|
||||
var ct = room.createTime || room.CreateTime;
|
||||
if (ct) {
|
||||
var date = new Date(ct);
|
||||
createTimeStr = date.getFullYear() + '-' +
|
||||
String(date.getMonth() + 1).padStart(2, '0') + '-' +
|
||||
String(date.getDate()).padStart(2, '0') + ' ' +
|
||||
String(date.getHours()).padStart(2, '0') + ':' +
|
||||
String(date.getMinutes()).padStart(2, '0') + ':' +
|
||||
String(date.getSeconds()).padStart(2, '0');
|
||||
}
|
||||
|
||||
var content =
|
||||
'<div style="padding: 20px;">' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>房间信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p>房间ID:' + (room.roomId || room.RoomId || '-') + '</p>' +
|
||||
'<p>房间状态:' + (stateMap[room.state] || '-') + '</p>' +
|
||||
'<p>游戏类型:' + (typeMap[room.gameType] || '-') + '</p>' +
|
||||
'<p>房间金币:' + (room.gold || 0) + '</p>' +
|
||||
'<p>密码:' + (room.password ? room.password : '无') + '</p>' +
|
||||
'<p>创建时间:' + createTimeStr + '</p>' +
|
||||
'<p>机器人数:' + (room.robotCount || 0) + '</p>' +
|
||||
'<p>创建者:' + (room.createUserId || '-') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>玩家列表 (' + ((room.users && room.users.length) || 0) + '人)</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
usersHtml +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '象棋房间详情',
|
||||
area: ['700px', '600px'],
|
||||
content: content,
|
||||
success: function(layero, index) {
|
||||
layero.find('.chess-kick-player').on('click', function() {
|
||||
var button = $(this);
|
||||
var roomId = button.attr('data-room-id');
|
||||
var userId = button.attr('data-user-id');
|
||||
if (button.prop('disabled')) return;
|
||||
layer.confirm('确定将玩家 ' + userId + ' 踢出房间 ' + roomId + ' 吗?', function(confirmIndex) {
|
||||
button.prop('disabled', true);
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/Admin/Room/KickChessPlayer',
|
||||
data: { roomId: roomId, userId: userId },
|
||||
done: function(res) {
|
||||
layer.close(confirmIndex);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.info || '踢人指令已提交', { icon: 1 });
|
||||
layer.close(index);
|
||||
setTimeout(function() {
|
||||
table.reload('LAY-chess-room-manage');
|
||||
loadChessStatistics();
|
||||
}, 800);
|
||||
} else {
|
||||
button.prop('disabled', false);
|
||||
layer.msg(res.info || '踢人失败', { icon: 2 });
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 页面切换时渲染象棋表格
|
||||
element.on('tab(room-tab-filter)', function(data){
|
||||
if (data.index === 1) {
|
||||
renderChessTable('', '');
|
||||
}
|
||||
});
|
||||
|
||||
// 页面卸载时清除定时器
|
||||
$(window).on('unload', function () {
|
||||
if (refreshIntervalFish) clearInterval(refreshIntervalFish);
|
||||
if (refreshIntervalChess) clearInterval(refreshIntervalChess);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
|
||||
<title>邮件服务</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>设置</cite></a>
|
||||
<a><cite>邮件服务</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">邮件服务</div>
|
||||
<div class="layui-card-body">
|
||||
|
||||
<div class="layui-form" wid100 lay-filter="">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SMTP服务器</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="smtp_server" value="smtp.aliyun.com" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">如:smtp.163.com</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">SMTP端口号</label>
|
||||
<div class="layui-input-inline" style="width: 80px;">
|
||||
<input type="text" name="cache" lay-verify="number" value="25" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">一般为 25 或 465</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">发件人邮箱</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="send_email" value="xianxin@layui-inc.com" lay-verify="email" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">发件人昵称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="send_nickname" value="贤心" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱登入密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="send_nickname" value="123456" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="set_system_email">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use('set', layui.factory('set'));
|
||||
</script>
|
||||
@@ -0,0 +1,93 @@
|
||||
<title>网站设置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>设置</cite></a>
|
||||
<a><cite>网站设置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">网站设置</div>
|
||||
<div class="layui-card-body" pad15>
|
||||
|
||||
<div class="layui-form" wid100 lay-filter="">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="sitename" value="layuiAdmin" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">网站域名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="domain" lay-verify="url" value="http://www.layui.com" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">缓存时间</label>
|
||||
<div class="layui-input-inline" style="width: 80px;">
|
||||
<input type="text" name="cache" lay-verify="number" value="0" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-input-inline layui-input-company">分钟</div>
|
||||
<div class="layui-form-mid layui-word-aux">本地开发一般推荐设置为 0,线上环境建议设置为 10。</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">最大文件上传</label>
|
||||
<div class="layui-input-inline" style="width: 80px;">
|
||||
<input type="text" name="cache" lay-verify="number" value="2048" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-input-inline layui-input-company">KB</div>
|
||||
<div class="layui-form-mid layui-word-aux">提示:1 M = 1024 KB</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上传文件类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="cache" value="png|gif|jpg|jpeg|zip|rar" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">首页标题</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="title" class="layui-textarea">layuiAdmin 通用后台管理模板系统</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">META关键词</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="keywords" class="layui-textarea" placeholder="多个关键词用英文状态 , 号分割"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">META描述</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="descript" class="layui-textarea">layuiAdmin 是 layui 官方出品的通用型后台模板解决方案,提供了单页版和 iframe 版两种开发模式。layuiAdmin 是目前非常流行的后台模板框架,广泛用于各类管理平台。</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">版权信息</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="copyright" class="layui-textarea">© 2018 layui.com MIT license</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="set_website">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use('set', layui.factory('set'));
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
<div class="layui-card-header">版本信息</div>
|
||||
<div class="layui-card-body layui-text layadmin-about">
|
||||
<script type="text/html" template>
|
||||
<p>当前版本:layuiAdmin-v{{ layui.admin.v }}</p>
|
||||
<p>基于框架:layui-v{{ layui.v }}</p>
|
||||
</script>
|
||||
<div class="layui-btn-container">
|
||||
<a href="http://www.layui.com/admin/" target="_blank" class="layui-btn layui-btn-danger">获取授权</a>
|
||||
<a href="http://fly.layui.com/download/layuiAdmin/" target="_blank" class="layui-btn">下载新版</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card-header">关于版权</div>
|
||||
<div class="layui-card-body layui-text layadmin-about">
|
||||
|
||||
<blockquote class="layui-elem-quote" style="border: none;">
|
||||
layuiAdmin 受国家计算机软件著作权保护,未经官网正规渠道授权擅自公开产品源文件、以及直接对产品二次出售的,我们将保留追究法律责任的权利。
|
||||
</blockquote>
|
||||
<p>© 2018 <a href="http://www.layui.com/">layui.com</a> 版权所有</p>
|
||||
</div>
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
<title>设置我的资料</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>设置</cite></a>
|
||||
<a><cite>我的资料</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">设置我的资料</div>
|
||||
<div class="layui-card-body" pad15>
|
||||
|
||||
<div class="layui-form" lay-filter="">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">我的角色</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="role" lay-verify="">
|
||||
<option value="1" selected>超级管理员</option>
|
||||
<option value="2" disabled>普通管理员</option>
|
||||
<option value="3" disabled>审核员</option>
|
||||
<option value="4" disabled>编辑人员</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">当前角色不可更改为其它角色</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="username" value="xianxin" readonly class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">不可修改。一般用于后台登入名</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">昵称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="nickname" value="贤心" lay-verify="nickname" autocomplete="off" placeholder="请输入昵称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">性别</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="sex" value="男" title="男">
|
||||
<input type="radio" name="sex" value="女" title="女" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="avatar" lay-verify="required" id="LAY_avatarSrc" placeholder="图片地址" value="http://cdn.layui.com/avatar/168.jpg" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-input-inline layui-btn-container" style="width: auto;">
|
||||
<button type="button" class="layui-btn layui-btn-primary" id="LAY_avatarUpload">
|
||||
<i class="layui-icon"></i>上传图片
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" layadmin-event="avartatPreview">查看图片</button >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="cellphone" value="" lay-verify="phone" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="email" value="" lay-verify="email" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="remarks" placeholder="请输入内容" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="setmyinfo">确认修改</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重新填写</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use('set', layui.factory('set'));
|
||||
</script>
|
||||
@@ -0,0 +1,53 @@
|
||||
<title>设置我的密码</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>设置</cite></a>
|
||||
<a><cite>我的密码</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">修改密码</div>
|
||||
<div class="layui-card-body" pad15>
|
||||
|
||||
<div class="layui-form" lay-filter="">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">当前密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="oldPassword" lay-verify="required" lay-verType="tips" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">新密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="password" lay-verify="pass" lay-verType="tips" autocomplete="off" id="LAY_password" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">6到16个字符</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">确认新密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="password" name="repassword" lay-verify="repass" lay-verType="tips" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="setmypass">确认修改</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use('set', layui.factory('set'));
|
||||
</script>
|
||||
@@ -0,0 +1,683 @@
|
||||
|
||||
<title>常见问题管理</title>
|
||||
|
||||
<link rel="stylesheet" href="/admin/component/pear/css/pear Module.css" />
|
||||
|
||||
<style>
|
||||
.faq-container { display: flex; gap: 15px; height: calc(100vh - 180px); }
|
||||
.faq-tree-panel { width: 280px; background: #fff; border-radius: 4px; padding: 15px; overflow: auto; }
|
||||
.faq-question-panel { flex: 1; background: #fff; border-radius: 4px; padding: 15px; }
|
||||
.tree-toolbar { margin-bottom: 15px; display: flex; gap: 8px; }
|
||||
.tree-node-item {
|
||||
padding: 8px 12px;
|
||||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.tree-node-item:hover { background: #f5f5f5; }
|
||||
.tree-node-item.active { background: #e6f7f5; border-color: #009688; }
|
||||
.tree-node-item .node-info { display: flex; align-items: center; gap: 8px; flex: 1; }
|
||||
.tree-node-item .node-actions { display: flex; gap: 5px; opacity: 0; }
|
||||
.tree-node-item:hover .node-actions { opacity: 1; }
|
||||
.tree-node-item .node-actions a { color: #666; font-size: 12px; }
|
||||
.tree-node-item .node-actions a:hover { color: #009688; }
|
||||
.tree-node-item .node-actions a.delete:hover { color: #f56c6c; }
|
||||
.tree-children { margin-left: 20px; }
|
||||
.icon-preview { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 14px; }
|
||||
.edit-dialog .layui-form-item { margin-bottom: 15px; }
|
||||
.edit-dialog .layui-form-label { width: 90px; }
|
||||
.edit-dialog .layui-input-block { margin-left: 110px; }
|
||||
.rich-editor { min-height: 200px; border: 1px solid #e6e6e6; border-radius: 4px; padding: 10px; }
|
||||
.rich-editor-toolbar { border-bottom: 1px solid #e6e6e6; padding: 5px; background: #fafafa; }
|
||||
.rich-editor-toolbar button { padding: 3px 8px; margin-right: 3px; border: 1px solid #ddd; background: #fff; border-radius: 3px; cursor: pointer; }
|
||||
.rich-editor-toolbar button:hover { background: #eee; }
|
||||
.rich-editor-content { min-height: 180px; padding: 10px; outline: none; }
|
||||
/* 图标选择器样式 */
|
||||
.icon-selector { position: relative; }
|
||||
.icon-selector .icon-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
min-height: 38px;
|
||||
}
|
||||
.icon-selector .icon-display:hover { border-color: #009688; }
|
||||
.icon-selector .icon-display .icon-preview { font-size: 18px; color: #666; }
|
||||
.icon-selector .icon-display .icon-placeholder { color: #999; font-size: 12px; }
|
||||
.icon-selector .icon-dropdown {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
z-index: 9999;
|
||||
padding: 10px;
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.icon-selector .icon-dropdown.show { display: block; }
|
||||
.icon-selector .icon-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; }
|
||||
.icon-selector .icon-item {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
}
|
||||
.icon-selector .icon-item:hover { background: #f5f5f5; border-color: #009688; }
|
||||
.icon-selector .icon-item.selected { background: #009688; color: #fff; border-color: #009688; }
|
||||
</style>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>系统</cite></a>
|
||||
<a><cite>常见问题管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="faq-container">
|
||||
<!-- 左侧:分类树 -->
|
||||
<div class="faq-tree-panel">
|
||||
<div class="tree-toolbar">
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add-root"><i class="layui-icon layui-icon-add-1"></i>添加分类</button>
|
||||
</div>
|
||||
<div id="categoryTree"></div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:问题列表 -->
|
||||
<div class="faq-question-panel">
|
||||
<div class="layui-card-header">
|
||||
<span id="currentCategoryName">请选择分类</span>
|
||||
<button class="layui-btn layui-btn-sm" id="btn-add-question" style="float:right;"><i class="layui-icon layui-icon-add-1"></i>添加问题</button>
|
||||
</div>
|
||||
<table id="table-question" lay-filter="table-question"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="toolbar-question">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="batchdel"><i class="layui-icon layui-icon-delete"></i>批量删除</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-operate">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="statusTpl">
|
||||
<input type="checkbox" name="isenable" value="{{d.id}}" lay-skin="switch" lay-text="启用|禁用" {{ d.isenable ? 'checked' : '' }} lay-filter="enable-switch">
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'layer'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
layer = layui.layer,
|
||||
setter = layui.setter;
|
||||
|
||||
var currentCategoryId = null;
|
||||
var categoryList = [];
|
||||
|
||||
// 加载分类树
|
||||
function loadCategoryTree() {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Faq/CategoryTree',
|
||||
done: function (res) {
|
||||
if (res.code === 0) {
|
||||
categoryList = res.data || [];
|
||||
renderTree(categoryList, $('#categoryTree'));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染树
|
||||
function renderTree(nodes, $container) {
|
||||
var html = '';
|
||||
nodes.forEach(function(node) {
|
||||
html += '<div class="tree-node-item' + (node.id === currentCategoryId ? ' active' : '') + '" data-id="' + node.id + '">';
|
||||
html += '<div class="node-info">';
|
||||
if (node.icon) {
|
||||
html += '<i class="layui-icon ' + node.icon + ' icon-preview"></i>';
|
||||
}
|
||||
html += '<span>' + node.name + '</span>';
|
||||
html += '<span style="color:#999;font-size:12px;">(' + (node.children ? node.children.length : 0) + ')</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="node-actions">';
|
||||
html += '<a href="javascript:;" class="add-child" title="添加子分类"><i class="layui-icon layui-icon-add-1"></i></a>';
|
||||
html += '<a href="javascript:;" class="edit" title="编辑"><i class="layui-icon layui-icon-edit"></i></a>';
|
||||
html += '<a href="javascript:;" class="delete" title="删除"><i class="layui-icon layui-icon-delete"></i></a>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
if (node.children && node.children.length > 0) {
|
||||
html += '<div class="tree-children">';
|
||||
html += renderTreeHtml(node.children);
|
||||
html += '</div>';
|
||||
}
|
||||
});
|
||||
$container.html(html);
|
||||
}
|
||||
|
||||
function renderTreeHtml(nodes) {
|
||||
var html = '';
|
||||
nodes.forEach(function(node) {
|
||||
html += '<div class="tree-node-item' + (node.id === currentCategoryId ? ' active' : '') + '" data-id="' + node.id + '">';
|
||||
html += '<div class="node-info">';
|
||||
if (node.icon) {
|
||||
html += '<i class="layui-icon ' + node.icon + ' icon-preview"></i>';
|
||||
}
|
||||
html += '<span>' + node.name + '</span>';
|
||||
html += '<span style="color:#999;font-size:12px;">(' + (node.children ? node.children.length : 0) + ')</span>';
|
||||
html += '</div>';
|
||||
html += '<div class="node-actions">';
|
||||
html += '<a href="javascript:;" class="add-child" title="添加子分类"><i class="layui-icon layui-icon-add-1"></i></a>';
|
||||
html += '<a href="javascript:;" class="edit" title="编辑"><i class="layui-icon layui-icon-edit"></i></a>';
|
||||
html += '<a href="javascript:;" class="delete" title="删除"><i class="layui-icon layui-icon-delete"></i></a>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
if (node.children && node.children.length > 0) {
|
||||
html += '<div class="tree-children">';
|
||||
html += renderTreeHtml(node.children);
|
||||
html += '</div>';
|
||||
}
|
||||
});
|
||||
return html;
|
||||
}
|
||||
|
||||
// 分类树点击
|
||||
$(document).on('click', '.tree-node-item', function(e) {
|
||||
if ($(e.target).closest('.node-actions').length > 0) return;
|
||||
$('.tree-node-item').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
currentCategoryId = $(this).data('id');
|
||||
var nodeName = $(this).find('.node-info span').eq(0).text();
|
||||
$('#currentCategoryName').text(nodeName);
|
||||
loadQuestions();
|
||||
});
|
||||
|
||||
// 添加根分类
|
||||
$('#btn-add-root').on('click', function() {
|
||||
showCategoryDialog(null, null);
|
||||
});
|
||||
|
||||
// 添加子分类
|
||||
$(document).on('click', '.add-child', function(e) {
|
||||
e.stopPropagation();
|
||||
var parentId = $(this).closest('.tree-node-item').data('id');
|
||||
showCategoryDialog(null, parentId);
|
||||
});
|
||||
|
||||
// 编辑分类
|
||||
$(document).on('click', '.edit', function(e) {
|
||||
e.stopPropagation();
|
||||
var id = $(this).closest('.tree-node-item').data('id');
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Faq/CategoryDetail',
|
||||
data: { id: id },
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
showCategoryDialog(res.data, res.data.parentid);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 删除分类
|
||||
$(document).on('click', '.delete', function(e) {
|
||||
e.stopPropagation();
|
||||
var id = $(this).closest('.tree-node-item').data('id');
|
||||
layer.confirm('确定删除该分类吗?', function(idx) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Faq/DeleteCategory',
|
||||
data: { id: id },
|
||||
done: function(res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
loadCategoryTree();
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 分类弹窗
|
||||
function showCategoryDialog(data, parentId) {
|
||||
data = data || {};
|
||||
var iconOptions = [
|
||||
{ value: 'layui-icon-user', text: '用户' },
|
||||
{ value: 'layui-icon-set', text: '设置' },
|
||||
{ value: 'layui-icon-help', text: '帮助' },
|
||||
{ value: 'layui-icon-notice', text: '通知' },
|
||||
{ value: 'layui-icon-util', text: '工具' },
|
||||
{ value: 'layui-icon-release', text: '发布' },
|
||||
{ value: 'layui-icon-survey', text: '问卷' },
|
||||
{ value: 'layui-icon-senior', text: '高级' },
|
||||
{ value: 'layui-icon-app', text: '应用' },
|
||||
{ value: 'layui-icon-website', text: '网站' },
|
||||
{ value: 'layui-icon-console', text: '控制台' },
|
||||
{ value: 'layui-icon-home', text: '首页' },
|
||||
{ value: 'layui-icon-reduce-circle', text: '减少' },
|
||||
{ value: 'layui-icon-chart', text: '图表' },
|
||||
{ value: 'layui-icon-dialogue', text: '对话' },
|
||||
{ value: 'layui-icon-edit', text: '编辑' },
|
||||
{ value: 'layui-icon-link', text: '链接' },
|
||||
{ value: 'layui-icon-picture', text: '图片' },
|
||||
{ value: 'layui-icon-file', text: '文件' },
|
||||
{ value: 'layui-icon-find-fill', text: '发现' },
|
||||
{ value: 'layui-icon-add-circle', text: '添加' },
|
||||
{ value: 'layui-icon-cart-simple', text: '购物' },
|
||||
{ value: 'layui-icon-cart', text: '购物车' },
|
||||
{ value: 'layui-icon-group', text: '群组' },
|
||||
{ value: 'layui-icon-fire', text: '热门' },
|
||||
{ value: 'layui-icon-gift', text: '礼物' },
|
||||
{ value: 'layui-icon-templeate', text: '模板' },
|
||||
{ value: 'layui-icon-voice', text: '语音' },
|
||||
{ value: 'layui-icon-mike', text: '麦克风' },
|
||||
{ value: 'layui-icon-news', text: '新闻' }
|
||||
];
|
||||
|
||||
var iconGridHtml = '';
|
||||
iconOptions.forEach(function(icon) {
|
||||
var selected = data.icon === icon.value ? 'selected' : '';
|
||||
iconGridHtml += '<div class="icon-item ' + selected + '" data-value="' + icon.value + '" title="' + icon.text + '"><i class="layui-icon ' + icon.value + '"></i></div>';
|
||||
});
|
||||
|
||||
var parentOptions = '<option value="">顶级分类</option>';
|
||||
categoryList.forEach(function(cat) {
|
||||
if (!data.id || cat.id !== data.id) {
|
||||
var selected = data.parentid === cat.id ? 'selected' : '';
|
||||
parentOptions += '<option value="' + cat.id + '" ' + selected + '>' + cat.name + '</option>';
|
||||
}
|
||||
});
|
||||
|
||||
var selectedIconHtml = data.icon
|
||||
? '<i class="layui-icon ' + data.icon + ' icon-preview"></i><span>' + (iconOptions.find(function(o){return o.value===data.icon;})?.text || data.icon) + '</span>'
|
||||
: '<span class="icon-placeholder">点击选择图标</span>';
|
||||
|
||||
var html = '<div class="edit-dialog" style="padding:20px;">' +
|
||||
'<form class="layui-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">上级分类</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="parentid">' + parentOptions + '</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">分类名称</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="name" value="' + (data.name || '') + '" required lay-verify="required" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">分类图标</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="icon-selector" id="iconSelector">' +
|
||||
'<div class="icon-display">' + selectedIconHtml + '</div>' +
|
||||
'<input type="hidden" name="icon" value="' + (data.icon || '') + '"/>' +
|
||||
'<div class="icon-dropdown" id="iconDropdown">' +
|
||||
'<div class="icon-grid">' + iconGridHtml + '</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">排序</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="sort" value="' + (data.sort || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">启用</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="isenable" lay-skin="switch" lay-text="启用|禁用" ' + (data.isenable !== false ? 'checked' : '') + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: data.id ? '编辑分类' : '添加分类',
|
||||
area: ['520px', '480px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
success: function(layero) {
|
||||
form.render('select');
|
||||
// 图标选择器交互
|
||||
var $selector = layero.find('#iconSelector');
|
||||
var $display = $selector.find('.icon-display');
|
||||
var $dropdown = $selector.find('.icon-dropdown');
|
||||
var $input = $selector.find('input[name="icon"]');
|
||||
|
||||
$display.on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
$('.icon-dropdown').not($dropdown).removeClass('show');
|
||||
$dropdown.toggleClass('show');
|
||||
});
|
||||
|
||||
$dropdown.on('click', '.icon-item', function(e) {
|
||||
e.stopPropagation();
|
||||
var val = $(this).data('value');
|
||||
var iconClass = $(this).find('i').attr('class');
|
||||
var iconText = $(this).attr('title');
|
||||
$input.val(val);
|
||||
$dropdown.find('.icon-item').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
$display.html('<i class="' + iconClass + ' icon-preview"></i><span>' + iconText + '</span>');
|
||||
$dropdown.removeClass('show');
|
||||
});
|
||||
|
||||
$(document).on('click', function() {
|
||||
$dropdown.removeClass('show');
|
||||
});
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
var name = layero.find('input[name="name"]').val();
|
||||
if (!name) {
|
||||
layer.msg('请输入分类名称');
|
||||
return;
|
||||
}
|
||||
var param = {
|
||||
name: name,
|
||||
parentid: layero.find('select[name="parentid"]').val() || null,
|
||||
icon: layero.find('select[name="icon"]').val() || null,
|
||||
sort: parseInt(layero.find('input[name="sort"]').val()) || 0,
|
||||
isenable: layero.find('input[name="isenable"]').prop('checked')
|
||||
};
|
||||
if (data.id) param.id = data.id;
|
||||
|
||||
var url = data.id ? 'adminapi/Faq/UpdateCategory' : 'adminapi/Faq/AddCategory';
|
||||
admin.req({
|
||||
url: setter.baseurl + url,
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify(param),
|
||||
done: function(res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功');
|
||||
loadCategoryTree();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加问题
|
||||
$('#btn-add-question').on('click', function() {
|
||||
if (!currentCategoryId) {
|
||||
return layer.msg('请先选择分类');
|
||||
}
|
||||
showQuestionDialog(null);
|
||||
});
|
||||
|
||||
// 加载问题列表
|
||||
function loadQuestions() {
|
||||
if (!currentCategoryId) {
|
||||
table.render({
|
||||
elem: '#table-question',
|
||||
data: [],
|
||||
cols: [[{ title: '请选择左侧分类查看问题' }]]
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
table.render({
|
||||
elem: '#table-question',
|
||||
url: setter.baseurl + 'adminapi/Faq/QuestionList',
|
||||
method: 'post',
|
||||
contentType: 'application/json',
|
||||
headers: { 'token': layui.data(setter.tableName)[setter.request.tokenName] },
|
||||
page: true,
|
||||
where: {
|
||||
categoryId: currentCategoryId
|
||||
},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "title", title: "问题标题", minWidth: 200 },
|
||||
{ field: "sort", title: "排序", width: 80, edit: 'text' },
|
||||
{ field: "isenable", title: "启用", width: 100, templet: '#statusTpl' },
|
||||
{ title: "操作", width: 120, fixed: 'right', toolbar: '#table-operate' }
|
||||
]],
|
||||
toolbar: '#toolbar-question',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 表格工具栏
|
||||
table.on('toolbar(table-question)', function(obj) {
|
||||
if (obj.event === 'batchdel') {
|
||||
var checkStatus = table.checkStatus('table-question');
|
||||
var data = checkStatus.data;
|
||||
if (data.length === 0) return layer.msg('请选择要删除的数据');
|
||||
|
||||
layer.confirm('确定删除选中的 ' + data.length + ' 条数据吗?', function(idx) {
|
||||
var ids = data.map(function(item) { return item.id; });
|
||||
var failCount = 0;
|
||||
var promises = ids.map(function(id) {
|
||||
return new Promise(function(resolve) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Faq/DeleteQuestion',
|
||||
data: { id: id },
|
||||
done: function(res) {
|
||||
if (res.code !== 0) failCount++;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Promise.all(promises).then(function() {
|
||||
layer.close(idx);
|
||||
if (failCount > 0) {
|
||||
layer.msg('部分删除失败(' + failCount + '条)');
|
||||
} else {
|
||||
layer.msg('删除成功');
|
||||
}
|
||||
loadQuestions();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 表格行工具栏
|
||||
table.on('tool(table-question)', function(obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
showQuestionDialog(data);
|
||||
} else if (obj.event === 'del') {
|
||||
layer.confirm('确定删除该问题吗?', function(idx) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Faq/DeleteQuestion',
|
||||
data: { id: data.id },
|
||||
done: function(res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
loadQuestions();
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 问题弹窗
|
||||
function showQuestionDialog(data) {
|
||||
data = data || {};
|
||||
var html = '<div class="edit-dialog" style="padding:20px;">' +
|
||||
'<form class="layui-form" id="questionForm">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">问题标题</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="text" name="title" value="' + (data.title || '') + '" required lay-verify="required" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">排序</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="number" name="sort" value="' + (data.sort || 0) + '" class="layui-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">启用</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<input type="checkbox" name="isenable" lay-skin="switch" lay-text="启用|禁用" ' + (data.isenable !== false ? 'checked' : '') + '>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item layui-form-text">' +
|
||||
'<label class="layui-form-label">问题内容</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<div class="rich-editor" id="richEditor">' +
|
||||
'<div class="rich-editor-toolbar">' +
|
||||
'<button type="button" onclick="execCmd(\'bold\')"><b>B</b></button>' +
|
||||
'<button type="button" onclick="execCmd(\'italic\')"><i>I</i></button>' +
|
||||
'<button type="button" onclick="execCmd(\'underline\')"><u>U</u></button>' +
|
||||
'<button type="button" onclick="execCmd(\'insertUnorderedList\')">• 列表</button>' +
|
||||
'<button type="button" onclick="execCmd(\'formatBlock\',\'<h3>\')">标题</button>' +
|
||||
'<button type="button" onclick="execCmd(\'createLink\')">链接</button>' +
|
||||
'<button type="button" onclick="execCmd(\'formatBlock\',\'<p>\')">段落</button>' +
|
||||
'</div>' +
|
||||
'<div class="rich-editor-content" contenteditable="true" id="editorContent">' + (data.content || '') + '</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: data.id ? '编辑问题' : '添加问题',
|
||||
area: ['700px', '550px'],
|
||||
content: html,
|
||||
btn: ['保存', '取消'],
|
||||
success: function(layero) {
|
||||
form.render();
|
||||
},
|
||||
yes: function(index, layero) {
|
||||
var title = layero.find('input[name="title"]').val();
|
||||
if (!title) {
|
||||
layer.msg('请输入问题标题');
|
||||
return;
|
||||
}
|
||||
var content = layero.find('#editorContent').html();
|
||||
var param = {
|
||||
categoryId: currentCategoryId,
|
||||
title: title,
|
||||
content: content,
|
||||
sort: parseInt(layero.find('input[name="sort"]').val()) || 0,
|
||||
isenable: layero.find('input[name="isenable"]').prop('checked')
|
||||
};
|
||||
if (data.id) param.id = data.id;
|
||||
|
||||
var url = data.id ? 'adminapi/Faq/UpdateQuestion' : 'adminapi/Faq/AddQuestion';
|
||||
admin.req({
|
||||
url: setter.baseurl + url,
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify(param),
|
||||
done: function(res) {
|
||||
layer.close(index);
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功');
|
||||
loadQuestions();
|
||||
} else {
|
||||
layer.msg(res.info || '保存失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 富文本命令
|
||||
window.execCmd = function(cmd, value) {
|
||||
document.execCommand(cmd, false, value || null);
|
||||
$('#editorContent').focus();
|
||||
};
|
||||
|
||||
// 启用/禁用
|
||||
form.on('switch(enable-switch)', function(obj) {
|
||||
var id = this.value;
|
||||
var isenable = obj.elem.checked;
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Faq/UpdateQuestion',
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify({ id: id, isenable: isenable }),
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg(isenable ? '已启用' : '已禁用');
|
||||
} else {
|
||||
layer.msg(res.info || '操作失败');
|
||||
obj.elem.checked = !isenable; // 回滚开关状态
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 排序编辑
|
||||
table.on('edit(table-question)', function(obj) {
|
||||
var id = obj.data.id;
|
||||
var sort = obj.value;
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Faq/UpdateQuestion',
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify({ id: id, sort: parseInt(sort) || 0 }),
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('排序已更新');
|
||||
} else {
|
||||
layer.msg(res.info || '操作失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 初始化
|
||||
loadCategoryTree();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,377 @@
|
||||
|
||||
<title>反馈管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>系统</cite></a>
|
||||
<a><cite>反馈管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-feedback-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">用户编号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="userNumber" placeholder="请输入" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">用户昵称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="userName" placeholder="请输入" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">反馈类型</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="type">
|
||||
<option value="">全部</option>
|
||||
<option value="1">功能建议</option>
|
||||
<option value="2">bug反馈</option>
|
||||
<option value="3">其他问题</option>
|
||||
<option value="4">充值问题</option>
|
||||
<option value="5">游戏问题</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">处理状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status">
|
||||
<option value="">全部</option>
|
||||
<option value="0">待处理</option>
|
||||
<option value="1">处理中</option>
|
||||
<option value="2">已回复</option>
|
||||
<option value="3">已解决</option>
|
||||
<option value="4">已关闭</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">时间范围</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="timeRange" id="timeRange" placeholder="选择时间范围" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-list" lay-submit lay-filter="LAY-feedback-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-feedback-front-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-feedback-manage" lay-filter="LAY-feedback-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-feedback-toolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-feedback-bar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="detail"><i class="layui-icon layui-icon-about"></i>详情</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="reply"><i class="layui-icon layui-icon-reply-fill"></i>回复</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="typeTpl">
|
||||
{{#
|
||||
var typeNames = {1:'功能建议',2:'bug反馈',3:'其他问题',4:'充值问题',5:'游戏问题'};
|
||||
return typeNames[d.type] || '未知';
|
||||
}}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="statusTpl">
|
||||
{{#
|
||||
var statusMap = {
|
||||
0:'<span class="layui-badge layui-bg-gray">待处理</span>',
|
||||
1:'<span class="layui-badge layui-bg-blue">处理中</span>',
|
||||
2:'<span class="layui-badge layui-bg-green">已回复</span>',
|
||||
3:'<span class="layui-badge layui-bg-cyan">已解决</span>',
|
||||
4:'<span class="layui-badge layui-bg-black">已关闭</span>'
|
||||
};
|
||||
return statusMap[d.status] || '未知';
|
||||
}}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="hasReplyTpl">
|
||||
{{# if(d.reply && d.reply.length > 0){ }}
|
||||
<span class="layui-badge layui-bg-green">已回复</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-gray">未回复</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'laydate'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
laydate = layui.laydate,
|
||||
setter = layui.setter;
|
||||
|
||||
// 时间范围选择器
|
||||
laydate.render({
|
||||
elem: '#timeRange',
|
||||
type: 'datetime',
|
||||
range: '~'
|
||||
});
|
||||
|
||||
form.render(null, 'layadmin-feedback-formlist');
|
||||
|
||||
// 监听搜索
|
||||
form.on('submit(LAY-feedback-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
if (field.timeRange) {
|
||||
var times = field.timeRange.split('~');
|
||||
field.startTime = new Date(times[0].trim()).getTime();
|
||||
field.endTime = new Date(times[1].trim()).getTime();
|
||||
}
|
||||
delete field.timeRange;
|
||||
|
||||
// 转换类型
|
||||
if (field.type) field.type = parseInt(field.type);
|
||||
if (field.status) field.status = parseInt(field.status);
|
||||
|
||||
table.reload('LAY-feedback-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 监听重置
|
||||
form.on('submit(LAY-feedback-front-reset)', function (data) {
|
||||
$('input[name="userNumber"]').val('');
|
||||
$('input[name="userName"]').val('');
|
||||
$('select[name="type"]').val('');
|
||||
$('select[name="status"]').val('');
|
||||
$('input[name="timeRange"]').val('');
|
||||
form.render('select');
|
||||
table.reload('LAY-feedback-manage', {
|
||||
where: {},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 刷新按钮
|
||||
$('.layui-btn-container').on('click', '[lay-event="refresh"]', function () {
|
||||
table.reload('LAY-feedback-manage');
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-feedback-manage",
|
||||
url: setter.baseurl + "adminapi/FeedbackManage/List",
|
||||
method: "post",
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
toolbar: '#table-feedback-toolbar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
where: {},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "userNumber", title: "用户编号", width: 100 },
|
||||
{ field: "userName", title: "用户昵称", width: 120 },
|
||||
{ field: "type", title: "类型", width: 100, templet: '#typeTpl' },
|
||||
{ field: "title", title: "标题", minWidth: 150 },
|
||||
{ field: "status", title: "状态", width: 100, templet: '#statusTpl' },
|
||||
{ field: "reply", title: "回复", width: 100, templet: '#hasReplyTpl' },
|
||||
{ field: "submitTime", title: "提交时间", width: 160, templet: function(d) {
|
||||
return formatDateTime(d.submitTime);
|
||||
}},
|
||||
{ width: 180, title: "操作", align: "center", fixed: "right", toolbar: "#table-feedback-bar" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
// 监听工具条
|
||||
table.on("tool(LAY-feedback-manage)", function (e) {
|
||||
var l = e.data;
|
||||
|
||||
if ("detail" === e.event) {
|
||||
showFeedbackDetail(l);
|
||||
} else if ("reply" === e.event) {
|
||||
showReplyDialog(l);
|
||||
} else if ("del" === e.event) {
|
||||
layer.confirm('确定删除该反馈吗?', function (idx) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/FeedbackManage/Delete',
|
||||
data: { id: l.id },
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload('LAY-feedback-manage');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 显示反馈详情
|
||||
function showFeedbackDetail(feedback) {
|
||||
var typeNames = {1:'功能建议',2:'bug反馈',3:'其他问题',4:'充值问题',5:'游戏问题'};
|
||||
var statusNames = {0:'待处理',1:'处理中',2:'已回复',3:'已解决',4:'已关闭'};
|
||||
|
||||
var content =
|
||||
'<div style="padding: 20px;">' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>用户信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>用户编号:</strong>' + (feedback.userNumber || '-') + '</p>' +
|
||||
'<p><strong>用户昵称:</strong>' + (feedback.userName || '-') + '</p>' +
|
||||
'<p><strong>联系方式:</strong>' + (feedback.contact || '-') + '</p>' +
|
||||
'<p><strong>QQ:</strong>' + (feedback.qq || '-') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>反馈信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>类型:</strong>' + (typeNames[feedback.type] || '未知') + '</p>' +
|
||||
'<p><strong>标题:</strong>' + (feedback.title || '-') + '</p>' +
|
||||
'<p><strong>内容:</strong></p>' +
|
||||
'<div style="background:#f5f5f5;padding:10px;border-radius:4px;margin-top:5px;">' + (feedback.content || '-') + '</div>' +
|
||||
'<p style="margin-top:10px;"><strong>提交时间:</strong>' + formatDateTime(feedback.submitTime) + '</p>' +
|
||||
'<p><strong>当前状态:</strong>' + (statusNames[feedback.status] || '未知') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>';
|
||||
|
||||
if (feedback.reply) {
|
||||
content +=
|
||||
'<fieldset class="layui-elem-field layui-field-green">' +
|
||||
'<legend>回复信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>回复内容:</strong></p>' +
|
||||
'<div style="background:#f5f5f5;padding:10px;border-radius:4px;margin-top:5px;">' + feedback.reply + '</div>' +
|
||||
'<p style="margin-top:10px;"><strong>回复时间:</strong>' + formatDateTime(feedback.replyTime) + '</p>' +
|
||||
'<p><strong>回复人:</strong>' + (feedback.replyAdminName || '-') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>';
|
||||
}
|
||||
|
||||
content += '</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '反馈详情',
|
||||
area: ['700px', '600px'],
|
||||
content: content
|
||||
});
|
||||
}
|
||||
|
||||
// 显示回复弹窗
|
||||
function showReplyDialog(feedback) {
|
||||
var statusNames = {0:'待处理',1:'处理中',2:'已回复',3:'已解决',4:'已关闭'};
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '回复反馈',
|
||||
area: ['600px', '450px'],
|
||||
content: '<div style="padding:20px;">' +
|
||||
'<form class="layui-form" lay-filter="reply-form">' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<label class="layui-form-label">当前状态</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<select name="status" lay-filter="status-select">' +
|
||||
'<option value="0" ' + (feedback.status === 0 ? 'selected' : '') + '>待处理</option>' +
|
||||
'<option value="1" ' + (feedback.status === 1 ? 'selected' : '') + '>处理中</option>' +
|
||||
'<option value="2" ' + (feedback.status === 2 ? 'selected' : '') + '>已回复</option>' +
|
||||
'<option value="3" ' + (feedback.status === 3 ? 'selected' : '') + '>已解决</option>' +
|
||||
'<option value="4" ' + (feedback.status === 4 ? 'selected' : '') + '>已关闭</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item layui-form-text">' +
|
||||
'<label class="layui-form-label">回复内容</label>' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<textarea name="reply" placeholder="请输入回复内容" class="layui-textarea" style="min-height:150px;">' + (feedback.reply || '') + '</textarea>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="layui-form-item">' +
|
||||
'<div class="layui-input-block">' +
|
||||
'<button class="layui-btn" lay-submit lay-filter="reply-submit">提交回复</button>' +
|
||||
'<button type="button" class="layui-btn layui-btn-primary" onclick="layer.closeAll();">取消</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</form>' +
|
||||
'</div>',
|
||||
success: function(layero, index) {
|
||||
form.render('select', 'reply-form');
|
||||
|
||||
form.on('submit(reply-submit)', function(data) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/FeedbackManage/Reply',
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify({
|
||||
id: feedback.id,
|
||||
reply: data.field.reply,
|
||||
status: parseInt(data.field.status)
|
||||
}),
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(index);
|
||||
layer.msg('回复成功');
|
||||
table.reload('LAY-feedback-manage');
|
||||
} else {
|
||||
layer.msg(res.info || '回复失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function formatDateTime(date) {
|
||||
if (!date) return '-';
|
||||
var d = new Date(date);
|
||||
var year = d.getFullYear();
|
||||
var month = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
var day = ('0' + d.getDate()).slice(-2);
|
||||
var hour = ('0' + d.getHours()).slice(-2);
|
||||
var minute = ('0' + d.getMinutes()).slice(-2);
|
||||
var second = ('0' + d.getSeconds()).slice(-2);
|
||||
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,335 @@
|
||||
|
||||
<title>操作日志</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>系统</cite></a>
|
||||
<a><cite>操作日志</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-log-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">管理员</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="adminId" id="adminSelect" lay-search>
|
||||
<option value="">全部</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">操作模块</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="module" id="moduleSelect">
|
||||
<option value="">全部</option>
|
||||
<option value="1">用户管理</option>
|
||||
<option value="2">系统用户</option>
|
||||
<option value="3">角色管理</option>
|
||||
<option value="4">菜单管理</option>
|
||||
<option value="5">字典管理</option>
|
||||
<option value="6">游戏配置</option>
|
||||
<option value="7">房间管理</option>
|
||||
<option value="8">客服管理</option>
|
||||
<option value="9">靓号管理</option>
|
||||
<option value="10">公告管理</option>
|
||||
<option value="11">任务管理</option>
|
||||
<option value="99">其他</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">操作时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="timeRange" id="timeRange" placeholder="选择时间范围" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-list" lay-submit lay-filter="LAY-log-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-log-front-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-log-manage" lay-filter="LAY-log-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-log-toolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="batchdel">
|
||||
<i class="layui-icon layui-icon-delete"></i> 批量删除
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-log-bar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="detail"><i class="layui-icon layui-icon-about"></i>详情</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="moduleTpl">
|
||||
{{# var moduleNames = {1:'用户管理',2:'系统用户',3:'角色管理',4:'菜单管理',5:'字典管理',6:'游戏配置',7:'房间管理',8:'客服管理',9:'靓号管理',10:'公告管理',11:'任务管理',99:'其他'}; }}
|
||||
{{# return moduleNames[d.module] || '未知'; }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="statusTpl">
|
||||
{{# if(d.status === 1){ }}
|
||||
<span class="layui-badge layui-bg-green">成功</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-red">失败</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'laydate'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
view = layui.view,
|
||||
table = layui.table,
|
||||
setter = layui.setter,
|
||||
form = layui.form,
|
||||
laydate = layui.laydate;
|
||||
|
||||
// 时间范围选择器
|
||||
laydate.render({
|
||||
elem: '#timeRange',
|
||||
type: 'datetime',
|
||||
range: '~'
|
||||
});
|
||||
|
||||
// 加载管理员下拉
|
||||
function loadAdmins() {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/OperationLog/admins',
|
||||
done: function (res) {
|
||||
var html = '<option value="">全部</option>';
|
||||
layui.each(res.data, function (index, item) {
|
||||
html += '<option value="' + item.value + '">' + item.label + '</option>';
|
||||
});
|
||||
$('#adminSelect').html(html);
|
||||
form.render('select');
|
||||
}
|
||||
});
|
||||
}
|
||||
loadAdmins();
|
||||
|
||||
form.render(null, 'layadmin-log-formlist');
|
||||
|
||||
// 监听搜索
|
||||
form.on('submit(LAY-log-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
if (field.timeRange) {
|
||||
var times = field.timeRange.split('~');
|
||||
field.startTime = new Date(times[0].trim()).getTime();
|
||||
field.endTime = new Date(times[1].trim()).getTime();
|
||||
}
|
||||
delete field.timeRange;
|
||||
|
||||
table.reload('LAY-log-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 监听重置
|
||||
form.on('submit(LAY-log-front-reset)', function (data) {
|
||||
$('#adminSelect').val('');
|
||||
$('#moduleSelect').val('');
|
||||
$('#timeRange').val('');
|
||||
form.render('select');
|
||||
table.reload('LAY-log-manage', {
|
||||
where: {},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 刷新按钮
|
||||
$('.layui-btn-container').on('click', '[lay-event="refresh"]', function () {
|
||||
table.reload('LAY-log-manage');
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-log-manage",
|
||||
url: setter.baseurl + "adminapi/OperationLog/list",
|
||||
method: "post",
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
toolbar: '#table-log-toolbar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
where: {},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "adminName", title: "管理员", width: 120 },
|
||||
{ field: "module", title: "模块", width: 100, templet: '#moduleTpl' },
|
||||
{ field: "actionType", title: "操作类型", width: 120 },
|
||||
{ field: "description", title: "操作描述", minWidth: 200 },
|
||||
{ field: "httpMethod", title: "请求方式", width: 100, templet: function(d) {
|
||||
var color = d.httpMethod === 'GET' ? 'layui-bg-blue' : (d.httpMethod === 'POST' ? 'layui-bg-green' : 'layui-bg-orange');
|
||||
return '<span class="layui-badge ' + color + '">' + d.httpMethod + '</span>';
|
||||
}},
|
||||
{ field: "ip", title: "IP地址", width: 130 },
|
||||
{ field: "status", title: "状态", width: 80, templet: '#statusTpl' },
|
||||
{ field: "operateTime", title: "操作时间", width: 160, templet: function(d) {
|
||||
return formatDateTime(d.operateTime);
|
||||
}},
|
||||
{ width: 120, title: "操作", align: "center", fixed: "right", toolbar: "#table-log-bar" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
// 监听工具条
|
||||
table.on("tool(LAY-log-manage)", function (e) {
|
||||
var l = e.data;
|
||||
|
||||
if ("detail" === e.event) {
|
||||
showLogDetail(l);
|
||||
} else if ("del" === e.event) {
|
||||
layer.confirm('确定删除该日志吗?', function (idx) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/OperationLog/Delete',
|
||||
data: { id: l.id },
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload('LAY-log-manage');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
table.on('toolbar(LAY-log-manage)', function (obj) {
|
||||
if (obj.event === 'batchdel') {
|
||||
var checkStatus = table.checkStatus('LAY-log-manage');
|
||||
var data = checkStatus.data;
|
||||
if (data.length === 0) return layer.msg('请选择要删除的数据');
|
||||
|
||||
layer.confirm('确定删除选中的 ' + data.length + ' 条日志吗?', function (idx) {
|
||||
var ids = data.map(function (item) { return item.id; });
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/OperationLog/BatchDelete',
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify(ids),
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload('LAY-log-manage');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 显示日志详情
|
||||
function showLogDetail(log) {
|
||||
var content =
|
||||
'<div style="padding: 20px;">' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>基本信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>管理员:</strong>' + (log.adminName || '-') + '</p>' +
|
||||
'<p><strong>模块:</strong>' + getModuleName(log.module) + '</p>' +
|
||||
'<p><strong>操作类型:</strong>' + (log.actionType || '-') + '</p>' +
|
||||
'<p><strong>操作描述:</strong>' + (log.description || '-') + '</p>' +
|
||||
'<p><strong>操作时间:</strong>' + formatDateTime(log.operateTime) + '</p>' +
|
||||
'<p><strong>IP地址:</strong>' + (log.ip || '-') + '</p>' +
|
||||
'<p><strong>状态:</strong>' + (log.status === 1 ? '成功' : '失败') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>请求信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>请求方式:</strong>' + (log.httpMethod || '-') + '</p>' +
|
||||
'<p><strong>请求参数:</strong></p>' +
|
||||
'<pre style="background:#f5f5f5;padding:10px;border-radius:4px;max-height:200px;overflow:auto;">' + formatJson(log.requestParams) + '</pre>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>响应信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<pre style="background:#f5f5f5;padding:10px;border-radius:4px;max-height:200px;overflow:auto;">' + formatJson(log.response) + '</pre>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'</div>';
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '操作日志详情',
|
||||
area: ['700px', '600px'],
|
||||
content: content
|
||||
});
|
||||
}
|
||||
|
||||
function getModuleName(module) {
|
||||
var moduleNames = {
|
||||
1: '用户管理', 2: '系统用户', 3: '角色管理', 4: '菜单管理',
|
||||
5: '字典管理', 6: '游戏配置', 7: '房间管理', 8: '客服管理',
|
||||
9: '靓号管理', 10: '公告管理', 11: '任务管理', 99: '其他'
|
||||
};
|
||||
return moduleNames[module] || '未知';
|
||||
}
|
||||
|
||||
function formatDateTime(date) {
|
||||
if (!date) return '-';
|
||||
var d = new Date(date);
|
||||
var year = d.getFullYear();
|
||||
var month = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
var day = ('0' + d.getDate()).slice(-2);
|
||||
var hour = ('0' + d.getHours()).slice(-2);
|
||||
var minute = ('0' + d.getMinutes()).slice(-2);
|
||||
var second = ('0' + d.getSeconds()).slice(-2);
|
||||
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
|
||||
}
|
||||
|
||||
function formatJson(str) {
|
||||
if (!str) return '无';
|
||||
try {
|
||||
var obj = typeof str === 'string' ? JSON.parse(str) : str;
|
||||
return JSON.stringify(obj, null, 2);
|
||||
} catch (e) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,340 @@
|
||||
|
||||
<title>登录日志</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>系统</cite></a>
|
||||
<a><cite>登录日志</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-loginformlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">用户编号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="userNumber" placeholder="请输入" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">用户昵称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="userName" placeholder="请输入" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">登录方式</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="loginType">
|
||||
<option value="">全部</option>
|
||||
<option value="1">账号密码</option>
|
||||
<option value="2">微信</option>
|
||||
<option value="3">手机号</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">登录平台</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="platform">
|
||||
<option value="">全部</option>
|
||||
<option value="1">Android</option>
|
||||
<option value="2">iOS</option>
|
||||
<option value="3">H5</option>
|
||||
<option value="4">PC</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">登录状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status">
|
||||
<option value="">全部</option>
|
||||
<option value="1">成功</option>
|
||||
<option value="0">失败</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">时间范围</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="timeRange" id="timeRange" placeholder="选择时间范围" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-list" lay-submit lay-filter="LAY-loginform-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-loginform-front-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-loginlog-manage" lay-filter="LAY-loginlog-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-loginlog-toolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="batchdel">
|
||||
<i class="layui-icon layui-icon-delete"></i> 批量删除
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="table-loginlog-bar">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="detail"><i class="layui-icon layui-icon-about"></i>详情</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="loginTypeTpl">
|
||||
{{#
|
||||
var typeNames = {1:'账号密码',2:'微信',3:'手机号'};
|
||||
return typeNames[d.loginType] || '未知';
|
||||
}}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="platformTpl">
|
||||
{{#
|
||||
var platformNames = {1:'Android',2:'iOS',3:'H5',4:'PC'};
|
||||
return platformNames[d.platform] || '未知';
|
||||
}}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="statusTpl">
|
||||
{{# if(d.status === 1){ }}
|
||||
<span class="layui-badge layui-bg-green">成功</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-red">失败</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'laydate'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
form = layui.form,
|
||||
laydate = layui.laydate,
|
||||
setter = layui.setter;
|
||||
|
||||
// 时间范围选择器
|
||||
laydate.render({
|
||||
elem: '#timeRange',
|
||||
type: 'datetime',
|
||||
range: '~'
|
||||
});
|
||||
|
||||
form.render(null, 'layadmin-loginform-formlist');
|
||||
|
||||
// 监听搜索
|
||||
form.on('submit(LAY-loginform-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
if (field.timeRange) {
|
||||
var times = field.timeRange.split('~');
|
||||
field.startTime = new Date(times[0].trim()).getTime();
|
||||
field.endTime = new Date(times[1].trim()).getTime();
|
||||
}
|
||||
delete field.timeRange;
|
||||
|
||||
// 转换类型
|
||||
if (field.loginType) field.loginType = parseInt(field.loginType);
|
||||
if (field.status) field.status = parseInt(field.status);
|
||||
if (field.platform) field.platform = parseInt(field.platform);
|
||||
|
||||
table.reload('LAY-loginlog-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 监听重置
|
||||
form.on('submit(LAY-loginform-front-reset)', function (data) {
|
||||
$('input[name="userNumber"]').val('');
|
||||
$('input[name="userName"]').val('');
|
||||
$('select[name="loginType"]').val('');
|
||||
$('select[name="status"]').val('');
|
||||
$('select[name="platform"]').val('');
|
||||
$('input[name="timeRange"]').val('');
|
||||
form.render('select');
|
||||
table.reload('LAY-loginlog-manage', {
|
||||
where: {},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 刷新按钮
|
||||
$('.layui-btn-container').on('click', '[lay-event="refresh"]', function () {
|
||||
table.reload('LAY-loginlog-manage');
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-loginlog-manage",
|
||||
url: setter.baseurl + "adminapi/UserLoginLog/List",
|
||||
method: "post",
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
toolbar: '#table-loginlog-toolbar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
where: {},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ type: 'checkbox', fixed: 'left' },
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "userNumber", title: "用户编号", width: 100 },
|
||||
{ field: "userName", title: "用户昵称", width: 120 },
|
||||
{ field: "loginType", title: "登录方式", width: 100, templet: '#loginTypeTpl' },
|
||||
{ field: "platform", title: "登录平台", width: 90, templet: '#platformTpl' },
|
||||
{ field: "status", title: "状态", width: 80, templet: '#statusTpl' },
|
||||
{ field: "ip", title: "IP地址", width: 130 },
|
||||
{ field: "ipLocation", title: "IP归属地", width: 120 },
|
||||
{ field: "clientVersion", title: "版本", width: 100 },
|
||||
{ field: "loginTime", title: "登录时间", width: 160, templet: function(d) {
|
||||
return formatDateTime(d.loginTime);
|
||||
}},
|
||||
{ width: 120, title: "操作", align: "center", fixed: "right", toolbar: "#table-loginlog-bar" }
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
// 监听工具条
|
||||
table.on("tool(LAY-loginlog-manage)", function (e) {
|
||||
var l = e.data;
|
||||
|
||||
if ("detail" === e.event) {
|
||||
showLogDetail(l);
|
||||
} else if ("del" === e.event) {
|
||||
layer.confirm('确定删除该日志吗?', function (idx) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/UserLoginLog/Delete',
|
||||
data: { id: l.id },
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload('LAY-loginlog-manage');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 批量删除
|
||||
table.on('toolbar(LAY-loginlog-manage)', function (obj) {
|
||||
if (obj.event === 'batchdel') {
|
||||
var checkStatus = table.checkStatus('LAY-loginlog-manage');
|
||||
var data = checkStatus.data;
|
||||
if (data.length === 0) return layer.msg('请选择要删除的数据');
|
||||
|
||||
layer.confirm('确定删除选中的 ' + data.length + ' 条日志吗?', function (idx) {
|
||||
var ids = data.map(function (item) { return item.id; });
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/UserLoginLog/BatchDelete',
|
||||
contentType: 'application/json',
|
||||
method: 'post',
|
||||
data: JSON.stringify(ids),
|
||||
done: function (res) {
|
||||
layer.close(idx);
|
||||
if (res.code === 0) {
|
||||
layer.msg('删除成功');
|
||||
table.reload('LAY-loginlog-manage');
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 显示日志详情
|
||||
function showLogDetail(log) {
|
||||
var typeNames = {1:'账号密码',2:'微信',3:'手机号'};
|
||||
var platformNames = {1:'Android',2:'iOS',3:'H5',4:'PC'};
|
||||
|
||||
var content =
|
||||
'<div style="padding: 20px;">' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>用户信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>用户编号:</strong>' + (log.userNumber || '-') + '</p>' +
|
||||
'<p><strong>用户昵称:</strong>' + (log.userName || '-') + '</p>' +
|
||||
'<p><strong>用户ID:</strong>' + (log.userId || '-') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>登录信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>登录方式:</strong>' + (typeNames[log.loginType] || '未知') + '</p>' +
|
||||
'<p><strong>登录平台:</strong>' + (platformNames[log.platform] || '未知') + '</p>' +
|
||||
'<p><strong>登录状态:</strong>' + (log.status === 1 ? '<span class="layui-badge layui-bg-green">成功</span>' : '<span class="layui-badge layui-bg-red">失败</span>') + '</p>' +
|
||||
'<p><strong>登录时间:</strong>' + formatDateTime(log.loginTime) + '</p>' +
|
||||
'<p><strong>失败原因:</strong>' + (log.failReason || '-') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'<fieldset class="layui-elem-field">' +
|
||||
'<legend>设备信息</legend>' +
|
||||
'<div class="layui-field-box">' +
|
||||
'<p><strong>IP地址:</strong>' + (log.ip || '-') + '</p>' +
|
||||
'<p><strong>IP归属地:</strong>' + (log.ipLocation || '-') + '</p>' +
|
||||
'<p><strong>设备类型:</strong>' + (log.deviceType || '-') + '</p>' +
|
||||
'<p><strong>设备ID:</strong>' + (log.deviceId || '-') + '</p>' +
|
||||
'<p><strong>客户端版本:</strong>' + (log.clientVersion || '-') + '</p>' +
|
||||
'</div>' +
|
||||
'</fieldset>' +
|
||||
'</div>';
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '登录日志详情',
|
||||
area: ['600px', '550px'],
|
||||
content: content
|
||||
});
|
||||
}
|
||||
|
||||
function formatDateTime(date) {
|
||||
if (!date) return '-';
|
||||
var d = new Date(date);
|
||||
var year = d.getFullYear();
|
||||
var month = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
var day = ('0' + d.getDate()).slice(-2);
|
||||
var hour = ('0' + d.getHours()).slice(-2);
|
||||
var minute = ('0' + d.getMinutes()).slice(-2);
|
||||
var second = ('0' + d.getSeconds()).slice(-2);
|
||||
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-admin" style="padding: 20px 30px 0 0;">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">登录名</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="id" value="{{ d.params.id}}" class="layui-input" style="display:none">
|
||||
</script>
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="userName" value="{{ d.params.userName || '' }}" lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="displayName" value="{{ d.params.displayName || '' }}" lay-verify="required" placeholder="请输入号码" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">头像</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<button type="button" class="layui-btn" id="layuiadmin-upload-admin">
|
||||
<i class="layui-icon layui-icon-upload"></i> 图片上传
|
||||
</button>
|
||||
<div style="width: 132px;">
|
||||
<div class="layui-upload-list">
|
||||
<img class="layui-upload-img" id="ID-upload-demo-img" src="{{ d.params.icon || '' }}" style="width: 100%; height: 92px;">
|
||||
<div id="ID-upload-demo-text"></div>
|
||||
<input type="text" name="icon" id="ID-upload-demo-img-v" value="{{ d.params.icon || '' }}" style="display:none"/>
|
||||
</div>
|
||||
<div class="layui-progress layui-progress-big" lay-showPercent="yes" lay-filter="filter-demo">
|
||||
<div class="layui-progress-bar" lay-percent=""></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="password" value="" lay-verify="" placeholder="请输入密码" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="systemRole" id="systemRole">
|
||||
</select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-back-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'upload'], function () {
|
||||
var $ = layui.$
|
||||
, form = layui.form
|
||||
, admin = layui.admin
|
||||
, setter = layui.setter
|
||||
, upload = layui.upload
|
||||
,element = layui.element;
|
||||
bindSelect();
|
||||
|
||||
function bindSelect() {
|
||||
admin.req({
|
||||
method: "get",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/role/list",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
done: function (res) {
|
||||
|
||||
res.data.forEach(function (option) {
|
||||
$('#systemRole').append("<option value='" + option.id + "'>" + option.roleName + "</option>");
|
||||
|
||||
});
|
||||
form.render('select');
|
||||
}
|
||||
})
|
||||
}
|
||||
var uploadInst = upload.render({
|
||||
elem: '#layuiadmin-upload-admin',
|
||||
url: setter.baseurl + "adminapi/ImageUpload/upload/temp",
|
||||
before: function (obj) {
|
||||
obj.preview(function (index, file, result) {
|
||||
$('#ID-upload-demo-img').attr('src', result); // 图片链接(base64)
|
||||
});
|
||||
|
||||
|
||||
element.progress('filter-demo', '0%'); // 进度条复位
|
||||
layer.msg('上传中', { icon: 16, time: 0 });
|
||||
},
|
||||
done: function (res) {
|
||||
// 若上传失败
|
||||
if (res.code > 0) {
|
||||
return layer.msg('上传失败');
|
||||
}
|
||||
|
||||
console.log($('#ID-upload-demo-img-v').val())
|
||||
// 上传成功的一些操作
|
||||
$('#ID-upload-demo-img-v').val(setter.baseurl +res.path);
|
||||
$('#ID-upload-demo-text').html(res.path); // 置空上传失败的状态
|
||||
},
|
||||
error: function () {
|
||||
// 演示失败状态,并实现重传
|
||||
var demoText = $('#ID-upload-demo-text');
|
||||
demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs demo-reload">重试</a>');
|
||||
demoText.find('.demo-reload').on('click', function () {
|
||||
uploadInst.upload();
|
||||
});
|
||||
},
|
||||
// 进度条
|
||||
progress: function (n, elem, e) {
|
||||
element.progress('filter-demo', n + '%'); // 可配合 layui 进度条元素使用
|
||||
if (n == 100) {
|
||||
layer.msg('上传完毕', { icon: 1 });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-admin" style="padding: 20px 30px 0 0;">
|
||||
<script type="text/html" lay-done="sendParams(d.params)" template>
|
||||
</script>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="id" value="{{ d.params.id}}" class="layui-input" style="display:none">
|
||||
</script>
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="title" value="{{ d.params.title || '' }}" lay-verify="required" placeholder="请输入标题" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">图片</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<button type="button" class="layui-btn" id="layuiadmin-upload-admin">
|
||||
<i class="layui-icon layui-icon-upload"></i> 图片上传
|
||||
</button>
|
||||
<div style="width: 132px;">
|
||||
<div class="layui-upload-list">
|
||||
<img class="layui-upload-img" id="ID-upload-demo-img" src="{{ d.params.picUrl || '' }}" style="width: 100%; height: 92px;">
|
||||
<div id="ID-upload-demo-text"></div>
|
||||
<input type="text" name="picUrl" id="ID-upload-demo-img-v" value="{{ d.params.picUrl || '' }}" style="display:none" />
|
||||
</div>
|
||||
<div class="layui-progress layui-progress-big" lay-showPercent="yes" lay-filter="filter-demo">
|
||||
<div class="layui-progress-bar" lay-percent=""></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">跳转地址</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="url" value="{{ d.params.url || '' }}" lay-verify="required" placeholder="请输入号码" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">时长(秒)</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="number" name="times" value="{{d.params.times||0}}" lay-verify="required" placeholder="时长(秒)" autocomplete="off" step="1" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">位置</label>
|
||||
<div class="layui-input-inline">
|
||||
|
||||
<div id="positionSelect"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-back-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/layui/xm-select.js"></script>
|
||||
<script>
|
||||
var position = '';
|
||||
var isLayUI = false;
|
||||
function sendParams(params) {
|
||||
|
||||
position = params.position;
|
||||
if (isLayUI) {
|
||||
layuiLoad();
|
||||
}
|
||||
|
||||
}
|
||||
layuiLoad();
|
||||
function layuiLoad() {
|
||||
layui.use(['admin', 'form', 'upload'], function () {
|
||||
var $ = layui.$
|
||||
, form = layui.form
|
||||
, admin = layui.admin
|
||||
, setter = layui.setter
|
||||
, upload = layui.upload
|
||||
, element = layui.element;
|
||||
|
||||
var selctdata = [];
|
||||
admin.req({
|
||||
method: "get",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/dic/list/code?code=bannerposition",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
|
||||
done: function (res) {
|
||||
|
||||
layui.each(res.data, function (index, val) {
|
||||
selctdata.push({ name: val.name, value: val.id });
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
var positionSelect = xmSelect.render({
|
||||
el: '#positionSelect',
|
||||
toolbar: { show: true },
|
||||
data: selctdata
|
||||
})
|
||||
|
||||
|
||||
positionSelect.setValue(position.map(item => ({
|
||||
value: item.value,
|
||||
name: item.title // 将name属性映射为title
|
||||
})));
|
||||
//监听提交
|
||||
form.on('submit(LAY-user-back-submit)', function (data) {
|
||||
|
||||
var selectArr = positionSelect.getValue();
|
||||
|
||||
const newArr = selectArr.map(item => ({
|
||||
value: item.value,
|
||||
title: item.name // 将name属性映射为title
|
||||
}));
|
||||
|
||||
var param = {
|
||||
id: data.field.id,
|
||||
title: data.field.title,
|
||||
url: data.field.url,
|
||||
times: data.field.times,
|
||||
picUrl: data.field.picUrl,
|
||||
position: newArr
|
||||
};
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/banner/" +(param.id==""?"add":"update"),//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
|
||||
//$.ajax({});
|
||||
layui.table.reload('LAY-user-back-manage'); //重载表格
|
||||
layer.closeAll(); //执行关闭
|
||||
}
|
||||
})
|
||||
//提交 Ajax 成功后,关闭当前弹层并重载表格
|
||||
|
||||
});
|
||||
var uploadInst = upload.render({
|
||||
elem: '#layuiadmin-upload-admin',
|
||||
url: setter.baseurl + "adminapi/ImageUpload/upload/temp",
|
||||
before: function (obj) {
|
||||
obj.preview(function (index, file, result) {
|
||||
$('#ID-upload-demo-img').attr('src', result); // 图片链接(base64)
|
||||
});
|
||||
|
||||
|
||||
element.progress('filter-demo', '0%'); // 进度条复位
|
||||
layer.msg('上传中', { icon: 16, time: 0 });
|
||||
},
|
||||
done: function (res) {
|
||||
// 若上传失败
|
||||
if (res.code > 0) {
|
||||
return layer.msg('上传失败');
|
||||
}
|
||||
|
||||
console.log($('#ID-upload-demo-img-v').val())
|
||||
// 上传成功的一些操作
|
||||
$('#ID-upload-demo-img-v').val(setter.baseurl + res.path);
|
||||
$('#ID-upload-demo-text').html(res.path); // 置空上传失败的状态
|
||||
},
|
||||
error: function () {
|
||||
// 演示失败状态,并实现重传
|
||||
var demoText = $('#ID-upload-demo-text');
|
||||
demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs demo-reload">重试</a>');
|
||||
demoText.find('.demo-reload').on('click', function () {
|
||||
uploadInst.upload();
|
||||
});
|
||||
},
|
||||
// 进度条
|
||||
progress: function (n, elem, e) {
|
||||
element.progress('filter-demo', n + '%'); // 可配合 layui 进度条元素使用
|
||||
if (n == 100) {
|
||||
layer.msg('上传完毕', { icon: 1 });
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
|
||||
|
||||
<title>广告位</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>广告位</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-banneradmin-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="keyWord" placeholder="请输入" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-banneradmin" lay-submit lay-filter="LAY-user-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="layui-btn layuiadmin-btn-admin" data-type="add">添加</button>
|
||||
</div>
|
||||
|
||||
<table id="LAY-user-back-manage" lay-filter="LAY-user-back-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-banneradmin-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
layui.use('banneradmin', layui.factory('banneradmin')).use(['admin', 'banneradmin', 'table'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, view = layui.view
|
||||
, table = layui.table
|
||||
, setter = layui.setter
|
||||
, form = layui.form;
|
||||
|
||||
form.render(null, 'layadmin-userfront-formlist');
|
||||
|
||||
//监听搜索
|
||||
form.on('submit(LAY-user-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
|
||||
//执行重载
|
||||
table.reload('LAY-user-back-manage', {
|
||||
where: field
|
||||
});
|
||||
});
|
||||
|
||||
//事件
|
||||
var active = {
|
||||
add: function () {
|
||||
|
||||
admin.popup({
|
||||
title: '添加广告位'
|
||||
, area: ["500px", "600px"]
|
||||
, id: 'LAY-popup-user-add'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('user/administrators/bannerform').done(function () {
|
||||
form.render(null, 'layuiadmin-form-admin');
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$('.layui-btn.layuiadmin-btn-admin').on('click', function () {
|
||||
|
||||
var type = $(this).data('type');
|
||||
active[type] ? active[type].call(this) : '';
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,233 @@
|
||||
|
||||
|
||||
<title>字典管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>用户</cite></a>
|
||||
<a><cite>字典管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="layui-btn layuiadmin-btn-dic" data-type="add">添加</button>
|
||||
</div>
|
||||
|
||||
<table id="LAY-user-dic" lay-filter="LAY-user-dic"></table>
|
||||
|
||||
<script type="text/html" id="table-dic-admin-tools">
|
||||
<div class="layui-btn-container">
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="addChild">新增</a>
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="del">删除</a>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
layui.use(['admin', "form", 'treeTable'], function () {
|
||||
var setter = layui.setter;
|
||||
var treeTable = layui.treeTable;
|
||||
var layer = layui.layer;
|
||||
var admin = layui.admin;
|
||||
var form = layui.form;
|
||||
var dropdown = layui.dropdown;
|
||||
var view = layui.view;
|
||||
var $ = layui.$;
|
||||
// 渲染
|
||||
var active = {
|
||||
add: function () {
|
||||
|
||||
admin.popup({
|
||||
title: '新增字典'
|
||||
, area: ['550px', '550px']
|
||||
, id: 'LAY-popup-content-add'
|
||||
, success: function (e, i) {
|
||||
view(this.id).render("user/administrators/dicform").done(function () {
|
||||
|
||||
form.render(null, "layuiadmin-form-dic"), form.on("submit(LAY-user-dic-submit)", function (e) {
|
||||
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/dic/add",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(e.field),
|
||||
done: function (res) {
|
||||
|
||||
inst.reloadData(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$('.layui-btn.layuiadmin-btn-dic').on('click', function () {
|
||||
|
||||
var type = $(this).data('type');
|
||||
active[type] ? active[type].call(this) : '';
|
||||
});
|
||||
|
||||
var inst = treeTable.render({
|
||||
elem: '#LAY-user-dic',
|
||||
url: setter.baseurl + "adminapi/System/dic/list", // 此处为静态模拟数据,实际使用时需换成真实接口
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
tree: {
|
||||
/*
|
||||
// 异步加载子节点
|
||||
async: {
|
||||
enable: true,
|
||||
url: '/static/json/2/treeTable/demo-async.json', // 此处为静态模拟数据,实际使用时需换成真实接口
|
||||
autoParam: ["parentId=id"]
|
||||
}
|
||||
*/
|
||||
},
|
||||
maxHeight: '501px',
|
||||
cols: [[
|
||||
|
||||
{ field: 'name', title: '名称',fixed: 'left' },
|
||||
{ field: 'order', title: '序号', fixed: 'left' },
|
||||
{ field: 'value', title: '值' },
|
||||
{ field: 'code', title: '编码' },
|
||||
{ field: 'remark', title: '备注' },
|
||||
{ field: 'remark1', title: '备注1' },
|
||||
{ fixed: "right", title: "操作", width: 190, align: "center", toolbar: "#table-dic-admin-tools" }
|
||||
]],
|
||||
page: false
|
||||
});
|
||||
// 表头工具栏工具事件
|
||||
treeTable.on("toolbar(table-dic-admin)", function (obj) {
|
||||
var config = obj.config;
|
||||
var tableId = config.id;
|
||||
var status = treeTable.checkStatus(tableId);
|
||||
// 获取选中行
|
||||
if (obj.event === "getChecked") {
|
||||
if (!status.data.length) return layer.msg('无选中数据');
|
||||
console.log(status);
|
||||
layer.alert("当前数据选中已经输出到控制台,<br>您可按 F12 从控制台中查看结果。");
|
||||
}
|
||||
});
|
||||
// 单元格工具事件
|
||||
treeTable.on('tool(' + inst.config.id + ')', function (obj) {
|
||||
var layEvent = obj.event; // 获得 lay-event 对应的值
|
||||
var trElem = obj.tr;
|
||||
var trData = obj.data;
|
||||
var tableId = obj.config.id;
|
||||
l = obj.data;
|
||||
if (layEvent === "addChild") {
|
||||
admin.popup({
|
||||
title: '新增字典'
|
||||
, area: ['550px', '550px']
|
||||
, id: 'LAY-popup-content-add'
|
||||
, success: function (e, i) {
|
||||
view(this.id).render("user/administrators/dicform").done(function () {
|
||||
|
||||
form.render(null, "layuiadmin-form-dic"), form.on("submit(LAY-user-dic-submit)", function (e) {
|
||||
|
||||
e.field.parentId = l.id;
|
||||
console.log(e.field);
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/dic/add",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(e.field),
|
||||
done: function (res) {
|
||||
|
||||
inst.reloadData(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (layEvent === "edit") {
|
||||
admin.popup({
|
||||
title: '编辑字典'
|
||||
, area: ['550px', '550px']
|
||||
, id: 'LAY-popup-content-add'
|
||||
, success: function (e, i) {
|
||||
view(this.id).render("user/administrators/dicform", l).done(function () {
|
||||
|
||||
form.render(null, "layuiadmin-form-dic"), form.on("submit(LAY-user-dic-submit)", function (e) {
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/dic/update",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(e.field),
|
||||
done: function (res) {
|
||||
|
||||
inst.reloadData(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (layEvent === "del") {
|
||||
layer.confirm("确定删除此字典么?", function (i) {
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/System/dic/delete?id=" + l.id,//实际使用请改成服务端真实接口
|
||||
async: true,
|
||||
done: function (res) {
|
||||
obj.del(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-dic" style="padding: 20px 30px 0 0;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名字</label>
|
||||
<div class="layui-input-block">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="id" value="{{ d.params.id}}" class="layui-input" style="display:none">
|
||||
<input type="text" name="parentId" value="{{ d.params.parentId}}" class="layui-input" style="display:none">
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="name" value="{{ d.params.name || '' }}" lay-verify="required" placeholder="名字" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">序号</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="number" name="order" value="{{ d.params.order || 0 }}" lay-verify="required" placeholder="序号" step="1" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">编码</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="code" value="{{ d.params.code || '' }}" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">值</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="value" value="{{ d.params.value || '' }}" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="remark" value="{{ d.params.remark || '' }}" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">备注1</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="remark1" value="{{ d.params.remark1 || '' }}" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-dic-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form','tree'], function(){
|
||||
var $ = layui.$
|
||||
, tree = layui.tree
|
||||
, form = layui.form
|
||||
, admin = layui.admin
|
||||
, setter = layui.setter
|
||||
,treedata = [];
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,136 @@
|
||||
|
||||
|
||||
<title>后台管理员</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>用户</cite></a>
|
||||
<a><cite>后台管理员</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-useradmin-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="keyWord" placeholder="请输入" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-useradmin" lay-submit lay-filter="LAY-user-front-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="layui-btn layuiadmin-btn-admin" data-type="add">添加</button>
|
||||
</div>
|
||||
|
||||
<table id="LAY-user-back-manage" lay-filter="LAY-user-back-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-useradmin-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
layui.use('useradmin', layui.factory('useradmin')).use(['admin', 'useradmin', 'table'], function () {
|
||||
var $ = layui.$
|
||||
, admin = layui.admin
|
||||
, view = layui.view
|
||||
, table = layui.table
|
||||
, setter = layui.setter
|
||||
, form = layui.form;
|
||||
|
||||
form.render(null, 'layadmin-userfront-formlist');
|
||||
|
||||
//监听搜索
|
||||
form.on('submit(LAY-user-front-search)', function (data) {
|
||||
var field = data.field;
|
||||
|
||||
//执行重载
|
||||
table.reload('LAY-user-back-manage', {
|
||||
where: field
|
||||
});
|
||||
});
|
||||
|
||||
//事件
|
||||
var active = {
|
||||
add: function () {
|
||||
|
||||
admin.popup({
|
||||
title: '添加管理员'
|
||||
, area: ["500px", "600px"]
|
||||
, id: 'LAY-popup-user-add'
|
||||
, success: function (layero, index) {
|
||||
view(this.id).render('user/administrators/adminform').done(function () {
|
||||
form.render(null, 'layuiadmin-form-admin');
|
||||
|
||||
//监听提交 - 使用 off().on() 防止重复绑定
|
||||
$(layero).find('[lay-filter="LAY-user-back-submit"]').off('click.adminsubmit').on('click.adminsubmit', function () {
|
||||
// 手动获取表单数据
|
||||
var userName = $(layero).find('input[name="userName"]').val();
|
||||
var displayName = $(layero).find('input[name="displayName"]').val();
|
||||
var icon = $(layero).find('input[name="icon"]').val();
|
||||
var password = $(layero).find('input[name="password"]').val();
|
||||
var systemRole = $(layero).find('select[name="systemRole"]').val();
|
||||
var systemRoleText = $(layero).find('select[name="systemRole"] option:selected').text();
|
||||
|
||||
var param = {
|
||||
userName: userName,
|
||||
displayName: displayName,
|
||||
icon: icon,
|
||||
password: password,
|
||||
systemRole: {
|
||||
id: systemRole,
|
||||
name: systemRoleText
|
||||
}
|
||||
};
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/user/add",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
//$.ajax({});
|
||||
layui.table.reload('LAY-user-back-manage'); //重载表格
|
||||
layer.close(index); //执行关闭
|
||||
}
|
||||
});
|
||||
return false; // 防止表单默认提交
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$('.layui-btn.layuiadmin-btn-admin').on('click', function () {
|
||||
|
||||
var type = $(this).data('type');
|
||||
active[type] ? active[type].call(this) : '';
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,231 @@
|
||||
|
||||
|
||||
<title>菜单管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>用户</cite></a>
|
||||
<a><cite>菜单管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="layui-btn layuiadmin-btn-nav" data-type="add">添加</button>
|
||||
</div>
|
||||
|
||||
<table id="LAY-user-nav" lay-filter="LAY-user-nav"></table>
|
||||
|
||||
<script type="text/html" id="table-nav-admin-tools">
|
||||
<div class="layui-btn-container">
|
||||
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="addChild">新增</a>
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="del">删除</a>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
layui.use(['admin', "form", 'treeTable'], function () {
|
||||
var setter = layui.setter;
|
||||
var treeTable = layui.treeTable;
|
||||
var layer = layui.layer;
|
||||
var admin = layui.admin;
|
||||
var form = layui.form;
|
||||
var dropdown = layui.dropdown;
|
||||
var view = layui.view;
|
||||
var $ = layui.$;
|
||||
// 渲染
|
||||
var active = {
|
||||
add: function () {
|
||||
|
||||
admin.popup({
|
||||
title: '新增菜单'
|
||||
, area: ['550px', '550px']
|
||||
, id: 'LAY-popup-content-add'
|
||||
, success: function (e, i) {
|
||||
view(this.id).render("user/administrators/navform").done(function () {
|
||||
|
||||
form.render(null, "layuiadmin-form-nav"), form.on("submit(LAY-user-nav-submit)", function (e) {
|
||||
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/nav/add",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(e.field),
|
||||
done: function (res) {
|
||||
|
||||
inst.reloadData(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$('.layui-btn.layuiadmin-btn-nav').on('click', function () {
|
||||
|
||||
var type = $(this).data('type');
|
||||
active[type] ? active[type].call(this) : '';
|
||||
});
|
||||
|
||||
var inst = treeTable.render({
|
||||
elem: '#LAY-user-nav',
|
||||
url: setter.baseurl + "adminapi/System/nav/list", // 此处为静态模拟数据,实际使用时需换成真实接口
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
tree: {
|
||||
/*
|
||||
// 异步加载子节点
|
||||
async: {
|
||||
enable: true,
|
||||
url: '/static/json/2/treeTable/demo-async.json', // 此处为静态模拟数据,实际使用时需换成真实接口
|
||||
autoParam: ["parentId=id"]
|
||||
}
|
||||
*/
|
||||
},
|
||||
maxHeight: '501px',
|
||||
cols: [[
|
||||
|
||||
{ field: 'name', title: '名称',fixed: 'left' },
|
||||
{ field: 'order', title: '序号', fixed: 'left' },
|
||||
{
|
||||
field: 'url', title: '地址'},
|
||||
{ fixed: "right", title: "操作", width: 190, align: "center", toolbar: "#table-nav-admin-tools" }
|
||||
]],
|
||||
page: false
|
||||
});
|
||||
// 表头工具栏工具事件
|
||||
treeTable.on("toolbar(table-nav-admin)", function (obj) {
|
||||
var config = obj.config;
|
||||
var tableId = config.id;
|
||||
var status = treeTable.checkStatus(tableId);
|
||||
// 获取选中行
|
||||
if (obj.event === "getChecked") {
|
||||
if (!status.data.length) return layer.msg('无选中数据');
|
||||
console.log(status);
|
||||
layer.alert("当前数据选中已经输出到控制台,<br>您可按 F12 从控制台中查看结果。");
|
||||
}
|
||||
});
|
||||
// 单元格工具事件
|
||||
treeTable.on('tool(' + inst.config.id + ')', function (obj) {
|
||||
var layEvent = obj.event; // 获得 lay-event 对应的值
|
||||
var trElem = obj.tr;
|
||||
var trData = obj.data;
|
||||
var tableId = obj.config.id;
|
||||
l = obj.data;
|
||||
if (layEvent === "addChild") {
|
||||
admin.popup({
|
||||
title: '新增菜单'
|
||||
, area: ['550px', '550px']
|
||||
, id: 'LAY-popup-content-add'
|
||||
, success: function (e, i) {
|
||||
view(this.id).render("user/administrators/navform").done(function () {
|
||||
|
||||
form.render(null, "layuiadmin-form-nav"), form.on("submit(LAY-user-nav-submit)", function (e) {
|
||||
|
||||
e.field.parentId = l.id;
|
||||
console.log(e.field);
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/nav/add",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(e.field),
|
||||
done: function (res) {
|
||||
|
||||
inst.reloadData(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (layEvent === "edit") {
|
||||
admin.popup({
|
||||
title: '编辑菜单'
|
||||
, area: ['550px', '550px']
|
||||
, id: 'LAY-popup-content-add'
|
||||
, success: function (e, i) {
|
||||
view(this.id).render("user/administrators/navform", l).done(function () {
|
||||
|
||||
form.render(null, "layuiadmin-form-nav"), form.on("submit(LAY-user-nav-submit)", function (e) {
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/nav/update",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(e.field),
|
||||
done: function (res) {
|
||||
|
||||
inst.reloadData(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (layEvent === "del") {
|
||||
layer.confirm("确定删除此菜单么?", function (i) {
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "get",
|
||||
url: setter.baseurl + "adminapi/System/nav/delete?id=" + l.id,//实际使用请改成服务端真实接口
|
||||
async: true,
|
||||
done: function (res) {
|
||||
obj.del(),
|
||||
layer.close(i)
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-nav" style="padding: 20px 30px 0 0;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名字</label>
|
||||
<div class="layui-input-block">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="id" value="{{ d.params.id}}" class="layui-input" style="display:none">
|
||||
<input type="text" name="parentId" value="{{ d.params.parentId}}" class="layui-input" style="display:none">
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="name" value="{{ d.params.name || '' }}" lay-verify="required" placeholder="名字" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">序号</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="number" name="order" value="{{ d.params.order || 0 }}" lay-verify="required" placeholder="序号" step="1" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">跳转地址</label>
|
||||
<div class="layui-input-block">
|
||||
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="url" value="{{ d.params.url || '' }}" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-nav-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form','tree'], function(){
|
||||
var $ = layui.$
|
||||
, tree = layui.tree
|
||||
, form = layui.form
|
||||
, admin = layui.admin
|
||||
, setter = layui.setter
|
||||
,treedata = [];
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
|
||||
<title>角色管理</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>用户</cite></a>
|
||||
<a><cite>角色管理</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
|
||||
<div class="layui-card-body">
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="layui-btn layuiadmin-btn-role" data-type="add">添加</button>
|
||||
</div>
|
||||
|
||||
<table id="LAY-user-back-role" lay-filter="LAY-user-back-role"></table>
|
||||
|
||||
<script type="text/html" id="table-useradmin-admin">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="role"><i class="layui-icon layui-icon-edit"></i>权限</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use('useradmin', layui.factory('useradmin')).use(['admin', 'useradmin', 'table'], function(){
|
||||
var $ = layui.$
|
||||
,admin = layui.admin
|
||||
,view = layui.view
|
||||
, table = layui.table
|
||||
, setter = layui.setter
|
||||
,form = layui.form;
|
||||
|
||||
|
||||
|
||||
//事件
|
||||
var active = {
|
||||
|
||||
add: function(){
|
||||
admin.popup({
|
||||
title: '添加新角色'
|
||||
,area: ['500px', '480px']
|
||||
,id: 'LAY-popup-user-add'
|
||||
,success: function(layero, index){
|
||||
view(this.id).render('user/administrators/roleform').done(function(){
|
||||
form.render(null, 'layuiadmin-form-role');
|
||||
|
||||
//监听提交
|
||||
form.on('submit(LAY-user-role-submit)', function(data){
|
||||
|
||||
var param = data.field
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/role/add",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify(param),
|
||||
done: function (res) {
|
||||
|
||||
layui.table.reload('LAY-user-back-role'); //重载表格
|
||||
layer.close(index); //执行关闭
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
$('.layui-btn.layuiadmin-btn-role').on('click', function(){
|
||||
var type = $(this).data('type');
|
||||
console.log(type);
|
||||
active[type] ? active[type].call(this) : '';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-role" style="padding: 20px 30px 0 0;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">角色</label>
|
||||
<div class="layui-input-block">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="id" value="{{ d.params.id}}" class="layui-input" style="display:none">
|
||||
</script>
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="roleName" value="{{ d.params.roleName || '' }}" lay-verify="required" placeholder="请输入角色名称" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">具体描述</label>
|
||||
<div class="layui-input-block">
|
||||
<script type="text/html" template>
|
||||
<textarea type="text" name="description" lay-verify="required" autocomplete="off" class="layui-textarea">{{ d.params.description || '' }}</textarea>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-role-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form','tree'], function(){
|
||||
var $ = layui.$
|
||||
, tree = layui.tree
|
||||
, form = layui.form
|
||||
, admin = layui.admin
|
||||
, setter = layui.setter
|
||||
,treedata = [];
|
||||
|
||||
});
|
||||
</script>
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-role-tree" style="padding: 20px 30px 0 0;">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">权限范围</label>
|
||||
<div class="layui-input-block">
|
||||
<ul id="navigationist"></ul>
|
||||
<script type="text/html" lay-done="sendParams(d.params)" template>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-front-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
var id = '';
|
||||
var isLayUI = false;
|
||||
function sendParams(params) {
|
||||
|
||||
id = params.id;
|
||||
if (isLayUI) {
|
||||
layuiLoad();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
layuiLoad();
|
||||
function layuiLoad() {
|
||||
|
||||
layui.use(['admin', 'form', 'tree', 'user', 'laydate'], function () {
|
||||
var $ = layui.$
|
||||
, tree = layui.tree
|
||||
, form = layui.form
|
||||
, admin = layui.admin
|
||||
, setter = layui.setter
|
||||
, router = layui.router()
|
||||
, user = layui.user
|
||||
, laydate = layui.laydate
|
||||
, treedata = [];
|
||||
|
||||
treedatas = [];
|
||||
treeselecedIds = [];
|
||||
form.on('submit(LAY-user-front-submit)', function (data) {
|
||||
var checkData = tree.getChecked("navigatioid");
|
||||
treeselecedIds = [];
|
||||
|
||||
gettreeSelectIds(checkData)
|
||||
|
||||
admin.req({
|
||||
method: "post",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/role/updatenav",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
data: JSON.stringify({ id: id, navIds: treeselecedIds }),
|
||||
done: function (res) {
|
||||
//关闭弹窗
|
||||
layer.closeAll()
|
||||
}
|
||||
})
|
||||
|
||||
return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。
|
||||
});
|
||||
|
||||
//提交数据
|
||||
admin.req({
|
||||
method: "get",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/nav/list",//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
|
||||
done: function (res) {
|
||||
|
||||
treedata = gettreedata(res.data);
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
function gettreedata(arr) {
|
||||
let arr1 = [];
|
||||
layui.each(arr, function (index, val) {
|
||||
if (val.children != null) {
|
||||
val.children = gettreedata(val.children);
|
||||
}
|
||||
arr1.push({ title: val.name, id: val.id, children: val.children, spread: tree, checked: false });
|
||||
})
|
||||
return arr1;
|
||||
}
|
||||
function gettreeSelectIds(arr) {
|
||||
|
||||
layui.each(arr, function (index, val) {
|
||||
|
||||
if (val.children != null && val.children.length>0) {
|
||||
val.children = gettreeSelectIds(val.children);
|
||||
} else {
|
||||
treeselecedIds.push(val.id);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
treeRender();
|
||||
if (id != null && id != "") {
|
||||
admin.req({
|
||||
method: "get",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
url: setter.baseurl + "adminapi/System/role/get?id=" + id,//实际使用请改成服务端真实接口
|
||||
async: false,
|
||||
done: function (res) {
|
||||
tree.setChecked('navigatioid', res.data.navIds); //批量勾选 id 为 2、3 的节点
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function treeRender() {
|
||||
isLayUI = true;
|
||||
|
||||
tree.render({
|
||||
elem: '#navigationist',
|
||||
id: 'navigatioid',
|
||||
data: treedata,
|
||||
showCheckbox: true, // 这里可以设置为true来显示复选框,但LAYUI原生不支持多选逻辑
|
||||
oncheck: function (node) {
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
<title>金币变动记录</title>
|
||||
<script src="/admin/layui/xm-select.js"></script>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>用户管理</cite></a>
|
||||
<a><cite>金币变动记录</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-form layui-card-header layuiadmin-card-header-auto" lay-filter="layadmin-assetchange-formlist">
|
||||
<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="userId" placeholder="请输入用户ID" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">关键词</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="keyWord" placeholder="用户编号/昵称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">货币类型</label>
|
||||
<div class="layui-input-block">
|
||||
<div id="currencyTypes-select"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">变动类型</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="changeTypes" multiple>
|
||||
<option value="1">增加</option>
|
||||
<option value="2">减少</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">事件来源</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="sources" multiple>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">时间范围</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="timeRange" id="timeRange" placeholder="选择时间范围" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-list" lay-submit lay-filter="LAY-assetchange-search">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i> 搜索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" lay-filter="LAY-assetchange-reset">
|
||||
<i class="layui-icon layui-icon-refresh layuiadmin-button-btn"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="LAY-assetchange-manage" lay-filter="LAY-assetchange-manage"></table>
|
||||
|
||||
<script type="text/html" id="table-assetchange-toolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" lay-event="refresh">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="changeTypeTpl">
|
||||
{{# if(d.type === 1){ }}
|
||||
<span class="layui-badge layui-bg-green">增加</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-red">减少</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="currencyTypeTpl">
|
||||
{{# if(d.currencyType === 1){ }}
|
||||
<span class="layui-badge layui-bg-orange">金币</span>
|
||||
{{# } else if(d.currencyType === 2){ }}
|
||||
<span class="layui-badge layui-bg-blue">保险箱金币</span>
|
||||
{{# } else { }}
|
||||
<span class="layui-badge layui-bg-purple">钻石</span>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="countTpl">
|
||||
<div>
|
||||
<div>变动前: {{d.beforeCount}}</div>
|
||||
<div style="color: {{d.type === 1 ? '#5FB878' : '#FF5722'}};">
|
||||
{{d.type === 1 ? '+' : '-'}}{{d.changeCount}}
|
||||
</div>
|
||||
<div>变动后: {{d.afterCount}}</div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'table', 'form', 'laydate'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
table = layui.table,
|
||||
setter = layui.setter,
|
||||
form = layui.form,
|
||||
laydate = layui.laydate;
|
||||
|
||||
// 时间范围选择器
|
||||
laydate.render({
|
||||
elem: '#timeRange',
|
||||
type: 'datetime',
|
||||
range: '~'
|
||||
});
|
||||
|
||||
// 加载事件来源列表
|
||||
function loadSources() {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/UserAssetChange/sources',
|
||||
done: function (res) {
|
||||
var html = '';
|
||||
layui.each(res.data, function (index, item) {
|
||||
html += '<option value="' + item.value + '">' + item.label + '</option>';
|
||||
});
|
||||
$('[name="sources"]').append(html);
|
||||
form.render('select');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadSources();
|
||||
|
||||
// 初始化货币类型 xm-select
|
||||
console.log('[资金变动] 开始初始化货币类型 xm-select');
|
||||
console.log('[资金变动] #currencyTypes-select 元素:', $('#currencyTypes-select').length);
|
||||
|
||||
var currencyTypesSelect = xmSelect.render({
|
||||
el: '#currencyTypes-select',
|
||||
data: [
|
||||
{name: '金币', value: 1},
|
||||
{name: '保险箱金币', value: 2},
|
||||
{name: '钻石', value: 3}
|
||||
],
|
||||
tips: '请选择货币类型',
|
||||
filterable: true,
|
||||
model: { label: { type: 'block', block: { showIcon: false } } },
|
||||
on: function(data) {
|
||||
console.log('[资金变动] 货币类型选择变化:', data.arr);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[资金变动] 货币类型 xm-select 初始化完成:', currencyTypesSelect);
|
||||
|
||||
form.render(null, 'layadmin-assetchange-formlist');
|
||||
|
||||
// 从URL获取userId参数(从用户列表跳转时带入)
|
||||
var urlParams = new URLSearchParams(window.location.hash.split('?')[1] || '');
|
||||
var initUserId = urlParams.get('userId') || '';
|
||||
var initNickName = urlParams.get('nickName') || '';
|
||||
if (initUserId) {
|
||||
$('input[name="userId"]').val(initUserId);
|
||||
if (initNickName) {
|
||||
$('.layui-breadcrumb a:last').text('金币变动记录 - ' + initNickName);
|
||||
}
|
||||
}
|
||||
|
||||
// 监听搜索
|
||||
form.on('submit(LAY-assetchange-search)', function (data) {
|
||||
var field = data.field;
|
||||
|
||||
console.log('[资金变动] 搜索参数:', field);
|
||||
|
||||
// 处理时间范围
|
||||
if (field.timeRange) {
|
||||
var times = field.timeRange.split('~');
|
||||
field.timeStart = Math.floor(new Date(times[0].trim()).getTime() / 1000);
|
||||
field.timeEnd = Math.floor(new Date(times[1].trim()).getTime() / 1000);
|
||||
}
|
||||
delete field.timeRange;
|
||||
|
||||
// 处理多选:layui 原生 select multiple(问题3修复:确保currencyTypes是数组)
|
||||
field.currencyTypes = currencyTypesSelect.getValue('value');
|
||||
console.log('[资金变动] 货币类型选择:', field.currencyTypes);
|
||||
|
||||
if (field.currencyTypes.length === 0) {
|
||||
delete field.currencyTypes;
|
||||
}
|
||||
|
||||
if (field.changeTypes) {
|
||||
field.changeTypes = Array.isArray(field.changeTypes) ? field.changeTypes : [field.changeTypes];
|
||||
} else {
|
||||
delete field.changeTypes;
|
||||
}
|
||||
|
||||
if (field.sources) {
|
||||
field.sources = Array.isArray(field.sources) ? field.sources : [field.sources];
|
||||
} else {
|
||||
delete field.sources;
|
||||
}
|
||||
|
||||
// 排除击杀鱼和开炮事件
|
||||
field.excludeSources = ['开炮', '击杀鱼'];
|
||||
console.log('[资金变动] 完整请求参数:', field);
|
||||
|
||||
table.reload('LAY-assetchange-manage', {
|
||||
where: field,
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 监听重置
|
||||
form.on('submit(LAY-assetchange-reset)', function (data) {
|
||||
$('input[name="userId"]').val('');
|
||||
$('input[name="keyWord"]').val('');
|
||||
$('[name="currencyTypes"]').val('');
|
||||
$('[name="changeTypes"]').val('');
|
||||
$('[name="sources"]').val('');
|
||||
$('#timeRange').val('');
|
||||
form.render('select');
|
||||
table.reload('LAY-assetchange-manage', {
|
||||
where: {},
|
||||
page: { curr: 1 }
|
||||
});
|
||||
});
|
||||
|
||||
// 刷新按钮
|
||||
$('.layui-btn-container').on('click', '[lay-event="refresh"]', function () {
|
||||
table.reload('LAY-assetchange-manage');
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: "#LAY-assetchange-manage",
|
||||
url: setter.baseurl + "adminapi/UserAssetChange/list",
|
||||
method: "post",
|
||||
contentType: "application/json",
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
toolbar: '#table-assetchange-toolbar',
|
||||
defaultToolbar: ['filter', 'exports', 'print'],
|
||||
where: {
|
||||
userId: initUserId
|
||||
},
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
limit: 10,
|
||||
cols: [[
|
||||
{ type: 'numbers', title: '序号', width: 60 },
|
||||
{ field: "userId", title: "用户ID", width: 120 },
|
||||
{ field: "userName", title: "用户名", width: 120 },
|
||||
{ field: "currencyType", title: "货币类型", width: 120, templet: '#currencyTypeTpl' },
|
||||
{ field: "type", title: "变动类型", width: 100, templet: '#changeTypeTpl' },
|
||||
{ field: "source", title: "事件来源", width: 150 },
|
||||
{ field: "beforeCount", title: "变动前", width: 120 },
|
||||
{ field: "changeCount", title: "变动值", width: 120, templet: function(d) {
|
||||
return '<span style="color: ' + (d.type === 1 ? '#5FB878' : '#FF5722') + ';">' +
|
||||
(d.type === 1 ? '+' : '-') + d.changeCount + '</span>';
|
||||
}},
|
||||
{ field: "afterCount", title: "变动后", width: 120 },
|
||||
{ field: "remark", title: "备注", minWidth: 200 },
|
||||
{ field: "createTime", title: "变动时间", width: 160, templet: function(d) {
|
||||
return formatDateTime(d.createTime);
|
||||
}}
|
||||
]],
|
||||
text: "对不起,加载出现异常!",
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
},
|
||||
done: function(res) {
|
||||
console.log('[资金变动] 表格数据加载完成:', res);
|
||||
if (res.data && res.data.length > 0) {
|
||||
console.log('[资金变动] 第一条数据示例:', res.data[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function formatDateTime(date) {
|
||||
if (!date) return '-';
|
||||
var d = new Date(date);
|
||||
var year = d.getFullYear();
|
||||
var month = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
var day = ('0' + d.getDate()).slice(-2);
|
||||
var hour = ('0' + d.getHours()).slice(-2);
|
||||
var minute = ('0' + d.getMinutes()).slice(-2);
|
||||
var second = ('0' + d.getSeconds()).slice(-2);
|
||||
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,144 @@
|
||||
|
||||
<script type="text/html" template>
|
||||
<link rel="stylesheet" href="{{ layui.setter.base }}style/login.css?v={{ layui.admin.v }}-1" media="all">
|
||||
</script>
|
||||
|
||||
|
||||
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login" style="display: none;">
|
||||
<div class="layadmin-user-login-main">
|
||||
<div class="layadmin-user-login-box layadmin-user-login-header">
|
||||
<h2>layuiAdmin</h2>
|
||||
<p>layui 官方出品的单页面后台管理模板系统</p>
|
||||
</div>
|
||||
<div class="layadmin-user-login-box layadmin-user-login-body layui-form">
|
||||
|
||||
<script type="text/html" template>
|
||||
{{# if(layui.router().search.type === 'resetpass'){ }}
|
||||
<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="pass" placeholder="新密码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-password" for="LAY-user-login-repass"></label>
|
||||
<input type="password" name="repass" id="LAY-user-login-repass" lay-verify="required" placeholder="确认密码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="LAY-user-forget-resetpass">重置新密码</button>
|
||||
</div>
|
||||
{{# } else { }}
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-cellphone" for="LAY-user-login-cellphone"></label>
|
||||
<input type="text" name="cellphone" id="LAY-user-login-cellphone" lay-verify="phone" placeholder="请输入注册时的手机号" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs7">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-vercode" for="LAY-user-login-vercode"></label>
|
||||
<input type="text" name="vercode" id="LAY-user-login-vercode" lay-verify="required" placeholder="图形验证码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs5">
|
||||
<div style="margin-left: 10px;">
|
||||
<img src="https://www.oschina.net/action/user/captcha" class="layadmin-user-login-codeimg" id="LAY-user-get-vercode">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs7">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-vercode" for="LAY-user-login-smscode"></label>
|
||||
<input type="text" name="vercode" id="LAY-user-login-smscode" lay-verify="required" placeholder="短信验证码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs5">
|
||||
<div style="margin-left: 10px;">
|
||||
<button type="button" class="layui-btn layui-btn-primary layui-btn-fluid" id="LAY-user-forget-getsmscode">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="LAY-user-forget-submit">找回密码</button>
|
||||
</div>
|
||||
{{# } }}
|
||||
</script>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-trans layadmin-user-login-footer">
|
||||
|
||||
<p>© 2018 <a href="http://www.layui.com/" target="_blank">layui.com</a></p>
|
||||
<p>
|
||||
<span><a href="http://www.layui.com/admin/#get" target="_blank">获取授权</a></span>
|
||||
<span><a href="http://www.layui.com/admin/pro/" target="_blank">在线演示</a></span>
|
||||
<span><a href="http://www.layui.com/admin/" target="_blank">前往官网</a></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'user'], function(){
|
||||
var $ = layui.$
|
||||
,setter = layui.setter
|
||||
,admin = layui.admin
|
||||
,form = layui.form
|
||||
,router = layui.router();
|
||||
|
||||
form.render();
|
||||
|
||||
//发送短信验证码
|
||||
admin.sendAuthCode({
|
||||
elem: '#LAY-user-forget-getsmscode'
|
||||
,elemPhone: '#LAY-user-login-cellphone'
|
||||
,elemVercode: '#LAY-user-login-vercode'
|
||||
,ajax: {
|
||||
url: './json/user/sms.js' //实际使用请改成服务端真实接口
|
||||
}
|
||||
});
|
||||
|
||||
//找回密码下一步
|
||||
form.on('submit(LAY-user-forget-submit)', function(obj){
|
||||
var field = obj.field;
|
||||
|
||||
//请求接口
|
||||
admin.req({
|
||||
url: './json/user/forget.js' //实际使用请改成服务端真实接口
|
||||
,data: field
|
||||
,done: function(res){
|
||||
location.hash = router.href + '/type=resetpass';
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
//重置密码
|
||||
form.on('submit(LAY-user-forget-resetpass)', function(obj){
|
||||
var field = obj.field;
|
||||
|
||||
//确认密码
|
||||
if(field.password !== field.repass){
|
||||
return layer.msg('两次密码输入不一致');
|
||||
}
|
||||
|
||||
//请求接口
|
||||
admin.req({
|
||||
url: './json/user/resetpass.js' //实际使用请改成服务端真实接口
|
||||
,data: field
|
||||
,done: function(res){
|
||||
layer.msg('密码已成功重置', {
|
||||
offset: '15px'
|
||||
,icon: 1
|
||||
,time: 1000
|
||||
}, function(){
|
||||
location.hash = '/user/login'; //跳转到登入页
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
<script type="text/html" template>
|
||||
<link rel="stylesheet" href="{{ layui.setter.base }}style/login.css?v={{ layui.admin.v }}-1" media="all">
|
||||
</script>
|
||||
|
||||
|
||||
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login" style="display: none;">
|
||||
|
||||
<div class="layadmin-user-login-main">
|
||||
<div class="layadmin-user-login-box layadmin-user-login-header">
|
||||
<h2>通用后台管理系统</h2>
|
||||
</div>
|
||||
<div class="layadmin-user-login-box layadmin-user-login-body layui-form">
|
||||
<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" lay-verify="required" placeholder="用户名" class="layui-input">
|
||||
</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">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs7">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-vercode" for="LAY-user-login-vercode"></label>
|
||||
<input type="text" name="vercode" id="LAY-user-login-vercode" lay-verify="required" placeholder="图形验证码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs5">
|
||||
<div style="margin-left: 10px;">
|
||||
<img src="https://www.oschina.net/action/user/captcha" class="layadmin-user-login-codeimg" id="LAY-user-get-vercode">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="LAY-user-login-submit">登 入</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'user'], function(){
|
||||
var $ = layui.$
|
||||
,setter = layui.setter
|
||||
,admin = layui.admin
|
||||
,form = layui.form
|
||||
,router = layui.router()
|
||||
,search = router.search;
|
||||
|
||||
form.render();
|
||||
|
||||
//提交
|
||||
form.on('submit(LAY-user-login-submit)', function(obj){
|
||||
|
||||
|
||||
//请求登入接口
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/System/user/login' //实际使用请改成服务端真实接口
|
||||
,data: obj.field
|
||||
,done: function(res){
|
||||
|
||||
//请求成功后,写入 access_token
|
||||
layui.data(setter.tableName, {
|
||||
key: setter.request.tokenName
|
||||
,value: res.data.token
|
||||
});
|
||||
|
||||
//登入成功的提示与跳转
|
||||
layer.msg('登入成功', {
|
||||
offset: '15px'
|
||||
,icon: 1
|
||||
,time: 1000
|
||||
}, function(){
|
||||
location.hash = search.redirect ? decodeURIComponent(search.redirect) : '/';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,125 @@
|
||||
|
||||
<script type="text/html" template>
|
||||
<link rel="stylesheet" href="{{ layui.setter.base }}style/login.css?v={{ layui.admin.v }}-1" media="all">
|
||||
</script>
|
||||
|
||||
|
||||
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login" style="display: none;">
|
||||
<div class="layadmin-user-login-main">
|
||||
<div class="layadmin-user-login-box layadmin-user-login-header">
|
||||
<h2>layuiAdmin</h2>
|
||||
<p>layui 官方出品的单页面后台管理模板系统</p>
|
||||
</div>
|
||||
<div class="layadmin-user-login-box layadmin-user-login-body layui-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-cellphone" for="LAY-user-login-cellphone"></label>
|
||||
<input type="text" name="cellphone" id="LAY-user-login-cellphone" lay-verify="phone" placeholder="手机" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs7">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-vercode" for="LAY-user-login-vercode"></label>
|
||||
<input type="text" name="vercode" id="LAY-user-login-vercode" lay-verify="required" placeholder="验证码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs5">
|
||||
<div style="margin-left: 10px;">
|
||||
<button type="button" class="layui-btn layui-btn-primary layui-btn-fluid" id="LAY-user-reg-getsmscode">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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="pass" placeholder="密码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-password" for="LAY-user-login-repass"></label>
|
||||
<input type="password" name="repass" id="LAY-user-login-repass" lay-verify="required" placeholder="确认密码" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layadmin-user-login-icon layui-icon layui-icon-username" for="LAY-user-login-nickname"></label>
|
||||
<input type="text" name="nickname" id="LAY-user-login-nickname" lay-verify="nickname" placeholder="昵称" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<input type="checkbox" name="agreement" lay-skin="primary" title="同意用户协议" checked>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="LAY-user-reg-submit">注 册</button>
|
||||
</div>
|
||||
<div class="layui-trans layui-form-item layadmin-user-login-other">
|
||||
<label>社交账号注册</label>
|
||||
<a href="javascript:;"><i class="layui-icon layui-icon-login-qq"></i></a>
|
||||
<a href="javascript:;"><i class="layui-icon layui-icon-login-wechat"></i></a>
|
||||
<a href="javascript:;"><i class="layui-icon layui-icon-login-weibo"></i></a>
|
||||
|
||||
<a lay-href="/user/login" class="layadmin-user-jump-change layadmin-link layui-hide-xs">用已有帐号登入</a>
|
||||
<a lay-href="/user/login" class="layadmin-user-jump-change layadmin-link layui-hide-sm layui-show-xs-inline-block">登入</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-trans layadmin-user-login-footer">
|
||||
|
||||
<p>© 2018 <a href="http://www.layui.com/" target="_blank">layui.com</a></p>
|
||||
<p>
|
||||
<span><a href="http://www.layui.com/admin/#get" target="_blank">获取授权</a></span>
|
||||
<span><a href="http://www.layui.com/admin/pro/" target="_blank">在线演示</a></span>
|
||||
<span><a href="http://www.layui.com/admin/" target="_blank">前往官网</a></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'user'], function(){
|
||||
var $ = layui.$
|
||||
,setter = layui.setter
|
||||
,admin = layui.admin
|
||||
,form = layui.form
|
||||
,router = layui.router();
|
||||
|
||||
form.render();
|
||||
|
||||
//发送短信验证码
|
||||
admin.sendAuthCode({
|
||||
elem: '#LAY-user-reg-getsmscode'
|
||||
,elemPhone: '#LAY-user-login-cellphone'
|
||||
,elemVercode: '#LAY-user-login-vercode'
|
||||
,ajax: {
|
||||
url: './json/user/sms.js' //实际使用请改成服务端真实接口
|
||||
}
|
||||
});
|
||||
|
||||
//提交
|
||||
form.on('submit(LAY-user-reg-submit)', function(obj){
|
||||
var field = obj.field;
|
||||
|
||||
//确认密码
|
||||
if(field.password !== field.repass){
|
||||
return layer.msg('两次密码输入不一致');
|
||||
}
|
||||
|
||||
//是否同意用户协议
|
||||
if(!field.agreement){
|
||||
return layer.msg('你必须同意用户协议才能注册');
|
||||
}
|
||||
|
||||
//请求接口
|
||||
admin.req({
|
||||
url: './json/user/reg.js' //实际使用请改成服务端真实接口
|
||||
,data: field
|
||||
,done: function(res){
|
||||
layer.msg('注册成功', {
|
||||
offset: '15px'
|
||||
,icon: 1
|
||||
,time: 1000
|
||||
}, function(){
|
||||
location.hash = '/user/login'; //跳转到登入页
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,416 @@
|
||||
|
||||
<title>用户因子配置</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="">主页</a>
|
||||
<a><cite>用户管理</cite></a>
|
||||
<a><cite>用户因子配置</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form" lay-filter="layadmin-factor-formlist">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">关键词</label>
|
||||
<div class="layui-input-inline" style="width:150px;">
|
||||
<input type="text" name="keyWord" placeholder="编号/昵称/手机" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">注册IP</label>
|
||||
<div class="layui-input-inline" style="width:130px;">
|
||||
<input type="text" name="registerIp" placeholder="注册IP" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">登录IP</label>
|
||||
<div class="layui-input-inline" style="width:130px;">
|
||||
<input type="text" name="loginIp" placeholder="登录IP" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">IP数量</label>
|
||||
<div class="layui-input-inline" style="width:60px;">
|
||||
<select name="ipCountOp">
|
||||
<option value="">不限</option>
|
||||
<option value="gt">大于</option>
|
||||
<option value="gte">大于等于</option>
|
||||
<option value="lt">小于</option>
|
||||
<option value="lte">小于等于</option>
|
||||
<option value="eq">等于</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width:60px;">
|
||||
<input type="number" name="ipCount" placeholder="数量" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">屏蔽状态</label>
|
||||
<div class="layui-input-inline" style="width:100px;">
|
||||
<select name="isBlack">
|
||||
<option value="">全部</option>
|
||||
<option value="1">已屏蔽</option>
|
||||
<option value="0">未屏蔽</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">在线</label>
|
||||
<div class="layui-input-inline" style="width:100px;">
|
||||
<select name="isOnline">
|
||||
<option value="">全部</option>
|
||||
<option value="1">在线</option>
|
||||
<option value="0">离线</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-submit lay-filter="btn-search">
|
||||
<i class="layui-icon layui-icon-search"></i> 搜索
|
||||
</button>
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary" id="btn-reset">
|
||||
<i class="layui-icon layui-icon-refresh"></i> 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="table-factor-list" lay-filter="table-factor-list"></table>
|
||||
<script type="text/html" id="toolbar-factor">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑因子</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-warm" lay-event="realtime" title="实时房间数据"><i class="layui-icon layui-icon-eye"></i>实时</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="setBlack"><i class="layui-icon layui-icon-fonts-del"></i>{{ d.isBlack ? '取消屏蔽' : '屏蔽' }}</a>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'table'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
setter = layui.setter,
|
||||
layer = layui.layer;
|
||||
|
||||
function formatTime(timestamp) {
|
||||
if (!timestamp) return '-';
|
||||
var date = new Date(timestamp * 1000);
|
||||
var y = date.getFullYear();
|
||||
var m = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
var d = date.getDate().toString().padStart(2, '0');
|
||||
return y + '-' + m + '-' + d;
|
||||
}
|
||||
|
||||
function esc(s) {
|
||||
if (s == null) return '';
|
||||
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
form.render();
|
||||
|
||||
table.render({
|
||||
elem: '#table-factor-list',
|
||||
url: setter.baseurl + 'adminapi/AdminUser/GetUserFactorList',
|
||||
method: 'POST',
|
||||
contentType: 'application/json;charset=UTF-8',
|
||||
headers: {
|
||||
'token': layui.data(setter.tableName)[setter.request.tokenName]
|
||||
},
|
||||
page: true,
|
||||
limit: 15,
|
||||
limits: [10, 15, 20, 30, 50],
|
||||
request: {
|
||||
pageName: 'pageIndex',
|
||||
limitName: 'pageSize'
|
||||
},
|
||||
response: {
|
||||
statusName: 'code',
|
||||
statusCode: 0,
|
||||
msgName: 'info',
|
||||
countName: 'count',
|
||||
dataName: 'data'
|
||||
},
|
||||
where: {},
|
||||
cols: [[
|
||||
{ field: 'userName', title: '昵称', width: 100, templet: function(d) { return esc(d.userName || '-'); } },
|
||||
{ field: 'number', title: '用户编号', width: 120, templet: function(d) { return esc(d.number || '-'); } },
|
||||
{ field: 'mobile', title: '手机号', width: 120, templet: function(d) { return esc(d.mobile || '-'); } },
|
||||
{ field: 'registerIp', title: '注册IP', width: 130, templet: function(d) { return esc(d.registerIp || '-'); } },
|
||||
{ field: 'loginIp', title: '登录IP', width: 130, templet: function(d) { return esc(d.loginIp || '-'); } },
|
||||
{ field: 'ipCount', title: 'IP数量', width: 80, templet: function(d) {
|
||||
var count = d.ipCount || 0;
|
||||
return count > 5 ? '<span style="color:red;font-weight:bold;">' + count + '</span>' : count;
|
||||
}},
|
||||
{ field: 'isBlack', title: '屏蔽', width: 70, templet: function(d) {
|
||||
return d.isBlack ? '<span class="layui-badge layui-bg-red">已屏蔽</span>' : '<span class="layui-badge layui-bg-green">正常</span>';
|
||||
}},
|
||||
{ field: 'violateValue', title: '系统因子', width: 90, templet: function(d) { return (d.violateValue || 0).toFixed(2); } },
|
||||
{ field: 'additionalFactor', title: '附加值', width: 80, templet: function(d) { return (d.additionalFactor || 0).toFixed(2); } },
|
||||
{ field: 'totalRecharge', title: '充值金额', width: 90, templet: function(d) { return (d.totalRecharge || 0).toFixed(2); } },
|
||||
{ field: 'totalRechargeGold', title: '金币本金统计(不计VIP)', width: 155, templet: function(d) { var v = d.totalRechargeGold || 0; return v.toLocaleString(); } },
|
||||
{ field: 'totalConsumeGold', title: '消费金币', width: 90, templet: function(d) { var v = d.totalConsumeGold || 0; return v.toLocaleString(); } },
|
||||
{ field: 'currentGold', title: '当前金币', width: 100, templet: function(d) { var v = d.currentGold || 0; return v.toLocaleString(); } },
|
||||
{ field: 'profit', title: '盈亏', width: 100, templet: function(d) {
|
||||
var v = d.profit || 0;
|
||||
var cls = v >= 0 ? 'color:green;' : 'color:red;';
|
||||
return '<span style="' + cls + 'font-weight:bold;">' + (v >= 0 ? '+' : '') + v.toLocaleString() + '</span>';
|
||||
}},
|
||||
{ field: 'startingBonus', title: '注册金币', width: 90, templet: function(d) { var v = d.startingBonus || 0; return v.toLocaleString(); } },
|
||||
{ field: 'compensateQuota', title: '补偿配额', width: 90, templet: function(d) { return d.compensateQuota || 0; } },
|
||||
{ field: 'penaltyQuota', title: '罚款配额', width: 90, templet: function(d) { return d.penaltyQuota || 0; } },
|
||||
{ field: 'missRate', title: '空炮率', width: 80, templet: function(d) { return (d.missRate || 0).toFixed(0) + '%'; } },
|
||||
{ field: 'compRate', title: '补偿系数', width: 140, templet: function(d) {
|
||||
var cr = d.compensateRate || {};
|
||||
return 'B:' + (cr.bossRate || 1) + ' G:' + (cr.goldRate || 1) + ' S:' + (cr.specialRate || 1) + ' O:' + (cr.ordinary || 1);
|
||||
}},
|
||||
{ field: 'penaltyRate', title: '罚款系数', width: 140, templet: function(d) {
|
||||
var pr = d.penaltyRate || {};
|
||||
return 'B:' + (pr.bossRate || 1) + ' G:' + (pr.goldRate || 1) + ' S:' + (pr.specialRate || 1) + ' O:' + (pr.ordinary || 1);
|
||||
}},
|
||||
{ field: 'createTime', title: '注册时间', width: 110, templet: function(d) { return formatTime(d.createTime); } },
|
||||
{ fixed: 'right', title: '操作', width: 250, align: 'center', toolbar: '#toolbar-factor' }
|
||||
]],
|
||||
text: { none: '暂无数据' },
|
||||
parseData: function(res) {
|
||||
console.log('API响应:', res);
|
||||
if (res.code !== 0) {
|
||||
layer.msg(res.info || '加载失败', { icon: 2 });
|
||||
}
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.info || "",
|
||||
"count": res.count || 0,
|
||||
"data": res.data || []
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
form.on('submit(btn-search)', function(data) {
|
||||
var field = data.field;
|
||||
var where = {
|
||||
keyWord: field.keyWord || '',
|
||||
registerIp: field.registerIp || '',
|
||||
loginIp: field.loginIp || '',
|
||||
isBlack: field.isBlack === '' ? null : (field.isBlack === '1'),
|
||||
isOnline: field.isOnline === '' ? null : (field.isOnline === '1'),
|
||||
ipCountOp: field.ipCountOp || '',
|
||||
ipCount: field.ipCount ? parseInt(field.ipCount) : null
|
||||
};
|
||||
table.reload('table-factor-list', { where: where, page: { curr: 1 } });
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#btn-reset').on('click', function() {
|
||||
$('input[name="keyWord"]').val('');
|
||||
$('input[name="registerIp"]').val('');
|
||||
$('input[name="loginIp"]').val('');
|
||||
$('input[name="ipCount"]').val('');
|
||||
$('select[name="ipCountOp"]').val('');
|
||||
$('select[name="isBlack"]').val('');
|
||||
$('select[name="isOnline"]').val('');
|
||||
form.render('select');
|
||||
table.reload('table-factor-list', { where: {}, page: { curr: 1 } });
|
||||
});
|
||||
|
||||
table.on('tool(table-factor-list)', function(obj) {
|
||||
var data = obj.data;
|
||||
var layEvent = obj.event;
|
||||
|
||||
if (layEvent === 'edit') {
|
||||
var cr = data.compensateRate || {};
|
||||
var pr = data.penaltyRate || {};
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '编辑用户因子 - ' + (data.userName || '-'),
|
||||
area: ['1000px', '750px'],
|
||||
content: '<form class="layui-form" lay-filter="factor-edit-form" style="padding:20px;">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">系统因子</label><div class="layui-input-inline"><input type="number" step="0.01" name="violateValue" class="layui-input" value="' + (data.violateValue || 1) + '" readonly></div><div class="layui-form-mid">系统自动计算,不可修改。仅可修改下方的附加值</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">附加值</label><div class="layui-input-inline"><input type="number" step="0.01" name="additionalFactor" class="layui-input" value="' + (data.additionalFactor || 0) + '"></div><div class="layui-form-mid">最终因子=当前因子+此值。例: 当前因子0.5+附加值1=1.5。鱼权重5000时击杀率75%</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">空炮率</label><div class="layui-input-inline"><input type="number" step="1" min="0" max="100" name="missRate" class="layui-input" value="' + (data.missRate || 0) + '"></div><div class="layui-form-mid">百分比(0-100),用户开炮打空的概率。值越高用户越难命中鱼</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">补偿配额</label><div class="layui-input-inline"><input type="number" name="compensateQuota" class="layui-input" value="' + (data.compensateQuota || 0) + '"></div><div class="layui-form-mid">配额>0时按鱼种乘以补偿系数提升击杀率。0=不启用补偿,值越大用户击杀补偿额度越高</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">罚款配额</label><div class="layui-input-inline"><input type="number" name="penaltyQuota" class="layui-input" value="' + (data.penaltyQuota || 0) + '"></div><div class="layui-form-mid">配额>0时按鱼种乘以罚款系数降低击杀率。0=不启用罚款,值越大用户击杀压制力度越大</div></div>' +
|
||||
'<fieldset class="layui-elem-field"><legend>补偿系数(补偿配额>0时生效,按鱼种乘以系数提升击杀率)</legend><div class="layui-form-item"><label class="layui-form-label">Boss</label><div class="layui-input-inline"><input type="number" step="0.1" name="cBossRate" class="layui-input" value="' + (cr.bossRate || 1) + '"></div><div class="layui-form-mid">Boss鱼补偿系数,默认1=无加成。设为2=Boss鱼击杀率翻倍</div></div><div class="layui-form-item"><label class="layui-form-label">黄金</label><div class="layui-input-inline"><input type="number" step="0.1" name="cGoldRate" class="layui-input" value="' + (cr.goldRate || 1) + '"></div><div class="layui-form-mid">黄金鱼补偿系数</div></div><div class="layui-form-item"><label class="layui-form-label">特殊</label><div class="layui-input-inline"><input type="number" step="0.1" name="cSpecialRate" class="layui-input" value="' + (cr.specialRate || 1) + '"></div><div class="layui-form-mid">特殊鱼补偿系数</div></div><div class="layui-form-item"><label class="layui-form-label">普通</label><div class="layui-input-inline"><input type="number" step="0.1" name="cOrdinary" class="layui-input" value="' + (cr.ordinary || 1) + '"></div><div class="layui-form-mid">普通鱼补偿系数</div></div></fieldset>' +
|
||||
'<fieldset class="layui-elem-field"><legend>罚款系数(罚款配额>0时生效,按鱼种乘以系数降低击杀率)</legend><div class="layui-form-item"><label class="layui-form-label">Boss</label><div class="layui-input-inline"><input type="number" step="0.1" name="pBossRate" class="layui-input" value="' + (pr.bossRate || 1) + '"></div><div class="layui-form-mid">Boss鱼罚款系数,默认1=无影响。设为0.5=Boss鱼击杀率减半</div></div><div class="layui-form-item"><label class="layui-form-label">黄金</label><div class="layui-input-inline"><input type="number" step="0.1" name="pGoldRate" class="layui-input" value="' + (pr.goldRate || 1) + '"></div><div class="layui-form-mid">黄金鱼罚款系数</div></div><div class="layui-form-item"><label class="layui-form-label">特殊</label><div class="layui-input-inline"><input type="number" step="0.1" name="pSpecialRate" class="layui-input" value="' + (pr.specialRate || 1) + '"></div><div class="layui-form-mid">特殊鱼罚款系数</div></div><div class="layui-form-item"><label class="layui-form-label">普通</label><div class="layui-input-inline"><input type="number" step="0.1" name="pOrdinary" class="layui-input" value="' + (pr.ordinary || 1) + '"></div><div class="layui-form-mid">普通鱼罚款系数</div></div></fieldset>' +
|
||||
'<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="submit-factor">保存</button></div></div>' +
|
||||
'</form>',
|
||||
success: function(layero) {
|
||||
form.render();
|
||||
form.on('submit(submit-factor)', function(formData) {
|
||||
var param = {
|
||||
userId: data.id,
|
||||
additionalFactor: parseFloat(formData.field.additionalFactor) || 0,
|
||||
violateValue: parseFloat(formData.field.violateValue) || 0.2,
|
||||
missRate: parseFloat(formData.field.missRate) || 0,
|
||||
compensateQuota: parseInt(formData.field.compensateQuota) || 0,
|
||||
penaltyQuota: parseInt(formData.field.penaltyQuota) || 0,
|
||||
compensateRate: {
|
||||
bossRate: parseFloat(formData.field.cBossRate) || 1,
|
||||
goldRate: parseFloat(formData.field.cGoldRate) || 1,
|
||||
specialRate: parseFloat(formData.field.cSpecialRate) || 1,
|
||||
ordinary: parseFloat(formData.field.cOrdinary) || 1
|
||||
},
|
||||
penaltyRate: {
|
||||
bossRate: parseFloat(formData.field.pBossRate) || 1,
|
||||
goldRate: parseFloat(formData.field.pGoldRate) || 1,
|
||||
specialRate: parseFloat(formData.field.pSpecialRate) || 1,
|
||||
ordinary: parseFloat(formData.field.pOrdinary) || 1
|
||||
}
|
||||
};
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/AdminUser/UpdateUserFactor',
|
||||
method: 'POST',
|
||||
contentType: 'application/json;charset=UTF-8',
|
||||
data: JSON.stringify(param),
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.closeAll();
|
||||
layer.msg('保存成功');
|
||||
table.reload('table-factor-list');
|
||||
} else {
|
||||
layer.msg(res.info || '操作失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (layEvent === 'setBlack') {
|
||||
var isBlack = data.isBlack;
|
||||
var action = isBlack ? '取消屏蔽' : '屏蔽';
|
||||
layer.confirm('确定要' + action + '此用户吗?', function(idx) {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/AdminUser/SetBlackUser?userId=' + data.id + '&isBlack=' + !isBlack,
|
||||
method: 'POST',
|
||||
done: function(res) {
|
||||
if (res.code === 0) {
|
||||
layer.close(idx);
|
||||
layer.msg(action + '成功');
|
||||
table.reload('table-factor-list');
|
||||
} else {
|
||||
layer.msg(res.info || '操作失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (layEvent === 'realtime') {
|
||||
showRealtimeRoomDialog(data);
|
||||
}
|
||||
});
|
||||
|
||||
function showRealtimeRoomDialog(userData) {
|
||||
var userId = userData.id;
|
||||
var timer = null;
|
||||
var layerIndex = null;
|
||||
|
||||
var html = '<div style="padding:15px;" id="realtime-room-content">' +
|
||||
'<div style="text-align:center;padding:30px;color:#999;">正在加载实时数据...</div>' +
|
||||
'</div>';
|
||||
|
||||
layerIndex = layer.open({
|
||||
type: 1,
|
||||
title: '实时房间数据 - ' + esc(userData.userName || userData.number || ''),
|
||||
area: ['480px', '620px'],
|
||||
content: html,
|
||||
success: function(layero) {
|
||||
loadRealtime();
|
||||
timer = setInterval(loadRealtime, 1000);
|
||||
},
|
||||
end: function() {
|
||||
if (timer) clearInterval(timer);
|
||||
}
|
||||
});
|
||||
|
||||
function loadRealtime() {
|
||||
admin.req({
|
||||
url: setter.baseurl + 'adminapi/Admin/Room/GetUserRoomRealtime?userId=' + userId + '&_t=' + Date.now(),
|
||||
method: 'get',
|
||||
done: function(res) {
|
||||
if (!res || res.code !== 0) {
|
||||
renderContent('<div style="text-align:center;padding:30px;color:#999;">无实时数据</div>');
|
||||
return;
|
||||
}
|
||||
var data = res.data || {};
|
||||
if (!data.found) {
|
||||
renderContent('<div style="text-align:center;padding:30px;color:#999;">无实时数据</div>');
|
||||
return;
|
||||
}
|
||||
renderContent(buildTable(data));
|
||||
},
|
||||
fail: function() {
|
||||
renderContent('<div style="text-align:center;padding:30px;color:#999;">加载失败</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderContent(innerHtml) {
|
||||
var $el = $('#realtime-room-content');
|
||||
if (!$el.length) return;
|
||||
$el.html(innerHtml);
|
||||
}
|
||||
|
||||
function buildTable(d) {
|
||||
var roomName = [d.roomName, d.roomNumber ? '(' + d.roomNumber + ')' : ''].filter(Boolean).join('') || '-';
|
||||
var inRoomHtml = d.inRoom
|
||||
? '<span style="color:green;font-weight:bold;">在房间</span>'
|
||||
: '<span style="color:#FF5722;font-weight:bold;">未在房间</span>';
|
||||
var win = d.winGold || 0;
|
||||
var lose = d.loseGold || 0;
|
||||
var profitHtml;
|
||||
if (d.inRoom) {
|
||||
var parts = [];
|
||||
if (win > 0) parts.push('<span style="color:green;font-weight:bold;">赢 +' + win.toLocaleString() + '</span>');
|
||||
if (lose > 0) parts.push('<span style="color:red;font-weight:bold;">输 -' + lose.toLocaleString() + '</span>');
|
||||
profitHtml = parts.length > 0 ? parts.join(' ') : '<span style="color:#999;">持平</span>';
|
||||
} else {
|
||||
profitHtml = '-';
|
||||
}
|
||||
var quotaRemain = d.compensateRemainingQuota != null
|
||||
? d.compensateRemainingQuota
|
||||
: (d.compensateTargetGold > 0 && d.gold != null
|
||||
? Math.max(0, d.compensateTargetGold - d.gold) : (d.compensateQuota || 0));
|
||||
var rows = [
|
||||
['是否在房间', inRoomHtml],
|
||||
['房间', roomName],
|
||||
['游戏类型', d.gameTypeName || d.gameType || '-'],
|
||||
['房间等级', d.roomLevel],
|
||||
['玩家/机器人', (d.currentOnlinePlayerCount || 0) + ' / ' + (d.robotCount || 0)],
|
||||
['座位', d.position != null ? (d.position + 1) : '-'],
|
||||
['系统因子', d.systemFactor != null ? d.systemFactor.toFixed(2) : '-'],
|
||||
['进房金币', d.beginCoin != null ? d.beginCoin.toLocaleString() : '-'],
|
||||
['房间金币', (d.gold != null ? d.gold.toLocaleString() : '-')],
|
||||
['最高金币', (d.maxGold != null ? d.maxGold.toLocaleString() : '-')],
|
||||
['实时输赢', profitHtml],
|
||||
['当前炮倍', d.cannonMultiple || '-'],
|
||||
['金币本金统计(不计VIP)', (d.totalRechargeGold != null ? d.totalRechargeGold.toLocaleString() : '-')],
|
||||
['状态', d.state === 1 ? '<span style="color:#FF5722;">断线中</span>' : (d.isAfk ? '<span style="color:#FFB800;">挂机中</span>' : '正常')],
|
||||
['黑名单', d.isBlack ? '<span style="color:#FF5722;">是</span>' : '否'],
|
||||
['是否忽略因子', d.isIgnore ? '是' : '否'],
|
||||
['玩家因子(平滑)', d.violateValue != null ? d.violateValue.toFixed(2) : '-'],
|
||||
['附加因子', d.additionalFactor != null ? d.additionalFactor.toFixed(2) : '-'],
|
||||
['空炮率', (d.missRate || 0) + '%'],
|
||||
['补偿额度', d.compensateQuota],
|
||||
['补偿剩余值', quotaRemain.toLocaleString()],
|
||||
['惩罚额度', d.penaltyQuota],
|
||||
['起始赠送', d.startingBonus != null ? d.startingBonus.toLocaleString() : '-'],
|
||||
['补偿系数(普/Boss/金/特)', [d.compensateRateOrdinary, d.compensateRateBoss, d.compensateRateGold, d.compensateRateSpecial].join(' / ')],
|
||||
['惩罚系数(普/Boss/金/特)', [d.penaltyRateOrdinary, d.penaltyRateBoss, d.penaltyRateGold, d.penaltyRateSpecial].join(' / ')]
|
||||
];
|
||||
var trs = rows.map(function(r) {
|
||||
return '<tr><td style="background:#f2f2f2;width:130px;font-weight:bold;">' + r[0] + '</td><td>' + r[1] + '</td></tr>';
|
||||
}).join('');
|
||||
return '<table class="layui-table" style="margin:0;">' + trs + '</table>' +
|
||||
'<div style="text-align:center;color:#999;font-size:12px;padding:8px;">每秒自动刷新</div>';
|
||||
}
|
||||
}
|
||||
|
||||
exports('factorlist', {});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-useradmin" style="padding: 20px 0 0 0;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="hidden" name="userId" value="{{ d.params.id || '' }}" lay-verify="required" autocomplete="off" class="layui-input">
|
||||
<input type="text" name="userName" readonly value="{{ d.params.userName || '' }}" lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户编号</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="number" readonly value="{{ d.params.number || '' }}" placeholder="请输入号码" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">封号原因</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="reason" value="{{ d.params.banReason || ''}}" placeholder="" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">天数</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="days" value="{{ d.params.banDays || '' }}" placeholder="" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-front-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'upload'], function(){
|
||||
var $ = layui.$
|
||||
,form = layui.form
|
||||
,upload = layui.upload;
|
||||
|
||||
})
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,357 @@
|
||||
|
||||
<title>用户详情</title>
|
||||
|
||||
<div class="layui-card layadmin-header">
|
||||
<div class="layui-breadcrumb" lay-filter="breadcrumb">
|
||||
<a lay-href="#/user/user/list">用户列表</a>
|
||||
<a><cite>用户详情</cite></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">基本信息</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form" wid100 id="basic-info-form">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md9">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary" id="btn-back"><i class="layui-icon layui-icon-return"></i> 返回</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" id="btn-refresh"><i class="layui-icon layui-icon-refresh"></i> 刷新</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" id="btn-init-pwd"><i class="layui-icon layui-icon-auz"></i> 初始化登录密码</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" id="btn-init-safebox-pwd"><i class="layui-icon layui-icon-auz"></i> 初始化保险箱密码</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="user-detail-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this" lay-id="assets">资产信息</li>
|
||||
<li lay-id="stat">统计信息</li>
|
||||
<li lay-id="equip">装备背包</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="padding:10px 0 0 0;">
|
||||
<div class="layui-tab-item layui-show" id="tab-assets"></div>
|
||||
<div class="layui-tab-item" id="tab-stat"></div>
|
||||
<div class="layui-tab-item" id="tab-equip"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'element'], function () {
|
||||
var $ = layui.$,
|
||||
admin = layui.admin,
|
||||
form = layui.form,
|
||||
element = layui.element,
|
||||
setter = layui.setter,
|
||||
layer = layui.layer,
|
||||
router = layui.router();
|
||||
|
||||
var userId = router.search.userId;
|
||||
var userData = null;
|
||||
|
||||
if (!userId) {
|
||||
layer.msg('缺少用户ID参数', {icon: 2});
|
||||
location.href = '#/user/user/list';
|
||||
return;
|
||||
}
|
||||
|
||||
$('#btn-back').on('click', function() {
|
||||
location.href = '#/user/user/list';
|
||||
});
|
||||
|
||||
$('#btn-refresh').on('click', function() {
|
||||
loadUserDetail();
|
||||
});
|
||||
|
||||
$('#btn-init-pwd').on('click', function() {
|
||||
layer.confirm('确定要初始化该用户的登录密码为123456吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/AdminUser/InitUserPassword?userId=' + encodeURIComponent(userId),
|
||||
done: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg(res.info || '初始化成功');
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn-init-safebox-pwd').on('click', function() {
|
||||
layer.confirm('确定要初始化该用户的保险箱密码为123456吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: 'get',
|
||||
url: setter.baseurl + 'adminapi/AdminUser/InitSafeBoxPassword?userId=' + encodeURIComponent(userId),
|
||||
done: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg(res.info || '初始化成功');
|
||||
} else {
|
||||
layer.msg(res.info || '初始化失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function renderEquipTab(user) {
|
||||
var cannonList = user.cannonList || [];
|
||||
var wingList = user.wingList || [];
|
||||
var godWarList = user.godWarList || [];
|
||||
var props = user.props || [];
|
||||
var cannonUsing = user.cannonUsing ? user.cannonUsing.number : '';
|
||||
var wingUsing = user.wingUsing ? user.wingUsing.number : '';
|
||||
var godWarUsing = user.godUsing ? user.godUsing.number : '';
|
||||
|
||||
var cannonHtml = cannonList.length > 0 ? '<table class="layui-table" style="margin:0;"><tr><th>名称</th><th>编号</th><th>状态</th></tr>' + cannonList.map(function(c){ return '<tr><td>' + c.name + '</td><td>' + c.number + '</td><td>' + (cannonUsing === c.number ? '<span style="color:#1e9fff">使用中</span>' : '') + '</td></tr>'; }).join('') + '</table>' : '<span style="color:#999">无</span>';
|
||||
|
||||
var wingHtml = wingList.length > 0 ? '<table class="layui-table" style="margin:0;"><tr><th>名称</th><th>编号</th><th>状态</th></tr>' + wingList.map(function(w){ return '<tr><td>' + w.name + '</td><td>' + w.number + '</td><td>' + (wingUsing === w.number ? '<span style="color:#1e9fff">使用中</span>' : '') + '</td></tr>'; }).join('') + '</table>' : '<span style="color:#999">无</span>';
|
||||
|
||||
var godWarHtml = godWarList.length > 0 ? '<table class="layui-table" style="margin:0;"><tr><th>名称</th><th>编号</th><th>状态</th></tr>' + godWarList.map(function(g){ return '<tr><td>' + g.name + '</td><td>' + g.number + '</td><td>' + (godWarUsing === g.number ? '<span style="color:#1e9fff">使用中</span>' : '') + '</td></tr>'; }).join('') + '</table>' : '<span style="color:#999">无</span>';
|
||||
|
||||
var validProps = props.filter(function(p){ return p.count > 0; });
|
||||
var propsHtml = validProps.length > 0
|
||||
? '<table class="layui-table" id="props-table"><thead><tr><th>编号</th><th>名称</th><th>类型</th><th>数量</th><th>操作</th></tr></thead><tbody>'
|
||||
+ validProps.map(function(p, i){
|
||||
var typeName = '';
|
||||
if (p.type === 0) typeName = '普通';
|
||||
else if (p.type === 1) typeName = '炮台';
|
||||
else if (p.type === 2) typeName = '翅膀';
|
||||
else if (p.type === 3) typeName = '战神';
|
||||
else if (p.type === 7) typeName = '刮刮卡';
|
||||
else if (p.type === 13) typeName = '鱼雷';
|
||||
else typeName = '道具' + p.type;
|
||||
return '<tr><td>' + (p.number || '-') + '</td><td>' + (p.name || '-') + '</td><td>' + typeName + '</td><td>' + p.count + '</td>'
|
||||
+ '<td>'
|
||||
+ '<button class="layui-btn layui-btn-xs layui-btn-normal" onclick="editPropCount(\'' + p.number + '\',\'' + (p.name || '') + '\',' + p.count + ')">修改</button> '
|
||||
+ '<button class="layui-btn layui-btn-xs layui-btn-danger" onclick="deleteProp(\'' + p.number + '\',\'' + (p.name || '') + '\')">删除</button>'
|
||||
+ '</td></tr>';
|
||||
}).join('')
|
||||
+ '</tbody></table>'
|
||||
: '<span style="color:#999">背包为空</span>';
|
||||
|
||||
var equipHtml = '<div style="max-width:100%;">'
|
||||
+ '<div class="layui-btn-container" style="margin-bottom:10px;">'
|
||||
+ '<button class="layui-btn layui-btn-sm" onclick="showAddPropForm()"><i class="layui-icon layui-icon-add-1"></i> 添加道具</button>'
|
||||
+ '<button class="layui-btn layui-btn-sm layui-btn-primary" onclick="loadUserDetail()"><i class="layui-icon layui-icon-refresh"></i> 刷新背包</button>'
|
||||
+ '</div>'
|
||||
+ '<fieldset class="layui-elem-field" style="margin-bottom:15px;"><legend>装备列表</legend><div class="layui-field-box">'
|
||||
+ '<div style="margin-bottom:10px;"><b>炮台:</b></div>' + cannonHtml
|
||||
+ '<div style="margin:10px 0;"><b>翅膀:</b></div>' + wingHtml
|
||||
+ '<div style="margin:10px 0;"><b>战神:</b></div>' + godWarHtml
|
||||
+ '</div></fieldset>'
|
||||
+ '<fieldset class="layui-elem-field"><legend>背包道具 <span style="font-size:12px;color:#999;">(共 ' + validProps.length + ' 种)</span></legend><div class="layui-field-box">' + propsHtml + '</div></fieldset>'
|
||||
+ '</div>';
|
||||
$('#tab-equip').html(equipHtml);
|
||||
}
|
||||
|
||||
window.showAddPropForm = function() {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '添加道具',
|
||||
area: ['450px', '280px'],
|
||||
content: '<div style="padding:20px;">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label" style="width:80px;">道具编号</label><div class="layui-input-block" style="margin-left:110px;"><input id="input-prop-number" class="layui-input" placeholder="输入道具编号,如 40005"></div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label" style="width:80px;">数量</label><div class="layui-input-block" style="margin-left:110px;"><input id="input-prop-count" class="layui-input" type="number" value="1" min="1"></div></div>'
|
||||
+ '<div style="text-align:center;margin-top:20px;"><button class="layui-btn" id="btn-add-prop-submit">确定添加</button></div>'
|
||||
+ '</div>'
|
||||
});
|
||||
$('#btn-add-prop-submit').off('click').on('click', function() {
|
||||
var propNumber = $('#input-prop-number').val().trim();
|
||||
var count = parseInt($('#input-prop-count').val()) || 1;
|
||||
if (!propNumber) { layer.msg('请输入道具编号'); return; }
|
||||
if (count <= 0) { layer.msg('数量必须大于0'); return; }
|
||||
admin.req({
|
||||
method: 'post',
|
||||
url: setter.baseurl + 'adminapi/AdminUser/AddUserProp',
|
||||
data: { userId: userId, propNumber: propNumber, count: count },
|
||||
done: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('添加成功');
|
||||
layer.closeAll();
|
||||
loadUserDetail();
|
||||
} else {
|
||||
layer.msg(res.info || '添加失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
window.editPropCount = function(propNumber, propName, currentCount) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '修改道具数量 - ' + propName,
|
||||
area: ['400px', '230px'],
|
||||
content: '<div style="padding:20px;">'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label" style="width:80px;">当前数量</label><div class="layui-form-mid" style="margin-left:110px;">' + currentCount + '</div></div>'
|
||||
+ '<div class="layui-form-item"><label class="layui-form-label" style="width:80px;">修改为</label><div class="layui-input-block" style="margin-left:110px;"><input id="input-edit-count" class="layui-input" type="number" value="' + currentCount + '" min="0"></div></div>'
|
||||
+ '<div style="text-align:center;margin-top:20px;font-size:12px;color:#999;">设为 0 则删除该道具</div>'
|
||||
+ '<div style="text-align:center;margin-top:10px;"><button class="layui-btn" id="btn-edit-prop-submit">确定修改</button></div>'
|
||||
+ '</div>'
|
||||
});
|
||||
$('#btn-edit-prop-submit').off('click').on('click', function() {
|
||||
var newCount = parseInt($('#input-edit-count').val());
|
||||
if (isNaN(newCount) || newCount < 0) { layer.msg('请输入有效数量'); return; }
|
||||
admin.req({
|
||||
method: 'post',
|
||||
url: setter.baseurl + 'adminapi/AdminUser/UpdateUserPropCount',
|
||||
data: { userId: userId, propNumber: propNumber, count: newCount },
|
||||
done: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('修改成功');
|
||||
layer.closeAll();
|
||||
loadUserDetail();
|
||||
} else {
|
||||
layer.msg(res.info || '修改失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
window.deleteProp = function(propNumber, propName) {
|
||||
layer.confirm('确定要删除道具 [' + propName + '] 吗?', function(idx) {
|
||||
layer.close(idx);
|
||||
admin.req({
|
||||
method: 'post',
|
||||
url: setter.baseurl + 'adminapi/AdminUser/DeleteUserProp',
|
||||
data: { userId: userId, propNumber: propNumber },
|
||||
done: function(res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
layer.msg('删除成功');
|
||||
loadUserDetail();
|
||||
} else {
|
||||
layer.msg(res.info || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function formatTimestamp(timestamp) {
|
||||
if (!timestamp) return '-';
|
||||
var date = new Date(timestamp * 1000);
|
||||
var y = date.getFullYear();
|
||||
var m = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
var d = date.getDate().toString().padStart(2, '0');
|
||||
return y + '-' + m + '-' + d;
|
||||
}
|
||||
|
||||
window.loadUserDetail = function() {
|
||||
admin.req({
|
||||
url: setter.baseurl + "adminapi/AdminUser/GetUserDetail",
|
||||
data: { userId: userId },
|
||||
done: function (res) {
|
||||
if (res.code === 0 || res.code === 200) {
|
||||
userData = res.data;
|
||||
renderUserDetail(userData);
|
||||
} else {
|
||||
layer.msg(res.info || '获取用户详情失败', {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderUserDetail(user) {
|
||||
var userTypeMap = {1: '普通用户', 2: '代理商', 3: '内部人员'};
|
||||
|
||||
var uName = user.baseInfo ? (user.baseInfo.userName || '-') : '-';
|
||||
var uNumber = user.baseInfo ? (user.baseInfo.number || '-') : '-';
|
||||
var uMobile = user.baseInfo ? (user.baseInfo.mobile || '-') : '-';
|
||||
var uChannel = user.baseInfo ? (user.baseInfo.channel || '-') : '-';
|
||||
var uCreateTime = formatTimestamp(user.createTime);
|
||||
var uRegisterIp = user.registerIp || '-';
|
||||
var uUserType = user.userType || 1;
|
||||
var uIsBlack = user.playerFactor && user.playerFactor.isBlack;
|
||||
var uRealName = user.realName ? (user.realName.realName || '-') : '-';
|
||||
var uIdCard = user.realName ? (user.realName.idCard || '-') : '-';
|
||||
|
||||
document.title = '用户详情 - ' + uName + ' [' + uNumber + ']';
|
||||
|
||||
var basicHtml = '<div class="layui-form-item"><label class="layui-form-label">昵称</label><div class="layui-form-mid">' + uName + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">编号</label><div class="layui-form-mid">' + uNumber + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">手机号</label><div class="layui-form-mid">' + uMobile + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">注册IP</label><div class="layui-form-mid">' + uRegisterIp + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">渠道</label><div class="layui-form-mid">' + uChannel + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">注册时间</label><div class="layui-form-mid">' + uCreateTime + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">用户身份</label><div class="layui-form-mid">' + userTypeMap[uUserType] + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">屏蔽状态</label><div class="layui-form-mid">' + (uIsBlack ? '<span style="color:#f44336;">已屏蔽</span>' : '<span style="color:#4caf50;">正常</span>') + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">真实姓名</label><div class="layui-form-mid">' + uRealName + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label">身份证号</label><div class="layui-form-mid">' + uIdCard + '</div></div>';
|
||||
$('#basic-info-form').html(basicHtml);
|
||||
|
||||
var uGold = user.assets ? (user.assets.gold || 0) : 0;
|
||||
var uDiamond = user.assets ? (user.assets.diamond || 0) : 0;
|
||||
var uLevel = user.assets ? (user.assets.level || 1) : 1;
|
||||
var uVipLevel = user.assets ? (user.assets.vipLevel || 0) : 0;
|
||||
var uVipExp = user.assets ? (user.assets.vipExp || 0) : 0;
|
||||
var uVipExpExtra = user.assets ? (user.assets.vipExpExtra || 0) : 0;
|
||||
var uExp = user.assets ? (user.assets.exp || 0) : 0;
|
||||
var uVipDayGift = user.assets && user.assets.isVipDayGift ? '已领取' : '未领取';
|
||||
|
||||
var uSafeBoxAmount = user.safeBox ? (user.safeBox.amount || 0) : 0;
|
||||
var uSafeBoxSaveTime = user.safeBox ? formatTimestamp(user.safeBox.saveTime) : '-';
|
||||
var uIsSign = user.sign && user.sign.isSign ? '是' : '否';
|
||||
var uSignTime = user.sign ? formatTimestamp(user.sign.signTime) : '-';
|
||||
|
||||
var assetsHtml = '<div class="layui-form" style="max-width:600px;">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">金币</label><div class="layui-form-mid" style="color:#ff5722;font-weight:bold;">' + uGold.toLocaleString() + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">钻石</label><div class="layui-form-mid" style="color:#1e88e5;font-weight:bold;">' + uDiamond.toLocaleString() + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">等级</label><div class="layui-form-mid">Lv.' + uLevel + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">VIP等级</label><div class="layui-form-mid">VIP' + uVipLevel + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">VIP经验</label><div class="layui-form-mid">' + uVipExp.toLocaleString() + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">额外VIP经验</label><div class="layui-form-mid">' + uVipExpExtra.toLocaleString() + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">VIP计算规则</label><div class="layui-form-mid">现金充值 × 10 + VIP经验包(金币及游戏输赢不参与)</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">经验值</label><div class="layui-form-mid">' + uExp.toLocaleString() + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">VIP礼包</label><div class="layui-form-mid">' + uVipDayGift + '</div></div>' +
|
||||
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">保险箱金额</label><div class="layui-form-mid">' + uSafeBoxAmount.toLocaleString() + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">保险箱时间</label><div class="layui-form-mid">' + uSafeBoxSaveTime + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">今日签到</label><div class="layui-form-mid">' + uIsSign + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:100px;">签到时间</label><div class="layui-form-mid">' + uSignTime + '</div></div>' +
|
||||
'</div>';
|
||||
$('#tab-assets').html(assetsHtml);
|
||||
|
||||
var uLastLoginTime = user.static ? formatTimestamp(user.static.lastLoginTime) : '-';
|
||||
var uLastLoginIp = user.static ? (user.static.lastLoginIp || '-') : '-';
|
||||
var uOnlineTime = user.static ? (user.static.onlineTime || 0) : 0;
|
||||
var uGameTime = user.static ? (user.static.gameTime || 0) : 0;
|
||||
var uRoomNumber = user.static ? (user.static.roomNumber || '-') : '-';
|
||||
var uTotalRecharge = user.static ? (user.static.totalRecharge || 0) : 0;
|
||||
var uTotalConsumeGold = user.static ? (user.static.totalConsumeGold || 0) : 0;
|
||||
var uReliefGoldCount = user.static ? (user.static.reliefGoldCount || 0) : 0;
|
||||
|
||||
var statHtml = '<div class="layui-form" style="max-width:600px;">' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">最后登录IP</label><div class="layui-form-mid">' + uLastLoginIp + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">最后登录时间</label><div class="layui-form-mid">' + uLastLoginTime + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">在线时长</label><div class="layui-form-mid">' + uOnlineTime + ' 秒</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">游戏时长</label><div class="layui-form-mid">' + uGameTime + ' 秒</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">累计充值</label><div class="layui-form-mid" style="color:#ff5722;">' + uTotalRecharge + ' 元</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">累计消费</label><div class="layui-form-mid">' + uTotalConsumeGold.toLocaleString() + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">所在房间</label><div class="layui-form-mid">' + uRoomNumber + '</div></div>' +
|
||||
'<div class="layui-form-item"><label class="layui-form-label" style="width:120px;">救济金次数</label><div class="layui-form-mid">' + uReliefGoldCount + '</div></div>' +
|
||||
'</div>';
|
||||
$('#tab-stat').html(statHtml);
|
||||
|
||||
renderEquipTab(user);
|
||||
}
|
||||
|
||||
loadUserDetail();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
|
||||
<div class="layui-form" lay-filter="layuiadmin-form-useradmin" style="padding: 20px 0 0 0;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="hidden" name="id" value="{{ d.params.id || '' }}" lay-verify="required" autocomplete="off" class="layui-input">
|
||||
<input type="text" name="userName" readonly value="{{ d.params.userName || '' }}" lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户编号</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="text" name="number" readonly value="{{ d.params.number || '' }}" placeholder="请输入号码" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">钻石</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="number" name="diamond" value="{{ d.params.assets.diamond || 0 }}" placeholder="" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">积分</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="number" name="scoreCount" value="{{ d.params.assets.scoreCount || 0 }}" placeholder="" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">等级</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="number" name="level" value="{{ d.params.assets.level || 0 }}" placeholder="" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">经验值</label>
|
||||
<div class="layui-input-inline">
|
||||
<script type="text/html" template>
|
||||
<input type="number" name="exp" value="{{ d.params.assets.exp || 0 }}" placeholder="" autocomplete="off" class="layui-input">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="button" lay-submit lay-filter="LAY-user-front-submit" value="确认" class="layui-btn">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['admin', 'form', 'upload'], function(){
|
||||
var $ = layui.$
|
||||
,form = layui.form
|
||||
,upload = layui.upload;
|
||||
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user