1
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
class code128b {
|
||||
// 输入数据
|
||||
data = ""
|
||||
|
||||
// Code 128 模式表:索引0..106 -> 二进制模块串(1=黑,0=白),来自业界通用表
|
||||
// 参考:StartB=104 -> 11010010000, Stop=106 -> 1100011101011
|
||||
private static PATTERNS = [
|
||||
"11011001100","11001101100","11001100110","10010011000","10010001100","10001001100",
|
||||
"10011001000","10011000100","10001100100","11001001000","11001000100","11000100100",
|
||||
"10110011100","10011011100","10011001110","10111001100","10011101100","10011100110",
|
||||
"11001110010","11001011100","11001001110","11011100100","11001110100","11101101110",
|
||||
"11101001100","11100101100","11100100110","11101100100","11100110100","11100110010",
|
||||
"11011011000","11011000110","11000110110","10100011000","10001011000","10001000110",
|
||||
"10110001000","10001101000","10001100010","11010001000","11000101000","11000100010",
|
||||
"10110111000","10110001110","10001101110","10111011000","10111000110","10001110110",
|
||||
"11101110110","11010001110","11000101110","11011101000","11011100010","11011101110",
|
||||
"11101011000","11101000110","11100010110","11101101000","11101100010","11100011010",
|
||||
"11101111010","11001000010","11110001010","10100110000","10100001100","10010110000",
|
||||
"10010000110","10000101100","10000100110","10110010000","10110000100","10011010000",
|
||||
"10011000010","10000110100","10000110010","11000010010","11001010000","11110111010",
|
||||
"11000010100","10001111010","10100111100","10010111100","10010011110","10111100100",
|
||||
"10011110100","10011110010","11110100100","11110010100","11110010010","11011011110",
|
||||
"11011110110","11110110110","10101111000","10100011110","10001011110","10111101000",
|
||||
"10111100010","11110101000","11110100010","10111011110","10111101110","11101011110",
|
||||
"11110101110","11010000100","11010010000","11010011100","1100011101011"
|
||||
]
|
||||
|
||||
// Code Set B: 字符到值(0..95 => ASCII 32..127)
|
||||
private mapCharToValueB(ch:string):number {
|
||||
const code = ch.charCodeAt(0)!;
|
||||
|
||||
if (code < 32 || code > 127) {
|
||||
return -1
|
||||
}
|
||||
return code - 32
|
||||
}
|
||||
|
||||
constructor(text:string) {
|
||||
this.data = text
|
||||
}
|
||||
|
||||
encode():string {
|
||||
if (this.data.length == 0) return ""
|
||||
const values = [] as number[]
|
||||
for (let i = 0; i < this.data.length; i++) {
|
||||
values.push(this.mapCharToValueB(this.data.charAt(i)))
|
||||
}
|
||||
// 起始码 CodeB=104
|
||||
const startVal = 104
|
||||
let checksum = startVal
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
checksum += values[i] * (i + 1)
|
||||
}
|
||||
checksum = checksum % 103
|
||||
// 组合:StartB + 数据 + 校验 + Stop
|
||||
const bits = [] as string[]
|
||||
bits.push(code128b.PATTERNS[startVal])
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
bits.push(code128b.PATTERNS[values[i]])
|
||||
}
|
||||
bits.push(code128b.PATTERNS[checksum])
|
||||
// Stop=106
|
||||
bits.push(code128b.PATTERNS[106])
|
||||
return bits.join("")
|
||||
}
|
||||
}
|
||||
|
||||
export { code128b };
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 商品条码严格按照国际通用码
|
||||
* @author tmzdy
|
||||
* @description 资料参考:https://zhuanlan.zhihu.com/p/120676811
|
||||
*/
|
||||
class ean13 {
|
||||
//编码数据
|
||||
data=""
|
||||
//护码
|
||||
safeCode = "101"
|
||||
middleCode = "01010"
|
||||
//编码方式,我们中国是6:LGGGLL
|
||||
EAN13_STRUCTURE = [
|
||||
'LLLLLL', 'LLGLGG', 'LLGGLG', 'LLGGGL', 'LGLLGG',
|
||||
'LGGLLG', 'LGGGLL', 'LGLGLG', 'LGLGGL', 'LGGLGL'
|
||||
];
|
||||
|
||||
|
||||
constructor(text:string) {
|
||||
let data = text;
|
||||
if (data.search(/^[0-9]{12}$/)!== -1 as number ) {
|
||||
data += (this.checksum(data)).toString();
|
||||
}
|
||||
this.data = data.toUpperCase();
|
||||
}
|
||||
//校验码。
|
||||
checksum(codestr:string):number{
|
||||
const res = codestr.substring(0, 12).split('')
|
||||
const resNumber = res.map((n:string):number => parseInt(n))
|
||||
|
||||
const jg=resNumber.reduce((sum:number, a:number, idx:number):number => (idx % 2) > 0 ? sum + a * 3 : sum + a, 0);
|
||||
|
||||
return (10 - (jg % 10)) % 10;
|
||||
}
|
||||
//按钮编码规则提取逻辑值,
|
||||
getEan13Str(key:string):string[]{
|
||||
if(key=="L") return [
|
||||
'0001101', '0011001', '0010011', '0111101', '0100011',
|
||||
'0110001', '0101111', '0111011', '0110111', '0001011'
|
||||
]
|
||||
if(key=="G") return [
|
||||
'0100111', '0110011', '0011011', '0100001', '0011101',
|
||||
'0111001', '0000101', '0010001', '0001001', '0010111'
|
||||
]
|
||||
if(key=="R") return [
|
||||
'1110010', '1100110', '1101100', '1000010', '1011100',
|
||||
'1001110', '1010000', '1000100', '1001000', '1110100'
|
||||
]
|
||||
return [] as string[];
|
||||
}
|
||||
|
||||
encodeByGuzhe(dataStr:string, structure:string):string{
|
||||
let encoded = dataStr.split('')
|
||||
let atrartys = [] as string[][]
|
||||
for(let i=0;i<encoded.length;i++){
|
||||
let chart = structure.substring(i,i+1)
|
||||
atrartys.push(this.getEan13Str(chart))
|
||||
}
|
||||
|
||||
let encoded_str = atrartys.map((val:string[], idx:number):string => {
|
||||
let stur = dataStr.substring(idx,idx+1)
|
||||
return val[parseInt(stur)]
|
||||
});
|
||||
|
||||
return encoded_str.join("")
|
||||
};
|
||||
encode():string[] {
|
||||
// 取编码方式。
|
||||
let codeFang = this.EAN13_STRUCTURE[parseInt(this.data.substring(0,1))]
|
||||
//取后面的12位数字
|
||||
let data = this.data.substring(1,13)
|
||||
let leftCode = data.substring(0,6)
|
||||
let rightCode = data.substring(6,13)
|
||||
|
||||
let left_code_str = this.encodeByGuzhe(leftCode,codeFang);
|
||||
//右资料码按规则是物料码+校验码
|
||||
let right_code_str = this.encodeByGuzhe(rightCode,"RRRRRR");
|
||||
// 组合码制
|
||||
//护码+左资料码+中间码+右资料码+护码
|
||||
// let totalcode = this.safeCode+left_code_str+this.middleCode+right_code_str+this.safeCode
|
||||
return [this.safeCode,left_code_str,this.middleCode,right_code_str,this.safeCode]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export { ean13 };
|
||||
@@ -0,0 +1,245 @@
|
||||
<script lang="ts">
|
||||
import { type PropType } from "vue"
|
||||
import { getUid } from "../../core/util/xCoreUtil.uts"
|
||||
import { getDefaultColor } from "../../core/util/xCoreColorUtil.uts"
|
||||
import { checkIsCssUnit } from "../../core/util/xCoreUtil.uts"
|
||||
import { xConfig } from "../../config/xConfig.uts"
|
||||
import { code128b } from "./utsbarcode/code128.uts"
|
||||
import { ean13 } from "./utsbarcode/ean13.uts"
|
||||
|
||||
/**
|
||||
* @name 条码 xBarcode
|
||||
* @page /pages/index/barcode
|
||||
* @category 其它组件
|
||||
* @description 本条码暂只开发了cdoebar,ean13两种。ean13是国际通用码,也是国内商品的码,
|
||||
* 我严格按照编码规则进行开发,所以提供商品码时,一定要准确。
|
||||
* @constant 平台兼容
|
||||
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
id: ('xCircleProgeress-' + getUid()) as string,
|
||||
boxWidth: 0,
|
||||
boxHeight: 0,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
/**
|
||||
* 窗口宽
|
||||
*/
|
||||
width: {
|
||||
type: String,
|
||||
default: 'auto'
|
||||
},
|
||||
/**
|
||||
* 宽器高,这将影响条码的高度
|
||||
*/
|
||||
height: {
|
||||
type: String,
|
||||
default: '140px'
|
||||
},
|
||||
/**
|
||||
* 上下间隙,单位是px
|
||||
*/
|
||||
pading: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
/**
|
||||
* 条码颜色
|
||||
*/
|
||||
color: {
|
||||
type: String,
|
||||
default: "black"
|
||||
},
|
||||
/**
|
||||
* 目前我仅开发两种常见的国内格式
|
||||
* codebar正常的数字字符条码
|
||||
* ean13国际通用物品编码,也是国内的商品码以69开头。
|
||||
*/
|
||||
encode: {
|
||||
type: String as PropType<"codebar" | "ean13" | "code128">,
|
||||
default: "ean13"
|
||||
},
|
||||
/**
|
||||
* 条码内容
|
||||
*/
|
||||
text: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
||||
_width() : string {
|
||||
return checkIsCssUnit(this.width, 'rpx')
|
||||
},
|
||||
_height() : string {
|
||||
|
||||
return checkIsCssUnit(this.height, 'rpx')
|
||||
},
|
||||
_color() : string {
|
||||
return getDefaultColor(this.color);
|
||||
},
|
||||
_text() : string {
|
||||
return this.text;
|
||||
},
|
||||
|
||||
},
|
||||
watch: {
|
||||
text(newValue : string) {
|
||||
if (newValue == "") return;
|
||||
this.getNodeInfo();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.text == "") return;
|
||||
// #ifndef APP-HARMONY
|
||||
this.getNodeInfo();
|
||||
// #endif
|
||||
// #ifdef APP-HARMONY
|
||||
let t = this;
|
||||
setTimeout(function() {
|
||||
t.getNodeInfo();
|
||||
}, 120);
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
getNodeInfo() {
|
||||
let _this = this;
|
||||
uni.createSelectorQuery().in(this)
|
||||
.select(".xBarcode")
|
||||
.boundingClientRect().exec((ret) => {
|
||||
let nodeinfo = ret[0] as NodeInfo
|
||||
this.boxWidth = nodeinfo.width!
|
||||
this.boxHeight = nodeinfo.height!
|
||||
// #ifdef APP-IOS || WEB
|
||||
_this.dreawer()
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID||APP-HARMONY
|
||||
setTimeout(function() {
|
||||
_this.dreawer()
|
||||
}, 50);
|
||||
// #endif
|
||||
})
|
||||
},
|
||||
dreawer() {
|
||||
this.clear()
|
||||
|
||||
let canvas = this.$refs['xBarcode'] as UniCanvasElement
|
||||
let ctx = canvas.getContext('2d')!
|
||||
// 处理高清屏逻辑
|
||||
const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
|
||||
canvas.width = canvas.offsetWidth * dpr;
|
||||
canvas.height = canvas.offsetHeight * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
let ratio = 1;
|
||||
let code = ""
|
||||
let eanCode = [] as string[]
|
||||
if (this.encode == "ean13") {
|
||||
eanCode = new ean13(this._text).encode()
|
||||
code = eanCode.join("")
|
||||
} else if (this.encode == "codebar" || this.encode == "code128") {
|
||||
code = new code128b(this._text).encode()
|
||||
}
|
||||
let strCode = code.split("");
|
||||
let linewidth = 2;
|
||||
let totalWidth = strCode.length * (linewidth);
|
||||
let barheight = this.boxHeight - this.pading * 2;
|
||||
let start_x = (this.boxWidth - totalWidth) / 2
|
||||
let start_y = this.pading
|
||||
ctx!.beginPath()
|
||||
ctx!.fillStyle = this._color
|
||||
|
||||
if (this.encode == "codebar" || this.encode == "code128") {
|
||||
ctx.font = `${16 * ratio}px Arial`;
|
||||
let texts = this._text.split("")
|
||||
let textwidth = ctx.measureText(this._text).width;
|
||||
let space = (totalWidth - textwidth)/(texts.length-1)
|
||||
// let textwidth = ctx.measureText(this._text).width + (texts.length-1) * 6
|
||||
// 绘制数字。
|
||||
let sx = (this.boxWidth-totalWidth)/2;
|
||||
for (let a0 = 0; a0 < texts.length; a0++) {
|
||||
let sxx = (ctx.measureText(texts[a0]).width+space) * a0 + sx
|
||||
ctx!.fillText(texts[a0], sxx * ratio, (start_y + barheight) * ratio)
|
||||
}
|
||||
|
||||
for (let i = 0; i < strCode.length; i++) {
|
||||
if (strCode[i] == "1") {
|
||||
ctx!.fillRect((i * linewidth + start_x + linewidth) * ratio, start_y * ratio, linewidth * ratio, (barheight - 24) * ratio)
|
||||
}
|
||||
}
|
||||
} else if (this.encode == "ean13") {
|
||||
let k = 0;
|
||||
ctx.font = `${13 * ratio}px Arial`;
|
||||
ctx!.fillText(this._text.substring(0, 1), (start_x - 10) * ratio, (start_y + barheight) * ratio)
|
||||
for (let j = 0; j < eanCode.length; j++) {
|
||||
let item = eanCode[j];
|
||||
let itemcodeas = item.split("")
|
||||
let offsetHeigt = (j == 0 || j == 2 || j == 4) ? 0 : 12
|
||||
// 绘制数字。
|
||||
if (j == 0) {
|
||||
let ncsr = this._text.substring(1, 7).split("")
|
||||
for (let a0 = 0; a0 < ncsr.length; a0++) {
|
||||
ctx!.fillText(ncsr[a0], (start_x + 10 + (a0 * 13) + linewidth) * ratio, (start_y + barheight) * ratio)
|
||||
}
|
||||
}
|
||||
if (j == 3) {
|
||||
let ncsr = this._text.substring(7).split("")
|
||||
for (let a0 = 0; a0 < ncsr.length; a0++) {
|
||||
ctx!.fillText(ncsr[a0], ((this.boxWidth / 2) + 10 + (a0 * 13) + linewidth) * ratio, (start_y + barheight) * ratio)
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < itemcodeas.length; i++) {
|
||||
if (itemcodeas[i] == "1") {
|
||||
ctx!.fillRect(
|
||||
(k * linewidth + start_x + linewidth) * ratio,
|
||||
start_y * ratio,
|
||||
linewidth * ratio,
|
||||
(barheight - offsetHeigt) * ratio)
|
||||
}
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
ctx.fill()
|
||||
|
||||
},
|
||||
clear() {
|
||||
let canvas = this.$refs['xBarcode'] as UniCanvasElement
|
||||
let ctx = canvas.getContext('2d')!
|
||||
// 处理高清屏逻辑
|
||||
const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
|
||||
canvas.width = canvas.offsetWidth * dpr;
|
||||
canvas.height = canvas.offsetHeight * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
let ratio = 1;
|
||||
|
||||
try{
|
||||
ctx?.reset()
|
||||
}catch(e){
|
||||
//TODO handle the exception
|
||||
}
|
||||
ctx.fillStyle = 'rgba(0,0,0,0)'
|
||||
ctx.fillRect(0, 0, this.boxWidth, this.boxHeight)
|
||||
ctx.fill()
|
||||
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<canvas class="xBarcode" ref="xBarcode" :id="id" :style="{width:_width,height:_height}"></canvas>
|
||||
</template>
|
||||
<style scoped>
|
||||
</style>
|
||||
Reference in New Issue
Block a user