工程管理
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

231 lines
6.6 KiB

<template>
<div class="step-device-category h-full flex flex-col">
<div class="mb-4 flex justify-end">
<el-button type="primary" @click="handleAdd">新增设备类别</el-button>
</div>
<div class="flex-1 overflow-y-auto">
<div class="grid grid-cols-[repeat(auto-fill,minmax(300px,1fr))] gap-4">
<div
v-for="(item, index) in modelValue"
:key="index"
class="bg-white rounded-lg shadow-sm p-4 border border-gray-200 hover:shadow-md transition-all duration-300"
>
<div class="flex justify-between items-start mb-3">
<div class="flex-1 min-w-0 flex items-center justify-between">
<h3
class="font-bold text-lg text-gray-900 truncate mb-1"
:title="item.name"
>
{{ item.name }}
</h3>
<el-tag v-if="item.fileName" size="small" type="success" effect="light">
已上传
</el-tag>
<el-tag v-else size="small" type="info" effect="light"> 未上传 </el-tag>
</div>
</div>
<!-- Upload Area or File Display -->
<div>
<div class="space-y-2">
<div class="text-sm">
<div class="flex items-center">
<div class="flex-1 flex gap-6">
<p class="text-gray-500 mb-0.5">点表文件:</p>
<p
class="text-sm font-medium text-gray-900 truncate"
:title="item.fileName"
>
{{ item.fileName }}
</p>
</div>
</div>
</div>
</div>
<div class="upload-area">
<el-upload
class="upload-demo"
drag
:auto-upload="false"
:limit="1"
:show-file-list="false"
:on-change="file => handleFileChange(file, index)"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
拖拽文件到此处<br /><em>点击{{ item.fileName ? '重新' : '' }}上传</em>
</div>
</el-upload>
</div>
</div>
<div class="flex justify-end pt-3 border-t border-gray-100">
<div class="flex gap-2">
<el-button type="primary" size="small" text @click="handleEdit(index)">
编辑
</el-button>
<el-button type="danger" size="small" text @click="handleDelete(index)">
删除
</el-button>
</div>
</div>
</div>
</div>
<el-empty
v-if="modelValue.length === 0"
description="暂无设备类别,请点击上方按钮添加"
/>
</div>
<!-- Create/Edit Category Dialog -->
<el-dialog
v-model="dialogVisible"
:title="editingIndex !== null ? '编辑设备类别' : '新增设备类别'"
width="500px"
append-to-body
destroy-on-close
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="类别名称" prop="name">
<el-input v-model="form.name" placeholder="请输入类别名称" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { UploadFilled } from '@element-plus/icons-vue'
import type { IDeviceCategory } from '@/api/module/device/index.d'
import type { FormInstance, FormRules, UploadFile } from 'element-plus'
import { ElMessage } from 'element-plus'
const props = defineProps<{
modelValue: IDeviceCategory[]
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: IDeviceCategory[]): void
}>()
const dialogVisible = ref(false)
const formRef = ref<FormInstance>()
const editingIndex = ref<number | null>(null)
const form = reactive<IDeviceCategory>({
name: '',
fileName: '',
})
const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入类别名称', trigger: 'blur' }],
})
const handleAdd = () => {
editingIndex.value = null
form.name = ''
form.fileName = ''
dialogVisible.value = true
}
const handleEdit = (index: number) => {
editingIndex.value = index
const item = props.modelValue[index]
form.name = item.name
form.fileName = item.fileName || ''
dialogVisible.value = true
}
const handleDelete = (index: number) => {
const newList = [...props.modelValue]
newList.splice(index, 1)
emit('update:modelValue', newList)
}
const handleSave = async () => {
if (!formRef.value) return
await formRef.value.validate(valid => {
if (valid) {
const newList = [...props.modelValue]
if (editingIndex.value !== null) {
// Edit mode - keep existing fileName
newList[editingIndex.value] = {
name: form.name,
fileName: newList[editingIndex.value].fileName || '',
}
} else {
// Add mode - no fileName yet
newList.push({
name: form.name,
fileName: '',
})
}
emit('update:modelValue', newList)
dialogVisible.value = false
}
})
}
const handleFileChange = async (file: UploadFile, index: number) => {
if (!file.raw) return
try {
// Mock: extract filename from the uploaded file
const fileName = file.name
// Simulate upload delay
await new Promise(resolve => setTimeout(resolve, 500))
// Update the category with the filename
const newList = [...props.modelValue]
newList[index] = {
...newList[index],
fileName: fileName,
}
emit('update:modelValue', newList)
ElMessage.success('文件上传成功')
} catch (error) {
ElMessage.error('文件上传失败')
}
}
const handleReupload = (index: number) => {
// Clear the filename to show upload area again
const newList = [...props.modelValue]
newList[index] = {
...newList[index],
fileName: '',
}
emit('update:modelValue', newList)
}
</script>
<style scoped>
.upload-demo {
width: 100%;
}
:deep(.el-upload-dragger) {
padding: 20px;
}
:deep(.el-icon--upload) {
font-size: 40px;
color: #409eff;
margin-bottom: 8px;
}
:deep(.el-upload__text) {
font-size: 14px;
line-height: 1.5;
}
</style>