Project

General

Profile

Feature #148 » 模具檢驗規則_0716.html

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

 
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<title>模具檢驗規則與狀態卡控系統</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
'teal-800': '#1e4646',
'teal-200': '#b2f0f0',
'teal-600': '#00a399',
'light-blue': '#4c9aff',
'dark-red': '#cc0000',
'gray-500': '#6b7280',
/* 模具狀態顏色 */
'status-ok': '#10b981', /* 生產中 */
'status-idle': '#2563eb', /* 待機庫存 */
'status-wip': '#f59e0b', /* 保養/維修 */
'status-ng': '#ef4444',
/* 背景色 */
'bg-ok': '#dcfce7',
'bg-idle': '#dbeafe',
'bg-wip': '#fef3c7',
'bg-ng': '#fee2e2',

/* 綁定單據相關 */
'bind-color': '#2563eb',
'bind-bg': '#eff6ff',
}
}
}
}
</script>
<style>
.filter-button {
padding: 8px 16px;
border-radius: 9999px;
font-weight: 600;
transition: all 0.2s;
cursor: pointer;
}
.action-button-mini {
padding: 4px 8px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 500;
transition: background-color 0.15s, opacity 0.15s;
}
.filter-button.active {
background-color: #3b82f6;
color: white;
}
.filter-button.inactive {
background-color: #e5e7eb;
color: #1f2937;
}
.required-label::after {
content: ' *';
color: #ef4444;
margin-left: 2px;
}
.detail-row-input {
width: 100%;
padding: 6px 8px;
border: 1px solid #d1d5db;
border-radius: 4px;
background-color: white;
}
.detail-input-pm {
padding: 8px;
border: 1px solid #d1d5db;
border-radius: 4px;
width: 100%;
}
.status-transition-tag {
background-color: #eff6ff;
color: #2563eb;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
margin-right: 4px;
border: 1px solid #2563eb;
}
</style>
</head>
<body class="bg-slate-100 p-10">

<div id="app">

<div v-if="viewMode === 'list'" class="main-content-wrapper">
<h1 class="text-3xl font-bold text-slate-800 mb-6 border-b-4 border-blue-200 pb-3">
🎛️ 模具檢驗規則與狀態轉移卡控設定
</h1>
<div class="bg-white p-6 rounded-2xl shadow-xl border border-gray-200">
<h2 class="text-xl font-bold text-gray-700 mb-4 border-b pb-2">
模具稼動與維護單據配置
</h2>

<div class="flex space-x-4 mb-6">
<button @click="activeFilter = '全部'" :class="['filter-button', activeFilter === '全部' ? 'active' : 'inactive']">全部</button>
<button @click="activeFilter = '光學模具'" :class="['filter-button', activeFilter === '光學模具' ? 'active' : 'inactive']">光學模具</button>
<button @click="activeFilter = '射出模具'" :class="['filter-button', activeFilter === '射出模具' ? 'active' : 'inactive']">射出模具</button>
<button @click="activeFilter = '沖壓模具'" :class="['filter-button', activeFilter === '沖壓模具' ? 'active' : 'inactive']">沖壓模具</button>
</div>
<div class="flex justify-between items-center mb-4">
<input v-model="searchKeyword" placeholder="搜尋模具編號/名稱..." class="p-2 border rounded-lg w-64">
</div>

<table class="min-w-full table-auto border border-gray-200 text-sm">
<thead class="bg-gray-100">
<tr>
<th class="px-3 py-2 border">模具編號</th>
<th class="px-3 py-2 border">模具名稱</th>
<th class="px-3 py-2 border">模具類型</th>
<th class="px-3 py-2 border">線別</th>
<th class="px-3 py-2 border w-32">表單配置</th>
<th class="px-3 py-2 border w-64">狀態變更維護 (已卡控流程)</th>
</tr>
</thead>
<tbody>
<tr v-for="mold in filteredMolds" :key="mold.id" class="hover:bg-blue-50">
<td class="px-3 py-2 border font-bold">{{ mold.no }}</td>
<td class="px-3 py-2 border">{{ mold.name }}</td>
<td class="px-3 py-2 border">{{ mold.type }}</td>
<td class="px-3 py-2 border">{{ mold.lineType }}</td>
<td class="px-3 py-2 border text-center">
<button @click="openDialog('bind_pm', mold)"
class="action-button-mini bg-blue-600 hover:bg-light-blue text-white w-full">
配置單據 ({{ mold.maintenanceForms ? Object.keys(mold.maintenanceForms).length : 0 }})
</button>
</td>
<td class="px-3 py-2 border text-center">
<div v-if="!mold.maintenanceForms || Object.keys(mold.maintenanceForms).length === 0" class="text-gray-400 italic text-sm">
無卡控點 (自由轉換)
</div>
<div v-else class="flex flex-wrap justify-center gap-1">
<span v-for="(formId, statusKey) in mold.maintenanceForms" :key="statusKey"
class="inline-block bg-orange-50 text-orange-700 border border-orange-200 text-xs font-semibold px-2 py-0.5 rounded">
{{ statusKey }}
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>

<div v-if="dialog.mode === 'bind_pm'" class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-60 z-40 p-4">
<div class="bg-white p-6 rounded-xl shadow-2xl w-11/12 max-w-xl border border-gray-200">
<h2 class="text-2xl font-bold text-blue-700 mb-4 border-b pb-2">
📋 配置模具狀態轉換卡控單據 ({{ dialog.data.no }})
</h2>
<div class="mb-6 space-y-4">
<p class="text-sm text-gray-600 mb-4">模具名稱:<span class="font-bold text-slate-800">{{ dialog.data.name }}</span></p>
<h3 class="text-lg font-bold text-gray-700 mb-3 border-t pt-3">檢驗單據卡控規則設定</h3>
<div class="space-y-3 max-h-64 overflow-y-auto p-2 border rounded-lg bg-gray-50">
<div v-for="(formId, status) in dialog.data.maintenanceForms" :key="status" class="flex items-center space-x-2 bg-white p-3 rounded shadow-sm border border-gray-200">
<div class="w-5/12">
<span class="status-transition-tag text-xs">{{ status }}</span>
</div>
<div class="flex-1">
<select v-model="dialog.data.maintenanceForms[status]" class="detail-row-input text-xs">
<option :value="null">-- 取消綁定 --</option>
<option v-for="form in pmFormPool" :key="form.id" :value="form.id">
{{ form.name }}
</option>
</select>
</div>
<button @click="removePMFormBinding(status)" class="text-dark-red hover:text-red-700 text-xs font-bold p-1">
刪除
</button>
</div>
<div v-if="!dialog.data.maintenanceForms || Object.keys(dialog.data.maintenanceForms).length === 0" class="p-3 text-center text-gray-500 text-sm">
目前沒有設定任何單據卡控點。
</div>
</div>
<h4 class="text-md font-semibold text-gray-700 pt-3 border-t">新增狀態卡控點</h4>
<div class="flex space-x-2">
<div class="w-1/3">
<select v-model="dialog.tempBinding.fromStatus" class="detail-row-input text-sm">
<option value="">-- 起始狀態 --</option>
<option v-for="status in statusOptions" :key="status" :value="status">{{ status }}</option>
</select>
</div>
<div class="w-1/3">
<select v-model="dialog.tempBinding.toStatus" class="detail-row-input text-sm">
<option value="">-- 目標狀態 --</option>
<option v-for="status in statusOptions" :key="status" :value="status">{{ status }}</option>
</select>
</div>
<div class="w-1/3">
<button @click="addPMFormBinding" class="px-3 py-1 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm h-full w-full">
+ 加入卡控
</button>
</div>
</div>
</div>
<div class="flex justify-end space-x-3 mt-4">
<button @click="closeDialog" class="px-5 py-2 bg-gray-200 text-gray-700 rounded hover:bg-gray-300">取消</button>
<button @click="saveMaintenanceBinding" class="px-5 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">確認儲存配置</button>
</div>
</div>
</div>

