添加项目文件。
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user