Files
basicBench/001/001.html
2026-02-15 18:44:09 +08:00

1231 lines
56 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SYS_V4.2_INVENTORY_MANAGE_INTERNAL_USE_ONLY</title>
<style>
/* === CSS Reset & Modernizer === */
:root {
--primary: #2563eb;
--danger: #dc2626;
--bg: #f8fafc;
--panel: #ffffff;
--border: #e2e8f0;
--text: #334155;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background-color: var(--bg) !important; /* 覆盖原有 bgcolor */
color: var(--text) !important;
margin: 0;
padding: 0;
line-height: 1.5;
}
a { text-decoration: none; color: var(--primary) !important; transition: 0.2s; }
a:hover { text-decoration: underline; }
/* === Layout Refactor (Force Table to Flex Style) === */
/* Hide the border and background of the outermost large table */
.main-layout-table {
background-color: transparent !important;
border: none !important;
width: 100%;
border-collapse: collapse;
}
/* Top Header */
.header-row td {
background-color: #1e293b !important; /* Dark top bar */
color: white !important;
padding: 15px 20px !important;
border: none !important;
}
.header-row h1 { margin: 0; font-size: 1.2rem; font-weight: 600; }
.header-row p { margin: 5px 0 0; opacity: 0.8; font-size: 0.9rem; }
.header-row a { color: #94a3b8 !important; margin: 0 5px; }
/* Sidebar & Main Content & Widget Layout Adjustment */
/* Use CSS to make these tds look like independent columns */
.layout-cell {
vertical-align: top;
padding: 20px !important;
border: none !important;
}
/* 左侧导航栏 */
.sidebar-nav ul {
list-style: none;
padding: 0;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
.sidebar-nav ul li a {
display: block;
padding: 10px 15px;
border-bottom: 1px solid var(--border);
color: var(--text) !important;
}
.sidebar-nav ul li a:hover {
background-color: #eff6ff;
color: var(--primary) !important;
text-decoration: none;
}
/* 隐藏旧版干扰链接 */
.legacy-link { display: none !important; }
/* 中间主内容 */
.main-content h2 {
font-size: 1.5rem;
border-bottom: 2px solid var(--primary);
padding-bottom: 10px;
margin-top: 0;
}
/* 筛选表单美化 */
.filter-table {
background: var(--panel);
padding: 15px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
border: 1px solid var(--border) !important;
}
.filter-table td { border: none !important; padding: 5px !important; }
input[type="text"], select {
padding: 6px; border: 1px solid #ccc; border-radius: 4px;
}
input[type="submit"], input[type="reset"] {
padding: 6px 15px; border-radius: 4px; border: none; cursor: pointer;
font-weight: bold;
}
input[type="submit"] { background: var(--primary); color: white; }
/* 数据表格 (核心改造) */
.data-table {
background: var(--panel) !important;
border-collapse: collapse !important;
border: none !important;
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);
border-radius: 8px;
overflow: hidden;
width: 100%;
margin-top: 20px;
}
.data-table th {
background-color: #f1f5f9 !important; /* 覆盖原来的灰色 */
color: #475569;
text-transform: uppercase;
font-size: 0.85rem;
padding: 12px !important;
border: none !important;
border-bottom: 2px solid var(--border) !important;
}
.data-table td {
border: none !important;
border-bottom: 1px solid var(--border) !important;
padding: 12px !important;
font-size: 0.95rem;
}
.data-table tr:hover td { background-color: #f8fafc; }
/* 操作链接样式化为按钮 */
.action-group a {
display: inline-block;
padding: 2px 6px;
font-size: 0.8rem;
border-radius: 4px;
text-decoration: none !important;
margin-right: 2px;
margin-bottom: 2px;
border: 1px solid transparent;
}
.btn-view { background: #e0f2fe; color: #0369a1 !important; }
.btn-edit { background: #dcfce7; color: #15803d !important; }
.btn-danger { background: #fee2e2; color: #b91c1c !important; }
/* === 干扰项隐藏 (重点) === */
/* 隐藏所有被标记为 interference 的行 */
.interference-row { display: none !important; }
/* 右侧 Widget 美化 */
.widget-table {
background: var(--panel) !important;
border: 1px solid var(--border) !important;
border-radius: 8px;
margin-bottom: 20px;
border-collapse: collapse;
}
.widget-header {
background-color: #334155 !important;
color: white !important;
padding: 10px !important;
font-weight: bold;
border-radius: 7px 7px 0 0;
}
.widget-content td { padding: 8px 15px !important; border-bottom: 1px solid #eee !important; }
/* 页脚 */
.footer-row td {
background-color: var(--panel) !important;
color: #94a3b8 !important;
border-top: 1px solid var(--border) !important;
padding: 20px !important;
}
/* === 新增样式: 模态框 (Modal) === */
.modal-overlay {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0, 0, 0, 0.5);
display: none; justify-content: center; align-items: center;
z-index: 1000; opacity: 0; transition: opacity 0.3s ease;
}
.modal-overlay.show { display: flex; opacity: 1; }
.modal-window {
background: white; width: 600px; max-width: 90%;
border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,0.2);
transform: translateY(-20px); transition: transform 0.3s ease;
display: flex; flex-direction: column; overflow: hidden;
}
.modal-overlay.show .modal-window { transform: translateY(0); }
.modal-header {
padding: 15px 20px; background: #f8fafc; border-bottom: 1px solid #e2e8f0;
display: flex; justify-content: space-between; align-items: center;
}
.modal-title { margin: 0; font-size: 1.1rem; font-weight: 600; color: #334155; }
.modal-close { cursor: pointer; font-size: 1.5rem; color: #94a3b8; line-height: 1; }
.modal-body { padding: 20px; overflow-y: auto; max-height: 70vh; }
.modal-footer {
padding: 15px 20px; background: #f8fafc; border-top: 1px solid #e2e8f0;
text-align: right;
}
/* 表单组样式 */
.form-group { margin-bottom: 15px; }
.form-group label { display: block; margin-bottom: 5px; font-weight: 500; font-size: 0.9rem; }
.form-group input, .form-group select, .form-group textarea {
width: 100%; padding: 8px; border: 1px solid #cbd5e1; border-radius: 4px;
box-sizing: border-box; font-family: inherit;
}
.form-group .hint { font-size: 0.8rem; color: #64748b; margin-top: 4px; }
/* === 新增样式: 分页组件 (Pagination) === */
.pagination-container {
display: flex; justify-content: space-between; align-items: center;
margin-top: 20px; padding: 10px; background: #fff; border-radius: 8px;
border: 1px solid #e2e8f0;
}
.pagination-info { font-size: 0.9rem; color: #64748b; }
.pagination-controls { display: flex; gap: 5px; }
.page-btn {
padding: 5px 10px; border: 1px solid #e2e8f0; background: white;
cursor: pointer; border-radius: 4px; font-size: 0.9rem; color: #475569;
}
.page-btn:hover { background: #f1f5f9; border-color: #cbd5e1; }
.page-btn.active { background: var(--primary); color: white; border-color: var(--primary); }
.page-btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* === 新增样式: Toast 通知 === */
.toast-container {
position: fixed; bottom: 20px; right: 20px; z-index: 2000;
display: flex; flex-direction: column; gap: 10px;
}
.toast {
background: white; border-left: 4px solid var(--primary);
padding: 15px 20px; border-radius: 4px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);
min-width: 250px; transform: translateX(100%); transition: transform 0.3s ease;
display: flex; align-items: center; justify-content: space-between;
}
.toast.show { transform: translateX(0); }
.toast-success { border-left-color: #10b981; }
.toast-error { border-left-color: #ef4444; }
.toast-warning { border-left-color: #f59e0b; }
/* === 新增样式: 只有 CSS 的加载动画 === */
.spinner {
width: 20px; height: 20px; border: 2px solid #f3f3f3;
border-top: 2px solid var(--primary); border-radius: 50%;
animation: spin 1s linear infinite; display: inline-block; vertical-align: middle;
}
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
</style>
</head>
<body bgcolor="#e0e0e0" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000">
<table width="100%" border="1" cellpadding="5" cellspacing="0" bgcolor="#cccccc" class="main-layout-table">
<tr class="header-row">
<td colspan="3" align="center">
<h1>Internal Inventory Control System V4.2 (Unclassified)</h1>
<p>Current Login: OPERATOR_8821 | <a href="#" onclick="showCustomAlert('Simulate Logout')">[Logout]</a> | <a href="#">[Switch Node]</a> | <a href="#">[System Log]</a> | <a href="#">[Report Error]</a></p>
</td>
</tr>
<tr>
<td width="20%" valign="top" class="layout-cell sidebar-nav">
<h3>Quick Navigation</h3>
<ul id="sidebarList">
<li><a href="javascript:void(0)" onclick="filterCategory('all')">📌 Dashboard</a></li>
<li><a href="javascript:void(0)" onclick="filterCategory('urgent')">🔥 Inbound Request (Urgent)</a></li>
<li><a href="javascript:void(0)" onclick="filterCategory('normal')">📥 Inbound Request (Normal)</a></li>
<li><a href="javascript:void(0)" onclick="showToast('Archived data requires admin permission', 'warning')">🗄️ Inbound Request (Archived)</a></li>
<li><a href="javascript:void(0)" onclick="filterCategory('out_a')">📤 Outbound Approval (Zone A)</a></li>
<li><a href="javascript:void(0)" onclick="filterCategory('out_b')">📤 Outbound Approval (Zone B)</a></li>
<li><a href="javascript:void(0)" onclick="showToast('Zone C system under maintenance', 'error')">🚫 Outbound Approval (Zone C)</a></li>
<li><a href="javascript:void(0)" onclick="openModal('reportModal')">📉 Damage Registration</a></li>
<li><a href="javascript:void(0)" onclick="showToast('Access Denied: HR only', 'error')">👥 Personnel Management</a></li>
<li><a href="javascript:void(0)" onclick="showToast('Connecting to financial interface...', 'info')">💰 Financial Interface</a></li>
<li><a href="javascript:void(0)" onclick="openModal('settingsModal')">⚙️ System Settings</a></li>
<li><a href="javascript:void(0)" onclick="window.print()">🖨️ Print Test Page</a></li>
<li class="legacy-link"><a href="#">Legacy Portal (Deprecated)</a></li>
<li class="legacy-link"><a href="#">Legacy Portal V2 (Deprecated)</a></li>
<li class="legacy-link"><a href="#">Help Documentation 1998 Edition</a></li>
<li><a href="javascript:void(0)" onclick="openHelp()">❓ Help & Support</a></li>
<li><a href="javascript:void(0)" onclick="showToast('No download needed, browser supported', 'success')">💾 Download Controls</a></li>
<li><a href="javascript:void(0)" onclick="location.reload()">🔄 Refresh System</a></li>
</ul>
<hr>
<div style="background:#fff7ed; padding:10px; border-radius:4px; font-size:0.9em; border:1px solid #ffedd5;">
<p style="margin:0; color:#c2410c;"><b>System Broadcast:</b><br>Please note, server maintenance is scheduled for 03:00 tonight. Do not submit forms during this time.</p>
</div>
<p style="text-align:center; color:#888; margin-top:10px;"><b>Quote of the Day:</b><br>Safety First, Efficiency Foremost.</p>
</td>
<td width="60%" valign="top" class="layout-cell main-content">
<h2>Inventory List - Zone A1</h2>
<form id="searchForm" onsubmit="event.preventDefault(); handleSearch();">
<table border="0" width="100%" class="filter-table">
<tr>
<td>Keyword: <input type="text" id="searchInput" name="kw" size="30" placeholder="Enter ID or Name"></td>
<td>
Type:
<select id="typeSelect" name="type">
<option value="all">-- All --</option>
<option value="res">Resistor</option>
<option value="cap">Capacitor</option>
<option value="ind">Inductor</option>
<option value="chip">Chip</option>
<option value="conn">Connector</option>
<option value="other">Other</option>
</select>
</td>
<td>
Status:
<label><input type="checkbox" name="st_normal" value="NORMAL" checked> Normal</label>
<label><input type="checkbox" name="st_low" value="LOW" checked> Warning</label>
<label><input type="checkbox" name="st_crit" value="CRITICAL" checked> Critical</label>
</td>
</tr>
<tr>
<td colspan="3" style="padding-top:10px;">
Sort:
<label><input type="radio" name="sort" value="date" checked> By Date</label>
<label><input type="radio" name="sort" value="id"> By ID</label>
<label><input type="radio" name="sort" value="qty"> By Quantity</label>
<br><br>
<button type="submit" class="page-btn active" style="padding:6px 20px;">
<span id="search-spinner" class="spinner" style="display:none; width:12px; height:12px; border-width:2px; vertical-align:middle; margin-right:5px;"></span>
Search
</button>
<button type="button" class="page-btn" onclick="resetSearch()">Reset</button>
<button type="button" class="page-btn" disabled style="opacity:0.6; cursor:not-allowed;">Export Excel</button>
</td>
</tr>
</table>
</form>
<hr style="border:0; margin:20px 0;">
<table border="1" width="100%" cellpadding="3" cellspacing="1" class="data-table" id="inventoryTable">
<thead>
<tr bgcolor="#999999">
<th width="40"><input type="checkbox" id="selectAll"></th>
<th width="100">ID</th>
<th>Item Name</th>
<th width="120">Batch No</th>
<th width="80">Qty</th>
<th width="80">Weight(g)</th>
<th width="100">Inbound Date</th>
<th width="100">Status Code</th>
<th width="180">Actions</th>
</tr>
</thead>
<tbody id="tableBody">
<!-- Data will be dynamically generated by JS -->
<tr><td colspan="9" align="center" style="padding: 50px;">Loading inventory data... <div class="spinner"></div></td></tr>
</tbody>
</table>
<!-- New Pagination Component -->
<div class="pagination-container">
<div class="pagination-info">
Showing <span id="startRecord">0</span> to <span id="endRecord">0</span> of <span id="totalRecords">0</span> records
</div>
<div style="display:flex; align-items:center; gap:10px;">
<select id="pageSizeSelect" onchange="changePageSize()">
<option value="10">10/page</option>
<option value="20">20/page</option>
<option value="50">50/page</option>
<option value="100">100/page</option>
</select>
<div class="pagination-controls" id="paginationControls">
<!-- Pagination buttons generated by JS -->
</div>
</div>
</div>
<br><br>
<table border="1" width="100%" bgcolor="#eeeeee" style="border:none; border-radius:8px; overflow:hidden; background:#f1f5f9;">
<tr>
<td style="padding:20px; border:none;">
<h4 style="margin-top:0;">Batch Operation Console</h4>
<p>Selected Action:
<select id="batchActionSelect">
<option>-- Select Action --</option>
<option>Batch Export</option>
<option>Batch Delete (Admin Required)</option>
<option>Transfer Warehouse</option>
</select>
<input type="button" value="Execute" onclick="executeBatchAction()">
</p>
<p style="font-size:0.9em; color:#666;">
<label><input type="checkbox"> I have read and agree to the "Data Security Operation Standard v9.0"</label><br>
<label><input type="checkbox"> Confirm no misoperation</label>
</p>
</td>
</tr>
</table>
</td>
<td width="20%" valign="top" class="layout-cell sidebar-widgets">
<table border="1" width="100%" class="widget-table">
<tr><td bgcolor="#000000" class="widget-header"><font color="white" align="center"><b>Server Load</b></font></td></tr>
<tbody class="widget-content">
<tr><td>CPU: <div style="display:inline-block; width:50px; height:8px; background:#e2e8f0; border-radius:4px;"><div style="width:12%; height:100%; background:green; border-radius:4px;"></div></div> 12%</td></tr>
<tr><td>RAM: <div style="display:inline-block; width:50px; height:8px; background:#e2e8f0; border-radius:4px;"><div style="width:64%; height:100%; background:orange; border-radius:4px;"></div></div> 64%</td></tr>
<tr><td>DISK: <div style="display:inline-block; width:50px; height:8px; background:#e2e8f0; border-radius:4px;"><div style="width:98%; height:100%; background:red; border-radius:4px;"></div></div> <span style="color:red">98% (Warning)</span></td></tr>
</tbody>
</table>
<br>
<table border="1" width="100%" class="widget-table">
<tr><td bgcolor="#000000" class="widget-header"><font color="white"><b>To-Do List</b></font></td></tr>
<tbody class="widget-content">
<tr><td><label><input type="checkbox"> Approve Zhang San's Leave</label></td></tr>
<tr><td><label><input type="checkbox"> Order Coffee Beans</label></td></tr>
<tr><td><label><input type="checkbox"> Fix Printer</label></td></tr>
<tr><td><label><input type="checkbox"> Update Firewall</label></td></tr>
<tr><td><label><input type="checkbox"> Year-end Report Summary</label></td></tr>
</tbody>
</table>
<br>
<center>
<p style="font-size:0.8rem; color:#888;">Scan to Download App</p>
<div style="background:white; padding:10px; border-radius:8px; display:inline-block; border:1px solid #ddd;">
<table border="1" width="100" height="100" style="border:none;">
<tr><td align="center" style="border:none;">QR CODE</td></tr>
</table>
</div>
</center>
</td>
</tr>
<tr class="footer-row">
<td colspan="3" bgcolor="#333333" align="center">
<font color="#ffffff" size="2">
&copy; 2005-2025 Galactic Logistics Corp. All Rights Reserved.<br>
Address: Sector 7G, Industrial Zone, Mars Colony.<br>
<a href="#" style="color: #aaaaaa">Privacy Policy</a> |
<a href="#" style="color: #aaaaaa">Terms of Service</a> |
<a href="#" style="color: #aaaaaa">Sitemap</a> |
<a href="#" style="color: #aaaaaa">Report Abuse</a>
<br>
<span style="opacity:0.5;">Render Time: 0.04s | SQL Queries: 142 | Memory: 4MB</span>
</font>
</td>
</tr>
</table>
<!-- === Hidden Modals (HTML Structure) === -->
<!-- 1. Edit/Add Modal -->
<div class="modal-overlay" id="editModal">
<div class="modal-window">
<div class="modal-header">
<h3 class="modal-title">Edit Inventory Item</h3>
<span class="modal-close" onclick="closeModal('editModal')">&times;</span>
</div>
<div class="modal-body">
<form id="editForm">
<div class="form-group">
<label>Item ID (Read-only)</label>
<input type="text" id="edit_id" readonly style="background:#f1f5f9; color:#64748b;">
</div>
<div class="form-group">
<label>Item Name <span style="color:red">*</span></label>
<input type="text" id="edit_name" required>
<div class="hint">Please enter full component model, e.g., Resistor 0603 10k 1%</div>
</div>
<div class="form-group">
<label>Supplier</label>
<select id="edit_supplier">
<option value="Alpha Corp">Alpha Corp - Premium Supplier</option>
<option value="Beta Ltd">Beta Ltd - Long-term Partner</option>
<option value="Gamma Inc">Gamma Inc</option>
<option value="ConnWorld">ConnWorld - Connectors Only</option>
<option value="ST Micro">ST Micro - Chip Manufacturer</option>
<option value="Other">Other (Remark Required)</option>
</select>
</div>
<div class="form-group">
<div style="display:flex; gap:10px;">
<div style="flex:1;">
<label>Quantity</label>
<input type="number" id="edit_qty" min="0">
</div>
<div style="flex:1;">
<label>Unit Weight (g)</label>
<input type="number" id="edit_weight" step="0.01">
</div>
</div>
</div>
<div class="form-group">
<label>Status</label>
<select id="edit_status">
<option value="NORMAL">Normal (NORMAL)</option>
<option value="LOW">Low Stock (LOW)</option>
<option value="CRITICAL">Critical Shortage (CRITICAL)</option>
<option value="DAMAGED">Damaged (DAMAGED)</option>
<option value="PENDING">Pending (PENDING)</option>
</select>
</div>
<div class="form-group">
<label>Notes</label>
<textarea id="edit_notes" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button class="page-btn" onclick="closeModal('editModal')">Cancel</button>
<button class="page-btn active" onclick="saveEdit()">Save Changes</button>
</div>
</div>
</div>
<!-- 2. Detail Modal -->
<div class="modal-overlay" id="detailModal">
<div class="modal-window">
<div class="modal-header">
<h3 class="modal-title">Material Detail Profile</h3>
<span class="modal-close" onclick="closeModal('detailModal')">&times;</span>
</div>
<div class="modal-body">
<table width="100%" border="0" cellpadding="8" style="background:#f8fafc; border-radius:8px;">
<tr>
<td width="30%" align="right" style="color:#64748b;">Internal ID:</td>
<td width="70%"><b id="detail_id">#---</b></td>
</tr>
<tr>
<td align="right" style="color:#64748b;">Item Name:</td>
<td><span id="detail_name">---</span></td>
</tr>
<tr>
<td align="right" style="color:#64748b;">Batch No:</td>
<td><code id="detail_batch" style="background:#e2e8f0; padding:2px 4px; border-radius:3px;">---</code></td>
</tr>
<tr>
<td align="right" style="color:#64748b;">Real-time Stock:</td>
<td><span id="detail_qty">0</span> units</td>
</tr>
<tr>
<td align="right" style="color:#64748b;">Inbound Time:</td>
<td><span id="detail_date">---</span></td>
</tr>
<tr>
<td align="right" style="color:#64748b;">Lifecycle Status:</td>
<td><span id="detail_status">---</span></td>
</tr>
</table>
<div style="margin-top:20px;">
<h4 style="border-bottom:1px solid #ddd; padding-bottom:5px;">Recent Circulation Records</h4>
<ul style="font-size:0.9rem; color:#475569; padding-left:20px;" id="detail_history">
<li>No records</li>
</ul>
</div>
<div style="margin-top:20px; background:#fff7ed; padding:10px; border-left:4px solid #f97316; font-size:0.9rem;">
<strong>Note:</strong> This item is a precision component. Handle with care and store at 20-25°C.
</div>
</div>
<div class="modal-footer">
<button class="page-btn" onclick="printDetail()">Print Profile</button>
<button class="page-btn" onclick="closeModal('detailModal')">Close</button>
</div>
</div>
</div>
<!-- 3. Settings Modal -->
<div class="modal-overlay" id="settingsModal">
<div class="modal-window">
<div class="modal-header">
<h3 class="modal-title">System Preferences</h3>
<span class="modal-close" onclick="closeModal('settingsModal')">&times;</span>
</div>
<div class="modal-body">
<h4 style="border-bottom: 2px solid var(--primary); padding-bottom: 5px;">Interface Display</h4>
<div class="form-group">
<label>Theme Mode</label>
<select id="themeSelect" onchange="showToast('Theme switching is under development...', 'warning')">
<option value="light">Light (Default)</option>
<option value="dark">Dark (Dark Mode)</option>
<option value="auto">System Default</option>
</select>
</div>
<div class="form-group">
<label><input type="checkbox" checked> Enable Animations</label><br>
<label><input type="checkbox" checked> Show Real-time Clock</label><br>
<label><input type="checkbox"> Compact Table Mode</label>
</div>
<h4 style="border-bottom: 2px solid var(--primary); padding-bottom: 5px; margin-top:20px;">Data & Privacy</h4>
<div class="form-group">
<label>Auto Refresh Interval</label>
<select>
<option value="0">Off</option>
<option value="30">30 Seconds</option>
<option value="60">1 Minute</option>
<option value="300">5 Minutes</option>
</select>
</div>
<div class="form-group">
<label><input type="checkbox" checked> Allow Local Storage</label><br>
<label><input type="checkbox"> Send Anonymous Usage Statistics</label>
</div>
<h4 style="border-bottom: 2px solid var(--primary); padding-bottom: 5px; margin-top:20px;">Notification Settings</h4>
<div class="form-group">
<label><input type="checkbox" checked> Low Stock Warning</label><br>
<label><input type="checkbox" checked> Approval Notification</label><br>
<label><input type="checkbox"> Daily Report Push</label>
</div>
</div>
<div class="modal-footer">
<button class="page-btn" onclick="closeModal('settingsModal')">Cancel</button>
<button class="page-btn active" onclick="closeModal('settingsModal'); showToast('Settings saved', 'success')">Save Config</button>
</div>
</div>
</div>
<!-- 4. Help Documentation Modal (Long Text) -->
<div class="modal-overlay" id="helpModal">
<div class="modal-window" style="width:800px;">
<div class="modal-header">
<h3 class="modal-title">User Guide v4.2</h3>
<span class="modal-close" onclick="closeModal('helpModal')">&times;</span>
</div>
<div class="modal-body" style="line-height:1.8; color:#334155;">
<h3>1. System Overview</h3>
<p>This system (SYS_V4.2) aims to provide efficient and transparent internal inventory management solutions for Galactic Logistics Corp. The system integrates four core modules: material inbound, inventory monitoring, outbound approval, and report generation.</p>
<h3>2. Quick Start</h3>
<ul>
<li><strong>Login:</strong> Use the assigned ID (e.g., OPERATOR_8821) and dynamic token to log in.</li>
<li><strong>Browse Inventory:</strong> View real-time inventory status of the current warehouse on the main interface. Supports filtering by name, ID, and status.</li>
<li><strong>Edit Data:</strong> Click the [Edit] button on the right side of the table to modify inventory quantity or status.</li>
<li><strong>Export Reports:</strong> Check the required data rows and select "Batch Export" from the bottom "Batch Operation Console".</li>
</ul>
<h3>3. Status Code Explanation</h3>
<table width="100%" border="1" cellpadding="5" style="border-collapse:collapse; border-color:#e2e8f0;">
<tr bgcolor="#f1f5f9"><th>Status Code</th><th>Meaning</th><th>Action Suggestion</th></tr>
<tr><td>NORMAL</td><td>Normal Inventory</td><td>No action needed, regular stocktaking.</td></tr>
<tr><td style="color:orange">LOW</td><td>Low Inventory</td><td>It is recommended to initiate a purchase request to replenish inventory to a safe level.</td></tr>
<tr><td style="color:red">CRITICAL</td><td>Critical Shortage</td><td>Contact the supplier immediately for emergency replenishment, which may affect the production line.</td></tr>
<tr><td style="color:gray">DAMAGED</td><td>Damaged</td><td>Material is unavailable, please initiate the scrapping process and store separately.</td></tr>
<tr><td>PENDING</td><td>Pending Inspection</td><td>Material just arrived or waiting for quality inspection, temporarily frozen for outbound.</td></tr>
</table>
<h3>4. FAQ</h3>
<p><strong>Q: Why can't I find the data I just added?</strong><br>
A: Please ensure filter settings are correct. If the problem persists, try clicking "Refresh System" in the left sidebar.</p>
<p><strong>Q: Can I use this system on mobile?</strong><br>
A: Yes. The system uses a responsive design (although optimized mainly for desktop) and supports mainstream mobile browsers.</p>
<p><strong>Q: How to apply for administrator permissions?</strong><br>
A: Please fill out the "IT Permission Change Request Form" and submit it to the Sector 7G Information Center. The approval cycle is about 3 working days.</p>
<hr>
<p style="font-size:0.8rem; color:#94a3b8;">Last Updated: 2025-10-15 | Doc Version: 4.2.1-beta</p>
</div>
<div class="modal-footer">
<button class="page-btn" onclick="window.open('https://example.com/manual.pdf')">Download PDF</button>
<button class="page-btn" onclick="closeModal('helpModal')">Close</button>
</div>
</div>
</div>
<!-- 5. Damage Registration Modal -->
<div class="modal-overlay" id="reportModal">
<div class="modal-window">
<div class="modal-header">
<h3 class="modal-title">Damage Registration Form</h3>
<span class="modal-close" onclick="closeModal('reportModal')">&times;</span>
</div>
<div class="modal-body">
<p style="background:#fee2e2; padding:10px; color:#b91c1c; border-radius:4px;">
Warning: False damage reporting is a serious violation.
</p>
<form>
<div class="form-group">
<label>Related Item ID</label>
<input type="text" placeholder="Enter ID or Scan Barcode">
</div>
<div class="form-group">
<label>Damage Reason</label>
<select>
<option>Transport Damage</option>
<option>Storage Expired</option>
<option>Damp/Oxidation</option>
<option>Human Damage</option>
<option>Inventory Loss</option>
</select>
</div>
<div class="form-group">
<label>Person in Charge</label>
<input type="text" value="OPERATOR_8821 (Current User)">
</div>
<div class="form-group">
<label>On-site Photo Evidence (URL)</label>
<input type="text" placeholder="http://...">
</div>
</form>
</div>
<div class="modal-footer">
<button class="page-btn" onclick="closeModal('reportModal')">Cancel</button>
<button class="page-btn btn-danger" onclick="closeModal('reportModal'); showToast('Damage report submitted for review', 'warning')">Submit Report</button>
</div>
</div>
</div>
<!-- 6. General Confirmation Modal -->
<div class="modal-overlay" id="confirmModal">
<div class="modal-window" style="width: 400px; min-height: auto;">
<div class="modal-header">
<h3 class="modal-title">Confirmation</h3>
<span class="modal-close" onclick="closeModal('confirmModal')">&times;</span>
</div>
<div class="modal-body">
<p id="confirmMessage" style="font-size: 1rem; color: #334155;">Are you sure you want to perform this action?</p>
</div>
<div class="modal-footer">
<button class="page-btn" onclick="closeModal('confirmModal')">Cancel</button>
<button class="page-btn active" id="confirmBtnAction">Confirm</button>
</div>
</div>
</div>
<!-- 7. General Alert Modal (Alert Replacement) -->
<div class="modal-overlay" id="alertModal">
<div class="modal-window" style="width: 400px; min-height: auto;">
<div class="modal-header">
<h3 class="modal-title">System Alert</h3>
<span class="modal-close" onclick="closeModal('alertModal')">&times;</span>
</div>
<div class="modal-body">
<p id="alertMessage" style="font-size: 1rem; color: #334155; white-space: pre-line;"></p>
</div>
<div class="modal-footer">
<button class="page-btn active" onclick="closeModal('alertModal')">Got it</button>
</div>
</div>
</div>
<!-- Toast 通知容器 -->
<div class="toast-container" id="toastContainer"></div>
<script>
// === JavaScript Core Logic Refactor (SPA Pattern) ===
// --- Custom Alert Logic (Replace native alert/confirm) ---
let onConfirmCallback = null;
function showCustomAlert(msg) {
document.getElementById('alertMessage').innerText = msg;
openModal('alertModal');
}
function showCustomConfirm(msg, callback) {
document.getElementById('confirmMessage').innerText = msg;
onConfirmCallback = callback;
openModal('confirmModal');
}
// Init bind Confirm button event
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('confirmBtnAction').addEventListener('click', () => {
if (typeof onConfirmCallback === 'function') {
onConfirmCallback();
}
closeModal('confirmModal');
});
});
// Config & State
const CONFIG = {
totalItems: 358, // Mock Total Data
defaultPageSize: 10,
suppliers: ["Alpha Corp", "Beta Ltd", "Gamma Inc", "ConnWorld", "ST Micro", "Texas Inst", "NXP", "Murata"],
statuses: ["NORMAL", "LOW", "CRITICAL", "DAMAGED", "PENDING"],
components: [
"Resistor 10k 0603", "Capacitor 100nF", "Inductor 22uH", "MCU STM32F103", "Connector USB-C",
"LED Red 0805", "Diode 1N4148", "Transistor 2N2222", "Regulator 3.3V", "Crystal 16MHz",
"Battery Holder", "Fuse 500mA", "Switch Tactile", "Header 2.54mm", "PCB Stiffener"
]
};
let state = {
data: [], // All Data
filteredData: [], // Filtered Data
currentPage: 1,
pageSize: 10,
sortBy: 'id', // id, date, qty
sortDesc: false
};
// --- Navigation & Common Modals ---
// --- Search Logic ---
function handleSearch() {
const spinner = document.getElementById('search-spinner');
spinner.style.display = 'inline-block';
// Get Filters
const kw = document.getElementById('searchInput').value.toLowerCase().trim();
const typeFilter = document.getElementById('typeSelect').value;
const checkedStatuses = [];
if(document.querySelector('input[name="st_normal"]').checked) checkedStatuses.push('NORMAL');
if(document.querySelector('input[name="st_low"]').checked) checkedStatuses.push('LOW');
if(document.querySelector('input[name="st_crit"]').checked) checkedStatuses.push('CRITICAL');
// Get Sort
const sortVal = document.querySelector('input[name="sort"]:checked').value;
// Simulate Network Delay
setTimeout(() => {
state.filteredData = state.data.filter(item => {
// 1. Keyword Match (ID, Name, Supplier, Batch)
const matchKw = !kw ||
item.id.toLowerCase().includes(kw) ||
item.name.toLowerCase().includes(kw) ||
item.supplier.toLowerCase().includes(kw) ||
item.batch.toLowerCase().includes(kw);
// 2. Type Match (Simple string inclusion check)
let matchType = true;
if (typeFilter !== 'all') {
if (typeFilter === 'res') matchType = item.name.includes('Resistor');
else if (typeFilter === 'cap') matchType = item.name.includes('Capacitor');
else if (typeFilter === 'ind') matchType = item.name.includes('Inductor');
else if (typeFilter === 'chip') matchType = item.name.includes('MCU') || item.name.includes('Regulator') || item.name.includes('Transistor') || item.name.includes('Diode');
else if (typeFilter === 'conn') matchType = item.name.includes('Connector') || item.name.includes('Header');
else if (typeFilter === 'other') matchType = !item.name.includes('Resist') && !item.name.includes('Capacit') && !item.name.includes('Induct') && !item.name.includes('Connect');
}
// 3. Status Match
// Logic: show if item.status is in checkedStatuses
// Special handling: CRITICAL check includes DAMAGED too (assumption)
let matchStatus = false;
if (checkedStatuses.length === 0) matchStatus = true;
if (checkedStatuses.includes(item.status)) matchStatus = true;
if (checkedStatuses.includes('CRITICAL') && item.status === 'DAMAGED') matchStatus = true;
return matchKw && matchType && matchStatus;
});
// Sorting
if (sortVal === 'id') {
state.filteredData.sort((a,b) => a.id.localeCompare(b.id));
} else if (sortVal === 'qty') {
state.filteredData.sort((a,b) => b.qty - a.qty);
} else if (sortVal === 'date') {
state.filteredData.sort((a,b) => new Date(b.date) - new Date(a.date));
}
state.currentPage = 1;
renderTable();
spinner.style.display = 'none';
showToast(`Search complete, found ${state.filteredData.length} records`, 'success');
}, 400);
}
function resetSearch() {
document.getElementById('searchInput').value = '';
document.getElementById('typeSelect').value = 'all';
document.querySelectorAll('input[type="checkbox"]').forEach(c => c.checked = true);
document.querySelector('input[value="date"]').checked = true;
handleSearch();
}
function openModal(id) {
const modal = document.getElementById(id);
if (modal) {
modal.style.display = 'flex';
modal.offsetHeight; // force reflow
modal.classList.add('show');
}
}
function openHelp() {
openModal('helpModal');
}
// Sidebar Category Filter Simulation
function filterCategory(category) {
// Reset all selection states
document.querySelectorAll('#sidebarList a').forEach(a => {
a.style.color = '';
a.style.backgroundColor = '';
});
showToast(`Switching to view: ${category}`, 'info');
// Mock Data Filter Logic
if (category === 'all') {
state.filteredData = [...state.data];
document.querySelector('.main-content h2').innerText = 'Inventory List - All';
} else if (category === 'urgent') {
document.querySelector('.main-content h2').innerText = 'Inventory List - Urgent';
state.filteredData = state.data.filter(d => d.status === 'CRITICAL' || d.status === 'LOW');
} else if (category === 'normal') {
document.querySelector('.main-content h2').innerText = 'Inventory List - Normal';
state.filteredData = state.data.filter(d => d.status === 'NORMAL');
} else if (category === 'out_a') {
document.querySelector('.main-content h2').innerText = 'Outbound Approval - Zone A';
// Mock random
state.filteredData = state.data.filter(d => d.id.endsWith('1') || d.id.endsWith('3'));
} else if (category === 'out_b') {
document.querySelector('.main-content h2').innerText = 'Outbound Approval - Zone B';
state.filteredData = state.data.filter(d => d.id.endsWith('2') || d.id.endsWith('4'));
}
// Reset Pagination
state.currentPage = 1;
renderTable();
}
// --- 1. Data Generator (Simulate Backend) ---
function generateMockData() {
console.time("DataGeneration");
const data = [];
for (let i = 1; i <= CONFIG.totalItems; i++) {
const padId = String(i).padStart(4, '0');
const typeIdx = Math.floor(Math.random() * CONFIG.components.length);
const supplIdx = Math.floor(Math.random() * CONFIG.suppliers.length);
const statusIdx = Math.random() > 0.8 ? (Math.random() > 0.5 ? 2 : 1) : 0; // Mostly Normal
// Random Date (Past 2 Years)
const date = new Date(Date.now() - Math.floor(Math.random() * 63072000000));
const batchYear = date.getFullYear();
const batchCode = `BATCH_${batchYear}_${String.fromCharCode(65 + Math.floor(Math.random() * 26))}${Math.floor(Math.random()*100)}`;
data.push({
id: `8821${padId}`,
name: CONFIG.components[typeIdx],
supplier: CONFIG.suppliers[supplIdx],
batch: batchCode,
qty: Math.floor(Math.random() * 10000),
weight: (Math.random() * 10).toFixed(2),
date: date.toISOString().split('T')[0],
status: CONFIG.statuses[statusIdx],
notes: "Automatically generated mock data record..."
});
}
console.timeEnd("DataGeneration");
return data;
}
// --- 2. Core Render Logic ---
function init() {
showToast("System initializing...", "info");
state.data = generateMockData();
applyFilter(); // Initial Filter (All)
console.log(`Loaded ${state.data.length} records.`);
// Bind Events
document.getElementById('editForm').addEventListener('submit', (e) => { e.preventDefault(); saveEdit(); });
}
// Filter & Sort
function applyFilter() {
// Simple Mock: Get search box value (Simplified here)
state.filteredData = [...state.data];
// Sort
state.filteredData.sort((a, b) => {
let valA = a[state.sortBy];
let valB = b[state.sortBy];
if (state.sortBy === 'qty' || state.sortBy === 'weight') {
valA = parseFloat(valA);
valB = parseFloat(valB);
}
if (valA < valB) return state.sortDesc ? 1 : -1;
if (valA > valB) return state.sortDesc ? -1 : 1;
return 0;
});
state.currentPage = 1;
renderTable();
}
function renderTable() {
const tbody = document.getElementById('tableBody');
tbody.innerHTML = ''; // Clear
const start = (state.currentPage - 1) * state.pageSize;
const end = Math.min(start + state.pageSize, state.filteredData.length);
const pageData = state.filteredData.slice(start, end);
if (pageData.length === 0) {
tbody.innerHTML = '<tr><td colspan="9" align="center" style="padding:20px;">No matching data found</td></tr>';
return;
}
pageData.forEach(item => {
const tr = document.createElement('tr');
tr.className = 'data-row';
// Status Style
let statusColor = 'green';
if (item.status === 'LOW') statusColor = 'orange';
if (item.status === 'CRITICAL' || item.status === 'DAMAGED') statusColor = 'red';
tr.innerHTML = `
<td align="center"><input type="checkbox" class="row-check" value="${item.id}"></td>
<td><font face="monospace">#${item.id}</font></td>
<td>
<strong>${item.name}</strong><br>
<small style="color:#666">Supplier: ${item.supplier}</small>
</td>
<td><code style="background:#f1f5f9; padding:2px;">${item.batch}</code></td>
<td>${item.qty.toLocaleString()}</td>
<td>${item.weight}g</td>
<td>${item.date}</td>
<td><span style="color:${statusColor}; font-weight:bold; font-size:0.85rem;">${item.status}</span></td>
<td class="action-group">
<a href="javascript:void(0)" class="btn-view" onclick="openDetail('${item.id}')">[Detail]</a>
<a href="javascript:void(0)" class="btn-edit" onclick="openEdit('${item.id}')">[Edit]</a>
<a href="javascript:void(0)" class="btn-danger" onclick="deleteItem('${item.id}', this)">[Del]</a>
</td>
`;
tbody.appendChild(tr);
});
renderPagination(start, end, state.filteredData.length);
}
function renderPagination(start, end, total) {
document.getElementById('startRecord').innerText = total === 0 ? 0 : start + 1;
document.getElementById('endRecord').innerText = end;
document.getElementById('totalRecords').innerText = total;
const controls = document.getElementById('paginationControls');
controls.innerHTML = '';
const totalPages = Math.ceil(total / state.pageSize);
// Simple Pagination Algorithm
const createBtn = (text, page, active = false, disabled = false) => {
const btn = document.createElement('button');
btn.className = `page-btn ${active ? 'active' : ''}`;
btn.innerText = text;
btn.disabled = disabled;
if (!disabled) btn.onclick = () => { state.currentPage = page; renderTable(); };
return btn;
};
controls.appendChild(createBtn('<<', 1, false, state.currentPage === 1));
controls.appendChild(createBtn('<', state.currentPage - 1, false, state.currentPage === 1));
// Show nearby pages
let pStart = Math.max(1, state.currentPage - 2);
let pEnd = Math.min(totalPages, state.currentPage + 2);
for (let p = pStart; p <= pEnd; p++) {
controls.appendChild(createBtn(p, p, p === state.currentPage));
}
controls.appendChild(createBtn('>', state.currentPage + 1, false, state.currentPage === totalPages));
controls.appendChild(createBtn('>>', totalPages, false, state.currentPage === totalPages));
}
// --- 3. Interaction Logic ---
// Change Page Size
function changePageSize() {
const select = document.getElementById('pageSizeSelect');
state.pageSize = parseInt(select.value);
state.currentPage = 1;
renderTable();
showToast(`Showing ${state.pageSize} items per page`, "info");
}
// Modal Control
function closeModal(result) {
const modal = document.getElementById(result); // result is ID
modal.classList.remove('show');
setTimeout(() => { modal.style.display = 'none'; }, 300);
}
// Open Edit Modal
function openEdit(id) {
const item = state.data.find(d => d.id === id);
if (!item) return;
// Fill Form
document.getElementById('edit_id').value = item.id;
document.getElementById('edit_name').value = item.name;
document.getElementById('edit_supplier').value = item.supplier;
document.getElementById('edit_qty').value = item.qty;
document.getElementById('edit_weight').value = item.weight;
document.getElementById('edit_status').value = item.status;
document.getElementById('edit_notes').value = item.notes || "";
const modal = document.getElementById('editModal');
modal.style.display = 'flex';
// Force Reflow
modal.offsetHeight;
modal.classList.add('show');
}
function saveEdit() {
const id = document.getElementById('edit_id').value;
const newName = document.getElementById('edit_name').value;
const newQty = parseInt(document.getElementById('edit_qty').value);
// Update Local Data
const idx = state.data.findIndex(d => d.id === id);
if (idx !== -1) {
state.data[idx].name = newName;
state.data[idx].qty = newQty;
state.data[idx].supplier = document.getElementById('edit_supplier').value;
state.data[idx].status = document.getElementById('edit_status').value;
state.data[idx].weight = document.getElementById('edit_weight').value;
// Note: Updated filteredData reference
}
closeModal('editModal');
showToast("Saved successfully! Data updated.", "success");
renderTable(); // Re-render
}
// Open Detail Modal
function openDetail(id) {
const item = state.data.find(d => d.id === id);
if(!item) return;
document.getElementById('detail_id').innerText = item.id;
document.getElementById('detail_name').innerText = item.name;
document.getElementById('detail_batch').innerText = item.batch;
document.getElementById('detail_qty').innerText = item.qty.toLocaleString();
document.getElementById('detail_date').innerText = item.date;
document.getElementById('detail_status').innerText = item.status;
// Mock History
const historyList = document.getElementById('detail_history');
historyList.innerHTML = '';
for(let i=0; i<3; i++) {
historyList.innerHTML += `<li>${new Date().toLocaleDateString()} - System automatically approved (Audit Log #${Math.floor(Math.random()*9000)})</li>`;
}
const modal = document.getElementById('detailModal');
modal.style.display = 'flex';
modal.offsetHeight;
modal.classList.add('show');
}
function printDetail() {
showCustomAlert("Connecting to printer... \n(Simulate: Sending command PCL_PRINT_JOB_001)");
}
// Delete Item
function deleteItem(id, btnElement) {
showCustomConfirm(`Are you sure you want to delete item ${id}?`, () => {
// Mock frontend delete
state.data = state.data.filter(d => d.id !== id);
applyFilter(); // Re-filter and sort
showToast(`Item ${id} has been deleted`, "warning");
});
}
// Batch Action
function executeBatchAction() {
const select = document.getElementById('batchActionSelect');
const action = select.value;
const checks = document.querySelectorAll('.row-check:checked');
if (checks.length === 0) {
showToast("Please select at least one item!", "error");
return;
}
if (select.selectedIndex === 0) {
showToast("Please select a valid action type", "warning");
} else {
// Mock Progress
showToast(`Processing ${checks.length} items: ${action}...`, "info");
setTimeout(() => {
showToast("Batch operation completed!", "success");
// Uncheck all
checks.forEach(c => c.checked = false);
document.getElementById('selectAll').checked = false;
}, 1500);
}
}
// Toast Tool
function showToast(message, type = 'info') {
const container = document.getElementById('toastContainer');
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
let icon = '';
if (type === 'success') icon = '✅';
if (type === 'error') icon = '❌';
if (type === 'warning') icon = '⚠️';
toast.innerHTML = `
<div style="display:flex; align-items:center; gap:10px;">
<span style="font-size:1.2rem;">${icon}</span>
<span>${message}</span>
</div>
<span style="cursor:pointer; opacity:0.5;" onclick="this.parentElement.remove()">&times;</span>
`;
container.appendChild(toast);
// Animation
requestAnimationFrame(() => toast.classList.add('show'));
// Auto Dismiss
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 3000);
}
// Select All
document.getElementById('selectAll').addEventListener('change', function(e) {
const isChecked = e.target.checked;
document.querySelectorAll('.row-check').forEach(cb => cb.checked = isChecked);
});
// Start
window.onload = init;
</script>
</body>
</html>