|
@@ -153,6 +153,29 @@
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
+ <!-- 设备铭牌照片(必填,单张) -->
|
|
|
|
|
+ <el-form-item label="设备铭牌照片" prop="nameplateUrl">
|
|
|
|
|
+ <div class="upload-row">
|
|
|
|
|
+ <el-button type="primary" plain @click="triggerNameplateUpload">选择文件</el-button>
|
|
|
|
|
+ <span class="upload-tip">{{ nameplatePhotoPreview ? '已选择 1 个文件' : '未选择任何文件' }}</span>
|
|
|
|
|
+ <el-button v-if="nameplatePhotoPreview" link type="danger" style="margin-left: 8px" @click="clearNameplatePhoto">清空</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <input
|
|
|
|
|
+ ref="nameplatePhotoInputRef"
|
|
|
|
|
+ type="file"
|
|
|
|
|
+ accept=".jpg,.jpeg,.png"
|
|
|
|
|
+ style="display: none"
|
|
|
|
|
+ @change="onNameplatePhotoInputChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div v-if="nameplatePhotoPreview" class="photo-preview-list">
|
|
|
|
|
+ <div class="photo-thumb">
|
|
|
|
|
+ <el-image :src="nameplatePhotoPreview" :preview-src-list="[nameplatePhotoPreview]" :initial-index="0" fit="cover" />
|
|
|
|
|
+ <el-icon class="photo-remove" @click="removeNameplatePhoto"><CircleCloseFilled /></el-icon>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="el-upload__tip">支持 JPG、PNG 格式,大小不超过 5MB(必填)</div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
<el-form-item label="设备照片">
|
|
<el-form-item label="设备照片">
|
|
|
<div class="upload-row">
|
|
<div class="upload-row">
|
|
|
<el-button type="primary" plain @click="triggerEquipmentUpload">选择文件</el-button>
|
|
<el-button type="primary" plain @click="triggerEquipmentUpload">选择文件</el-button>
|
|
@@ -419,6 +442,10 @@ const equipmentPhotoList = ref<any[]>([]);
|
|
|
const equipmentPhotoPreview = ref<string[]>([]);
|
|
const equipmentPhotoPreview = ref<string[]>([]);
|
|
|
const equipmentPhotoInputRef = ref<HTMLInputElement>();
|
|
const equipmentPhotoInputRef = ref<HTMLInputElement>();
|
|
|
|
|
|
|
|
|
|
+// 设备铭牌照片(必填,单张)
|
|
|
|
|
+const nameplatePhotoPreview = ref<string>('');
|
|
|
|
|
+const nameplatePhotoInputRef = ref<HTMLInputElement>();
|
|
|
|
|
+
|
|
|
// 维护照片队列(自管文件)
|
|
// 维护照片队列(自管文件)
|
|
|
const maintainPreviewPhotos = ref<string[]>([]);
|
|
const maintainPreviewPhotos = ref<string[]>([]);
|
|
|
const maintainPhotoInputRef = ref<HTMLInputElement>();
|
|
const maintainPhotoInputRef = ref<HTMLInputElement>();
|
|
@@ -434,7 +461,9 @@ const data = reactive<any>({
|
|
|
equipmentName: '',
|
|
equipmentName: '',
|
|
|
equipmentType: '',
|
|
equipmentType: '',
|
|
|
location: '',
|
|
location: '',
|
|
|
- photoList: []
|
|
|
|
|
|
|
+ photoList: [],
|
|
|
|
|
+ nameplateUrl: '',
|
|
|
|
|
+ nameplateName: ''
|
|
|
} as any,
|
|
} as any,
|
|
|
queryParams: {
|
|
queryParams: {
|
|
|
pageNum: 1,
|
|
pageNum: 1,
|
|
@@ -449,7 +478,20 @@ const data = reactive<any>({
|
|
|
equipmentCode: [{ required: true, message: '设备编号不能为空', trigger: 'blur' }],
|
|
equipmentCode: [{ required: true, message: '设备编号不能为空', trigger: 'blur' }],
|
|
|
equipmentName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
|
|
equipmentName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
|
|
|
equipmentType: [{ required: true, message: '请选择设备类型', trigger: 'change' }],
|
|
equipmentType: [{ required: true, message: '请选择设备类型', trigger: 'change' }],
|
|
|
- location: [{ required: true, message: '请输入安装位置', trigger: 'blur' }]
|
|
|
|
|
|
|
+ location: [{ required: true, message: '请输入安装位置', trigger: 'blur' }],
|
|
|
|
|
+ // 设备铭牌照片:必填(新增校验,失败时弹错)
|
|
|
|
|
+ nameplateUrl: [
|
|
|
|
|
+ {
|
|
|
|
|
+ validator: (_rule: any, value: any, callback: any) => {
|
|
|
|
|
+ if (!value) {
|
|
|
|
|
+ callback(new Error('请上传设备铭牌照片'));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ callback();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ trigger: 'change'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -534,7 +576,7 @@ const recordEquipmentName = ref('');
|
|
|
|
|
|
|
|
const mapDictData = (list: DictDataVO[]) => {
|
|
const mapDictData = (list: DictDataVO[]) => {
|
|
|
return (list || [])
|
|
return (list || [])
|
|
|
- .filter((d) => d.status === '0' || d.status === undefined)
|
|
|
|
|
|
|
+ .filter((d: any) => d.status === '0' || d.status === undefined)
|
|
|
.sort((a, b) => (a.dictSort || 0) - (b.dictSort || 0))
|
|
.sort((a, b) => (a.dictSort || 0) - (b.dictSort || 0))
|
|
|
.map((d) => ({ label: d.dictLabel, value: d.dictValue }));
|
|
.map((d) => ({ label: d.dictLabel, value: d.dictValue }));
|
|
|
};
|
|
};
|
|
@@ -639,6 +681,8 @@ const handleUpdate = async (row: RiskSpecialEquipmentVo) => {
|
|
|
const photos = parsePhotoList(form.value.photoList);
|
|
const photos = parsePhotoList(form.value.photoList);
|
|
|
equipmentPhotoPreview.value = [...photos];
|
|
equipmentPhotoPreview.value = [...photos];
|
|
|
equipmentPhotoList.value = [];
|
|
equipmentPhotoList.value = [];
|
|
|
|
|
+ // 回填设备铭牌照片(编辑场景)
|
|
|
|
|
+ nameplatePhotoPreview.value = form.value.nameplateUrl || '';
|
|
|
dialog.visible = true;
|
|
dialog.visible = true;
|
|
|
dialog.title = '编辑特种设备';
|
|
dialog.title = '编辑特种设备';
|
|
|
};
|
|
};
|
|
@@ -701,6 +745,58 @@ const clearEquipmentPhotos = () => {
|
|
|
equipmentPhotoPreview.value = [];
|
|
equipmentPhotoPreview.value = [];
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// ============ 设备铭牌照片上传(必填,单张) ============
|
|
|
|
|
+const triggerNameplateUpload = () => {
|
|
|
|
|
+ nameplatePhotoInputRef.value?.click();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const onNameplatePhotoInputChange = async (e: Event) => {
|
|
|
|
|
+ const input = e.target as HTMLInputElement;
|
|
|
|
|
+ const files = Array.from(input.files || []);
|
|
|
|
|
+ if (files.length === 0) return;
|
|
|
|
|
+ const file = files[0];
|
|
|
|
|
+ if (!['image/jpeg', 'image/png', 'image/jpg'].includes(file.type)) {
|
|
|
|
|
+ ElMessage.error(`文件 ${file.name} 格式不支持,仅允许 JPG/PNG`);
|
|
|
|
|
+ input.value = '';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (file.size / 1024 / 1024 >= 5) {
|
|
|
|
|
+ ElMessage.error(`文件 ${file.name} 超过 5MB`);
|
|
|
|
|
+ input.value = '';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ await uploadNameplatePhoto(file);
|
|
|
|
|
+ input.value = '';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const uploadNameplatePhoto = async (file: File) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res: any = await uploadFile(file);
|
|
|
|
|
+ const url: string | undefined = res?.url || res?.data?.url;
|
|
|
|
|
+ const originalName: string = res?.data?.originalName || file.name;
|
|
|
|
|
+ if (url) {
|
|
|
|
|
+ nameplatePhotoPreview.value = url;
|
|
|
|
|
+ form.value.nameplateUrl = url;
|
|
|
|
|
+ form.value.nameplateName = originalName;
|
|
|
|
|
+ ElMessage.success(`${file.name} 上传成功`);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage.error(`${file.name} 上传失败`);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e: any) {
|
|
|
|
|
+ ElMessage.error(`${file.name} 上传失败: ${e?.message || '网络异常'}`);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const removeNameplatePhoto = () => {
|
|
|
|
|
+ nameplatePhotoPreview.value = '';
|
|
|
|
|
+ form.value.nameplateUrl = '';
|
|
|
|
|
+ form.value.nameplateName = '';
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const clearNameplatePhoto = () => {
|
|
|
|
|
+ removeNameplatePhoto();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// ============ 维护照片上传 ============
|
|
// ============ 维护照片上传 ============
|
|
|
const triggerMaintainUpload = () => {
|
|
const triggerMaintainUpload = () => {
|
|
|
maintainPhotoInputRef.value?.click();
|
|
maintainPhotoInputRef.value?.click();
|
|
@@ -776,10 +872,13 @@ const reset = () => {
|
|
|
equipmentName: '',
|
|
equipmentName: '',
|
|
|
equipmentType: '',
|
|
equipmentType: '',
|
|
|
location: '',
|
|
location: '',
|
|
|
- photoList: []
|
|
|
|
|
|
|
+ photoList: [],
|
|
|
|
|
+ nameplateUrl: '',
|
|
|
|
|
+ nameplateName: ''
|
|
|
} as any;
|
|
} as any;
|
|
|
equipmentPhotoPreview.value = [];
|
|
equipmentPhotoPreview.value = [];
|
|
|
equipmentPhotoList.value = [];
|
|
equipmentPhotoList.value = [];
|
|
|
|
|
+ nameplatePhotoPreview.value = '';
|
|
|
formRef.value?.resetFields();
|
|
formRef.value?.resetFields();
|
|
|
};
|
|
};
|
|
|
|
|
|