From d9ff374c80f3ed9077eae5136a7edea37668afbf Mon Sep 17 00:00:00 2001
From: zhou zhou <zozhouo3o@gmail.com>
Date: 星期五, 17 四月 2026 09:59:08 +0800
Subject: [PATCH] #条码自定义增加图片
---
rsf-design/src/views/basic-info/wh-mat/modules/matnr-print-property-panel.vue | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 226 insertions(+), 2 deletions(-)
diff --git a/rsf-design/src/views/basic-info/wh-mat/modules/matnr-print-property-panel.vue b/rsf-design/src/views/basic-info/wh-mat/modules/matnr-print-property-panel.vue
index cec4625..5a5e529 100644
--- a/rsf-design/src/views/basic-info/wh-mat/modules/matnr-print-property-panel.vue
+++ b/rsf-design/src/views/basic-info/wh-mat/modules/matnr-print-property-panel.vue
@@ -180,7 +180,7 @@
}}</span>
<ElInputNumber
:model-value="selectedElement.h"
- :min="0.4"
+ :min="selectedElement.type === 'image' ? imageMinHeight : 0.4"
:step="0.2"
controls-position="right"
@update:model-value="updateElement('h', $event)"
@@ -341,6 +341,77 @@
@focus="setPlaceholderTarget('valueTemplate')"
@update:model-value="updateElement('valueTemplate', $event)"
/>
+ </label>
+ </div>
+ </template>
+
+ <template v-else-if="selectedElement.type === 'image'">
+ <div class="matnr-print-property-panel__grid">
+ <label class="matnr-print-property-panel__span-2">
+ <span>{{
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.fields.imageSource')
+ }}</span>
+ <ElInput
+ :model-value="selectedElement.src"
+ @update:model-value="updateElement('src', $event)"
+ @change="handleImageSourceChange"
+ />
+ </label>
+ <label>
+ <span>{{
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.fields.fitMode')
+ }}</span>
+ <ElSelect
+ :model-value="selectedElement.objectFit"
+ @update:model-value="updateElement('objectFit', $event)"
+ >
+ <ElOption
+ value="contain"
+ :label="
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.options.contain')
+ "
+ />
+ <ElOption
+ value="cover"
+ :label="t('pages.basicInfo.whMat.printTemplate.propertyPanel.options.cover')"
+ />
+ <ElOption
+ value="fill"
+ :label="t('pages.basicInfo.whMat.printTemplate.propertyPanel.options.fill')"
+ />
+ </ElSelect>
+ </label>
+ <label class="matnr-print-property-panel__upload">
+ <span>{{
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.actions.uploadImage')
+ }}</span>
+ <ElUpload
+ accept="image/*"
+ :auto-upload="false"
+ :show-file-list="false"
+ @change="handleImageFileChange"
+ >
+ <ElButton>
+ {{
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.actions.uploadImage')
+ }}
+ </ElButton>
+ </ElUpload>
+ </label>
+ <label class="matnr-print-property-panel__span-2">
+ <span>{{
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.fields.previewImage')
+ }}</span>
+ <div class="matnr-print-property-panel__image-preview">
+ <ElImage
+ v-if="selectedElement.src"
+ :src="selectedElement.src"
+ fit="contain"
+ preview-teleported
+ class="matnr-print-property-panel__image-preview-inner"
+ />
+ <div v-else class="matnr-print-property-panel__image-preview-empty"></div>
+ </div>
</label>
</div>
</template>
@@ -623,8 +694,13 @@
<script setup>
import { computed } from 'vue'
+ import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n'
- import { getFieldListTableRows, updateFieldListTableRows } from '../matnrPrintTemplate.helpers'
+ import {
+ getFieldListTableRows,
+ getImageMinHeight,
+ updateFieldListTableRows
+ } from '../matnrPrintTemplate.helpers'
defineOptions({ name: 'MatnrPrintPropertyPanel' })
@@ -650,6 +726,11 @@
])
const tableRows = computed(() => getFieldListTableRows(props.selectedElement))
+ const imageMinHeight = computed(() =>
+ props.selectedElement?.type === 'image'
+ ? getImageMinHeight(props.selectedElement?.w, props.selectedElement, props.selectedElement?.h)
+ : 0.4
+ )
function updateTemplateMeta(field, value) {
emit('update-template-meta', { field, value })
@@ -742,6 +823,116 @@
id: props.selectedElement?.id,
patch: updateFieldListTableRows(props.selectedElement, rows)
})
+ }
+
+ function validateImageFile(rawFile) {
+ const isImageFile =
+ String(rawFile?.type || '').startsWith('image/') ||
+ /\.(png|jpe?g|gif|bmp|webp|svg)$/i.test(rawFile?.name || '')
+ if (!isImageFile) {
+ ElMessage.error(
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.messages.uploadOnlyImage')
+ )
+ return false
+ }
+
+ const isLt5MB = Number(rawFile?.size || 0) / 1024 / 1024 < 5
+ if (!isLt5MB) {
+ ElMessage.error(
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.messages.uploadSizeLimit')
+ )
+ return false
+ }
+
+ return true
+ }
+
+ function readFileAsDataUrl(file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+ reader.onload = () => resolve(String(reader.result || ''))
+ reader.onerror = reject
+ reader.readAsDataURL(file)
+ })
+ }
+
+ function loadImageNaturalSize(src) {
+ return new Promise((resolve, reject) => {
+ const image = new Image()
+ image.onload = () => {
+ resolve({
+ naturalWidth: Number(image.naturalWidth) || 0,
+ naturalHeight: Number(image.naturalHeight) || 0
+ })
+ }
+ image.onerror = reject
+ image.src = src
+ })
+ }
+
+ async function applyImageSource(src) {
+ const nextSrc = String(src || '').trim()
+ if (!props.selectedElement?.id) {
+ return
+ }
+ if (!nextSrc) {
+ emit('update-element', {
+ id: props.selectedElement.id,
+ patch: {
+ src: '',
+ naturalWidth: 0,
+ naturalHeight: 0
+ }
+ })
+ return
+ }
+
+ const size = await loadImageNaturalSize(nextSrc)
+ const nextHeight = getImageMinHeight(props.selectedElement?.w, size, props.selectedElement?.h)
+ emit('update-element', {
+ id: props.selectedElement.id,
+ patch: {
+ src: nextSrc,
+ naturalWidth: size.naturalWidth,
+ naturalHeight: size.naturalHeight,
+ h: Math.max(Number(props.selectedElement?.h) || 0, nextHeight)
+ }
+ })
+ }
+
+ async function handleImageSourceChange(value) {
+ const nextSrc = String(value || '').trim()
+ if (!nextSrc) {
+ await applyImageSource('')
+ return
+ }
+ try {
+ await applyImageSource(nextSrc)
+ } catch (error) {
+ ElMessage.error(
+ error?.message ||
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.messages.readImageFailed')
+ )
+ }
+ }
+
+ async function handleImageFileChange(uploadFile) {
+ const rawFile = uploadFile?.raw
+ if (!rawFile || !props.selectedElement?.id) {
+ return
+ }
+ if (!validateImageFile(rawFile)) {
+ return
+ }
+ try {
+ const dataUrl = await readFileAsDataUrl(rawFile)
+ await applyImageSource(dataUrl)
+ } catch (error) {
+ ElMessage.error(
+ error?.message ||
+ t('pages.basicInfo.whMat.printTemplate.propertyPanel.messages.readImageFailed')
+ )
+ }
}
</script>
@@ -847,6 +1038,39 @@
color: var(--art-text-primary);
}
+ .matnr-print-property-panel__upload {
+ justify-content: flex-end;
+ }
+
+ .matnr-print-property-panel__image-preview {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 120px;
+ padding: 12px;
+ border: 1px dashed rgba(148, 163, 184, 0.35);
+ border-radius: 12px;
+ background: rgba(248, 250, 252, 0.75);
+ }
+
+ .matnr-print-property-panel__image-preview-inner {
+ width: 100%;
+ height: 140px;
+ border-radius: 8px;
+ overflow: hidden;
+ background: #ffffff;
+ }
+
+ .matnr-print-property-panel__image-preview-empty {
+ width: 100%;
+ height: 96px;
+ border-radius: 10px;
+ border: 1px dashed rgba(148, 163, 184, 0.5);
+ background:
+ linear-gradient(135deg, rgba(226, 232, 240, 0.75), rgba(241, 245, 249, 0.35)),
+ linear-gradient(45deg, rgba(203, 213, 225, 0.35), transparent);
+ }
+
@media (max-width: 1280px) {
.matnr-print-property-panel__grid {
grid-template-columns: minmax(0, 1fr);
--
Gitblit v1.9.1