<div v-if="viewMode === 'pm_entry'" class="main-content-wrapper">
<h1 class="text-3xl font-bold text-slate-800 mb-6 border-b-4 border-blue-200 pb-3">
📝 模具檢驗與維護數據填寫
</h1>
<div class="bg-white p-6 rounded-2xl shadow-xl border border-gray-200">
<h2 class="text-xl font-bold text-gray-700 mb-4">
工作單據:<span class="text-blue-600">{{ pmEntryForm.pmFormName }}</span>
</h2>
<div class="grid grid-cols-2 gap-4 mb-6 pb-4 border-b text-sm">
<div><span class="font-semibold text-gray-500">模具編號:</span><span class="text-blue-600 font-bold">{{ pmEntryForm.equipmentNo }}</span></div>
<div><span class="font-semibold text-gray-500">模具名稱:</span><span>{{ pmEntryForm.equipmentName }}</span></div>
<div><span class="font-semibold text-gray-500">表單類型:</span><span>{{ pmEntryForm.pmFormType }}</span></div>
<div><span class="font-semibold text-gray-500">檢驗人員:</span><input v-model="pmEntryForm.inspector" class="detail-input-pm w-2/3 py-1 px-2" placeholder="請輸入姓名"></div>
</div>
<table class="min-w-full table-auto border border-gray-200 text-sm">
<thead class="bg-gray-100">
<tr>
<th class="px-3 py-2 border w-1/4">檢驗項目</th>
<th class="px-3 py-2 border w-1/4">驗收標準</th>
<th class="px-3 py-2 border w-1/6">檢驗方法</th>
<th class="px-3 py-2 border w-1/6 required-label">判定結果</th>
<th class="px-3 py-2 border w-1/6">備註</th>
</tr>
</thead>
<tbody>
<tr v-for="(detail, index) in pmEntryForm.details" :key="index">
<td class="px-3 py-2 border font-medium">{{ detail.content }}</td>
<td class="px-3 py-2 border text-gray-600">{{ detail.standard }}</td>
<td class="px-3 py-2 border text-gray-500">{{ detail.method }}</td>
<td class="px-3 py-2 border">
<select v-model="detail.result" class="detail-input-pm py-1 px-2 text-sm">
<option value="">-- 選擇 --</option>
<option value="PASS">PASS (合格)</option>
<option value="FAIL">FAIL (不合格)</option>
</select>
</td>
<td class="px-3 py-2 border"><input v-model="detail.notes" type="text" class="detail-input-pm py-1 px-2 text-sm" placeholder="選填"></td>
</tr>
</tbody>
</table>
<div class="flex justify-end space-x-3 mt-6">
<button @click="viewMode = 'list'" class="px-5 py-2 bg-gray-200 text-gray-700 rounded hover:bg-gray-300">返回列表</button>
<button @click="submitPMForm" class="px-5 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">儲存並執行狀態切換</button>
</div>
</div>
</div>

</div>

<script>
const { createApp, ref, reactive, computed } = Vue;

createApp({
setup() {
const viewMode = ref('list');
const activeFilter = ref('全部');
const searchKeyword = ref('');
const statusOptions = ref(['生產中', '待機庫存', '保養中', '維修中']);

const mockMoldDetails = [
{ content: '模面外觀與刮傷檢驗', standard: '光學區無刮傷、麻點與銹斑', method: '強光燈顯微目視', result: '', notes: '' },
{ content: '入子/型腔磨損量測', standard: '設計公差 ±0.005 mm 以內', method: '三次元/千分表量測', result: '', notes: '' },
{ content: '射出嘴套與澆道清潔', standard: '無塑料殘留、無焦黑積碳', method: '目視與擦拭檢驗', result: '', notes: '' },
{ content: '模具冷水路暢通與氣密', standard: '無漏水、水壓阻力符合規範', method: '氣密水壓測試儀', result: '', notes: '' }
];

const pmFormPool = ref([
{ id: 1, name: '日點檢-下線洗模點檢表', type: '下線清洗', details: mockMoldDetails },
{ id: 2, name: '定期保養-超音波清洗與潤滑紀錄', type: '定期保養', details: mockMoldDetails },
{ id: 3, name: '模具大修維修檢驗報告', type: '故障維修', details: mockMoldDetails },
{ id: 4, name: '光學模面精密拋光校正單', type: '光學精密', details: mockMoldDetails },
]);

const moldRecords = ref([
{ id: 1, no: 'MOLD-2026-A1', name: '隱形眼鏡前弧成型模 A型', type: '光學模具', lineType: '手動線', status: '生產中', maintenanceForms: { '生產中->保養中': 1 } },
{ id: 2, no: 'MOLD-2026-B3', name: '隱形眼鏡後弧成型模 B型', type: '光學模具', lineType: '自動線', status: '生產中', maintenanceForms: {} },
{ id: 3, no: 'MOLD-PL-V2', name: 'PIM 載台特製模組', type: '射出模具', lineType: '自動線', status: '生產中', maintenanceForms: { '生產中->維修中': 3 } },
{ id: 4, no: 'MOLD-ST-99', name: '外殼固定鋼片沖壓模', type: '沖壓模具', lineType: '手動線', status: '待機庫存', maintenanceForms: { '待機庫存->保養中': 2 } },
]);

const dialog = reactive({
mode: null,
data: {},
tempBinding: { fromStatus: '', toStatus: '' },
});

const pmEntryForm = reactive({
equipmentNo: '', equipmentName: '', pmFormId: '', pmFormName: '', pmFormType: '', inspector: '', details: []
});

const getPMFormInfo = (id) => {
const form = pmFormPool.value.find(f => f.id === id);
return form ? { name: form.name, type: form.type } : { name: '未配置單據', type: 'N/A' };
};
const filteredMolds = computed(() => {
let records = moldRecords.value;
const keyword = searchKeyword.value.toLowerCase();
const filterType = activeFilter.value;

if (filterType !== '全部') records = records.filter(m => m.type === filterType);
if (keyword) {
records = records.filter(m =>
m.no.toLowerCase().includes(keyword) || m.name.toLowerCase().includes(keyword)
);
}
return records;
});

const addPMFormBinding = () => {
const fromS = dialog.tempBinding.fromStatus;
const toS = dialog.tempBinding.toStatus;
if (!fromS || !toS) { alert('請選擇起始與目標狀態!'); return; }
if (fromS === toS) { alert('起始與目標狀態不能相同!'); return; }
const key = `${fromS}->${toS}`;
if (!dialog.data.maintenanceForms) dialog.data.maintenanceForms = {};
dialog.data.maintenanceForms[key] = pmFormPool.value[0].id;
dialog.tempBinding.fromStatus = '';
dialog.tempBinding.toStatus = '';
};

const removePMFormBinding = (statusKey) => {
delete dialog.data.maintenanceForms[statusKey];
};

const saveMaintenanceBinding = () => {
const index = moldRecords.value.findIndex(m => m.id === dialog.data.id);
if (index !== -1) {
moldRecords.value[index].maintenanceForms = { ...dialog.data.maintenanceForms };
alert('配置成功儲存!');
}
closeDialog();
};

const openDialog = (mode, mold = {}) => {
dialog.mode = mode;
dialog.data = JSON.parse(JSON.stringify(mold));
if (!dialog.data.maintenanceForms) dialog.data.maintenanceForms = {};
dialog.tempBinding = { fromStatus: '', toStatus: '' };
};

const closeDialog = () => { dialog.mode = null; };

const submitPMForm = () => {
alert('單據填寫成功!已解除流程卡控。');
viewMode.value = 'list';
};

return {
Object,
viewMode,
activeFilter,
searchKeyword,
filteredMolds,
dialog,
pmFormPool,
pmEntryForm,
statusOptions,
openDialog,
closeDialog,
getPMFormInfo,
addPMFormBinding,
removePMFormBinding,
saveMaintenanceBinding,
submitPMForm
};
}
}).mount('#app');
</script>
</body>
</html>
    (1-1/1)