feat: 将产品图/说明书备注字段从JSON数组中分离为独立数据库列
- 数据库新增 product_image_remark 和 manual_link_remark 两个TEXT列 - 备注文字不再与上传文件URL混存在 generalImage/generalManual JSON数组中 - 前端输入框改为textarea,绑定独立的备注字段 - 修复 handlePasteLink 忽略field参数的bug - 新增 isInternalFile 辅助函数,用于区分上传文件与纯文本 - 同步修改 list.vue 和 buyOdoo.vue 两个页面
This commit is contained in:
@ -29,6 +29,10 @@ class MaterialBase(db.Model):
|
|||||||
manual_link = db.Column(db.Text, comment='通用说明书')
|
manual_link = db.Column(db.Text, comment='通用说明书')
|
||||||
product_image = db.Column(db.Text, comment='通用产品图')
|
product_image = db.Column(db.Text, comment='通用产品图')
|
||||||
|
|
||||||
|
# 备注字段(纯文本,与文件 URL 分离存储)
|
||||||
|
product_image_remark = db.Column(db.Text, default='', comment='产品图备注')
|
||||||
|
manual_link_remark = db.Column(db.Text, default='', comment='说明书备注')
|
||||||
|
|
||||||
# 启用状态
|
# 启用状态
|
||||||
is_enabled = db.Column(db.Boolean, default=True, comment='是否启用')
|
is_enabled = db.Column(db.Boolean, default=True, comment='是否启用')
|
||||||
|
|
||||||
@ -86,6 +90,8 @@ class MaterialBase(db.Model):
|
|||||||
'visibilityLevel': self.visibility_level,
|
'visibilityLevel': self.visibility_level,
|
||||||
'generalManual': parse_list(self.manual_link),
|
'generalManual': parse_list(self.manual_link),
|
||||||
'generalImage': parse_list(self.product_image),
|
'generalImage': parse_list(self.product_image),
|
||||||
|
'productImageRemark': self.product_image_remark or '',
|
||||||
|
'manualLinkRemark': self.manual_link_remark or '',
|
||||||
# 【核心修改】:直接返回布尔值,不再转成 1 或 0
|
# 【核心修改】:直接返回布尔值,不再转成 1 或 0
|
||||||
'isEnabled': bool(self.is_enabled),
|
'isEnabled': bool(self.is_enabled),
|
||||||
# 强制质检标记
|
# 强制质检标记
|
||||||
|
|||||||
@ -580,6 +580,8 @@ class MaterialBaseService:
|
|||||||
visibility_level=data.get('visibilityLevel'),
|
visibility_level=data.get('visibilityLevel'),
|
||||||
manual_link=json.dumps(data.get('generalManual', [])),
|
manual_link=json.dumps(data.get('generalManual', [])),
|
||||||
product_image=json.dumps(data.get('generalImage', [])),
|
product_image=json.dumps(data.get('generalImage', [])),
|
||||||
|
product_image_remark=data.get('productImageRemark', ''),
|
||||||
|
manual_link_remark=data.get('manualLinkRemark', ''),
|
||||||
is_enabled=is_enabled_val
|
is_enabled=is_enabled_val
|
||||||
)
|
)
|
||||||
db.session.add(new_material)
|
db.session.add(new_material)
|
||||||
@ -623,6 +625,9 @@ class MaterialBaseService:
|
|||||||
if 'unit' in data: material.unit = data['unit']
|
if 'unit' in data: material.unit = data['unit']
|
||||||
if 'visibilityLevel' in data: material.visibility_level = data['visibilityLevel']
|
if 'visibilityLevel' in data: material.visibility_level = data['visibilityLevel']
|
||||||
|
|
||||||
|
if 'productImageRemark' in data: material.product_image_remark = data['productImageRemark']
|
||||||
|
if 'manualLinkRemark' in data: material.manual_link_remark = data['manualLinkRemark']
|
||||||
|
|
||||||
if 'generalManual' in data:
|
if 'generalManual' in data:
|
||||||
material.manual_link = json.dumps(data['generalManual'])
|
material.manual_link = json.dumps(data['generalManual'])
|
||||||
if 'generalImage' in data:
|
if 'generalImage' in data:
|
||||||
|
|||||||
@ -510,13 +510,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="imageExternalUrl"
|
v-model="form.productImageRemark"
|
||||||
placeholder="如有外部图片链接,请在此输入"
|
type="textarea"
|
||||||
|
:rows="1"
|
||||||
|
placeholder="请输入产品图备注信息"
|
||||||
style="margin-top: 8px;"
|
style="margin-top: 8px;"
|
||||||
clearable
|
clearable
|
||||||
>
|
/>
|
||||||
<template #prefix><el-icon><Link /></el-icon></template>
|
|
||||||
</el-input>
|
|
||||||
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -564,13 +564,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="manualExternalUrl"
|
v-model="form.manualLinkRemark"
|
||||||
placeholder="如有外部说明书链接,请在此输入"
|
type="textarea"
|
||||||
|
:rows="1"
|
||||||
|
placeholder="请输入说明书备注信息"
|
||||||
style="margin-top: 8px;"
|
style="margin-top: 8px;"
|
||||||
clearable
|
clearable
|
||||||
>
|
/>
|
||||||
<template #prefix><el-icon><Link /></el-icon></template>
|
|
||||||
</el-input>
|
|
||||||
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -674,7 +674,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
|
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
|
||||||
import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Link, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture, FolderOpened } from '@element-plus/icons-vue';
|
import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture, FolderOpened } from '@element-plus/icons-vue';
|
||||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
import type { FormInstance, FormRules } from 'element-plus';
|
||||||
import { useUserStore } from '@/stores/user';
|
import { useUserStore } from '@/stores/user';
|
||||||
@ -786,8 +786,6 @@ const operatorOptions = ref([
|
|||||||
|
|
||||||
const fileListImage = ref<any[]>([]);
|
const fileListImage = ref<any[]>([]);
|
||||||
const fileListManual = ref<any[]>([]);
|
const fileListManual = ref<any[]>([]);
|
||||||
const imageExternalUrl = ref('');
|
|
||||||
const manualExternalUrl = ref('');
|
|
||||||
const dialogVisibleImage = ref(false);
|
const dialogVisibleImage = ref(false);
|
||||||
const dialogImageUrl = ref('');
|
const dialogImageUrl = ref('');
|
||||||
const cameraDialogVisible = ref(false);
|
const cameraDialogVisible = ref(false);
|
||||||
@ -1025,7 +1023,8 @@ const dialog = reactive({ visible: false, title: '' });
|
|||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const initForm = {
|
const initForm = {
|
||||||
id: undefined, companyName: '', name: '', commonName: '', category: '', type: '', spec: '', unit: '',
|
id: undefined, companyName: '', name: '', commonName: '', category: '', type: '', spec: '', unit: '',
|
||||||
visibilityLevel: 0, generalManual: [] as string[], generalImage: [] as string[], isEnabled: true
|
visibilityLevel: 0, generalManual: [] as string[], generalImage: [] as string[], isEnabled: true,
|
||||||
|
productImageRemark: '', manualLinkRemark: ''
|
||||||
};
|
};
|
||||||
const form = ref({...initForm});
|
const form = ref({...initForm});
|
||||||
|
|
||||||
@ -1176,13 +1175,12 @@ const handleEdit = (row: MaterialBaseVO) => {
|
|||||||
} else { tempCategoryPrefix.value = []; tempCategorySuffix.value = ''; }
|
} else { tempCategoryPrefix.value = []; tempCategorySuffix.value = ''; }
|
||||||
|
|
||||||
const images = row.generalImage || []; const manuals = row.generalManual || [];
|
const images = row.generalImage || []; const manuals = row.generalManual || [];
|
||||||
const imgFiles = images.filter(u => !isExternalLink(u)); const imgLinks = images.filter(u => isExternalLink(u));
|
// 只显示真正的上传文件,备注字段已由 Object.assign 自动回显
|
||||||
const manualFiles = manuals.filter(u => !isExternalLink(u)); const manualLinks = manuals.filter(u => isExternalLink(u));
|
const imgFiles = images.filter(u => isInternalFile(u));
|
||||||
|
const manualFiles = manuals.filter(u => isInternalFile(u));
|
||||||
|
|
||||||
fileListImage.value = imgFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
fileListImage.value = imgFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
||||||
imageExternalUrl.value = imgLinks.length > 0 ? imgLinks[0] : '';
|
|
||||||
fileListManual.value = manualFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
fileListManual.value = manualFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
||||||
manualExternalUrl.value = manualLinks.length > 0 ? manualLinks[0] : '';
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1210,7 +1208,7 @@ const isArraysEqual = (a: any[], b: any[]): boolean => {
|
|||||||
|
|
||||||
const buildPartialPayload = (current: any, original: any): any => {
|
const buildPartialPayload = (current: any, original: any): any => {
|
||||||
const payload: any = { id: current.id };
|
const payload: any = { id: current.id };
|
||||||
const compareFields = ['name', 'commonName', 'category', 'type', 'spec', 'unit', 'visibilityLevel', 'isEnabled', 'isInspectionRequired', 'generalImage', 'generalManual', 'companyName'];
|
const compareFields = ['name', 'commonName', 'category', 'type', 'spec', 'unit', 'visibilityLevel', 'isEnabled', 'isInspectionRequired', 'generalImage', 'generalManual', 'companyName', 'productImageRemark', 'manualLinkRemark'];
|
||||||
for (const key of compareFields) {
|
for (const key of compareFields) {
|
||||||
const currentVal = current[key]; const originalVal = original[key];
|
const currentVal = current[key]; const originalVal = original[key];
|
||||||
if (Array.isArray(currentVal) && Array.isArray(originalVal)) { if (!isArraysEqual(currentVal, originalVal)) payload[key] = currentVal; }
|
if (Array.isArray(currentVal) && Array.isArray(originalVal)) { if (!isArraysEqual(currentVal, originalVal)) payload[key] = currentVal; }
|
||||||
@ -1228,10 +1226,9 @@ const submitForm = async () => {
|
|||||||
const isDuplicate = await checkDuplicate(form.value.name, form.value.spec);
|
const isDuplicate = await checkDuplicate(form.value.name, form.value.spec);
|
||||||
if (isDuplicate) { submitLoading.value = false; return; }
|
if (isDuplicate) { submitLoading.value = false; return; }
|
||||||
|
|
||||||
const finalImageList = form.value.generalImage.filter(item => !isExternalLink(item));
|
// 只保留上传文件,过滤掉旧数据中混入的备注文字和外部链接
|
||||||
if (imageExternalUrl.value) finalImageList.push(imageExternalUrl.value);
|
const finalImageList = form.value.generalImage.filter(item => isInternalFile(item));
|
||||||
const finalManualList = form.value.generalManual.filter(item => !isExternalLink(item));
|
const finalManualList = form.value.generalManual.filter(item => isInternalFile(item));
|
||||||
if (manualExternalUrl.value) finalManualList.push(manualExternalUrl.value);
|
|
||||||
|
|
||||||
const prefixStr = tempCategoryPrefix.value.join('/'); const suffixStr = tempCategorySuffix.value.trim();
|
const prefixStr = tempCategoryPrefix.value.join('/'); const suffixStr = tempCategorySuffix.value.trim();
|
||||||
let fullCategory = '';
|
let fullCategory = '';
|
||||||
@ -1272,7 +1269,7 @@ const resetForm = () => {
|
|||||||
form.value = JSON.parse(JSON.stringify(initForm));
|
form.value = JSON.parse(JSON.stringify(initForm));
|
||||||
fileListImage.value = []; fileListManual.value = [];
|
fileListImage.value = []; fileListManual.value = [];
|
||||||
tempCategoryPrefix.value = []; tempCategorySuffix.value = '';
|
tempCategoryPrefix.value = []; tempCategorySuffix.value = '';
|
||||||
imageExternalUrl.value = ''; manualExternalUrl.value = ''; originalForm.value = null;
|
originalForm.value = null;
|
||||||
if (formRef.value) formRef.value.resetFields();
|
if (formRef.value) formRef.value.resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1337,6 +1334,7 @@ const tableRowClassName = ({ row }: { row: MaterialBaseVO }) => {
|
|||||||
|
|
||||||
const getImageUrl = (url: string) => { return !url ? '' : (url.startsWith('http') ? url : url) }
|
const getImageUrl = (url: string) => { return !url ? '' : (url.startsWith('http') ? url : url) }
|
||||||
const isExternalLink = (str: string) => { return str && (str.startsWith('http://') || str.startsWith('https://')) && !str.includes('/api/v1/common/files') }
|
const isExternalLink = (str: string) => { return str && (str.startsWith('http://') || str.startsWith('https://')) && !str.includes('/api/v1/common/files') }
|
||||||
|
const isInternalFile = (str: string) => { return str && (str.includes('/api/v1/common/files') || /\.(jpg|jpeg|png|gif|webp|bmp|pdf|zip|rar|7z)$/i.test(str)) }
|
||||||
const isImageFile = (url: string) => { return /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(url) }
|
const isImageFile = (url: string) => { return /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(url) }
|
||||||
const isCompressedFile = (url: string) => { return /\.(zip|rar|7z)$/i.test(url) }
|
const isCompressedFile = (url: string) => { return /\.(zip|rar|7z)$/i.test(url) }
|
||||||
const getImagesOnly = (list: string[]) => { return !list ? [] : list.filter(item => !isExternalLink(item) && isImageFile(item)) }
|
const getImagesOnly = (list: string[]) => { return !list ? [] : list.filter(item => !isExternalLink(item) && isImageFile(item)) }
|
||||||
@ -1378,9 +1376,9 @@ const customUpload = async (options: any, targetField: 'generalImage' | 'general
|
|||||||
} catch (e) { ElMessage.error('网络错误'); onError(e) } finally { isUploading.value = false }
|
} catch (e) { ElMessage.error('网络错误'); onError(e) } finally { isUploading.value = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePasteLink = (link: string, field: string) => { imageExternalUrl.value = link }
|
// 粘贴上传处理器(仅处理实际图片文件,不再将链接自动填入备注框)
|
||||||
usePasteUpload(customUpload, 'generalImage', '#upload-generalImage', handlePasteLink)
|
usePasteUpload(customUpload, 'generalImage', '#upload-generalImage')
|
||||||
usePasteUpload(customUpload, 'generalManual', '#upload-generalManual', handlePasteLink)
|
usePasteUpload(customUpload, 'generalManual', '#upload-generalManual')
|
||||||
|
|
||||||
const handleRemoveImage = async (uploadFile: any, targetField: 'generalImage' | 'generalManual') => {
|
const handleRemoveImage = async (uploadFile: any, targetField: 'generalImage' | 'generalManual') => {
|
||||||
const fileName = uploadFile.name || uploadFile.url?.split('/').pop() || '此文件'
|
const fileName = uploadFile.name || uploadFile.url?.split('/').pop() || '此文件'
|
||||||
|
|||||||
@ -505,13 +505,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="imageExternalUrl"
|
v-model="form.productImageRemark"
|
||||||
placeholder="如有外部图片链接,请在此输入"
|
type="textarea"
|
||||||
|
:rows="1"
|
||||||
|
placeholder="请输入产品图备注信息"
|
||||||
style="margin-top: 8px;"
|
style="margin-top: 8px;"
|
||||||
clearable
|
clearable
|
||||||
>
|
/>
|
||||||
<template #prefix><el-icon><Link /></el-icon></template>
|
|
||||||
</el-input>
|
|
||||||
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -559,13 +559,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="manualExternalUrl"
|
v-model="form.manualLinkRemark"
|
||||||
placeholder="如有外部说明书链接,请在此输入"
|
type="textarea"
|
||||||
|
:rows="1"
|
||||||
|
placeholder="请输入说明书备注信息"
|
||||||
style="margin-top: 8px;"
|
style="margin-top: 8px;"
|
||||||
clearable
|
clearable
|
||||||
>
|
/>
|
||||||
<template #prefix><el-icon><Link /></el-icon></template>
|
|
||||||
</el-input>
|
|
||||||
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
<div style="color: #409EFF; font-size: 12px; margin-top: 4px;">支持将鼠标悬停于虚线框内通过 Ctrl+V 粘贴图片快速上传</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -672,7 +672,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
|
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
|
||||||
import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Link, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture } from '@element-plus/icons-vue';
|
import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture } from '@element-plus/icons-vue';
|
||||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
import type { FormInstance, FormRules } from 'element-plus';
|
||||||
import { useUserStore } from '@/stores/user';
|
import { useUserStore } from '@/stores/user';
|
||||||
@ -787,8 +787,6 @@ const operatorOptions = ref([
|
|||||||
// 文件上传相关
|
// 文件上传相关
|
||||||
const fileListImage = ref<any[]>([]);
|
const fileListImage = ref<any[]>([]);
|
||||||
const fileListManual = ref<any[]>([]);
|
const fileListManual = ref<any[]>([]);
|
||||||
const imageExternalUrl = ref('');
|
|
||||||
const manualExternalUrl = ref('');
|
|
||||||
const dialogVisibleImage = ref(false);
|
const dialogVisibleImage = ref(false);
|
||||||
const dialogImageUrl = ref('');
|
const dialogImageUrl = ref('');
|
||||||
const cameraDialogVisible = ref(false);
|
const cameraDialogVisible = ref(false);
|
||||||
@ -1101,7 +1099,9 @@ const initForm = {
|
|||||||
visibilityLevel: 0,
|
visibilityLevel: 0,
|
||||||
generalManual: [] as string[],
|
generalManual: [] as string[],
|
||||||
generalImage: [] as string[],
|
generalImage: [] as string[],
|
||||||
isEnabled: true // 已修改为默认 true
|
isEnabled: true, // 已修改为默认 true
|
||||||
|
productImageRemark: '',
|
||||||
|
manualLinkRemark: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const form = ref({...initForm});
|
const form = ref({...initForm});
|
||||||
@ -1357,16 +1357,12 @@ const handleEdit = (row: MaterialBaseVO) => {
|
|||||||
const images = row.generalImage || [];
|
const images = row.generalImage || [];
|
||||||
const manuals = row.generalManual || [];
|
const manuals = row.generalManual || [];
|
||||||
|
|
||||||
const imgFiles = images.filter(u => !isExternalLink(u));
|
// 只显示真正的上传文件,备注字段已由 Object.assign 自动回显到 form.productImageRemark / form.manualLinkRemark
|
||||||
const imgLinks = images.filter(u => isExternalLink(u));
|
const imgFiles = images.filter(u => isInternalFile(u));
|
||||||
const manualFiles = manuals.filter(u => !isExternalLink(u));
|
const manualFiles = manuals.filter(u => isInternalFile(u));
|
||||||
const manualLinks = manuals.filter(u => isExternalLink(u));
|
|
||||||
|
|
||||||
fileListImage.value = imgFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
fileListImage.value = imgFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
||||||
imageExternalUrl.value = imgLinks.length > 0 ? imgLinks[0] : '';
|
|
||||||
|
|
||||||
fileListManual.value = manualFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
fileListManual.value = manualFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
|
||||||
manualExternalUrl.value = manualLinks.length > 0 ? manualLinks[0] : '';
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1414,7 +1410,7 @@ const isArraysEqual = (a: any[], b: any[]): boolean => {
|
|||||||
|
|
||||||
const buildPartialPayload = (current: any, original: any): any => {
|
const buildPartialPayload = (current: any, original: any): any => {
|
||||||
const payload: any = { id: current.id };
|
const payload: any = { id: current.id };
|
||||||
const compareFields = ['name', 'commonName', 'category', 'type', 'spec', 'unit', 'visibilityLevel', 'isEnabled', 'isInspectionRequired', 'generalImage', 'generalManual', 'companyName'];
|
const compareFields = ['name', 'commonName', 'category', 'type', 'spec', 'unit', 'visibilityLevel', 'isEnabled', 'isInspectionRequired', 'generalImage', 'generalManual', 'companyName', 'productImageRemark', 'manualLinkRemark'];
|
||||||
|
|
||||||
for (const key of compareFields) {
|
for (const key of compareFields) {
|
||||||
const currentVal = current[key];
|
const currentVal = current[key];
|
||||||
@ -1445,11 +1441,9 @@ const submitForm = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalImageList = form.value.generalImage.filter(item => !isExternalLink(item));
|
// 只保留上传文件,过滤掉旧数据中混入的备注文字和外部链接
|
||||||
if (imageExternalUrl.value) finalImageList.push(imageExternalUrl.value);
|
const finalImageList = form.value.generalImage.filter(item => isInternalFile(item));
|
||||||
|
const finalManualList = form.value.generalManual.filter(item => isInternalFile(item));
|
||||||
const finalManualList = form.value.generalManual.filter(item => !isExternalLink(item));
|
|
||||||
if (manualExternalUrl.value) finalManualList.push(manualExternalUrl.value);
|
|
||||||
|
|
||||||
const prefixStr = tempCategoryPrefix.value.join('/');
|
const prefixStr = tempCategoryPrefix.value.join('/');
|
||||||
const suffixStr = tempCategorySuffix.value.trim();
|
const suffixStr = tempCategorySuffix.value.trim();
|
||||||
@ -1535,8 +1529,6 @@ const resetForm = () => {
|
|||||||
tempCategoryPrefix.value = [];
|
tempCategoryPrefix.value = [];
|
||||||
tempCategorySuffix.value = '';
|
tempCategorySuffix.value = '';
|
||||||
|
|
||||||
imageExternalUrl.value = '';
|
|
||||||
manualExternalUrl.value = '';
|
|
||||||
originalForm.value = null;
|
originalForm.value = null;
|
||||||
if (formRef.value) formRef.value.resetFields();
|
if (formRef.value) formRef.value.resetFields();
|
||||||
};
|
};
|
||||||
@ -1690,6 +1682,7 @@ const tableRowClassName = ({ row }: { row: MaterialBaseVO }) => {
|
|||||||
|
|
||||||
const getImageUrl = (url: string) => { return !url ? '' : (url.startsWith('http') ? url : url) }
|
const getImageUrl = (url: string) => { return !url ? '' : (url.startsWith('http') ? url : url) }
|
||||||
const isExternalLink = (str: string) => { return str && (str.startsWith('http://') || str.startsWith('https://')) && !str.includes('/api/v1/common/files') }
|
const isExternalLink = (str: string) => { return str && (str.startsWith('http://') || str.startsWith('https://')) && !str.includes('/api/v1/common/files') }
|
||||||
|
const isInternalFile = (str: string) => { return str && (str.includes('/api/v1/common/files') || /\.(jpg|jpeg|png|gif|webp|bmp|pdf|zip|rar|7z)$/i.test(str)) }
|
||||||
const isImageFile = (url: string) => { return /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(url) }
|
const isImageFile = (url: string) => { return /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(url) }
|
||||||
const isCompressedFile = (url: string) => { return /\.(zip|rar|7z)$/i.test(url) }
|
const isCompressedFile = (url: string) => { return /\.(zip|rar|7z)$/i.test(url) }
|
||||||
const getImagesOnly = (list: string[]) => { return !list ? [] : list.filter(item => !isExternalLink(item) && isImageFile(item)) }
|
const getImagesOnly = (list: string[]) => { return !list ? [] : list.filter(item => !isExternalLink(item) && isImageFile(item)) }
|
||||||
@ -1766,12 +1759,9 @@ const customUpload = async (options: any, targetField: 'generalImage' | 'general
|
|||||||
finally { isUploading.value = false }
|
finally { isUploading.value = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 粘贴上传处理器(PC 端:鼠标悬停 + Ctrl+V 直接粘贴图片)
|
// 粘贴上传处理器(仅处理实际图片文件,不再将链接自动填入备注框)
|
||||||
const handlePasteLink = (link: string, field: string) => {
|
usePasteUpload(customUpload, 'generalImage', '#upload-generalImage')
|
||||||
imageExternalUrl.value = link
|
usePasteUpload(customUpload, 'generalManual', '#upload-generalManual')
|
||||||
}
|
|
||||||
usePasteUpload(customUpload, 'generalImage', '#upload-generalImage', handlePasteLink)
|
|
||||||
usePasteUpload(customUpload, 'generalManual', '#upload-generalManual', handlePasteLink)
|
|
||||||
|
|
||||||
const handleRemoveImage = async (uploadFile: any, targetField: 'generalImage' | 'generalManual') => {
|
const handleRemoveImage = async (uploadFile: any, targetField: 'generalImage' | 'generalManual') => {
|
||||||
const fileName = uploadFile.name || uploadFile.url?.split('/').pop() || '此文件'
|
const fileName = uploadFile.name || uploadFile.url?.split('/').pop() || '此文件'
|
||||||
|
|||||||
Reference in New Issue
Block a user