Project

General

Profile

Feature #140 » 設備歷程查詢_0716.html

鎮源 游, 07/16/2026 03:45 AM

 
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>設備歷程查詢系統</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
:root {
--primary-blue: #2563eb;
--primary-hover: #1d4ed8;
--success-green: #10b981;
--success-hover: #059669;
--orange-warning: #f59e0b;
--bg-gray: #f8fafc;
--border-color: #e2e8f0;
--text-dark: #1e293b;
--text-muted: #64748b;
--accent-bg: #eff6ff;
--danger-red: #ef4444;
}

* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

body {
background-color: var(--bg-gray);
color: var(--text-dark);
padding: 40px 20px;
}

.container {
max-width: 1400px;
margin: 0 auto;
}

.header {
margin-bottom: 24px;
border-bottom: 4px solid #dbeafe;
padding-bottom: 16px;
}

.header h1 {
font-size: 28px;
color: var(--text-dark);
display: flex;
align-items: center;
gap: 10px;
}

/* 篩選面板 */
.filter-card {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
border: 1px solid var(--border-color);
margin-bottom: 24px;
}

.filter-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 16px;
}

.form-group {
display: flex;
flex-direction: column;
gap: 6px;
}

.form-group label {
font-size: 14px;
font-weight: 600;
color: var(--text-dark);
}

.form-control {
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}

.form-control:focus {
border-color: var(--primary-blue);
}

.btn-group {
display: flex;
justify-content: flex-end;
gap: 12px;
}

.btn {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
transition: background-color 0.2s;
}

.btn-primary {
background-color: var(--primary-blue);
color: white;
}

.btn-primary:hover {
background-color: var(--primary-hover);
}

.btn-success {
background-color: var(--success-green);
color: white;
}

.btn-success:hover {
background-color: var(--success-hover);
}

.btn-action {
padding: 4px 10px;
background-color: #f1f5f9;
border: 1px solid var(--border-color);
color: var(--primary-blue);
font-size: 12px;
font-weight: 600;
border-radius: 4px;
cursor: pointer;
transition: all 0.15s;
}

.btn-action:hover {
background-color: var(--primary-blue);
color: white;
border-color: var(--primary-blue);
}

/* 資料表格 */
.table-card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
border: 1px solid var(--border-color);
overflow: hidden;
}

table {
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 14px;
}

th {
background-color: #f1f5f9;
color: var(--text-dark);
font-weight: 600;
padding: 12px 16px;
border-bottom: 1px solid var(--border-color);
}

td {
padding: 14px 16px;
border-bottom: 1px solid var(--border-color);
color: var(--text-dark);
}

tr:hover {
background-color: #f8fafc;
}

.badge {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 700;
display: inline-block;
}

