eext-leye/iframe/newLeye.html

558 lines
25 KiB
HTML
Raw Normal View History

2026-02-09 11:40:12 +08:00
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>查看库存 - LEYE</title>
<link href="/iframe/css/index.css" rel="stylesheet" />
<style>
html { user-select: none; }
.scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; }
.scrollbar-hide::-webkit-scrollbar { display: none; }
#fixed-window { width: 1280px; height: 680px; border: 1px solid #e5e7eb; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }
.table-container { height: calc(680px - 48px - 52px - 64px); overflow-y: auto; }
.sticky-header { position: sticky; top: 0; z-index: 10; }
.sort-icon { display: inline-block; margin-left: 4px; font-size: 10px; color: #9ca3af; }
.sort-active { color: #2563eb !important; }
.hidden { display: none !important; }
.cat-toggle { transition: transform 0.2s; cursor: pointer; padding: 4px; }
.cat-toggle.collapsed { transform: rotate(-90deg); }
.children-container { overflow: hidden; transition: max-height 0.3s ease-out; }
.children-container.hidden { display: none; }
</style>
</head>
<body class="bg-gray-100 font-sans text-sm">
<div id="fixed-window" class="bg-gray-50 flex flex-col overflow-hidden">
<header class="flex-shrink-0 bg-white border-b border-gray-200 shadow-sm p-2 text-sm">
<div class="max-w-full mx-auto flex items-center space-x-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input id="global-search-input" type="text" placeholder="搜索型号、CID、品牌、值..." class="w-[92%] px-2 py-1 text-sm border-0 focus:ring-0 focus:outline-none placeholder-gray-400" />
<button id="search-btn" class="w-[5%] px-3 py-1 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-xs">搜索</button>
</div>
</header>
<div id="main-content" class="flex-grow flex p-3 space-x-3 overflow-hidden">
<aside class="w-60 flex-shrink-0 bg-white border border-gray-200 rounded-lg shadow-md p-3 flex flex-col overflow-hidden">
<h3 class="text-base font-semibold text-gray-800 border-b pb-1 mb-2">筛选类别</h3>
<div id="category-tree" class="flex-grow overflow-y-auto scrollbar-hide space-y-0.5 text-xs">
</div>
</aside>
<main class="flex-grow flex flex-col bg-white border border-gray-200 rounded-lg shadow-md overflow-hidden">
<div class="table-container overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-100 sticky-header text-xs uppercase tracking-wider text-gray-600">
<tr>
<th scope="col" class="w-12 px-2 py-2 text-center">ID</th>
<th scope="col" class="w-48 px-3 py-2 text-left">型号</th>
<th scope="col" id="sort-type" class="w-24 px-3 py-2 text-left cursor-pointer hover:bg-gray-200">类型 <span class="sort-icon"></span></th>
<th scope="col" id="sort-value" class="w-20 px-3 py-2 text-left cursor-pointer hover:bg-gray-200"><span class="sort-icon"></span></th>
<th scope="col" class="w-24 px-3 py-2 text-left">封装</th>
<th scope="col" class="w-32 px-3 py-2 text-left">品牌</th>
<th scope="col" id="sort-quantity" class="w-24 px-3 py-2 text-right cursor-pointer hover:bg-gray-200">余量 <span class="sort-icon"></span></th>
<th scope="col" class="w-32 px-3 py-2 text-left">CID</th>
</tr>
</thead>
<tbody id="data-table-body" class="bg-white divide-y divide-gray-200 text-xs">
<tr><td colspan="8" class="text-center py-6 text-gray-500">正在初始化器件数据...</td></tr>
</tbody>
</table>
</div>
<div class="flex-shrink-0 border-t border-gray-200 bg-gray-50 p-2 flex justify-between items-center text-xs">
<div class="text-gray-600"><span id="selected-rows-info">未选择行</span></div>
<div class="flex items-center space-x-4">
<div class="text-gray-600">展示 <span id="display-range">0-0</span> / 共 <span id="total-items">0</span></div>
<div class="flex items-center space-x-1">
<button id="prev-page" class="px-2 py-0.5 border border-gray-300 rounded-md hover:bg-gray-200 disabled:opacity-30">上页</button>
<span class="px-2 font-medium" id="page-num">1</span>
<button id="next-page" class="px-2 py-0.5 border border-gray-300 rounded-md hover:bg-gray-200 disabled:opacity-30">下页</button>
</div>
</div>
</div>
</main>
</div>
<div class="flex-shrink-0 p-3 bg-white border-t border-gray-200 flex justify-end space-x-3 shadow-lg">
<button id="cancel-btn" class="px-4 py-1.5 border border-gray-300 text-gray-700 rounded-md hover:bg-gray-100 text-sm">关闭</button>
<button id="edit-btn" class="px-4 py-1.5 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-sm">出入库</button>
<button id="place-btn" class="px-4 py-1.5 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-sm">放置</button>
</div>
<div id="edit-dialog" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white rounded-lg shadow-xl w-96 overflow-hidden">
<div class="bg-gray-50 px-4 py-3 border-b border-gray-200 flex justify-between items-center">
<h3 class="text-sm font-semibold text-gray-700">编辑器件信息</h3>
<span class="text-[10px] text-gray-400">ID: <span id="dialog-id-display">-</span></span>
</div>
<div class="p-4 space-y-4">
<div class="grid grid-cols-2 gap-3">
<div class="col-span-2">
<label class="block text-xs text-gray-500 mb-1">型号 (Manufacturer Part) <span class="text-red-500">*</span></label>
<input id="edit-name-input" type="text" class="w-full px-2 py-1.5 border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 outline-none text-sm" placeholder="必填" />
</div>
<div class="col-span-2">
<label class="block text-xs text-gray-500 mb-1">LCSC ID (Supplier Part) <span class="text-red-500">*</span></label>
<input id="edit-lcsc-input" type="text" class="w-full px-2 py-1.5 border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 outline-none text-sm" placeholder="必填" />
</div>
</div>
<hr class="border-gray-100">
<div>
<label class="block text-xs text-gray-500 mb-1">变更库存</label>
<div class="flex space-x-2 mb-2">
<button id="op-add" class="flex-1 py-1.5 border border-blue-600 bg-blue-50 text-blue-600 rounded text-xs font-medium">入库 (+)</button>
<button id="op-sub" class="flex-1 py-1.5 border border-gray-300 text-gray-600 rounded text-xs font-medium">出库 (-)</button>
</div>
<div class="flex items-center space-x-3">
<input id="edit-qty-input" type="number" min="0" value="0" class="w-24 px-2 py-1.5 border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 outline-none text-sm" />
<div class="text-[10px] text-gray-400">
<span id="current-qty-val">0</span><span id="target-qty-val">0</span>
</div>
</div>
</div>
</div>
<div class="flex border-t border-gray-100">
<button id="dialog-cancel" class="flex-1 px-4 py-3 text-gray-500 hover:bg-gray-50 text-xs">取消</button>
<button id="dialog-confirm" class="flex-1 px-4 py-3 bg-blue-600 text-white hover:bg-blue-700 text-xs font-bold">提交更改</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const categoryTree = document.getElementById('category-tree');
const tableBody = document.getElementById('data-table-body');
const placeButton = document.getElementById('place-btn');
const searchButton = document.getElementById('search-btn');
const searchInput = document.getElementById('global-search-input');
const selectedRowsInfo = document.getElementById('selected-rows-info');
const totalItemsSpan = document.getElementById('total-items');
const pageNumSpan = document.getElementById('page-num');
const displayRangeSpan = document.getElementById('display-range');
const editBtn = document.getElementById('edit-btn');
const editDialog = document.getElementById('edit-dialog');
const editQtyInput = document.getElementById('edit-qty-input');
const currentQtySpan = document.getElementById('current-qty-val');
const targetQtySpan = document.getElementById('target-qty-val');
const opAddBtn = document.getElementById('op-add');
const opSubBtn = document.getElementById('op-sub');
const dialogCancel = document.getElementById('dialog-cancel');
const dialogConfirm = document.getElementById('dialog-confirm');
const editNameInput = document.getElementById('edit-name-input');
const editLcscInput = document.getElementById('edit-lcsc-input');
const dialogIdDisplay = document.getElementById('dialog-id-display');
const SERVER = eda.sys_Storage.getExtensionUserConfig('server-host') || 'http://localhost:21816/api';
const AUTO_RUN = eda.sys_Storage.getExtensionUserConfig('server-auto-run') || true;
const CACHE_KEY = 'cache-leye-device-details';
let allDevicesData = [];
let filteredData = [];
let selectedRowData = null;
let sortRules = [
{ key: 'type', order: 'desc' },
{ key: 'value', order: 'desc' }
];
let currentOp = 'add';
let currentPage = 1;
const pageSize = 20;
const unitMap = new Map([['M', 1e6], ['k', 1e3], ['m', 1e-3], ['u', 1e-6], ['n', 1e-9], ['p', 1e-12]]);
function parseValue(val) {
if (!val || val === '-') return -Infinity;
const str = String(val).trim();
if (/^\d/.test(str)) {
const numPart = parseFloat(str);
const match = str.match(/[\d.]+\s*([a-zA-Z])/);
if (match && match[1] && unitMap.has(match[1])) return numPart * unitMap.get(match[1]);
return numPart;
}
return str;
}
async function initInventoryData() {
tableBody.innerHTML = `<tr><td colspan="8" class="text-center py-6 text-gray-500">正在同步库存状态...</td></tr>`;
try {
const cachedRaw = await eda.sys_Storage.getExtensionUserConfig(CACHE_KEY);
let cachedDetails = [];
try { cachedDetails = cachedRaw ? JSON.parse(cachedRaw) : []; } catch(e) { cachedDetails = []; }
let listRes = await eda.sys_ClientUrl.request(SERVER + '/getLeyeList?pageSize=1000&current=1');
let listResult = await listRes.json();
if (AUTO_RUN && !listResult.success) {
window.open('leye://open');
for (let i = 0; i < 3 && !listResult.success; i++) {
eda.sys_Message.showToastMessage('等待拉起本地服务端...', ESYS_ToastMessageType.INFO);
listRes = await eda.sys_ClientUrl.request(SERVER + '/getLeyeList?pageSize=1000&current=1');
listResult = await listRes.json();
await new Promise(resolve => setTimeout(resolve, 1500));
}
}
if (!listResult.success || !listResult.data) {
throw new Error('同步失败');
}
const validItems = listResult.data.filter(item => item.lcscId);
const currentLcscIds = validItems.map(item => String(item.lcscId).toUpperCase());
const cachedLcscIds = cachedDetails.map(d => String(d.lcscId).toUpperCase());
const newLcscIds = currentLcscIds.filter(id => !cachedLcscIds.includes(id));
let updatedDetails = cachedDetails.filter(d => currentLcscIds.includes(String(d.lcscId).toUpperCase()));
if (newLcscIds.length > 0) {
const devices = await eda.lib_Device.getByLcscIds(newLcscIds);
const chunkSize = 20;
for (let i = 0; i < devices.length; i += chunkSize) {
const chunk = devices.slice(i, i + chunkSize);
tableBody.innerHTML = `<tr><td colspan="8" class="text-center py-6 text-gray-500">发现 ${newLcscIds.length} 个新器件,正在更新 (${Math.min(i+chunkSize, devices.length)}/${devices.length})...</td></tr>`;
const chunkData = await Promise.all(chunk.map(async (dev) => {
try {
const EDA_HOST = eda.sys_Environment.isClient() ? "https://client" : "https://pro.lceda.cn";
const infoRes = await eda.sys_ClientUrl.request(EDA_HOST + '/api/v2/devices/' + dev.uuid, 'GET', null, { headers: { path: '0819f05c4eef4c71ace90d822a990e87' } });
const infoJson = await infoRes.json();
const info = infoJson.result;
return {
uuid: dev.uuid,
parentCat: info.tags?.parent_tag?.name_cn || '其他',
childCat: info.tags?.child_tag?.name_cn || '其他',
name: info.attributes['Manufacturer Part'] || '-',
footprint: info.attributes['Supplier Footprint'] || '-',
value: info.attributes['Value'] || '-',
brand: info.attributes['Manufacturer'] || '-',
lcscId: String(info.attributes['Supplier Part']).toUpperCase(),
};
} catch (e) { return null; }
}));
updatedDetails.push(...chunkData.filter(d => d !== null));
}
await eda.sys_Storage.setExtensionUserConfig(CACHE_KEY, JSON.stringify(updatedDetails));
}
allDevicesData = updatedDetails.map(detail => {
const invItem = validItems.find(vi => String(vi.lcscId).toUpperCase() === detail.lcscId);
return { ...detail, id: invItem ? invItem.id : '?', quantity: invItem ? invItem.quantity : 0 };
});
generateCategoryTree();
handleLocalSearch();
} catch (error) {
tableBody.innerHTML = `<tr><td colspan="8" class="text-center py-6 text-red-500">加载失败: ${error.message}</td></tr>`;
console.log('加载失败: ', error);
eda.sys_Log.add('加载失败: ', error.message);
}
}
function generateCategoryTree() {
const tree = {};
allDevicesData.forEach(d => {
if (!tree[d.parentCat]) tree[d.parentCat] = new Set();
tree[d.parentCat].add(d.childCat);
});
let html = `
<div class="cursor-pointer hover:bg-blue-50 rounded p-1 flex items-center" data-cat="all">
<div class="w-4"></div>
<input type="radio" name="category" value="all" id="cat-all" checked class="mr-2">
<label for="cat-all" class="font-bold text-gray-900 cursor-pointer">全部</label>
</div>`;
Object.keys(tree).sort().forEach(parent => {
const parentId = btoa(encodeURIComponent(parent)).replace(/=/g, '');
html += `
<div class="parent-group">
<div class="cursor-pointer hover:bg-blue-50 rounded p-1 flex items-center" data-cat="${parent}">
<span class="cat-toggle text-gray-400 hover:text-blue-600 collapsed" data-toggle="${parentId}"></span>
<input type="radio" name="category" value="${parent}" id="cat-${parentId}" class="mr-2">
<label for="cat-${parentId}" class="text-gray-700 font-semibold cursor-pointer truncate">${parent}</label>
</div>
<div id="children-${parentId}" class="children-container ml-4 border-l border-gray-100 pl-2 hidden">`;
Array.from(tree[parent]).sort().forEach(child => {
const childId = btoa(encodeURIComponent(child)).replace(/=/g, '');
html += `
<div class="cursor-pointer hover:bg-blue-50 rounded p-1 flex items-center" data-cat="${child}">
<div class="w-4"></div>
<input type="radio" name="category" value="${child}" id="cat-${childId}" class="mr-2">
<label for="cat-${childId}" class="text-gray-600 cursor-pointer truncate">${child}</label>
</div>`;
});
html += `</div></div>`;
});
categoryTree.innerHTML = html;
categoryTree.querySelectorAll('.cat-toggle').forEach(btn => {
btn.onclick = (e) => {
e.stopPropagation();
const targetId = btn.dataset.toggle;
const container = document.getElementById(`children-${targetId}`);
btn.classList.toggle('collapsed');
container.classList.toggle('hidden');
};
});
}
function handleLocalSearch() {
currentPage = 1;
const keyword = searchInput.value.toLowerCase().trim();
const selectedRadio = document.querySelector('input[name="category"]:checked');
const catValue = selectedRadio ? selectedRadio.value : 'all';
filteredData = allDevicesData.filter(d => {
const matchesSearch = !keyword ||
(d.name && d.name.toLowerCase().includes(keyword)) ||
(d.lcscId && d.lcscId.toLowerCase().includes(keyword)) ||
(d.brand && d.brand.toLowerCase().includes(keyword)) ||
(d.value && d.value.toLowerCase().includes(keyword));
const matchesCat = catValue === 'all' || d.parentCat === catValue || d.childCat === catValue;
return matchesSearch && matchesCat;
});
applySortAndRender();
}
function applySortAndRender() {
let data = [...filteredData];
if (sortRules.length > 0) {
data.sort((a, b) => {
for (const rule of sortRules) {
let valA, valB;
if (rule.key === 'type') { valA = a.childCat; valB = b.childCat; }
else if (rule.key === 'value') { valA = parseValue(a.value); valB = parseValue(b.value); }
else if (rule.key === 'quantity') { valA = a.quantity; valB = b.quantity; }
if (valA === valB) continue;
if (typeof valA === 'number' && typeof valB === 'number') {
return rule.order === 'asc' ? valA - valB : valB - valA;
}
const res = String(valA).localeCompare(String(valB), 'zh-CN');
return rule.order === 'asc' ? res : -res;
}
return 0;
});
}
renderTable(data);
updateSortIcons();
}
function renderTable(data) {
const total = data.length;
totalItemsSpan.textContent = total;
if (total === 0) {
tableBody.innerHTML = `<tr><td colspan="8" class="text-center py-6 text-gray-500">未找到匹配库存项</td></tr>`;
displayRangeSpan.textContent = '0-0';
return;
}
const start = (currentPage - 1) * pageSize;
const end = Math.min(start + pageSize, total);
const pageData = data.slice(start, end);
displayRangeSpan.textContent = `${start + 1}-${end}`;
pageNumSpan.textContent = currentPage;
document.getElementById('prev-page').disabled = currentPage === 1;
document.getElementById('next-page').disabled = end >= total;
tableBody.innerHTML = pageData.map(item => `
<tr class="hover:bg-blue-50 cursor-pointer ${selectedRowData && selectedRowData.lcscId === item.lcscId ? 'bg-blue-100' : ''}" data-row='${JSON.stringify(item)}'>
<td class="px-2 py-1.5 text-center text-gray-500">${item.id}</td>
<td class="px-3 py-1.5 font-medium text-blue-600">${item.name}</td>
<td class="px-3 py-1.5 text-left text-gray-700">${item.childCat}</td>
<td class="px-3 py-1.5 text-left text-gray-700">${item.value}</td>
<td class="px-3 py-1.5 text-left text-gray-700">${item.footprint}</td>
<td class="px-3 py-1.5 text-left text-gray-700">${item.brand}</td>
<td class="px-3 py-1.5 text-right ${item.quantity > 0 ? 'text-green-600' : 'text-red-500'}">${item.quantity}</td>
<td class="px-3 py-1.5 text-left text-gray-500">${item.lcscId}</td>
</tr>
`).join('');
}
function selectRow(row) {
tableBody.querySelectorAll('tr').forEach(r => r.classList.remove('bg-blue-100'));
row.classList.add('bg-blue-100');
selectedRowData = JSON.parse(row.dataset.row);
selectedRowsInfo.textContent = '已选择 1 行';
}
function updateSortIcons() {
['type', 'value', 'quantity'].forEach(key => {
const th = document.getElementById(`sort-${key}`);
const icon = th.querySelector('.sort-icon');
const ruleIndex = sortRules.findIndex(r => r.key === key);
const rule = sortRules[ruleIndex];
if (rule) {
icon.textContent = (rule.order === 'asc' ? '↑' : '↓') + (sortRules.length > 1 ? `(${ruleIndex + 1})` : '');
icon.classList.add('sort-active');
th.classList.add('bg-blue-50');
} else {
icon.textContent = '⇅';
icon.classList.remove('sort-active');
th.classList.remove('bg-blue-50');
}
});
}
searchButton.onclick = handleLocalSearch;
searchInput.onkeyup = (e) => e.key === 'Enter' && handleLocalSearch();
document.getElementById('prev-page').onclick = () => { if (currentPage > 1) { currentPage--; applySortAndRender(); } };
document.getElementById('next-page').onclick = () => { if (currentPage * pageSize < filteredData.length) { currentPage++; applySortAndRender(); } };
categoryTree.onclick = (e) => {
const div = e.target.closest('div[data-cat]');
if (div && !e.target.classList.contains('cat-toggle')) {
div.querySelector('input').checked = true;
handleLocalSearch();
}
};
const onSortClick = (key) => {
const idx = sortRules.findIndex(r => r.key === key);
if (idx > -1) {
if (sortRules[idx].order === 'asc') sortRules[idx].order = 'desc';
else sortRules.splice(idx, 1);
} else {
sortRules.push({ key, order: 'asc' });
}
applySortAndRender();
};
document.getElementById('sort-type').onclick = () => onSortClick('type');
document.getElementById('sort-value').onclick = () => onSortClick('value');
document.getElementById('sort-quantity').onclick = () => onSortClick('quantity');
tableBody.onclick = (e) => {
const row = e.target.closest('tr');
if (row && row.dataset.row) selectRow(row);
};
tableBody.ondblclick = (e) => {
const row = e.target.closest('tr');
if (row && row.dataset.row) {
selectRow(row);
placeButton.click();
}
};
placeButton.onclick = async () => {
if (!selectedRowData) return;
await eda.sys_IFrame.closeIFrame('leye-main');
try {
await eda.sch_PrimitiveComponent.placeComponentWithMouse({
uuid: selectedRowData.uuid,
libraryUuid: '0819f05c4eef4c71ace90d822a990e87',
});
} catch (e) { console.error(e); }
};
editBtn.onclick = () => {
if (!selectedRowData) {
eda.sys_Message.showToastMessage('请先在列表中选择一个器件', ESYS_ToastMessageType.WARNING);
return;
}
dialogIdDisplay.textContent = selectedRowData.id;
editNameInput.value = selectedRowData.name || '';
editLcscInput.value = selectedRowData.lcscId || '';
editQtyInput.value = 0;
currentQtySpan.textContent = selectedRowData.quantity;
const change = parseInt(editQtyInput.value) || 0;
const current = parseInt(selectedRowData.quantity) || 0;
const target = currentOp === 'add' ? current + change : current - change;
targetQtySpan.textContent = target;
targetQtySpan.className = target < 0 ? 'text-red-500 font-bold' : 'text-blue-600 font-bold';
editDialog.classList.remove('hidden');
};
opAddBtn.onclick = () => {
currentOp = 'add';
opAddBtn.className = 'flex-1 py-1.5 border border-blue-600 bg-blue-50 text-blue-600 rounded text-xs font-medium';
opSubBtn.className = 'flex-1 py-1.5 border border-gray-300 text-gray-600 rounded text-xs font-medium';
const change = parseInt(editQtyInput.value) || 0;
const current = parseInt(selectedRowData.quantity) || 0;
const target = currentOp === 'add' ? current + change : current - change;
targetQtySpan.textContent = target;
targetQtySpan.className = target < 0 ? 'text-red-500 font-bold' : 'text-blue-600 font-bold';
};
opSubBtn.onclick = () => {
currentOp = 'sub';
opSubBtn.className = 'flex-1 py-1.5 border border-red-600 bg-red-50 text-red-600 rounded text-xs font-medium';
opAddBtn.className = 'flex-1 py-1.5 border border-gray-300 text-gray-600 rounded text-xs font-medium';
const change = parseInt(editQtyInput.value) || 0;
const current = parseInt(selectedRowData.quantity) || 0;
const target = currentOp === 'add' ? current + change : current - change;
targetQtySpan.textContent = target;
targetQtySpan.className = target < 0 ? 'text-red-500 font-bold' : 'text-blue-600 font-bold';
};
editQtyInput.oninput = () => {
const change = parseInt(editQtyInput.value) || 0;
const current = parseInt(selectedRowData.quantity) || 0;
const target = currentOp === 'add' ? current + change : current - change;
targetQtySpan.textContent = target;
targetQtySpan.className = target < 0 ? 'text-red-500 font-bold' : 'text-blue-600 font-bold';
};
dialogCancel.onclick = () => editDialog.classList.add('hidden');
dialogConfirm.onclick = async () => {
const newName = editNameInput.value.trim();
const newLcscId = editLcscInput.value.trim();
const changeQty = parseInt(editQtyInput.value) || 0;
if (!newName || !newLcscId) {
eda.sys_Message.showToastMessage('型号和 LCSC ID 不能为空', ESYS_ToastMessageType.ERROR);
return;
}
const newQuantity = currentOp === 'add' ?
selectedRowData.quantity + changeQty :
selectedRowData.quantity - changeQty;
dialogConfirm.disabled = true;
dialogConfirm.textContent = '正在保存...';
try {
const res = await eda.sys_ClientUrl.request(SERVER + '/editLeyeList', 'POST', JSON.stringify({
id: selectedRowData.id,
name: newName,
lcscId: newLcscId,
quantity: newQuantity
}), { headers: { 'Content-Type': 'application/json' } });
const result = await res.json();
if (result.success) {
eda.sys_Message.showToastMessage('更新成功', ESYS_ToastMessageType.SUCCESS);
const deviceIndex = allDevicesData.findIndex(d => d.id === selectedRowData.id);
if (deviceIndex !== -1) {
allDevicesData[deviceIndex].name = newName;
allDevicesData[deviceIndex].lcscId = newLcscId;
allDevicesData[deviceIndex].quantity = newQuantity;
selectedRowData = { ...allDevicesData[deviceIndex] };
}
await eda.sys_Storage.setExtensionUserConfig(CACHE_KEY, JSON.stringify(allDevicesData));
handleLocalSearch();
editDialog.classList.add('hidden');
} else {
throw new Error(result.message || '后端处理失败');
}
} catch (e) {
eda.sys_Message.showToastMessage('提交失败: ' + e.message, ESYS_ToastMessageType.ERROR);
} finally {
dialogConfirm.disabled = false;
dialogConfirm.textContent = '提交更改';
}
};
document.getElementById('cancel-btn').onclick = () => eda.sys_IFrame.closeIFrame('leye-main');
initInventoryData();
});
</script>
</body>
</html>