feat(全局):增加 barcode 二维码组件
parent
4933180560
commit
0e4012c623
|
|
@ -41,6 +41,7 @@
|
||||||
"@vben/types": "workspace:*",
|
"@vben/types": "workspace:*",
|
||||||
"@vueuse/core": "catalog:",
|
"@vueuse/core": "catalog:",
|
||||||
"@vueuse/integrations": "catalog:",
|
"@vueuse/integrations": "catalog:",
|
||||||
|
"jsbarcode": "catalog:",
|
||||||
"json-bigint": "catalog:",
|
"json-bigint": "catalog:",
|
||||||
"qrcode": "catalog:",
|
"qrcode": "catalog:",
|
||||||
"tippy.js": "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 './api-component';
|
||||||
|
export * from './barcode';
|
||||||
export * from './captcha';
|
export * from './captcha';
|
||||||
export * from './card/comparison-card';
|
export * from './card/comparison-card';
|
||||||
export * from './card/statistic-card';
|
export * from './card/statistic-card';
|
||||||
|
|
|
||||||
|
|
@ -357,6 +357,9 @@ catalogs:
|
||||||
is-ci:
|
is-ci:
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
|
jsbarcode:
|
||||||
|
specifier: ^3.12.3
|
||||||
|
version: 3.12.3
|
||||||
jsencrypt:
|
jsencrypt:
|
||||||
specifier: ^3.5.4
|
specifier: ^3.5.4
|
||||||
version: 3.5.4
|
version: 3.5.4
|
||||||
|
|
@ -1955,6 +1958,9 @@ importers:
|
||||||
'@vueuse/integrations':
|
'@vueuse/integrations':
|
||||||
specifier: 'catalog:'
|
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))
|
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:
|
json-bigint:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|
@ -9196,6 +9202,9 @@ packages:
|
||||||
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
jsbarcode@3.12.3:
|
||||||
|
resolution: {integrity: sha512-CuHU9hC6dPsHF5oVFMo8NW76uQVjH4L22CsP4hW+dNnGywJHC/B0ThA1CTDVLnxKLrrpYdicBLnd2xsgTfRnvg==}
|
||||||
|
|
||||||
jsdoc-type-pratt-parser@7.1.1:
|
jsdoc-type-pratt-parser@7.1.1:
|
||||||
resolution: {integrity: sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==}
|
resolution: {integrity: sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==}
|
||||||
engines: {node: '>=20.0.0'}
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
@ -19810,6 +19819,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse: 2.0.1
|
argparse: 2.0.1
|
||||||
|
|
||||||
|
jsbarcode@3.12.3: {}
|
||||||
|
|
||||||
jsdoc-type-pratt-parser@7.1.1: {}
|
jsdoc-type-pratt-parser@7.1.1: {}
|
||||||
|
|
||||||
jsencrypt@3.5.4: {}
|
jsencrypt@3.5.4: {}
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ catalog:
|
||||||
highlight.js: ^11.11.1
|
highlight.js: ^11.11.1
|
||||||
html-minifier-terser: ^7.2.0
|
html-minifier-terser: ^7.2.0
|
||||||
is-ci: ^4.1.0
|
is-ci: ^4.1.0
|
||||||
|
jsbarcode: ^3.12.3
|
||||||
jsencrypt: ^3.5.4
|
jsencrypt: ^3.5.4
|
||||||
json-bigint: ^1.0.0
|
json-bigint: ^1.0.0
|
||||||
lefthook: ^2.1.5
|
lefthook: ^2.1.5
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue