515 lines
22 KiB
Vue
515 lines
22 KiB
Vue
<script setup lang="ts">
|
||
import { ref, computed } from 'vue'
|
||
import {
|
||
CheckCircle2,
|
||
AlertTriangle,
|
||
Camera,
|
||
Upload,
|
||
Check,
|
||
Download,
|
||
X,
|
||
FileSpreadsheet,
|
||
} from 'lucide-vue-next'
|
||
|
||
const showImportDialog = ref(false)
|
||
const importFile = ref<File | null>(null)
|
||
|
||
const showPhotoDialog = ref(false)
|
||
const photoDialogItemId = ref(0)
|
||
const photoFiles = ref<{ name: string; url: string }[]>([])
|
||
const photoNote = ref('')
|
||
|
||
const openPhotoDialog = (itemId: number) => {
|
||
photoDialogItemId.value = itemId
|
||
photoFiles.value = []
|
||
photoNote.value = ''
|
||
showPhotoDialog.value = true
|
||
}
|
||
|
||
const onPhotoSelect = (e: Event) => {
|
||
const target = e.target as HTMLInputElement
|
||
if (target.files) {
|
||
for (const f of Array.from(target.files)) {
|
||
photoFiles.value.push({ name: f.name, url: URL.createObjectURL(f) })
|
||
}
|
||
}
|
||
target.value = ''
|
||
}
|
||
|
||
const removePhoto = (index: number) => {
|
||
photoFiles.value.splice(index, 1)
|
||
}
|
||
|
||
const confirmPhotos = () => {
|
||
const item = checklistItems.value.find((i: any) => i.id === photoDialogItemId.value)
|
||
if (item) {
|
||
item.photos = photoFiles.value.length
|
||
item.completed = true
|
||
}
|
||
showPhotoDialog.value = false
|
||
}
|
||
|
||
const onFileChange = (e: Event) => {
|
||
const target = e.target as HTMLInputElement
|
||
if (target.files && target.files.length > 0) importFile.value = target.files[0]
|
||
}
|
||
|
||
const selectedModel = ref('GD30')
|
||
const checklistItems = ref([
|
||
{ id: 1, text: '主板安装及固定', completed: true, photos: 3, needPhoto: true, versionCheck: true, versionMatch: true },
|
||
{ id: 2, text: '采集板连接', completed: true, photos: 2, needPhoto: true, versionCheck: true, versionMatch: true },
|
||
{ id: 3, text: '测控板安装', completed: true, photos: 2, needPhoto: true, versionCheck: true, versionMatch: false },
|
||
{ id: 4, text: '电源线连接检查', completed: false, photos: 0, needPhoto: true, versionCheck: false, versionMatch: true },
|
||
{ id: 5, text: '外壳密封性检测', completed: false, photos: 0, needPhoto: true, versionCheck: false, versionMatch: true },
|
||
])
|
||
|
||
const bomData = [
|
||
{ code: 'MB-2024-001', name: '主控板', sn: 'MB20240308001', spec: 'GD30-MB-V2.3', calibration: '无需校准', quantity: 1 },
|
||
{ code: 'RX-2024-002', name: '采集板', sn: 'RX20240308002', spec: 'GD30-RX-V1.8', calibration: '已校准', quantity: 2 },
|
||
{ code: 'MC-2024-003', name: '测控板', sn: 'MC20240308003', spec: 'GD30-MC-V1.5', calibration: '无需校准', quantity: 1 },
|
||
{ code: 'TX-2024-003', name: '发射板', sn: 'TX20240308003', spec: 'GD30-TX-V1.5', calibration: '无需校准', quantity: 1 },
|
||
{ code: 'BO-2024-004', name: '升压板', sn: 'BO20240308004', spec: 'BP600', calibration: '无需校准', quantity: 1 },
|
||
{ code: 'CS-2024-005', name: '外壳机箱', sn: '-', spec: 'AL6061-T6', calibration: '无需校准', quantity: 1 },
|
||
]
|
||
|
||
const completedCount = computed(() => checklistItems.value.filter((item: typeof checklistItems.value[number]) => item.completed).length)
|
||
const totalCount = computed(() => checklistItems.value.length)
|
||
|
||
const toggleChecklistItem = (id: number) => {
|
||
checklistItems.value = checklistItems.value.map((item: typeof checklistItems.value[number]) =>
|
||
item.id === id ? { ...item, completed: !item.completed } : item
|
||
)
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="p-6">
|
||
<!-- Page Header -->
|
||
<div class="mb-6">
|
||
<h2 class="text-2xl font-semibold mb-1">设备登记</h2>
|
||
<p class="text-sm" :style="{ color: 'rgba(0, 0, 0, 0.45)' }">登记新设备信息及装配记录</p>
|
||
</div>
|
||
|
||
<!-- Installation Info Card -->
|
||
<div class="bg-white p-6 rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||
<h3 class="text-lg font-semibold mb-6">装机信息</h3>
|
||
<div class="grid grid-cols-3 gap-6">
|
||
<div>
|
||
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||
设备型号 <span :style="{ color: '#FF4D4F' }">*</span>
|
||
</label>
|
||
<select
|
||
v-model="selectedModel"
|
||
class="w-full px-3 py-2 border rounded"
|
||
:style="{ borderColor: '#D9D9D9', backgroundColor: '#fff' }"
|
||
>
|
||
<option value="GD30">GD30 高密度电法仪</option>
|
||
<option value="GT20">GT20 瞬变电磁仪</option>
|
||
<option value="GTXD">GM10 大地电磁仪</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||
主机SN号 <span :style="{ color: '#FF4D4F' }">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
class="w-full px-3 py-2 border rounded"
|
||
:style="{ borderColor: '#D9D9D9' }"
|
||
placeholder="请输入主机SN号"
|
||
value="GD30-20240308-001"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||
主板SN号 <span :style="{ color: '#FF4D4F' }">*</span>
|
||
</label>
|
||
<div class="flex items-center gap-2">
|
||
<input
|
||
type="text"
|
||
class="flex-1 px-3 py-2 border rounded"
|
||
:style="{ borderColor: '#D9D9D9' }"
|
||
placeholder="请输入主板SN号"
|
||
value="MB20240308001"
|
||
/>
|
||
<span
|
||
class="px-2 py-1 rounded text-xs whitespace-nowrap"
|
||
:style="{ backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' }"
|
||
>
|
||
已绑定
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||
装机测试状态
|
||
</label>
|
||
<div class="w-full px-3 py-2 border rounded" :style="{ borderColor: '#D9D9D9', backgroundColor: '#FAFAFA' }">
|
||
<select>
|
||
<option>测试通过</option>
|
||
<option>测试不通过</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||
生产日期
|
||
</label>
|
||
<input
|
||
type="date"
|
||
class="w-full px-3 py-2 border rounded"
|
||
:style="{ borderColor: '#D9D9D9' }"
|
||
value="2024-03-08"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||
登记人
|
||
</label>
|
||
<input
|
||
type="text"
|
||
class="w-full px-3 py-2 border rounded"
|
||
:style="{ borderColor: '#D9D9D9', backgroundColor: '#FAFAFA' }"
|
||
value="张工"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Success Banner -->
|
||
<div
|
||
class="mb-4 p-4 rounded-lg flex items-start gap-3"
|
||
:style="{ backgroundColor: '#F6FFED', border: '1px solid #B7EB8F' }"
|
||
>
|
||
<CheckCircle2 :size="20" :style="{ color: '#52C41A', flexShrink: 0, marginTop: '2px' }" />
|
||
<div>
|
||
<div :style="{ color: '#389E0D', fontWeight: 500 }">型号已匹配:GD30</div>
|
||
<div class="text-sm mt-1" :style="{ color: '#52C41A' }">
|
||
授权文件:auth_gd30_v2.3.lic | 配置文件:config_gd30_v1.5.json | 固件版本:v2.3.5
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Warning Banner (Optional - shown when model doesn't match) -->
|
||
<div
|
||
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||
:style="{ backgroundColor: '#FFFBE6', border: '1px solid #FFE58F', display: 'none' }"
|
||
>
|
||
<AlertTriangle :size="20" :style="{ color: '#FAAD14', flexShrink: 0, marginTop: '2px' }" />
|
||
<div>
|
||
<div :style="{ color: '#D46B08', fontWeight: 500 }">未匹配到型号关联信息</div>
|
||
<div class="text-sm mt-1" :style="{ color: '#FAAD14' }">
|
||
请先在型号管理中配置该型号的授权文件、配置文件和固件版本
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- BOM List Card -->
|
||
<div class="bg-white rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||
<div class="p-6 border-b" :style="{ borderColor: '#F0F0F0' }">
|
||
<div class="flex items-center justify-between">
|
||
<h3 class="text-lg font-semibold">设备BOM清单</h3>
|
||
<button
|
||
class="px-4 py-2 rounded flex items-center gap-2"
|
||
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||
@click="showImportDialog = true"
|
||
>
|
||
<Upload :size="16" />
|
||
导入
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="overflow-x-auto">
|
||
<table class="w-full">
|
||
<thead :style="{ backgroundColor: '#FAFAFA' }">
|
||
<tr>
|
||
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">物料编码</th>
|
||
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">物料名称</th>
|
||
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">SN号</th>
|
||
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">规格型号</th>
|
||
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">校准状态</th>
|
||
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">数量</th>
|
||
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr
|
||
v-for="(item, index) in bomData"
|
||
:key="index"
|
||
class="border-b"
|
||
:style="{ borderColor: '#F0F0F0' }"
|
||
>
|
||
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ item.code }}</td>
|
||
<td class="px-6 py-4">{{ item.name }}</td>
|
||
<td class="px-6 py-4">{{ item.sn }}</td>
|
||
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ item.spec }}</td>
|
||
<td class="px-6 py-4">
|
||
<span
|
||
class="px-2 py-1 rounded text-xs"
|
||
:style="{
|
||
backgroundColor: item.calibration === '已校准' ? '#F6FFED' : '#F0F2F5',
|
||
color: item.calibration === '已校准' ? '#52C41A' : 'rgba(0, 0, 0, 0.65)',
|
||
border: `1px solid ${item.calibration === '已校准' ? '#B7EB8F' : '#D9D9D9'}`,
|
||
}"
|
||
>
|
||
{{ item.calibration }}
|
||
</span>
|
||
</td>
|
||
<td class="px-6 py-4">{{ item.quantity }}</td>
|
||
<td class="px-6 py-4">
|
||
<div class="flex items-center gap-3">
|
||
<button class="text-sm" :style="{ color: '#4a7c59' }">编辑</button>
|
||
<button class="text-sm" :style="{ color: '#FF4D4F' }">删除</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Assembly Checklist Card -->
|
||
<div class="bg-white rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||
<div class="p-6 border-b" :style="{ borderColor: '#F0F0F0' }">
|
||
<div class="flex items-center justify-between">
|
||
<h3 class="text-lg font-semibold">装配Checklist</h3>
|
||
<div class="flex items-center gap-2">
|
||
<span class="text-sm" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">完成进度</span>
|
||
<span class="text-sm font-semibold" :style="{ color: '#4a7c59' }">
|
||
{{ completedCount }}/{{ totalCount }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="p-6">
|
||
<div class="space-y-3">
|
||
<div
|
||
v-for="item in checklistItems"
|
||
:key="item.id"
|
||
class="flex items-center gap-4 p-4 rounded border"
|
||
:style="{
|
||
backgroundColor: item.completed ? '#F6FFED' : '#FAFAFA',
|
||
borderColor: item.completed ? '#B7EB8F' : '#F0F0F0',
|
||
}"
|
||
>
|
||
<button
|
||
@click="toggleChecklistItem(item.id)"
|
||
class="w-6 h-6 rounded border flex items-center justify-center flex-shrink-0 transition-colors"
|
||
:style="{
|
||
borderColor: item.completed ? '#52C41A' : '#D9D9D9',
|
||
backgroundColor: item.completed ? '#52C41A' : '#fff',
|
||
}"
|
||
>
|
||
<Check v-if="item.completed" :size="16" color="#fff" />
|
||
</button>
|
||
<div
|
||
class="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0"
|
||
:style="{ backgroundColor: item.completed ? '#52C41A' : '#D9D9D9', color: 'white' }"
|
||
>
|
||
{{ item.id }}
|
||
</div>
|
||
<div class="flex-1">
|
||
<div class="flex items-center gap-2">
|
||
<span :style="{ color: item.completed ? 'rgba(0, 0, 0, 0.85)' : 'rgba(0, 0, 0, 0.65)' }">
|
||
{{ item.text }}
|
||
</span>
|
||
<span
|
||
v-if="item.versionCheck && !item.versionMatch"
|
||
class="px-2 py-1 rounded text-xs flex items-center gap-1"
|
||
:style="{ backgroundColor: '#FFF1F0', color: '#FF4D4F', border: '1px solid #FFCCC7' }"
|
||
>
|
||
<AlertTriangle :size="12" />
|
||
版本不一致!
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button
|
||
v-if="item.needPhoto && item.completed && item.photos > 0"
|
||
class="px-3 py-1 rounded text-xs flex items-center gap-1 cursor-pointer"
|
||
:style="{ backgroundColor: '#eef5f0', color: '#4a7c59' }"
|
||
@click="openPhotoDialog(item.id)"
|
||
>
|
||
<Camera :size="12" />
|
||
已上传 {{ item.photos }}张
|
||
</button>
|
||
<button
|
||
v-if="item.needPhoto && !item.completed"
|
||
class="px-3 py-1 rounded text-xs flex items-center gap-1"
|
||
:style="{ backgroundColor: '#4a7c59', color: '#fff' }"
|
||
@click="openPhotoDialog(item.id)"
|
||
>
|
||
<Camera :size="12" />
|
||
拍照上传
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Action Bar -->
|
||
<div
|
||
class="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0"
|
||
:style="{ boxShadow: '0 -2px 8px rgba(0, 0, 0, 0.05)' }"
|
||
>
|
||
<button
|
||
class="px-6 py-2 rounded"
|
||
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
class="px-6 py-2 rounded"
|
||
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||
>
|
||
更新
|
||
</button>
|
||
<button
|
||
class="px-6 py-2 rounded text-white"
|
||
:style="{ backgroundColor: '#4a7c59' }"
|
||
>
|
||
提交
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Photo Upload Dialog -->
|
||
<div v-if="showPhotoDialog" class="fixed inset-0 z-50 flex items-center justify-center" style="background-color: rgba(0,0,0,0.45)">
|
||
<div class="bg-white rounded-lg w-[560px] max-h-[80vh] flex flex-col" style="box-shadow: 0 4px 12px rgba(0,0,0,0.15)">
|
||
<div class="flex items-center justify-between p-5 border-b" style="border-color: #F0F0F0">
|
||
<h3 class="text-lg font-semibold">上传照片</h3>
|
||
<button @click="showPhotoDialog = false" class="p-1 rounded hover:bg-gray-100" style="color: rgba(0,0,0,0.45)">
|
||
<X :size="18" />
|
||
</button>
|
||
</div>
|
||
|
||
<div class="p-6 overflow-y-auto flex-1">
|
||
<!-- Photo grid -->
|
||
<div class="mb-4">
|
||
<div class="text-sm font-medium mb-2">照片({{ photoFiles.length }}张)</div>
|
||
<div class="flex flex-wrap gap-3">
|
||
<!-- Uploaded photos -->
|
||
<div v-for="(photo, i) in photoFiles" :key="i" class="relative w-24 h-24 rounded-lg overflow-hidden" style="border: 1px solid #F0F0F0">
|
||
<img :src="photo.url" :alt="photo.name" class="w-full h-full object-cover" />
|
||
<button
|
||
class="absolute top-1 right-1 w-5 h-5 rounded-full flex items-center justify-center"
|
||
style="background-color: rgba(0,0,0,0.5); color: #fff"
|
||
@click="removePhoto(i)"
|
||
>
|
||
<X :size="12" />
|
||
</button>
|
||
</div>
|
||
<!-- Add button -->
|
||
<div
|
||
class="w-24 h-24 rounded-lg flex flex-col items-center justify-center cursor-pointer transition-colors hover:border-blue-400"
|
||
style="border: 2px dashed #D9D9D9; color: rgba(0,0,0,0.45)"
|
||
@click="($refs.photoInput as HTMLInputElement)?.click()"
|
||
>
|
||
<Camera :size="24" />
|
||
<span class="text-xs mt-1">添加照片</span>
|
||
</div>
|
||
<input ref="photoInput" type="file" accept="image/*" multiple class="hidden" @change="onPhotoSelect" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Note -->
|
||
<div>
|
||
<div class="text-sm font-medium mb-2">装配记录信息</div>
|
||
<textarea
|
||
v-model="photoNote"
|
||
class="w-full px-3 py-2 border rounded text-sm"
|
||
style="border-color: #D9D9D9; min-height: 80px; resize: vertical"
|
||
placeholder="输入装配记录信息..."
|
||
></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex items-center justify-end gap-3 p-5 border-t" style="border-color: #F0F0F0">
|
||
<button class="px-4 py-2 rounded text-sm" style="border: 1px solid #D9D9D9; color: rgba(0,0,0,0.85)" @click="showPhotoDialog = false">取消</button>
|
||
<button
|
||
class="px-4 py-2 rounded text-white text-sm"
|
||
:style="{ backgroundColor: photoFiles.length > 0 ? '#4a7c59' : '#D9D9D9' }"
|
||
:disabled="photoFiles.length === 0"
|
||
@click="confirmPhotos"
|
||
>确认上传({{ photoFiles.length }}张)</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Import Excel Dialog -->
|
||
<div v-if="showImportDialog" class="fixed inset-0 z-50 flex items-center justify-center" style="background-color: rgba(0,0,0,0.45)">
|
||
<div class="bg-white rounded-lg w-[520px]" style="box-shadow: 0 4px 12px rgba(0,0,0,0.15)">
|
||
<!-- Dialog Header -->
|
||
<div class="flex items-center justify-between p-5 border-b" style="border-color: #F0F0F0">
|
||
<h3 class="text-lg font-semibold">导入BOM清单</h3>
|
||
<button @click="showImportDialog = false; importFile = null" class="p-1 rounded hover:bg-gray-100" style="color: rgba(0,0,0,0.45)">
|
||
<X :size="18" />
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Dialog Body -->
|
||
<div class="p-6">
|
||
<!-- Step 1: Download Template -->
|
||
<div class="mb-6">
|
||
<div class="text-sm font-medium mb-2">第一步:下载导入模板</div>
|
||
<div class="p-4 rounded-lg flex items-center justify-between" style="background-color: #FAFAFA; border: 1px solid #F0F0F0">
|
||
<div class="flex items-center gap-3">
|
||
<FileSpreadsheet :size="24" style="color: #52C41A" />
|
||
<div>
|
||
<div class="text-sm">BOM导入模板.xlsx</div>
|
||
<div class="text-xs" style="color: rgba(0,0,0,0.45)">包含物料编码、物料名称、SN号、规格型号等字段</div>
|
||
</div>
|
||
</div>
|
||
<button class="px-3 py-1.5 rounded text-sm flex items-center gap-1" style="border: 1px solid #4a7c59; color: #4a7c59">
|
||
<Download :size="14" />
|
||
下载模板
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 2: Upload File -->
|
||
<div class="mb-6">
|
||
<div class="text-sm font-medium mb-2">第二步:上传Excel文件</div>
|
||
<div
|
||
class="p-8 rounded-lg text-center cursor-pointer transition-colors"
|
||
:style="{
|
||
border: importFile ? '2px solid #52C41A' : '2px dashed #D9D9D9',
|
||
backgroundColor: importFile ? '#F6FFED' : '#FAFAFA',
|
||
}"
|
||
@click="($refs.fileInput as HTMLInputElement)?.click()"
|
||
>
|
||
<input ref="fileInput" type="file" accept=".xlsx,.xls,.csv" class="hidden" @change="onFileChange" />
|
||
<template v-if="importFile">
|
||
<FileSpreadsheet :size="32" style="color: #52C41A; margin: 0 auto 8px" />
|
||
<div class="text-sm" style="color: #52C41A">{{ importFile.name }}</div>
|
||
<div class="text-xs mt-1" style="color: rgba(0,0,0,0.45)">点击重新选择文件</div>
|
||
</template>
|
||
<template v-else>
|
||
<Upload :size="32" style="color: #D9D9D9; margin: 0 auto 8px" />
|
||
<div class="text-sm" style="color: rgba(0,0,0,0.65)">点击或拖拽文件到此处上传</div>
|
||
<div class="text-xs mt-1" style="color: rgba(0,0,0,0.45)">支持 .xlsx、.xls、.csv 格式</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tips -->
|
||
<div class="p-3 rounded text-xs" style="background-color: #FFFBE6; border: 1px solid #FFE58F; color: #D46B08">
|
||
提示:请确保Excel文件格式与模板一致,物料编码和SN号为必填字段。导入后可在BOM清单中编辑。
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Dialog Footer -->
|
||
<div class="flex items-center justify-end gap-3 p-5 border-t" style="border-color: #F0F0F0">
|
||
<button class="px-4 py-2 rounded text-sm" style="border: 1px solid #D9D9D9; color: rgba(0,0,0,0.85)" @click="showImportDialog = false; importFile = null">取消</button>
|
||
<button
|
||
class="px-4 py-2 rounded text-white text-sm"
|
||
:style="{ backgroundColor: importFile ? '#4a7c59' : '#D9D9D9' }"
|
||
:disabled="!importFile"
|
||
@click="showImportDialog = false; importFile = null"
|
||
>确认导入</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|