feat(全局):增加 barcode 二维码组件
parent
4933180560
commit
0e4012c623
|
|
@ -41,6 +41,7 @@
|
|||
"@vben/types": "workspace:*",
|
||||
"@vueuse/core": "catalog:",
|
||||
"@vueuse/integrations": "catalog:",
|
||||
"jsbarcode": "catalog:",
|
||||
"json-bigint": "catalog:",
|
||||
"qrcode": "catalog:",
|
||||
"tippy.js": "catalog:",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
<script lang="ts" setup>
|
||||
import type { QRCodeRenderersOptions } from 'qrcode';
|
||||
|
||||
import type { BarcodeFormat } from './types';
|
||||
|
||||
import { computed, nextTick, ref, unref, watch } from 'vue';
|
||||
|
||||
import JsBarcode from 'jsbarcode';
|
||||
import QRCode from 'qrcode';
|
||||
|
||||
import { BARCODE_FORMAT_MAP, BarcodeFormatEnum } from './types';
|
||||
|
||||
defineOptions({ name: 'Barcode' });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
content?: string;
|
||||
displayValue?: boolean;
|
||||
format?: BarcodeFormat;
|
||||
height?: number;
|
||||
width?: number;
|
||||
}>(),
|
||||
{
|
||||
content: '',
|
||||
displayValue: true,
|
||||
format: BarcodeFormatEnum.QR_CODE,
|
||||
height: 100,
|
||||
width: 200,
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
done: [base64: string];
|
||||
}>();
|
||||
|
||||
const loading = ref(true);
|
||||
const canvasRef = ref<HTMLCanvasElement>();
|
||||
const imgRef = ref<HTMLImageElement>();
|
||||
const isQRCode = computed(() => props.format === BarcodeFormatEnum.QR_CODE);
|
||||
|
||||
const wrapStyle = computed(() => {
|
||||
if (isQRCode.value) {
|
||||
return {
|
||||
height: `${props.width}px`,
|
||||
width: `${props.width}px`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
width: `${props.width}px`,
|
||||
};
|
||||
});
|
||||
|
||||
async function generateQRCode() {
|
||||
const canvas = unref(canvasRef);
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
const options: QRCodeRenderersOptions = {
|
||||
errorCorrectionLevel: 'M',
|
||||
width: props.width,
|
||||
};
|
||||
await QRCode.toCanvas(canvas, props.content, options);
|
||||
emit('done', canvas.toDataURL());
|
||||
}
|
||||
|
||||
function generateOneDimensionalBarcode() {
|
||||
const img = unref(imgRef);
|
||||
if (!img) {
|
||||
return;
|
||||
}
|
||||
JsBarcode(img, props.content, {
|
||||
displayValue: props.displayValue,
|
||||
format: BARCODE_FORMAT_MAP[props.format] || 'CODE39',
|
||||
height: props.height,
|
||||
margin: 10,
|
||||
width: 2,
|
||||
});
|
||||
emit('done', img.src);
|
||||
}
|
||||
|
||||
async function generateBarcode() {
|
||||
if (!props.content) {
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
await nextTick();
|
||||
try {
|
||||
if (isQRCode.value) {
|
||||
await generateQRCode();
|
||||
return;
|
||||
}
|
||||
generateOneDimensionalBarcode();
|
||||
} catch (error) {
|
||||
console.error('生成条码失败:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [
|
||||
props.content,
|
||||
props.displayValue,
|
||||
props.format,
|
||||
props.height,
|
||||
props.width,
|
||||
],
|
||||
() => {
|
||||
generateBarcode();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function getImageBase64() {
|
||||
if (isQRCode.value) {
|
||||
return unref(canvasRef)?.toDataURL() || '';
|
||||
}
|
||||
return unref(imgRef)?.src || '';
|
||||
}
|
||||
|
||||
defineExpose({ getImageBase64 });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :aria-busy="loading" class="inline-block" :style="wrapStyle">
|
||||
<canvas v-if="isQRCode" ref="canvasRef" class="block max-w-full"></canvas>
|
||||
<img v-else ref="imgRef" alt="barcode" class="block max-w-full" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as Barcode } from './barcode.vue';
|
||||
export * from './types';
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/** 条码格式枚举 */
|
||||
export const BarcodeFormatEnum = {
|
||||
QR_CODE: 1,
|
||||
EAN13: 2,
|
||||
CODE39: 3,
|
||||
UPC_A: 4,
|
||||
} as const;
|
||||
|
||||
export type BarcodeFormat =
|
||||
(typeof BarcodeFormatEnum)[keyof typeof BarcodeFormatEnum];
|
||||
|
||||
/** 条码格式映射表(枚举值 -> JsBarcode 格式名) */
|
||||
export const BARCODE_FORMAT_MAP: Record<BarcodeFormat, string> = {
|
||||
[BarcodeFormatEnum.QR_CODE]: 'QR_CODE',
|
||||
[BarcodeFormatEnum.EAN13]: 'EAN13',
|
||||
[BarcodeFormatEnum.CODE39]: 'CODE39',
|
||||
[BarcodeFormatEnum.UPC_A]: 'UPC_A',
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
export * from './api-component';
|
||||
export * from './barcode';
|
||||
export * from './captcha';
|
||||
export * from './card/comparison-card';
|
||||
export * from './card/statistic-card';
|
||||
|
|
|
|||
|
|
@ -357,6 +357,9 @@ catalogs:
|
|||
is-ci:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
jsbarcode:
|
||||
specifier: ^3.12.3
|
||||
version: 3.12.3
|
||||
jsencrypt:
|
||||
specifier: ^3.5.4
|
||||
version: 3.5.4
|
||||
|
|
@ -1955,6 +1958,9 @@ importers:
|
|||
'@vueuse/integrations':
|
||||
specifier: 'catalog:'
|
||||
version: 14.2.1(async-validator@4.2.5)(axios@1.15.0)(change-case@5.4.4)(focus-trap@8.0.1)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.7)(vue@3.5.32(typescript@6.0.2))
|
||||
jsbarcode:
|
||||
specifier: 'catalog:'
|
||||
version: 3.12.3
|
||||
json-bigint:
|
||||
specifier: 'catalog:'
|
||||
version: 1.0.0
|
||||
|
|
@ -9196,6 +9202,9 @@ packages:
|
|||
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
||||
hasBin: true
|
||||
|
||||
jsbarcode@3.12.3:
|
||||
resolution: {integrity: sha512-CuHU9hC6dPsHF5oVFMo8NW76uQVjH4L22CsP4hW+dNnGywJHC/B0ThA1CTDVLnxKLrrpYdicBLnd2xsgTfRnvg==}
|
||||
|
||||
jsdoc-type-pratt-parser@7.1.1:
|
||||
resolution: {integrity: sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
|
@ -19810,6 +19819,8 @@ snapshots:
|
|||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
jsbarcode@3.12.3: {}
|
||||
|
||||
jsdoc-type-pratt-parser@7.1.1: {}
|
||||
|
||||
jsencrypt@3.5.4: {}
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ catalog:
|
|||
highlight.js: ^11.11.1
|
||||
html-minifier-terser: ^7.2.0
|
||||
is-ci: ^4.1.0
|
||||
jsbarcode: ^3.12.3
|
||||
jsencrypt: ^3.5.4
|
||||
json-bigint: ^1.0.0
|
||||
lefthook: ^2.1.5
|
||||
|
|
|
|||
Loading…
Reference in New Issue