459 lines
20 KiB
HTML
459 lines
20 KiB
HTML
<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>
|