From 025b619a356e575e7efecc937f9e24a6b56497df Mon Sep 17 00:00:00 2001 From: hwj Date: Fri, 12 Jun 2026 18:31:32 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=A8=A1=E5=85=B7=E7=BB=84-?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E7=BA=B8=E3=80=81=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=89=8B=E5=86=8C=E3=80=81=E6=93=8D=E4=BD=9C=E8=A7=86=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/erp/mold/index.ts | 3 + src/locales/en.ts | 10 +++ src/locales/zh-CN.ts | 10 +++ src/views/erp/mold/MoldBrandForm.vue | 75 +++++++++++++++++++++++ src/views/erp/mold/detail/brand.vue | 92 ++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+) diff --git a/src/api/erp/mold/index.ts b/src/api/erp/mold/index.ts index 56c7aba4..3280cab1 100644 --- a/src/api/erp/mold/index.ts +++ b/src/api/erp/mold/index.ts @@ -11,6 +11,9 @@ export interface MoldBrandVO { productIds?: Array | string // 产品ID列表 products?: any[] images?: string // 图片 + drawings?: string // 图纸 + operationManual?: string // 操作手册 + operationVideo?: string // 操作视频 version?: string // 版本 status?: number // 状态 currentPosition?: string // 当前位置 diff --git a/src/locales/en.ts b/src/locales/en.ts index 8158f4cd..49e6628f 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -2713,6 +2713,9 @@ export default { tabRepair: 'Repair Records', tabMaintain: 'Maintenance Records', tabInstall: 'Installation Records', + tabDrawings: 'Drawings', + tabOperationManual: 'Operation Manual', + tabOperationVideo: 'Operation Video', time: 'Time', startTime: 'Start Time', endTime: 'End Time', @@ -2726,6 +2729,9 @@ export default { images: 'Images', remark: 'Remark', operator: 'Operator', + drawings: 'Drawings', + operationManual: 'Operation Manual', + operationVideo: 'Operation Video', projectContent: 'Project Content', repairResult: 'Repair Result', finishDate: 'Finish Date', @@ -2756,6 +2762,7 @@ export default { creatorName: 'Operator', createTime: 'Operation Time', noInstallRecords: 'No installation records', + noRecords: 'No data', pending: 'Pending', pass: 'Pass', fail: 'Fail', @@ -2775,6 +2782,9 @@ export default { moldSize: 'Cavity Number', useTime: 'Expected Life', images: 'Image', + drawings: 'Drawings', + operationManual: 'Operation Manual', + operationVideo: 'Operation Video', remark: 'Remark', isEnable: 'Is Enable', enable: 'Enable', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 57266c39..1793396d 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -2192,6 +2192,9 @@ export default { tabRepair: '维修记录', tabMaintain: '保养记录', tabInstall: '安装记录', + tabDrawings: '图纸', + tabOperationManual: '操作手册', + tabOperationVideo: '操作视频', // 筛选 time: '时间', startTime: '开始时间', @@ -2207,6 +2210,9 @@ export default { images: '图片', remark: '备注', operator: '操作人', + drawings: '图纸', + operationManual: '操作手册', + operationVideo: '操作视频', // 维修 projectContent: '项目内容', repairResult: '维修结果', @@ -2240,6 +2246,7 @@ export default { creatorName: '操作人', createTime: '操作时间', noInstallRecords: '暂无安装记录', + noRecords: '暂无数据', // 检测结果 pending: '待检测', pass: '通过', @@ -2260,6 +2267,9 @@ export default { moldSize: '模穴数', useTime: '预期寿命', images: '图片', + drawings: '图纸', + operationManual: '操作手册', + operationVideo: '操作视频', inputValue: '输入值', remark: '备注', isEnable: '是否启用', diff --git a/src/views/erp/mold/MoldBrandForm.vue b/src/views/erp/mold/MoldBrandForm.vue index 7fa1b920..25e0adfe 100644 --- a/src/views/erp/mold/MoldBrandForm.vue +++ b/src/views/erp/mold/MoldBrandForm.vue @@ -61,6 +61,31 @@ + + + + + + + + + + + + + + + @@ -213,6 +238,9 @@ const formData = ref({ productName: '', productIds: [], images: '', + drawings: '', + operationManual: '', + operationVideo: '', status: 0, useTime: 0, maintainType: undefined, @@ -223,6 +251,47 @@ const formData = ref({ isCode: true }) +const manualFileTypes = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt'] +const videoFileTypes = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm'] + +const splitAssetValue = (value: unknown): string[] => { + if (!value) return [] + if (Array.isArray(value)) return value.flatMap((item) => splitAssetValue(item)) + if (typeof value === 'object' && (value as any)?.fileUrl) { + return [String((value as any).fileUrl).trim()].filter(Boolean) + } + const text = String(value).trim() + if (!text) return [] + if (text.startsWith('{') || text.startsWith('[')) { + try { + const parsed = JSON.parse(text) + return splitAssetValue(parsed) + } catch {} + } + return text + .replace(/[`'"]/g, '') + .split(',') + .map((item) => item.trim()) + .filter(Boolean) +} + +const normalizeAssetString = (value: unknown) => splitAssetValue(value).join(',') + +const drawingsValue = computed({ + get: () => splitAssetValue((formData.value as any).drawings), + set: (value: any) => { ;(formData.value as any).drawings = normalizeAssetString(value) } +}) + +const operationManualValue = computed({ + get: () => splitAssetValue((formData.value as any).operationManual), + set: (value: any) => { ;(formData.value as any).operationManual = normalizeAssetString(value) } +}) + +const operationVideoValue = computed({ + get: () => splitAssetValue((formData.value as any).operationVideo), + set: (value: any) => { ;(formData.value as any).operationVideo = normalizeAssetString(value) } +}) + const validateCode = (_rule: any, value: any, callback: any) => { if (Boolean(formData.value.isCode)) { callback() @@ -261,6 +330,9 @@ const resetForm = () => { productName: '', productIds: [], images: '', + drawings: '', + operationManual: '', + operationVideo: '', status: 1, useTime: 0, maintainType: undefined, @@ -383,6 +455,9 @@ const submitForm = async () => { const payload: MoldBrandVO = { ...formData.value, productIds: Array.isArray(formData.value.productIds) ? formData.value.productIds : [], + drawings: normalizeAssetString((formData.value as any).drawings), + operationManual: normalizeAssetString((formData.value as any).operationManual), + operationVideo: normalizeAssetString((formData.value as any).operationVideo), isEnable: Boolean(formData.value.isEnable) } if (formType.value === 'create') { diff --git a/src/views/erp/mold/detail/brand.vue b/src/views/erp/mold/detail/brand.vue index 00c7db97..0991d41d 100644 --- a/src/views/erp/mold/detail/brand.vue +++ b/src/views/erp/mold/detail/brand.vue @@ -303,6 +303,44 @@ @pagination="fetchInstallRecords" /> + + + + + + + + + + + + + + + + + + + + + + + + @@ -362,6 +400,9 @@ const maintainLoading = ref(false) const installLoading = ref(false) const imageList = computed(() => parseImages(detailData.value?.images)) +const drawingRows = computed(() => parseAssetRows(detailData.value?.drawings)) +const operationManualRows = computed(() => parseAssetRows(detailData.value?.operationManual)) +const operationVideoRows = computed(() => parseAssetRows(detailData.value?.operationVideo)) const lifeRate = computed(() => { const raw = detailData.value?.lifeRate ?? detailData.value?.lifeStatus ?? detailData.value?.useRate if (raw === undefined || raw === null || raw === '') return null @@ -398,6 +439,42 @@ const parseImages = (value: any): string[] => { .filter(Boolean) } +const parseAssetUrls = (value: any): string[] => { + if (!value) return [] + if (Array.isArray(value)) return value.flatMap((item) => parseAssetUrls(item)) + if (typeof value === 'object' && value.fileUrl) return [String(value.fileUrl).trim()].filter(Boolean) + const text = String(value).trim() + if (!text) return [] + if (text.startsWith('{') || text.startsWith('[')) { + try { + return parseAssetUrls(JSON.parse(text)) + } catch {} + } + return text + .replace(/[`'"]/g, '') + .split(',') + .map((item) => item.trim()) + .filter(Boolean) +} + +const getAssetName = (url: string) => { + const cleanUrl = String(url || '').split('?')[0] + const idx = cleanUrl.lastIndexOf('/') + const name = idx !== -1 ? cleanUrl.substring(idx + 1) : cleanUrl + try { + return decodeURIComponent(name) + } catch { + return name + } +} + +const parseAssetRows = (value: any) => { + return parseAssetUrls(value).map((url) => ({ + url, + name: getAssetName(url) + })) +} + const getResultLabel = (value: any) => { const v = value === '' || value === null || value === undefined ? undefined : String(value) if (!v) return '-' @@ -974,6 +1051,21 @@ onMounted(() => { background: var(--el-fill-color-light); } +.mold-brand-asset-image { + width: 96px; + height: 96px; + border: 1px solid var(--el-border-color-lighter); + border-radius: 6px; +} + +.mold-brand-asset-video { + width: 280px; + max-width: 100%; + height: 160px; + border-radius: 6px; + background: #000; +} + @media (max-width: 1024px) { .mold-brand-detail__hero { grid-template-columns: 1fr;