483 lines
15 KiB
HTML
483 lines
15 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>立库可视化功能截图预览</title>
|
||
<style>
|
||
* { box-sizing: border-box; }
|
||
body {
|
||
margin: 0;
|
||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||
background: #eef2f7;
|
||
color: #303133;
|
||
}
|
||
.app-container { padding: 20px; }
|
||
.card {
|
||
height: 850px;
|
||
background: #fff;
|
||
border: 1px solid #e4e7ed;
|
||
box-shadow: 0 2px 12px rgba(0,0,0,.06);
|
||
}
|
||
.tab {
|
||
height: 44px;
|
||
border-bottom: 1px solid #dcdfe6;
|
||
background: #f5f7fa;
|
||
display: flex;
|
||
align-items: end;
|
||
padding-left: 0;
|
||
}
|
||
.tab span {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
height: 44px;
|
||
padding: 0 22px;
|
||
background: #fff;
|
||
border-right: 1px solid #dcdfe6;
|
||
border-top: 2px solid #409eff;
|
||
font-size: 14px;
|
||
color: #409eff;
|
||
}
|
||
.toolbar {
|
||
margin: 7px 0;
|
||
padding: 0 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
height: 42px;
|
||
}
|
||
.toolbar label { font-size: 13px; color: #000; }
|
||
.select, .button, .switch {
|
||
height: 32px;
|
||
border-radius: 4px;
|
||
font-size: 13px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
}
|
||
.select {
|
||
width: 120px;
|
||
border: 1px solid #dcdfe6;
|
||
padding: 0 10px;
|
||
justify-content: space-between;
|
||
color: #606266;
|
||
background: #fff;
|
||
}
|
||
.select::after { content: "⌄"; color: #909399; }
|
||
.button {
|
||
border: 1px solid transparent;
|
||
padding: 0 12px;
|
||
color: #fff;
|
||
gap: 4px;
|
||
}
|
||
.primary { background: #409eff; }
|
||
.default { background: #fff; color: #606266; border-color: #dcdfe6; }
|
||
.success { background: #67c23a; }
|
||
.switch {
|
||
margin-left: 10px;
|
||
gap: 8px;
|
||
color: #606266;
|
||
}
|
||
.switch-track {
|
||
width: 42px;
|
||
height: 22px;
|
||
border-radius: 12px;
|
||
background: #409eff;
|
||
position: relative;
|
||
}
|
||
.switch-track::after {
|
||
content: "";
|
||
position: absolute;
|
||
right: 2px;
|
||
top: 2px;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 50%;
|
||
background: #fff;
|
||
}
|
||
.stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(6, 1fr);
|
||
gap: 10px;
|
||
margin: 10px 12px;
|
||
}
|
||
.stat {
|
||
border: 1px solid #ebeef5;
|
||
border-radius: 4px;
|
||
text-align: center;
|
||
padding: 10px 0;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,.04);
|
||
}
|
||
.stat .label { color: #909399; font-size: 12px; }
|
||
.stat .value { font-size: 20px; font-weight: bold; margin-top: 4px; }
|
||
.legend {
|
||
margin-bottom: 15px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 20px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.legend-item {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 12px;
|
||
}
|
||
.legend-color {
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 4px;
|
||
border: 1px solid #ddd;
|
||
margin-right: 5px;
|
||
}
|
||
.warehouse-area {
|
||
height: 600px;
|
||
overflow: auto;
|
||
border: 1px solid #e4e7ed;
|
||
border-radius: 4px;
|
||
margin: 0 12px;
|
||
padding: 15px;
|
||
background: #f5f7fa;
|
||
}
|
||
.warehouse-group {
|
||
margin-bottom: 30px;
|
||
padding: 15px;
|
||
background: white;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,.1);
|
||
}
|
||
.group-title {
|
||
text-align: center;
|
||
margin-bottom: 10px;
|
||
color: #303133;
|
||
font-weight: bold;
|
||
background: #e8f4fd;
|
||
padding: 5px;
|
||
border-radius: 4px;
|
||
}
|
||
table {
|
||
width: 100%;
|
||
min-width: 1200px;
|
||
border-collapse: collapse;
|
||
margin: 0 auto;
|
||
table-layout: fixed;
|
||
}
|
||
th, td {
|
||
border: 1px solid #e4e7ed;
|
||
text-align: center;
|
||
height: 40px;
|
||
min-width: 40px;
|
||
font-size: 12px;
|
||
position: relative;
|
||
}
|
||
th {
|
||
background: #f5f7fa;
|
||
font-weight: bold;
|
||
color: #303133;
|
||
}
|
||
.row-layer-header, .row-layer-cell {
|
||
width: 80px;
|
||
min-width: 80px;
|
||
background: #e8f4fd;
|
||
color: #2196f3;
|
||
font-weight: bold;
|
||
}
|
||
.row-layer-cell { background: #f5f7fa; color: #303133; }
|
||
.highlight-row .row-layer-cell {
|
||
background: #bbdefb;
|
||
color: #1976d2;
|
||
}
|
||
.highlight-col { background: #bbdefb; color: #1976d2; }
|
||
.cell {
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
transition: all .2s;
|
||
}
|
||
.cell:hover {
|
||
transform: scale(1.08);
|
||
z-index: 2;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,.2);
|
||
}
|
||
.status-2 { background: #4caf50; color: #fff; }
|
||
.status-1 { background: #ff9800; color: #fff; }
|
||
.status-0 { background: #e0e0e0; color: #666; }
|
||
.status-9 { background: skyblue; color: #fff; }
|
||
.selected {
|
||
box-shadow: 0 0 0 2px #2196f3 inset;
|
||
outline: 2px solid #2196f3;
|
||
outline-offset: -2px;
|
||
}
|
||
.tooltip {
|
||
position: absolute;
|
||
bottom: calc(100% + 6px);
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: rgba(0,0,0,.82);
|
||
color: white;
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
white-space: nowrap;
|
||
z-index: 4;
|
||
font-weight: normal;
|
||
}
|
||
.pagination {
|
||
text-align: center;
|
||
margin-top: 10px;
|
||
color: #606266;
|
||
font-size: 13px;
|
||
}
|
||
.page-box {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
border: 1px solid #ebeef5;
|
||
padding: 6px 10px;
|
||
border-radius: 4px;
|
||
background: #fff;
|
||
}
|
||
.page-num {
|
||
min-width: 28px;
|
||
height: 28px;
|
||
border-radius: 3px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.page-current { background: #409eff; color: #fff; }
|
||
.modal-backdrop {
|
||
display: none;
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0,0,0,.2);
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 10;
|
||
}
|
||
body.show-detail #detailModal,
|
||
body.show-material #materialModal { display: flex; }
|
||
.dialog {
|
||
background: #fff;
|
||
border-radius: 2px;
|
||
box-shadow: 0 4px 18px rgba(0,0,0,.18);
|
||
overflow: hidden;
|
||
}
|
||
.detail-dialog { width: 500px; }
|
||
.material-dialog { width: 941px; }
|
||
.dialog-title {
|
||
height: 54px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 18px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
.dialog-body { padding: 20px; }
|
||
.detail-box {
|
||
padding: 10px;
|
||
background: #f5f7fa;
|
||
border-radius: 4px;
|
||
line-height: 1.7;
|
||
}
|
||
.dialog-footer {
|
||
border-top: 1px solid #ebeef5;
|
||
padding: 10px 20px;
|
||
text-align: right;
|
||
}
|
||
.close-button {
|
||
height: 32px;
|
||
padding: 0 15px;
|
||
border: 1px solid #dcdfe6;
|
||
background: #fff;
|
||
border-radius: 4px;
|
||
color: #606266;
|
||
}
|
||
.material-table {
|
||
min-width: 0;
|
||
table-layout: auto;
|
||
font-size: 13px;
|
||
}
|
||
.material-table th {
|
||
color: #606266;
|
||
height: 38px;
|
||
background: #f5f7fa;
|
||
}
|
||
.material-table td { height: 46px; }
|
||
.qty { color: #67c23a; font-weight: bold; }
|
||
.lockqty { color: #e6a23c; font-weight: bold; }
|
||
.unit { font-size: 10px; color: #909399; }
|
||
.mode-icon .cell { font-size: 18px; }
|
||
.mode-icon .text-symbol { display: none; }
|
||
.mode-icon .icon-symbol { display: inline; }
|
||
.icon-symbol { display: none; }
|
||
.callout {
|
||
position: absolute;
|
||
right: 30px;
|
||
top: 105px;
|
||
background: #fffbe6;
|
||
border: 1px solid #ffe58f;
|
||
color: #6b4c00;
|
||
padding: 8px 12px;
|
||
border-radius: 4px;
|
||
font-size: 13px;
|
||
z-index: 5;
|
||
display: none;
|
||
}
|
||
body.show-filter-tip .callout { display: block; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<div class="card">
|
||
<div class="tab"><span>立库可视化</span></div>
|
||
<div class="toolbar">
|
||
<label>库位筛选</label>
|
||
<div class="select" id="aisleSelect">第一巷道</div>
|
||
<div class="select" id="rowSelect">03-01</div>
|
||
<div class="button primary">🔍 搜索</div>
|
||
<div class="button default">↻ 重置</div>
|
||
<div class="button success">⟲ 刷新数据</div>
|
||
<div class="switch"><span id="modeText">显示文字</span><span class="switch-track"></span></div>
|
||
</div>
|
||
<div class="callout">筛选区支持按巷道重新取数、按行-层收窄视图,并可切换文字/图标显示模式。</div>
|
||
<div class="stats">
|
||
<div class="stat"><div class="label">总库位数</div><div class="value">384</div></div>
|
||
<div class="stat"><div class="label">有物料有托盘</div><div class="value" style="color:#4caf50">138</div></div>
|
||
<div class="stat"><div class="label">有托盘无物料</div><div class="value" style="color:#ff9800">76</div></div>
|
||
<div class="stat"><div class="label">空闲库位</div><div class="value" style="color:#9e9e9e">154</div></div>
|
||
<div class="stat"><div class="label">使用率</div><div class="value" style="color:#2196f3">55.7%</div></div>
|
||
<div class="stat"><div class="label">数据行数</div><div class="value" style="color:#9c27b0">8</div></div>
|
||
</div>
|
||
<div class="legend">
|
||
<div class="legend-item"><div class="legend-color" style="background:#4caf50"></div>有物料有托盘 (物)</div>
|
||
<div class="legend-item"><div class="legend-color" style="background:#ff9800"></div>有托盘无物料 (盘)</div>
|
||
<div class="legend-item"><div class="legend-color" style="background:#e0e0e0"></div>空库位 (空)</div>
|
||
<div class="legend-item"><div class="legend-color" style="background:#bbdefb;border:2px solid #2196f3"></div>选中库位</div>
|
||
</div>
|
||
<div class="warehouse-area">
|
||
<div class="warehouse-group">
|
||
<div class="group-title">立库组</div>
|
||
<table id="warehouseTable">
|
||
<thead>
|
||
<tr id="headRow"><th class="row-layer-header">行-层</th></tr>
|
||
</thead>
|
||
<tbody id="tableBody"></tbody>
|
||
</table>
|
||
</div>
|
||
<div style="text-align:center;margin-top:20px;color:#909399;font-size:12px">显示 8 行数据</div>
|
||
</div>
|
||
<div class="pagination">
|
||
<div class="page-box">
|
||
<span>共 8 条</span>
|
||
<span>8条/页</span>
|
||
<span>‹</span>
|
||
<span class="page-num page-current">1</span>
|
||
<span>›</span>
|
||
<span>前往 1 页</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-backdrop" id="detailModal">
|
||
<div class="dialog detail-dialog">
|
||
<div class="dialog-title">库位详情 03-08-01</div>
|
||
<div class="dialog-body">
|
||
<div class="detail-box">有托盘但无物料,需补充物料。当前库位已被识别为托盘占用状态,适合仓储人员核对托盘与物料绑定情况。</div>
|
||
</div>
|
||
<div class="dialog-footer"><button class="close-button">关闭</button></div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-backdrop" id="materialModal">
|
||
<div class="dialog material-dialog">
|
||
<div class="dialog-title">库位信息 03-12-01</div>
|
||
<div class="dialog-body">
|
||
<table class="material-table">
|
||
<thead>
|
||
<tr>
|
||
<th>物料编号</th>
|
||
<th>物料名称</th>
|
||
<th>图号</th>
|
||
<th>型号</th>
|
||
<th>库存数量</th>
|
||
<th>锁定库存</th>
|
||
<th>批次</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>02.009.001.0012</td>
|
||
<td>直线导轨组件</td>
|
||
<td>LRS3056-0312-01</td>
|
||
<td>HGW25CA</td>
|
||
<td><div class="qty">14.000</div><div class="unit">台</div></td>
|
||
<td><div class="lockqty">2.000</div><div class="unit">台</div></td>
|
||
<td>BATCH031201</td>
|
||
</tr>
|
||
<tr>
|
||
<td>02.009.001.0013</td>
|
||
<td>滑块组件</td>
|
||
<td>LRS3056-0312-02</td>
|
||
<td>HGW25CC</td>
|
||
<td><div class="qty">6.000</div><div class="unit">台</div></td>
|
||
<td><div style="color:#909399">0.000</div><div class="unit">台</div></td>
|
||
<td>BATCH031202</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="dialog-footer"><button class="close-button">关闭</button></div>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
const columns = 48;
|
||
const rows = ['04-04','04-03','04-02','04-01','03-04','03-03','03-02','03-01'];
|
||
const statuses = [2,0,1,2,0,0,2,1,0,2,1,2,0,9,2,0,1,0,2,2,0,1,0,2,0,0,1,2,0,2,0,1,2,0,0,9,2,1,0,2,0,1,2,0,0,2,1,0];
|
||
const head = document.getElementById('headRow');
|
||
for (let c = 1; c <= columns; c++) {
|
||
const th = document.createElement('th');
|
||
th.textContent = c;
|
||
if (c === 12) th.className = 'highlight-col';
|
||
head.appendChild(th);
|
||
}
|
||
const tbody = document.getElementById('tableBody');
|
||
rows.forEach((row, rIndex) => {
|
||
const tr = document.createElement('tr');
|
||
if (row === '03-01') tr.className = 'highlight-row';
|
||
const rowCell = document.createElement('td');
|
||
rowCell.className = 'row-layer-cell';
|
||
rowCell.textContent = row;
|
||
tr.appendChild(rowCell);
|
||
for (let c = 1; c <= columns; c++) {
|
||
const status = statuses[(c + rIndex * 5) % statuses.length];
|
||
const td = document.createElement('td');
|
||
td.className = 'cell status-' + status;
|
||
if (row === '03-01' && c === 12) td.className += ' selected';
|
||
const text = status === 2 ? '物' : status === 1 ? '盘' : status === 9 ? '锁' : '空';
|
||
const icon = status === 2 ? '▣' : status === 1 ? '▤' : status === 9 ? '🔒' : '-';
|
||
td.innerHTML = '<span class="text-symbol">' + text + '</span><span class="icon-symbol">' + icon + '</span>';
|
||
if (row === '03-01' && c === 12) {
|
||
const tip = document.createElement('span');
|
||
tip.className = 'tooltip';
|
||
tip.textContent = '有物料有托盘';
|
||
td.appendChild(tip);
|
||
}
|
||
tr.appendChild(td);
|
||
}
|
||
tbody.appendChild(tr);
|
||
});
|
||
const params = new URLSearchParams(location.search);
|
||
const shot = params.get('shot');
|
||
if (shot === 'filter') {
|
||
document.body.classList.add('show-filter-tip');
|
||
document.body.classList.add('mode-icon');
|
||
document.getElementById('modeText').textContent = '显示图标';
|
||
document.getElementById('aisleSelect').textContent = '第三巷道';
|
||
document.getElementById('rowSelect').textContent = '03-01';
|
||
}
|
||
if (shot === 'detail') document.body.classList.add('show-detail');
|
||
if (shot === 'material') document.body.classList.add('show-material');
|
||
</script>
|
||
</body>
|
||
</html>
|