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
231 lines
6.6 KiB
|
2 months ago
|
<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>
|