.badge-green { background-color: #dcfce7; color: #16a34a; border: 1px solid #bbf7d0; } /* 運轉中/生產 */
.badge-blue { background-color: #dbeafe; color: #2563eb; border: 1px solid #bfdbfe; } /* 待機 */
.badge-orange { background-color: #fef3c7; color: #d97706; border: 1px solid #fde68a; } /* 維護中/故障 */

.text-null {
color: #94a3b8;
font-style: italic;
}

/* 彈出視窗 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;
}

.modal-content {
background: white;
border-radius: 12px;
width: 90%;
max-width: 850px;
padding: 24px;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
max-height: 90vh;
overflow-y: auto;
}

.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
border-bottom: 2px solid var(--primary-blue);
padding-bottom: 12px;
}

.modal-title {
font-size: 20px;
font-weight: 700;
color: var(--text-dark);
}

.close-modal {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: var(--text-muted);
}

.modal-section-title {
font-size: 15px;
font-weight: 700;
color: #1e293b;
margin: 20px 0 10px 0;
padding-left: 8px;
border-left: 4px solid var(--primary-blue);
background-color: #f8fafc;
padding-top: 4px;
padding-bottom: 4px;
}

/* 上半部資訊網格 (移除設備類型) */
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
background: #fff;
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 16px;
}

.info-grid-full {
grid-column: span 2;
}

.info-item {
display: flex;
align-items: center;
font-size: 14px;
}

.info-label {
width: 110px;
font-weight: 600;
color: var(--text-muted);
}

.info-value {
flex: 1;
color: var(--text-dark);
}

/* 下半部檢驗表單表格 */
.detail-table {
width: 100%;
border-collapse: collapse;
margin-top: 8px;
font-size: 13px;
}

.detail-table th {
background-color: #f1f5f9;
font-weight: 600;
padding: 10px 12px;
border: 1px solid var(--border-color);
}

.detail-table td {
padding: 10px 12px;
border: 1px solid var(--border-color);
}

.text-pass {
color: var(--success-green);
font-weight: bold;
}

.text-ng {
color: var(--danger-red);
font-weight: bold;
}

.form-meta-block {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 13px;
background: #f0f7ff;
padding: 8px 12px;
border-radius: 6px;
margin-bottom: 8px;
border: 1px solid #d0e7ff;
}
</style>
</head>
<body>

<div class="container">
<div class="header">
<h1><i class="fas fa-desktop text-blue-600"></i> 設備歷程查詢系統</h1>
</div>

<div class="filter-card">
<div class="filter-grid">
<div class="form-group">
<label for="eqSearch">設備編號/名稱</label>
<input type="text" id="eqSearch" class="form-control" placeholder="輸入關鍵字搜尋設備...">
</div>
<div class="form-group">
<label for="eqType">設備類型</label>
<select id="eqType" class="form-control">
<option value="ALL">全部類型</option>
<option value="模具生產設備">模具生產設備</option>
<option value="表面處理設備">表面處理設備</option>
<option value="自動化組裝線">自動化組裝線</option>
</select>
</div>
<div class="form-group">
<label for="operator">操作人員</label>
<input type="text" id="operator" class="form-control" placeholder="輸入人員姓名...">
</div>
</div>
<div class="btn-group">
<button class="btn btn-primary" onclick="filterHistory()"><i class="fas fa-search"></i> 查詢</button>
<button class="btn btn-success" onclick="exportToCSV()"><i class="fas fa-file-excel"></i> 匯出 CSV</button>
</div>
</div>

<div class="table-card">
<table>
<thead>
<tr>
<th>異動時間</th>
<th>設備編號</th>
<th>設備名稱</th>
<th>設備類型</th>
<th>變更前狀態</th>
<th>變更後狀態</th>
<th>模具</th>
<th>操作人員</th>
<th style="text-align: center; width: 80px;">操作</th>
</tr>
</thead>
<tbody id="history-table-body">
</tbody>
</table>
</div>
</div>

<div class="modal-overlay" id="detailModal">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title"><i class="far fa-list-alt text-blue-600"></i> 設備狀態變更詳細資訊</div>
<button class="close-modal" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<div class="modal-section-title">基本與狀態變更資訊</div>
<div class="info-grid">
<div class="info-item">
<div class="info-label">設備編號</div>
<div class="info-value" id="m-eq-id" style="font-weight: bold; color: var(--primary-blue);">-</div>
</div>
<div class="info-item">
<div class="info-label">設備名稱</div>
<div class="info-value" id="m-eq-name">-</div>
</div>
<div class="info-item">
<div class="info-label">線別</div>
<div class="info-value" id="m-line" style="font-weight: 500; color: #0f172a;">-</div>
</div>
<div class="info-item">
<div class="info-label">區域</div>
<div class="info-value" id="m-area" style="font-weight: 500; color: #0f172a;">-</div>
</div>
<div class="info-item">
<div class="info-label">變更前狀態</div>
<div class="info-value" id="m-status-before">-</div>
</div>
<div class="info-item">
<div class="info-label">變更後狀態</div>
<div class="info-value" id="m-status-after">-</div>
</div>
<div class="info-item">
<div class="info-label">操作人員</div>
<div class="info-value" id="m-user">-</div>
</div>
<div class="info-item">
</div>
<div class="info-item info-grid-full" style="align-items: flex-start;">
<div class="info-label">狀況描述/備註</div>
<div class="info-value" id="m-desc" style="background: #f8fafc; padding: 6px 10px; border-radius: 4px; border: 1px solid var(--border-color); color: var(--text-dark); min-height: 40px;">-</div>
</div>
</div>

<div class="modal-section-title">設備檢驗表單</div>
<div id="no-form-block" style="display: none; text-align: center; color: var(--text-muted); padding: 20px; border: 1px dashed var(--border-color); border-radius: 8px;">
<i class="fas fa-info-circle"></i> 此狀態切換點未設定/未觸發任何設備檢驗表單。
</div>

<div id="has-form-block" style="display: block;">
<div class="form-meta-block">
<div><strong>表單名稱:</strong><span id="m-form-name" style="color:var(--primary-blue); font-weight: 600;">-</span></div>
<div><strong>檢驗人:</strong><span id="m-form-inspector">-</span></div>
</div>
<table class="detail-table">
<thead>
<tr>
<th style="width: 15%; text-align: center;">項目標號</th>
<th style="width: 35%;">項目名稱</th>
<th style="width: 15%; text-align: center;">單位</th>
<th style="width: 15%; text-align: center;">檢驗結果</th>
<th style="width: 20%; text-align: right;">檢驗值</th>
</tr>
</thead>
<tbody id="modal-detail-table-body">
</tbody>
</table>
</div>

</div>
</div>
</div>

<script>
// 模擬設備歷程數據池
const mockEquipmentData = [
{
time: '2026-07-16 11:15:00', id: 'EQ-INJ-01', name: '精密高壓射出成型機A', type: '模具生產設備',
line: '自動化A線', area: '射出二廠區', fromStatus: '待機', toStatus: '運轉中', mold: 'MOLD-2026-B3', user: '張志明',
desc: '工單開工正式生產,上機綁定隱形眼鏡後弧成型模B型。',
form: '', inspector: '', details: []
},
{
time: '2026-07-16 10:15:22', id: 'EQ-INJ-01', name: '精密高壓射出成型機A', type: '模具生產設備',
line: '自動化A線', area: '射出二廠區', fromStatus: '運轉中', toStatus: '維護中', mold: '', user: '陳大同',
desc: '射出螺桿油壓溫度異常過高,下線切換至維護狀態排除故障。',
form: '設備維護段緊急點檢表', inspector: '王大維',
details: [
{ code: 'EQ-001', name: '油壓缸油溫量測', unit: '°C', res: 'PASS', val: '58.5' },
{ code: 'EQ-002', name: '冷卻循環水閥流量', unit: 'L/min', res: 'PASS', val: '14.2' },
{ code: 'EQ-003', name: '螺桿中心偏擺公差值', unit: 'mm', res: 'PASS', val: '0.003' }
]
},
{
time: '2026-07-15 16:30:00', id: 'EQ-CNC-05', name: '高速五軸CNC加工機', type: '模具生產設備',
line: '手動精修線', area: '精密加工區', fromStatus: '待機', toStatus: '維護中', mold: '', user: '林小華',
desc: '例行季度預防性維護保養,執行主軸校正與皮帶張力點檢。',
form: '設備季度定期保養單', inspector: '林小華',
details: [
{ code: 'PM-E01', name: '主軸中心動態偏擺度', unit: 'µm', res: 'PASS', val: '1.2' },
{ code: 'PM-E02', name: '傳動皮帶張力扭力值', unit: 'N·m', res: 'PASS', val: '45.0' },
{ code: 'PM-E03', name: '三軸軌道潤滑油壓磅數', unit: 'psi', res: 'PASS', val: '32.5' }
]
},
{
time: '2026-07-15 08:00:00', id: 'EQ-SUR-02', name: '超音波表面洗淨槽', type: '表面處理設備',
line: '後處理線', area: '清洗包裝區', fromStatus: '維護中', toStatus: '待機', mold: '', user: '張志明',
desc: '保養完成,複驗合格後回復待機狀態。',
form: '設備保養完成復機驗收單', inspector: '張志明',
details: [
{ code: 'CL-01', name: '超音波震盪頻率輸出', unit: 'kHz', res: 'PASS', val: '40.0' },
{ code: 'CL-02', name: '槽體純水電導度值', unit: 'µS/cm', res: 'PASS', val: '1.1' }
]
}
];

const tableBody = document.getElementById('history-table-body');
const modal = document.getElementById('detailModal');

window.onload = function() {
renderTable(mockEquipmentData);
};

function renderTable(data) {
tableBody.innerHTML = '';
if(data.length === 0) {
tableBody.innerHTML = `<tr><td colspan="9" style="text-align:center; color:var(--text-muted); font-style: italic;">查無對應的設備異動歷程資料。</td></tr>`;
return;
}

data.forEach((item, index) => {
const row = document.createElement('tr');
const fromBadgeClass = getBadgeColor(item.fromStatus);
const toBadgeClass = getBadgeColor(item.toStatus);

const moldDisplay = (item.toStatus === '運轉中' && item.mold)
? `<strong style="color:#2563eb;">${item.mold}</strong>`
: `<span class="text-null">NULL</span>`;

row.innerHTML = `
<td>${item.time}</td>
<td style="font-weight:bold;">${item.id}</td>
<td>${item.name}</td>
<td>${item.type}</td>
<td><span class="badge ${fromBadgeClass}">${item.fromStatus}</span></td>
<td><span class="badge ${toBadgeClass}">${item.toStatus}</span></td>
<td>${moldDisplay}</td>
<td>${item.user}</td>
<td style="text-align: center;">
<button class="btn-action" onclick="showDetail(${index})">詳細</button>
</td>
`;
tableBody.appendChild(row);
});
}

function getBadgeColor(status) {
if (status === '運轉中') return 'badge-green';
if (status === '待機') return 'badge-blue';
return 'badge-orange';
}

function filterHistory() {
const keyword = document.getElementById('eqSearch').value.trim().toLowerCase();
const selectedType = document.getElementById('eqType').value;
const operator = document.getElementById('operator').value.trim().toLowerCase();

const filtered = mockEquipmentData.filter(item => {
const matchesKeyword = !keyword || item.id.toLowerCase().includes(keyword) || item.name.toLowerCase().includes(keyword);
const matchesType = selectedType === 'ALL' || item.type === selectedType;
const matchesOperator = !operator || item.user.toLowerCase().includes(operator);
return matchesKeyword && matchesType && matchesOperator;
});

renderTable(filtered);
}

function showDetail(index) {
const item = mockEquipmentData[index];
// 1. 上半部欄位填值
document.getElementById('m-eq-id').innerText = item.id;
document.getElementById('m-eq-name').innerText = item.name;
document.getElementById('m-line').innerText = item.line;
document.getElementById('m-area').innerText = item.area;
document.getElementById('m-status-before').innerText = item.fromStatus;
document.getElementById('m-status-after').innerText = item.toStatus;
document.getElementById('m-user').innerText = item.user;
document.getElementById('m-desc').innerText = item.desc || '無特定狀況描述或備註。';
// 2. 下半部設備檢驗表單處理
const noFormBlock = document.getElementById('no-form-block');
const hasFormBlock = document.getElementById('has-form-block');
const detailTbody = document.getElementById('modal-detail-table-body');
detailTbody.innerHTML = '';

if (item.form) {
noFormBlock.style.display = 'none';
hasFormBlock.style.display = 'block';
document.getElementById('m-form-name').innerText = item.form;
document.getElementById('m-form-inspector').innerText = item.inspector || item.user;
item.details.forEach(det => {
const tr = document.createElement('tr');
const resClass = (det.res === 'PASS') ? 'text-pass' : 'text-ng';
tr.innerHTML = `
<td style="text-align: center; font-family: monospace; color: #475569;">${det.code}</td>
<td style="font-weight: 500;">${det.name}</td>
<td style="text-align: center; color: #64748b;">${det.unit}</td>
<td class="text-center ${resClass}" style="text-align: center;">${det.res}</td>
<td style="text-align: right; font-weight: 600; color: #0f172a;">${det.val}</td>
`;
detailTbody.appendChild(tr);
});
} else {
noFormBlock.style.display = 'block';
hasFormBlock.style.display = 'none';
}
modal.style.display = 'flex';
}

function closeModal() {
modal.style.display = 'none';
}

window.onclick = function(event) {
if (event.target === modal) {
closeModal();
}
}

function exportToCSV() {
let csvContent = "\uFEFF";
csvContent += "異動時間,設備編號,設備名稱,設備類型,變更前狀態,變更後狀態,模具,操作人員,備註描述\n";
const keyword = document.getElementById('eqSearch').value.trim().toLowerCase();
const selectedType = document.getElementById('eqType').value;
const operator = document.getElementById('operator').value.trim().toLowerCase();
let exportCount = 0;

mockEquipmentData.forEach(item => {
const matchesKeyword = !keyword || item.id.toLowerCase().includes(keyword) || item.name.toLowerCase().includes(keyword);
const matchesType = selectedType === 'ALL' || item.type === selectedType;
const matchesOperator = !operator || item.user.toLowerCase().includes(operator);
if (matchesKeyword && matchesType && matchesOperator) {
const moldStr = (item.toStatus === '運轉中') ? item.mold : 'NULL';
csvContent += `"${item.time}","${item.id}","${item.name}","${item.type}","${item.fromStatus}","${item.toStatus}","${moldStr}","${item.user}","${item.desc}"\n`;
exportCount++;
}
});

if (exportCount === 0) {
alert("目前無符合條件的數據可供匯出。");
return;
}

const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement("a");
const url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", `設備歷程結果_${new Date().toISOString().slice(0,10)}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
</body>
</html>
    (1-1/1)