From a5ba206e72ee063409dbd8df02630d5681f6b9d1 Mon Sep 17 00:00:00 2001 From: hwj Date: Fri, 27 Mar 2026 17:31:48 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E8=AE=BE=E5=A4=87=E5=8F=B0?= =?UTF-8?q?=E8=B4=A6=E3=80=81=E6=A8=A1=E5=85=B7=E5=8F=B0=E8=B4=A6=E3=80=81?= =?UTF-8?q?=E5=A4=87=E4=BB=B6=E3=80=81=E8=AE=BE=E5=A4=87=E5=85=B3=E9=94=AE?= =?UTF-8?q?=E4=BB=B6=E6=A8=A1=E5=9D=97=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E8=B0=83=E7=94=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/QrcodeActionCard/index.vue | 125 +++++++++++++--- .../erp/component/product/ProductForm.vue | 133 ++++-------------- src/views/erp/mold/components/MoldForm.vue | 129 ++++------------- .../CriticalComponentForm.vue | 129 ++++------------- src/views/mes/deviceledger/index.vue | 49 ++----- 5 files changed, 200 insertions(+), 365 deletions(-) diff --git a/src/components/QrcodeActionCard/index.vue b/src/components/QrcodeActionCard/index.vue index 016d0a33..ca74d771 100644 --- a/src/components/QrcodeActionCard/index.vue +++ b/src/components/QrcodeActionCard/index.vue @@ -9,18 +9,24 @@ class="qrcode-action-card__img" >
{{ emptyText }}
-
- +
+ - + - +
@@ -48,6 +54,15 @@ const props = withDefaults( refreshDisabled?: boolean printDisabled?: boolean refreshConfirmText?: string + errorText?: string + showPreview?: boolean + showPrint?: boolean + showRefresh?: boolean + printAdaptive?: boolean + printPaperWidth?: number + printPaperHeight?: number + printMaxWidth?: number + printMaxHeight?: number }>(), { imageUrl: '', @@ -58,7 +73,16 @@ const props = withDefaults( refreshMethod: 'post', refreshDisabled: false, printDisabled: false, - refreshConfirmText: '' + refreshConfirmText: '', + errorText: '', + showPreview: true, + showPrint: true, + showRefresh: true, + printAdaptive: true, + printPaperWidth: 80, + printPaperHeight: 80, + printMaxWidth: 180, + printMaxHeight: 120 } ) @@ -69,13 +93,21 @@ const emit = defineEmits<{ const hiprintPreviewDialogRef = ref() const refreshLoading = ref(false) -const buildQrcodeTemplateJson = (qrcodeUrl: string, printId: string | number) => ({ +const showActionMask = computed(() => props.showPreview || props.showPrint || props.showRefresh) + +const buildQrcodeTemplateJson = ( + qrcodeUrl: string, + printId: string, + imageWidth: number, + imageHeight: number, + paperHeight: number +) => ({ panels: [ { index: 0, name: 1, - width: 80, - height: 80, + width: imageWidth, + height: paperHeight, paperHeader: 0, paperFooter: 0, printElements: [ @@ -83,8 +115,8 @@ const buildQrcodeTemplateJson = (qrcodeUrl: string, printId: string | number) => options: { left: 0, top: 0, - width: 100, - height: 100, + width: imageWidth, + height: imageHeight, src: qrcodeUrl, field: 'qrcodeUrl', title: '二维码图片', @@ -95,12 +127,12 @@ const buildQrcodeTemplateJson = (qrcodeUrl: string, printId: string | number) => type: 'image' } }, - { + { options: { - left: 20, - top: 100, - height: 8, - width: 60, + left: 0, + top: imageHeight + 2, + height: 10, + width: imageWidth, testData: printId, title: 'ID', field: 'printId', @@ -121,6 +153,47 @@ const buildQrcodeTemplateJson = (qrcodeUrl: string, printId: string | number) => ] }) +const getImageSize = (src: string) => + new Promise<{ width: number; height: number }>((resolve, reject) => { + const img = new Image() + img.onload = () => { + const width = img.naturalWidth || img.width + const height = img.naturalHeight || img.height + if (!width || !height) { + reject(new Error('invalid image size')) + return + } + resolve({ width, height }) + } + img.onerror = () => reject(new Error('image load failed')) + img.src = src + }) + +const resolvePrintSize = async (src: string) => { + const fallbackWidth = Math.max(20, Number(props.printPaperWidth) || 80) + const fallbackHeight = Math.max(20, Number(props.printPaperHeight) || 80) + if (!props.printAdaptive) { + return { width: fallbackWidth, height: fallbackHeight } + } + try { + const size = await getImageSize(src) + const ratio = size.width / size.height + if (!Number.isFinite(ratio) || ratio <= 0) { + return { width: fallbackWidth, height: fallbackHeight } + } + if (ratio >= 1) { + const height = fallbackHeight + const width = Math.min(Math.max(fallbackWidth, Math.round(height * ratio)), Number(props.printMaxWidth) || 180) + return { width, height } + } + const width = fallbackWidth + const height = Math.min(Math.max(fallbackHeight, Math.round(width / ratio)), Number(props.printMaxHeight) || 120) + return { width, height } + } catch { + return { width: fallbackWidth, height: fallbackHeight } + } +} + const handlePreview = () => { if (!props.imageUrl) return createImageViewer({ @@ -129,25 +202,31 @@ const handlePreview = () => { }) } -const handlePrint = () => { - if (!props.imageUrl) return +const handlePrint = async () => { + if (!props.imageUrl || !props.showPrint) return + const printSize = await resolvePrintSize(props.imageUrl) + const imageWidth = printSize.width + const imageHeight = printSize.height + const printId = props.printId === undefined || props.printId === null ? '' : String(props.printId) + const idAreaHeight = printId ? 14 : 0 + const paperHeight = imageHeight + idAreaHeight hiprintPreviewDialogRef.value?.open({ title: props.printTitle, printData: { qrcodeUrl: props.imageUrl, - printId: props.printId ? String(props.printId) : '' + printId }, - templateJson: buildQrcodeTemplateJson(props.imageUrl,props.printId), + templateJson: buildQrcodeTemplateJson(props.imageUrl, printId, imageWidth, imageHeight, paperHeight), withDefaultQrcodeLayout: false, paperSize: { - width: 80, - height: 80 + width: imageWidth, + height: paperHeight } }) } const handleRefresh = async () => { - if (!props.refreshUrl || props.refreshDisabled) return + if (!props.refreshUrl || props.refreshDisabled || !props.showRefresh) return try { await message.confirm(props.refreshConfirmText || '确认刷新二维码吗?') } catch { diff --git a/src/views/erp/component/product/ProductForm.vue b/src/views/erp/component/product/ProductForm.vue index ae9e14d3..8125056b 100644 --- a/src/views/erp/component/product/ProductForm.vue +++ b/src/views/erp/component/product/ProductForm.vue @@ -101,42 +101,20 @@ -
- - - -
- {{ t('SparePartsManagement.SpareInfo.qrcodeEmpty') }} -
-
- - - - - - -
-
+
@@ -155,7 +133,7 @@ - + diff --git a/src/views/erp/mold/components/MoldForm.vue b/src/views/erp/mold/components/MoldForm.vue index c48bd250..72c6d109 100644 --- a/src/views/erp/mold/components/MoldForm.vue +++ b/src/views/erp/mold/components/MoldForm.vue @@ -85,38 +85,20 @@ -
- - - -
{{ t('MoldManagement.Mold.qrcodeEmpty') }}
-
- - - - - - -
-
+
@@ -155,7 +137,7 @@ import { getIntDictOptions, DICT_TYPE, getBoolDictOptions } from '@/utils/dict' import { MoldBrandApi } from '@/api/erp/mold' import { ProductUnitApi, ProductUnitVO } from '@/api/erp/product/unit' -import { createImageViewer } from '@/components/ImageViewer' +import QrcodeActionCard from '@/components/QrcodeActionCard/index.vue' const unitList = ref([]) // 产品单位列表 const { t } = useI18n() // 国际化 @@ -165,7 +147,6 @@ const dialogVisible = ref(false) // 弹窗的是否展示 const dialogTitle = ref('') // 弹窗的标题 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const regenerateCodeLoading = ref(false) const formData = ref({ id: undefined, code: undefined, @@ -245,30 +226,20 @@ const handleCodeAutoChange = (value: boolean) => { formRef.value?.clearValidate('code') } -const handleRegenerateCode = async () => { - if (!formData.value.id || !formData.value.code) return - regenerateCodeLoading.value = true - try { - const data = await MoldBrandApi.regenerateCode(formData.value.id, formData.value.code) - if (data?.qrcodeUrl) { - formData.value.qrcodeUrl = data.qrcodeUrl - } else { - const moldData = await MoldBrandApi.getMold(formData.value.id) - formData.value.qrcodeUrl = moldData?.qrcodeUrl - formData.value.code = moldData?.code ?? formData.value.code - } - message.success(t('common.updateSuccess')) - } finally { - regenerateCodeLoading.value = false - } +const getQrcodeRefreshUrl = () => { + if (!formData.value.id || !formData.value.code) return '' + return `/erp/mold-brand/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.code))}` } -const handlePreviewQrcode = () => { - if (!formData.value.qrcodeUrl) return - createImageViewer({ - zIndex: 9999999, - urlList: [formData.value.qrcodeUrl] - }) +const handleQrcodeRefreshSuccess = async (data: any) => { + if (!formData.value.id) return + if (data?.qrcodeUrl) { + formData.value.qrcodeUrl = data.qrcodeUrl + return + } + const moldData = await MoldBrandApi.getMold(formData.value.id) + formData.value.qrcodeUrl = moldData?.qrcodeUrl + formData.value.code = moldData?.code ?? formData.value.code } /** 提交表单 */ @@ -317,48 +288,4 @@ const resetForm = () => { formRef.value?.resetFields() } - + diff --git a/src/views/mes/criticalComponent/CriticalComponentForm.vue b/src/views/mes/criticalComponent/CriticalComponentForm.vue index 4b0efa05..2d1e3202 100644 --- a/src/views/mes/criticalComponent/CriticalComponentForm.vue +++ b/src/views/mes/criticalComponent/CriticalComponentForm.vue @@ -46,38 +46,20 @@ /> -
- - - -
{{ t('EquipmentManagement.EquipmentKeyItems.qrcodeEmpty') }}
-
- - - - - - -
-
+
import { CriticalComponentApi, CriticalComponentVO } from '@/api/mes/criticalComponent' -import { createImageViewer } from '@/components/ImageViewer' +import QrcodeActionCard from '@/components/QrcodeActionCard/index.vue' defineOptions({ name: 'CriticalComponentForm' }) @@ -108,7 +90,6 @@ const dialogVisible = ref(false) const dialogTitle = ref('') const formLoading = ref(false) const formType = ref<'create' | 'update'>('create') -const regenerateCodeLoading = ref(false) const formRef = ref() const formData = ref>({ @@ -160,30 +141,20 @@ const handleCodeAutoChange = (value: boolean) => { formRef.value?.clearValidate('code') } -const handleRegenerateCode = async () => { - if (!formData.value.id || !formData.value.code) return - regenerateCodeLoading.value = true - try { - const data = await CriticalComponentApi.regenerateCode(formData.value.id, formData.value.code) - if (data?.qrcodeUrl) { - formData.value.qrcodeUrl = data.qrcodeUrl - } else { - const detail = await CriticalComponentApi.getCriticalComponent(formData.value.id) - formData.value.qrcodeUrl = detail?.qrcodeUrl - formData.value.code = detail?.code ?? formData.value.code - } - message.success(t('common.updateSuccess')) - } finally { - regenerateCodeLoading.value = false - } +const getQrcodeRefreshUrl = () => { + if (!formData.value.id || !formData.value.code) return '' + return `/mes/critical-component/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.code))}` } -const handlePreviewQrcode = () => { - if (!formData.value.qrcodeUrl) return - createImageViewer({ - zIndex: 9999999, - urlList: [formData.value.qrcodeUrl] - }) +const handleQrcodeRefreshSuccess = async (data: any) => { + if (!formData.value.id) return + if (data?.qrcodeUrl) { + formData.value.qrcodeUrl = data.qrcodeUrl + return + } + const detail = await CriticalComponentApi.getCriticalComponent(formData.value.id) + formData.value.qrcodeUrl = detail?.qrcodeUrl + formData.value.code = detail?.code ?? formData.value.code } const open = async (type: 'create' | 'update', id?: number) => { @@ -233,48 +204,4 @@ const submitForm = async () => { } } - + diff --git a/src/views/mes/deviceledger/index.vue b/src/views/mes/deviceledger/index.vue index 0cd54439..4ff0c86a 100644 --- a/src/views/mes/deviceledger/index.vue +++ b/src/views/mes/deviceledger/index.vue @@ -156,21 +156,19 @@ link type="danger" @click="handleDelete(scope.row.id)" -
-
- - - +
+
-
@@ -452,6 +450,7 @@ import DeviceLedgerForm from './DeviceLedgerForm.vue' import { getIntDictOptions } from '@/utils/dict' import { isHexColor } from '@/utils/color' import { useDictStoreWithOut } from '@/store/modules/dict' +import QrcodeActionCard from '@/components/QrcodeActionCard/index.vue' /** 设备类型 列表 */ defineOptions({ name: 'DeviceLedger' }) @@ -1209,26 +1208,6 @@ onMounted(async () => { } .device-ledger-detail-qrcode { - width: fit-content; - padding: 8px; - border-radius: 10px; - border: 1px solid var(--el-border-color-lighter); - background: var(--el-fill-color-blank); -} - -.device-ledger-detail-qrcode-img { - width: auto; - height: 150px; - display: block; -} - -.device-ledger-detail-qrcode-error { - width: 150px; - height: 150px; - display: flex; - align-items: center; - justify-content: center; - color: var(--el-text-color-secondary); - font-size: 12px; + margin-top: 10px; }