Files
SMANAGE/backup/GERP old/User/Backpack.html
T

1065 lines
39 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<resource-share type="style" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"></resource-share>
<style>
/* 全局样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #fff;
font-family: "Microsoft YaHei", sans-serif;
overflow: hidden;
height: 100vh;
}
/* 顶部操作栏 */
.top-actions {
padding: 10px 20px;
background-color: #f8f9fa;
border-bottom: 1px solid #e6e6e6;
display: flex;
justify-content: flex-end;
align-items: center;
}
/* 重载按钮样式 */
.reload-btn {
padding: 6px 12px;
background-color: #1E9FFF;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
display: flex;
align-items: center;
gap: 5px;
transition: all 0.3s ease;
}
.reload-btn:hover {
background-color: #0088ff;
transform: translateY(-2px);
box-shadow: 0 2px 6px rgba(30, 159, 255, 0.3);
}
.reload-btn i {
font-size: 12px;
}
.reload-btn.loading {
background-color: #999;
cursor: not-allowed;
}
.reload-btn.loading:hover {
background-color: #999;
transform: none;
box-shadow: none;
}
/* 背包容器 */
.backpack-container {
display: flex;
height: calc(100vh - 57px); /* 减去顶部操作栏高度 */
padding: 20px;
gap: 20px;
}
/* 左侧背包区域 */
.backpack-left {
flex: 7;
display: flex;
flex-direction: column;
gap: 15px;
height: 100%;
}
/* 分类标签栏 */
.category-tabs {
display: flex;
gap: 10px;
flex-wrap: wrap;
padding: 10px;
background-color: #f8f9fa;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.category-tab {
padding: 8px 16px;
background-color: #fff;
border: 1px solid #e6e6e6;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
}
.category-tab.active {
background-color: #009688;
color: #fff;
border-color: #009688;
box-shadow: 0 2px 8px rgba(0,150,136,0.3);
}
.category-tab:hover:not(.active) {
border-color: #009688;
color: #009688;
transform: translateY(-2px);
}
/* 物品列表容器 */
.items-container {
flex: 1;
background-color: #f8f9fa;
border-radius: 8px;
padding: 15px;
overflow-y: auto;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
/* 物品网格 */
.items-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 15px;
}
/* 物品卡片 */
.item-card {
background-color: #fff;
border-radius: 8px;
padding: 12px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
cursor: pointer;
transition: all 0.3s ease;
border: 2px solid transparent;
height: auto; /* 确保height不是100% */
}
.item-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0,0,0,0.1);
border-color: #009688;
}
.item-card.active {
border-color: #009688;
box-shadow: 0 8px 16px rgba(0,150,136,0.2);
}
/* 物品图标容器 */
.item-icon {
width: 80px;
height: 80px;
margin: 0 auto 10px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
position: relative;
}
.item-icon::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.02);
z-index: 1;
}
.item-icon img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
z-index: 2;
transition: transform 0.3s ease;
}
.item-card:hover .item-icon img {
transform: scale(1.1);
}
/* 物品名称 */
.item-name {
font-size: 14px;
font-weight: 600;
text-align: center;
margin-bottom: 5px;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 物品数量 */
.item-count {
font-size: 12px;
text-align: center;
color: #666;
background-color: #f0f0f0;
padding: 2px 8px;
border-radius: 10px;
display: inline-block;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}
/* 右侧详情区域 */
.backpack-right {
flex: 3;
background-color: #f8f9fa;
border-radius: 8px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
height: 100%;
}
/* 详情头部 */
.detail-header {
text-align: center;
position: relative; /* 新增:为高级链接定位做准备 */
padding-right: 60px; /* 新增:给高级链接留出空间 */
}
/* 新增:高级链接样式 */
.advanced-link {
position: absolute;
top: 0;
right: 0;
color: #009688;
text-decoration: none;
font-size: 14px;
padding: 5px 10px;
border-radius: 4px;
transition: all 0.3s ease;
}
.advanced-link:hover {
color: #fff;
background-color: #009688;
text-decoration: none;
transform: translateY(-2px);
box-shadow: 0 2px 6px rgba(0,150,136,0.3);
}
.advanced-link i {
margin-right: 5px;
font-size: 12px;
}
.detail-icon {
width: 250px;
height: 250px;
margin: 0 auto 15px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
overflow: hidden;
}
.detail-icon img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.detail-name {
font-size: 18px;
font-weight: 700;
color: #333;
margin-bottom: 5px;
}
/* 详情描述 */
.detail-desc {
background-color: #fff;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
flex: 1;
overflow-y: auto;
font-size: 14px;
color: #555;
line-height: 1.6;
}
/* 操作按钮区域 */
.detail-actions {
display: flex;
flex-direction: column;
gap: 15px;
}
/* 数量选择器 */
.count-selector {
display: flex;
align-items: center;
gap: 10px;
background-color: #fff;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.count-label {
font-size: 14px;
color: #333;
font-weight: 600;
}
.count-input {
flex: 1;
display: flex;
align-items: center;
}
.count-btn {
width: 30px;
height: 30px;
border: 1px solid #e6e6e6;
background-color: #fff;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
.count-btn:hover {
background-color: #009688;
color: #fff;
border-color: #009688;
}
.count-num {
width: 60px;
height: 30px;
text-align: center;
border: 1px solid #e6e6e6;
border-radius: 4px;
margin: 0 5px;
}
/* 功能按钮 */
.action-buttons {
display: flex;
gap: 10px;
}
.action-btn {
flex: 1;
padding: 10px;
border-radius: 6px;
border: none;
cursor: pointer;
font-size: 14px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-view {
background-color: #1E9FFF;
color: #fff;
}
.btn-use {
background-color: #009688;
color: #fff;
}
.btn-discard {
background-color: #FF5722;
color: #fff;
}
.action-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
/* 加载动画 */
.loading {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
flex-direction: column;
gap: 15px;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #009688;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 空数据样式 */
.empty-data {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
flex-direction: column;
gap: 10px;
color: #999;
font-size: 16px;
}
.empty-data i {
font-size: 48px;
color: #ddd;
}
/* 高级API弹窗样式 */
.advanced-api-content {
padding: 15px;
max-height: 60vh;
overflow-y: auto;
}
.api-item {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #e6e6e6;
}
.api-key {
font-weight: 600;
color: #009688;
margin-bottom: 5px;
}
.api-value {
font-family: "Consolas", monospace;
font-size: 13px;
color: #333;
background-color: #f8f9fa;
padding: 8px;
border-radius: 4px;
word-break: break-all;
}
/* 滚动条美化 */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #009688;
}
</style>
<!-- 新增顶部操作栏 -->
<div class="top-actions">
<button class="reload-btn" id="reloadBackpackBtn">
<i class="layui-icon layui-icon-refresh"></i>
</button>
</div>
<div class="backpack-container">
<!-- 左侧背包区域 -->
<div class="backpack-left">
<!-- 分类标签 -->
<div class="category-tabs" id="categoryTabs">
<div class="category-tab active" data-tag="all">全部</div>
</div>
<!-- 物品列表 -->
<div class="items-container" id="itemsContainer">
<!-- 加载中 -->
<div class="loading">
<div class="loading-spinner"></div>
<div>加载背包数据中...</div>
</div>
</div>
</div>
<!-- 右侧详情区域 -->
<div class="backpack-right" id="detailPanel">
<div class="empty-data">
<i class="layui-icon layui-icon-component"></i>
<div>请选择一个物品查看详情</div>
</div>
</div>
</div>
<script>
layui.use(['layer', 'form'], function() {
var layer = layui.layer;
var form = layui.form;
// 全局变量
var backpackItems = []; // 所有背包物品
var allTags = new Set(); // 所有分类标签
var selectedItem = null; // 当前选中的物品
var selectedCount = 1; // 当前选择的数量
var isLoading = false; // 加载状态标识
// 新增:图片缓存Map - key: 原始URL, value: Blob URL
var imageCache = new Map();
// 新增:默认占位图URL
const defaultIconUrl = 'https://placeholder.pics/svg/80x80/FFFFFF-E6E6E6/暂无图标';
// 初始化函数
function init() {
// 获取背包数据
getBackpackItems();
// 绑定重载按钮事件
bindReloadButtonEvent();
// 新增:页面卸载时清理Blob URL,避免内存泄漏
window.addEventListener('beforeunload', cleanImageCache);
}
// 新增:清理图片缓存(释放Blob URL)
function cleanImageCache() {
imageCache.forEach(blobUrl => {
try {
URL.revokeObjectURL(blobUrl);
} catch (e) {
console.warn('释放Blob URL失败:', e);
}
});
imageCache.clear();
}
// 新增:加载图片并转换为Blob URL(带缓存)
function loadImageToBlob(url) {
// 处理默认占位图
if (!url || url === defaultIconUrl) {
return Promise.resolve(defaultIconUrl);
}
// 检查缓存,存在则直接返回
if (imageCache.has(url)) {
return Promise.resolve(imageCache.get(url));
}
// 不存在则加载图片并转换为Blob
return fetch(url)
.then(response => {
// 检查响应是否成功
if (!response.ok) {
throw new Error(`图片加载失败: ${response.status}`);
}
// 转换为Blob
return response.blob();
})
.then(blob => {
// 创建Blob URL并缓存
const blobUrl = URL.createObjectURL(blob);
imageCache.set(url, blobUrl);
return blobUrl;
})
.catch(error => {
console.error(`加载图片失败(${url}):`, error);
// 失败时返回默认占位图
return defaultIconUrl;
});
}
// 绑定重载按钮事件
function bindReloadButtonEvent() {
const reloadBtn = document.getElementById('reloadBackpackBtn');
reloadBtn.addEventListener('click', function() {
if (isLoading) return; // 如果正在加载,不重复请求
// 禁用按钮并显示加载状态
this.classList.add('loading');
const btnHtml = this.innerHTML;
this.innerHTML = '<i class="layui-icon layui-icon-loading"></i>';
// 清空选中状态
selectedItem = null;
selectedCount = 1;
// 重置详情面板为加载状态
document.getElementById('detailPanel').innerHTML = `
<div class="empty-data">
<i class="layui-icon layui-icon-component"></i>
<div>请选择一个物品查看详情</div>
</div>
`;
// 重新加载背包数据
getBackpackItems()
.finally(() => {
// 恢复按钮状态
this.classList.remove('loading');
this.innerHTML = btnHtml;
});
});
}
// 获取背包物品数据(修改为返回Promise)
function getBackpackItems() {
isLoading = true;
// 显示加载状态
document.getElementById('itemsContainer').innerHTML = `
<div class="loading">
<div class="loading-spinner"></div>
<div>加载背包数据中...</div>
</div>
`;
return fetch('/API/Backpack/GetBackpackItems', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
isLoading = false;
if (data.code === 0) {
backpackItems = data.data || [];
// 处理分类标签
processItemTags();
// 渲染分类标签
renderCategoryTabs();
// 渲染物品列表
renderItemsList('all');
// 提示加载成功
layer.msg('背包数据已更新', {icon: 1, time: 1500});
} else {
// 显示错误信息
document.getElementById('itemsContainer').innerHTML = `
<div class="empty-data">
<i class="layui-icon layui-icon-face-cry"></i>
<div>${data.msg || '加载失败,请重试'}</div>
</div>
`;
layer.msg(data.msg || '加载失败,请重试', {icon: 2});
}
})
.catch(error => {
isLoading = false;
console.error('获取背包数据失败:', error);
document.getElementById('itemsContainer').innerHTML = `
<div class="empty-data">
<i class="layui-icon layui-icon-face-cry"></i>
<div>网络错误,无法加载背包数据</div>
</div>
`;
layer.msg('网络错误,无法加载背包数据', {icon: 2});
});
}
// 处理物品标签(兼容null)
function processItemTags() {
allTags.clear();
backpackItems.forEach(item => {
// 处理ItemTags可能为null的情况
const tags = item.ItemTags && Array.isArray(item.ItemTags) ? item.ItemTags : [];
tags.forEach(tag => {
if (tag && tag.trim()) {
allTags.add(tag.trim());
}
});
});
}
// 渲染分类标签
function renderCategoryTabs() {
const tabsContainer = document.getElementById('categoryTabs');
// 保留全部标签,清空其他
tabsContainer.innerHTML = '<div class="category-tab active" data-tag="all">全部</div>';
// 添加其他标签
Array.from(allTags).forEach(tag => {
const tab = document.createElement('div');
tab.className = 'category-tab';
tab.dataset.tag = tag;
tab.textContent = tag;
tabsContainer.appendChild(tab);
// 绑定点击事件
tab.addEventListener('click', function() {
// 切换激活状态
document.querySelectorAll('.category-tab').forEach(t => {
t.classList.remove('active');
});
this.classList.add('active');
// 渲染对应物品
renderItemsList(this.dataset.tag);
});
});
// 绑定全部标签点击事件
document.querySelector('.category-tab[data-tag="all"]').addEventListener('click', function() {
document.querySelectorAll('.category-tab').forEach(t => {
t.classList.remove('active');
});
this.classList.add('active');
renderItemsList('all');
});
}
// 渲染物品列表(修改:使用图片缓存)
function renderItemsList(filterTag) {
const container = document.getElementById('itemsContainer');
// 过滤物品
let filteredItems = backpackItems;
if (filterTag !== 'all') {
filteredItems = backpackItems.filter(item => {
const tags = item.ItemTags && Array.isArray(item.ItemTags) ? item.ItemTags : [];
return tags.includes(filterTag);
});
}
// 渲染物品
if (filteredItems.length === 0) {
container.innerHTML = `
<div class="empty-data">
<i class="layui-icon layui-icon-component"></i>
<div>暂无该分类的物品</div>
</div>
`;
return;
}
// 生成物品网格
let itemsHtml = '<div class="items-grid">';
filteredItems.forEach(item => {
// 处理元数据默认值
const metaData = item.ItemMetaData || {};
const allowUsed = metaData.AllowUsed !== undefined ? metaData.AllowUsed : false;
const disposable = metaData.Disposable !== undefined ? metaData.Disposable : false;
// 生成唯一ID用于图片加载
const itemId = `item-${item.BackpackItemUUID}`;
itemsHtml += `
<div class="item-card animate__animated animate__fadeIn" data-uuid="${item.BackpackItemUUID}">
<div class="item-icon">
<img id="${itemId}" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
alt="${item.ItemName || '未知物品'}"
data-original="${item.ItemIcon || defaultIconUrl}">
</div>
<div class="item-name">${item.ItemName || '未知物品'}</div>
<div class="item-count">数量: ${item.ItemLength || 0}</div>
</div>
`;
});
itemsHtml += '</div>';
container.innerHTML = itemsHtml;
// 批量加载图片(使用缓存)
filteredItems.forEach(item => {
const itemId = `item-${item.BackpackItemUUID}`;
const imgElement = document.getElementById(itemId);
const originalUrl = imgElement.dataset.original;
// 加载图片并替换src
loadImageToBlob(originalUrl).then(blobUrl => {
if (imgElement) {
imgElement.src = blobUrl;
}
});
});
// 绑定物品卡片点击事件
document.querySelectorAll('.item-card').forEach(card => {
card.addEventListener('click', function() {
// 切换选中状态
document.querySelectorAll('.item-card').forEach(c => {
c.classList.remove('active');
});
this.classList.add('active');
// 获取选中物品
const uuid = this.dataset.uuid;
selectedItem = backpackItems.find(item => item.BackpackItemUUID === uuid);
selectedCount = 1; // 重置选择数量
// 渲染详情面板
renderDetailPanel();
});
});
}
// 渲染详情面板(修改:使用图片缓存)
function renderDetailPanel() {
if (!selectedItem) {
document.getElementById('detailPanel').innerHTML = `
<div class="empty-data">
<i class="layui-icon layui-icon-component"></i>
<div>请选择一个物品查看详情</div>
</div>
`;
return;
}
// 处理元数据默认值
const metaData = selectedItem.ItemMetaData || {};
const allowUsed = metaData.AllowUsed !== undefined ? metaData.AllowUsed : false;
const disposable = metaData.Disposable !== undefined ? metaData.Disposable : false;
const usedRunJs = metaData.UsedRunJs || '';
const viewRunJs = metaData.ViewRunJs || '';
const itemCount = selectedItem.ItemLength || 0;
// 生成详情图片ID
const detailImgId = `detail-${selectedItem.BackpackItemUUID}`;
// 构建详情HTML
let detailHtml = `
<div class="detail-header animate__animated animate__fadeIn">
<!-- 新增:高级链接 -->
<a href="javascript:;" class="advanced-link" id="advancedLink">
<i class="layui-icon layui-icon-set"></i>高级
</a>
<div class="detail-icon">
<img id="${detailImgId}" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
alt="${selectedItem.ItemName || '未知物品'}"
data-original="${selectedItem.ItemIcon || defaultIconUrl}">
</div>
<div class="detail-name">${selectedItem.ItemName || '未知物品'}</div>
</div>
<div class="detail-desc animate__animated animate__fadeIn animate__delay-100ms">
${selectedItem.ItemDescription || '<div style="text-align:center; color:#999">暂无物品介绍</div>'}
</div>
<div class="detail-actions animate__animated animate__fadeIn animate__delay-200ms">
<div class="count-selector">
<div class="count-label">选择数量:</div>
<div class="count-input">
<button class="count-btn minus">-</button>
<input type="number" class="count-num" value="${selectedCount}" min="1" max="${itemCount}">
<button class="count-btn plus">+</button>
</div>
</div>
<div class="action-buttons">
<button class="action-btn btn-view">查看</button>
${allowUsed ? `<button class="action-btn btn-use">使用</button>` : ''}
<button class="action-btn btn-discard">丢弃</button>
</div>
</div>
`;
document.getElementById('detailPanel').innerHTML = detailHtml;
// 加载详情图片(使用缓存)
const detailImgElement = document.getElementById(detailImgId);
const originalUrl = detailImgElement.dataset.original;
loadImageToBlob(originalUrl).then(blobUrl => {
if (detailImgElement) {
detailImgElement.src = blobUrl;
}
});
// 绑定高级链接点击事件(替换原来的高级按钮事件)
document.getElementById('advancedLink').addEventListener('click', function() {
showAdvancedApiInfo();
});
// 绑定数量选择器事件
const minusBtn = document.querySelector('.count-btn.minus');
const plusBtn = document.querySelector('.count-btn.plus');
const countInput = document.querySelector('.count-num');
minusBtn.addEventListener('click', function() {
if (selectedCount > 1) {
selectedCount--;
countInput.value = selectedCount;
}
});
plusBtn.addEventListener('click', function() {
if (selectedCount < itemCount) {
selectedCount++;
countInput.value = selectedCount;
}
});
countInput.addEventListener('change', function() {
let val = parseInt(this.value);
if (isNaN(val)) val = 1;
if (val < 1) val = 1;
if (val > itemCount) val = itemCount;
selectedCount = val;
this.value = val;
});
// 绑定查看按钮事件 - 新增ViewRunJs执行逻辑
document.querySelector('.btn-view').addEventListener('click', function() {
// 执行查看JS代码
if (viewRunJs) {
try {
eval(viewRunJs);
} catch (e) {
console.error('执行物品查看JS失败:', e);
layer.msg('物品查看脚本执行失败', {icon: 2});
}
}
// 默认提示
else { layer.msg(`查看 ${selectedItem.ItemName} x ${selectedCount}`, {icon: 1}); }
});
// 绑定使用按钮事件(如果存在)
const useBtn = document.querySelector('.btn-use');
if (useBtn) {
useBtn.addEventListener('click', function() {
layer.confirm(`确定使用 ${selectedItem.ItemName} x ${selectedCount} 吗?`, {
title: '使用物品',
btn: ['确定', '取消']
}, function(index) {
layer.close(index);
// 执行使用JS代码
if (usedRunJs) {
try {
eval(usedRunJs);
} catch (e) {
console.error('执行物品使用JS失败:', e);
layer.msg('物品使用脚本执行失败', {icon: 2});
}
}
layer.msg(`已使用 ${selectedItem.ItemName} x ${selectedCount}`, {icon: 1});
// 可添加更新物品数量的逻辑
});
});
}
// 绑定丢弃按钮事件 - 修改为POST提交表单数据
document.querySelector('.btn-discard').addEventListener('click', function() {
layer.confirm(`确定丢弃 ${selectedItem.ItemName} x ${selectedCount} 吗?该操作不可恢复!`, {
title: '丢弃物品',
btn: ['确定', '取消'],
icon: 3
}, function(index) {
layer.close(index);
// 显示加载层
const loadIndex = layer.load(2, {
shade: [0.3, '#000'],
time: 10*1000
});
// 构建表单数据
const formData = new FormData();
formData.append('BackpackItemUUID', selectedItem.BackpackItemUUID);
formData.append('Count', selectedCount);
// POST提交到丢弃API
fetch('/API/Backpack/DiscardItem', {
method: 'POST',
body: formData
})
.then(response => {
// 忽略状态码,尝试解析JSON
return response.text().then(text => {
try {
return JSON.parse(text);
} catch (e) {
console.error('解析返回数据失败:', e, text);
return { code: 1, msg: '返回数据格式错误' };
}
});
})
.then(data => {
layer.close(loadIndex);
// 处理返回结果
if (data.code === 0) {
layer.msg(`成功丢弃 ${selectedItem.ItemName} x ${selectedCount}`, {icon: 1});
// 更新本地数据并重新渲染
// 1. 找到物品索引
const itemIndex = backpackItems.findIndex(item => item.BackpackItemUUID === selectedItem.BackpackItemUUID);
if (itemIndex !== -1) {
// 2. 更新物品数量
backpackItems[itemIndex].ItemLength = Math.max(0, backpackItems[itemIndex].ItemLength - selectedCount);
// 3. 如果数量为0,移除该物品
if (backpackItems[itemIndex].ItemLength === 0) {
backpackItems.splice(itemIndex, 1);
// 清空选中状态
selectedItem = null;
selectedCount = 1;
// 重置详情面板
document.getElementById('detailPanel').innerHTML = `
<div class="empty-data">
<i class="layui-icon layui-icon-component"></i>
<div>请选择一个物品查看详情</div>
</div>
`;
}
}
// 4. 重新渲染物品列表
const activeTag = document.querySelector('.category-tab.active').dataset.tag;
renderItemsList(activeTag);
} else {
layer.msg(data.msg || '丢弃物品失败', {icon: 2});
}
})
.catch(error => {
layer.close(loadIndex);
console.error('丢弃物品请求失败:', error);
layer.msg('网络错误,丢弃物品失败', {icon: 2});
});
});
});
}
// 显示高级API信息弹窗
function showAdvancedApiInfo() {
if (!selectedItem) return;
function escapeHtml(str) {
if (str === undefined || str === null) return '无';
const strType = typeof str;
if (strType !== 'string') {
return strType === 'object' ? JSON.stringify(str) : String(str);
}
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/`/g, '&#96;');
}
// 处理元数据默认值
const metaData = selectedItem.ItemMetaData || {};
const allowUsed = metaData.AllowUsed !== undefined ? metaData.AllowUsed : false;
const disposable = metaData.Disposable !== undefined ? metaData.Disposable : false;
const usedRunJs = metaData.UsedRunJs || '';
const viewRunJs = metaData.ViewRunJs || '';
// 构建API信息HTML(所有动态内容都经过转义)
let apiHtml = '<div class="advanced-api-content">';
// 基础信息(全量转义)
apiHtml += `
<div class="api-item">
<div class="api-key">基础信息</div>
<div class="api-value">
BackpackItemUUID: ${escapeHtml(selectedItem.BackpackItemUUID)}<br>
ItemName: ${escapeHtml(selectedItem.ItemName)}<br>
ItemLength: ${escapeHtml(selectedItem.ItemLength || 0)}<br>
ItemIcon: ${escapeHtml(selectedItem.ItemIcon)}<br>
ItemIconColor: #${escapeHtml(selectedItem.ItemIconColor)}<br>
ItemTags: ${escapeHtml(
selectedItem.ItemTags && Array.isArray(selectedItem.ItemTags)
? selectedItem.ItemTags.join(', ')
: '无'
)}<br>
ItemDescription: ${escapeHtml(selectedItem.ItemDescription)}
</div>
</div>
`;
// 元数据信息(全量转义)
apiHtml += `
<div class="api-item">
<div class="api-key">元数据 (ItemMetaData)</div>
<div class="api-value">
AllowUsed: ${escapeHtml(allowUsed)}<br>
Disposable: ${escapeHtml(disposable)}<br>
UsedRunJs: ${escapeHtml(usedRunJs)}<br>
ViewRunJs: ${escapeHtml(viewRunJs)}<br>
原始数据: <pre>${escapeHtml(JSON.stringify(metaData, null, 2))}</pre>
</div>
</div>
`;
apiHtml += '</div>';
// 弹出层
layer.open({
type: 1,
title: `[高级] ${escapeHtml(selectedItem.ItemName)} API信息`, // 标题也需要转义
area: ['80%', '70%'],
content: apiHtml,
shade: 0.5,
anim: 1,
maxmin: true
});
}
// 初始化
init();
});
</script>