You need to sign in or sign up before continuing.
提交 2d1109c2 编写于 作者: G guop 提交者: ninecents

添加生成条形码功能 #89

1. 添加以来vue-color,jsbarcode。
vue-color 是一个颜色选择器.
https://github.com/xiaokaike/vue-color.git

jsbarcode 是该功能的核心工具,能够生成各类条形码
https://github.com/lindell/JsBarcode.git

2. 仿照jsbarcode的demo页面将条码生成功能集成到CTool中
https://lindell.me/JsBarcode/generator/
上级 4b3b7016
{ {
"name": "c-tool", "name": "c-tool",
"version": "1.8.1", "version": "1.8.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
...@@ -3265,6 +3265,11 @@ ...@@ -3265,6 +3265,11 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"clamp": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz",
"integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ="
},
"class-utils": { "class-utils": {
"version": "0.3.6", "version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
...@@ -7001,6 +7006,11 @@ ...@@ -7001,6 +7006,11 @@
"esprima": "^4.0.0" "esprima": "^4.0.0"
} }
}, },
"jsbarcode": {
"version": "3.11.5",
"resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.5.tgz",
"integrity": "sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA=="
},
"jsbn": { "jsbn": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
...@@ -7636,6 +7646,11 @@ ...@@ -7636,6 +7646,11 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
...@@ -12345,6 +12360,17 @@ ...@@ -12345,6 +12360,17 @@
"integrity": "sha512-cCjEgTD4nO5YQeRgdrrOqN7Qc2MzBx2u90J/CJ3Gp4PZ2sUONZE67/Qy+zWNHCWVCYsSEIvbnPSuiiQeEr1KSQ==", "integrity": "sha512-cCjEgTD4nO5YQeRgdrrOqN7Qc2MzBx2u90J/CJ3Gp4PZ2sUONZE67/Qy+zWNHCWVCYsSEIvbnPSuiiQeEr1KSQ==",
"dev": true "dev": true
}, },
"vue-color": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/vue-color/-/vue-color-2.8.1.tgz",
"integrity": "sha512-BoLCEHisXi2QgwlhZBg9UepvzZZmi4176vbr+31Shen5WWZwSLVgdScEPcB+yrAtuHAz42309C0A4+WiL9lNBw==",
"requires": {
"clamp": "^1.0.1",
"lodash.throttle": "^4.0.0",
"material-colors": "^1.0.0",
"tinycolor2": "^1.1.2"
}
},
"vue-eslint-parser": { "vue-eslint-parser": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"js-base64": "^2.6.4", "js-base64": "^2.6.4",
"js-htmlencode": "^0.3.0", "js-htmlencode": "^0.3.0",
"js-yaml": "^3.14.1", "js-yaml": "^3.14.1",
"jsbarcode": "^3.11.5",
"json-to-properties": "^1.1.3", "json-to-properties": "^1.1.3",
"jsonlint": "^1.6.3", "jsonlint": "^1.6.3",
"jsrsasign": "^10.4.1", "jsrsasign": "^10.4.1",
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
"uuid": "^8.3.2", "uuid": "^8.3.2",
"view-design": "^4.6.1", "view-design": "^4.6.1",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-color": "^2.8.1",
"vue-router": "^3.5.3", "vue-router": "^3.5.3",
"x2js": "github:abdolence/x2js" "x2js": "github:abdolence/x2js"
}, },
......
...@@ -40,6 +40,7 @@ const tool = [ ...@@ -40,6 +40,7 @@ const tool = [
{'name': 'url', 'title': 'URL编码', 'cat': ['conversion']}, {'name': 'url', 'title': 'URL编码', 'cat': ['conversion']},
{'name': 'timestamp', 'title': '时间戳', 'cat': ['conversion']}, {'name': 'timestamp', 'title': '时间戳', 'cat': ['conversion']},
{'name': 'qrCode', 'title': '二维码', 'cat': ['generate']}, {'name': 'qrCode', 'title': '二维码', 'cat': ['generate']},
{'name': 'barcode', 'title': '条形码', 'cat': ['generate']},
{'name': 'pinyin', 'title': '汉字转拼音', 'cat': ['conversion']}, {'name': 'pinyin', 'title': '汉字转拼音', 'cat': ['conversion']},
{'name': 'ip', 'title': 'IP地址查询', 'cat': ['other']}, {'name': 'ip', 'title': 'IP地址查询', 'cat': ['other']},
{'name': 'code', 'title': '代码格式化', 'cat': ['other']}, {'name': 'code', 'title': '代码格式化', 'cat': ['other']},
......
...@@ -70,6 +70,10 @@ const routes = [ ...@@ -70,6 +70,10 @@ const routes = [
path: '/tool/qrCode', path: '/tool/qrCode',
component: r => require(['./views/tool/qrCode.vue'], r) component: r => require(['./views/tool/qrCode.vue'], r)
}, },
{
path: '/tool/barcode',
component: r => require(['./views/tool/barcode.vue'], r)
},
{ {
path: '/tool/randomString', path: '/tool/randomString',
component: r => require(['./views/tool/randomString.vue'], r) component: r => require(['./views/tool/randomString.vue'], r)
......
<template> <template>
<div> <div>
<div style="height: 250px;line-height: 250px;text-align: center;vertical-align: middle;"> <Row>
<canvas @click="saveImage" :style="`border: ${canvasBorder};vertical-align: middle;`" ref="barcode"
class="barcode" v-show="!validStr" style="cursor:pointer"></canvas>
<p style="color: red" v-show="validStr">{{ validStr }}</p>
</div>
<div id="barcode-setting">
<Row :gutter="10">
<Col span="12"> <Col span="12">
<Form :label-width="80"> <Card>
<FormItem :label="$t('barcode_content')"> <Form :label-width="100">
<FormItem label="条码内容">
<Input v-model="current.text"> <Input v-model="current.text">
<Select v-model="current.format" slot="append" style="width: 100px"> <Select v-model="current.format" slot="append" style="width: 100px">
<Option v-for="type in barcodeFormat" :key="type" :value="type">{{ type }}</Option> <Option v-for="type in barcodeFormat" :key="type" :value="type">{{ type }}</Option>
</Select> </Select>
</Input> </Input>
</FormItem> </FormItem>
<FormItem label="条码宽" class="line-item">
<Row> <Row>
<Col span="12"> <Col span="22">
<FormItem :label="$t('barcode_background')"> <Slider v-model="current.width" :min="0" :max="4"></Slider>
<ColorPicker recommend v-model="current.background"/>
</FormItem>
</Col>
<Col span="12">
<FormItem :label="$t('barcode_line_color')">
<ColorPicker recommend v-model="current.lineColor"/>
</FormItem>
</Col>
</Row>
<FormItem :label="$t('barcode_bar_width')">
<Row>
<Col span="21">
<Slider v-model="current.width" :min="1" :max="4"></Slider>
</Col> </Col>
<Col span="3"> <Col span="2">
<span style="float: right">{{ this.current.width }}</span> <span style="float: right">{{ this.current.width }}</span>
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
<FormItem :label="$t('barcode_height')"> <FormItem label="条码高" class="line-item">
<Row> <Row>
<Col span="21"> <Col span="22">
<Slider v-model="current.height" :min="10" :max="150"></Slider> <Slider v-model="current.height" :min="10" :max="150"></Slider>
</Col> </Col>
<Col span="3"> <Col span="2">
<span style="float: right">{{ this.current.height }}</span> <span style="float: right">{{ this.current.height }}</span>
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
<FormItem :label="$t('barcode_margin')"> <FormItem label="条码外边距" class="line-item">
<Row> <Row>
<Col span="21"> <Col span="22">
<Slider v-model="current.margin" :min="0" :max="25"></Slider> <Slider v-model="current.margin" :min="0" :max="25"></Slider>
</Col> </Col>
<Col span="3"> <Col span="2">
<span style="float: right">{{ this.current.margin }}</span> <span style="float: right">{{ this.current.margin }}</span>
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
</Form> <FormItem label="背景" class="line-item">
</Col> <Input type="text" id="backgroundInput" v-model="current.background.hex"
<Col span="12"> @on-focus="openBackgroundPicker($event)"></Input>
<Form :label-width="80"> <chrome-picker v-show="showBackgroundPicker" id="backgroundPicker" style="position: fixed;z-index: 1000"
<FormItem :label="$t('barcode_show_text')"> v-model="current.background"
<RadioGroup v-model="current.textPosition" type="button"> @input="updateBackground"/>
<Radio label="close"> </FormItem>
<span>{{ $t('barcode_hide') }}</span> <FormItem label="线条颜色" class="line-item">
</Radio> <Input type="text" id="lineColorInput" v-model="current.lineColor.hex"
<Radio label="top"> @on-focus="openLineColorPicker"></Input>
<span>{{ $t('barcode_top') }}</span> <chrome-picker v-show="showLineColoePicker" id="lineColorPicker" style="position: fixed;z-index: 1000"
v-model="current.lineColor"
@input="updateLineColor"/>
</FormItem>
<FormItem label="显示文本" class="line-item">
<RadioGroup v-model="current.showText" type="button">
<Radio label="true">
<span>显示</span>
</Radio> </Radio>
<Radio label="bottom"> <Radio label="false">
<span>{{ $t('barcode_bottom') }}</span> <span>隐藏</span>
</Radio> </Radio>
</RadioGroup> </RadioGroup>
</FormItem> </FormItem>
<FormItem :label="$t('barcode_text_align')"> <div v-if="this.current.showText === 'true'">
<FormItem label="字体位置" class="line-item">
<RadioGroup v-model="current.textAlign" type="button"> <RadioGroup v-model="current.textAlign" type="button">
<Radio :disabled="!showText" label="left"> <Radio label="left">
<span>{{ $t('barcode_left') }}</span> <span>居左</span>
</Radio> </Radio>
<Radio :disabled="!showText" label="center"> <Radio label="center">
<span>{{ $t('barcode_center') }}</span> <span>居中</span>
</Radio> </Radio>
<Radio :disabled="!showText" label="right"> <Radio label="right">
<span>{{ $t('barcode_right') }}</span> <span>居右</span>
</Radio> </Radio>
</RadioGroup> </RadioGroup>
</FormItem> </FormItem>
<FormItem :label="$t('barcode_font')"> <FormItem label="字体" class="line-item">
<Row :gutter="10"> <Select v-model="current.font">
<Col span="12">
<Select :disabled="!showText" v-model="current.font">
<Option v-for="font in fontFamily" :key="font" :value="font">{{ font }}</Option> <Option v-for="font in fontFamily" :key="font" :value="font">{{ font }}</Option>
</Select> </Select>
</Col> </FormItem>
<Col span="12"> <FormItem label="字体样式" class="line-item">
<CheckboxGroup v-model="current.fontOptions"> <CheckboxGroup v-model="current.fontOptions">
<Checkbox :disabled="!showText" label="bold"> <Checkbox label="bold">
<span>{{ $t('barcode_bold') }}</span> <span>粗体</span>
</Checkbox> </Checkbox>
<Checkbox :disabled="!showText" label="italic"> <Checkbox label="italic">
<span>{{ $t('barcode_italic') }}</span> <span>斜体</span>
</Checkbox> </Checkbox>
</CheckboxGroup> </CheckboxGroup>
</Col>
</Row>
</FormItem> </FormItem>
<FormItem :label="$t('barcode_font_size')"> <FormItem label="字体大小" class="line-item">
<Row> <Row>
<Col span="22"> <Col span="22">
<Slider :disabled="!showText" v-model="current.fontSize" :min="8" <Slider v-model="current.fontSize" :min="8" :max="36"></Slider>
:max="36"></Slider>
</Col> </Col>
<Col span="2"> <Col span="2">
<span style="float: right">{{ this.current.fontSize }}</span> <span style="float: right">{{ this.current.fontSize }}</span>
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
<FormItem :label="$t('barcode_text_margin')"> <FormItem label="字体外边距" class="line-item">
<Row> <Row>
<Col span="22"> <Col span="22">
<Slider :disabled="!showText" v-model="current.textMargin" :min="-15" <Slider v-model="current.textMargin" :min="-15" :max="40"></Slider>
:max="40"></Slider>
</Col> </Col>
<Col span="2"> <Col span="2">
<span style="float: right">{{ this.current.textMargin }}</span> <span style="float: right">{{ this.current.textMargin }}</span>
</Col> </Col>
</Row> </Row>
</FormItem> </FormItem>
</div>
</Form> </Form>
</Card>
</Col> </Col>
</Row> <Col span="12">
<Card>
<div>
<canvas id="barcode"></canvas>
<p style="color: red">{{ validStr }}</p>
</div> </div>
</Card>
</Col>
</Row>
</div> </div>
</template> </template>
<script> <script>
...@@ -141,27 +135,29 @@ ...@@ -141,27 +135,29 @@
* @date 2021/10/30 * @date 2021/10/30
* 基于jsbarcode生成条形码,可以自定义条码各项属性 * 基于jsbarcode生成条形码,可以自定义条码各项属性
* 不支持中文 * 不支持中文
* 颜色选择器采用vue-color
*/ */
import JsBarcode from 'jsbarcode' import JsBarcode from 'jsbarcode'
import {Chrome} from 'vue-color'
export default { export default {
created() { created() {
this.$initToolData('text') this.current = Object.assign(this.current, this.$getToolData("content"))
}, },
computed: { components: {
showText() { 'chrome-picker': Chrome,
return ['top', 'bottom'].includes(this.current.textPosition)
},
canvasBorder() {
if (this.current.background.toUpperCase() === "#FFFFFF") {
return "1px dashed #666"
}
return "1px dashed #fff";
}
}, },
mounted() { mounted() {
// 加载颜色选择器消失的事件
this.loadEvent()
// 生成默认的条形码
this.generate() this.generate()
}, },
beforeDestroy() {
// 移除挂载时添加的事件
document.removeEventListener('click', () => {
}, true)
},
watch: { watch: {
current: { current: {
handler() { handler() {
...@@ -170,57 +166,112 @@ export default { ...@@ -170,57 +166,112 @@ export default {
deep: true deep: true
} }
}, },
methods: { methods: {
/**
* 检查
* @param event
* @param id
* @returns {boolean}
*/
checkNodeContainsId(event, id) {
// 检查目标元素及目标元素上层是否存在指定id元素
let et = event.target
while (et && et.id !== undefined) {
// 检查当前元素上是否存在指定
if (et.id === id) {
return true
}
et = et.parentNode
}
},
loadEvent() {
let _this = this
document.addEventListener('click', (e) => {
// 如果点击的区域不是输入框或者是背景色选择器则将背景选择器隐藏
if (!_this.checkNodeContainsId(e, 'backgroundInput') && !_this.checkNodeContainsId(e, 'backgroundPicker')) {
_this.showBackgroundPicker = false
}
// 同理
if (!_this.checkNodeContainsId(e, 'lineColorInput') && !_this.checkNodeContainsId(e, 'lineColorPicker')) {
_this.showLineColoePicker = false
}
})
},
openBackgroundPicker() {
this.showBackgroundPicker = true
this.showLineColoePicker = false
},
updateBackground(val) {
this.current.background = val
},
openLineColorPicker() {
this.showLineColoePicker = true
this.showBackgroundPicker = false
},
updateLineColor(val) {
this.current.lineColor = val
},
closeColorPicker() {
this.showLineColoePicker = false
this.showBackgroundPicker = false
},
generate() { generate() {
let _this = this;
// 处理字体样式 // 处理字体样式
let fontOptions = this.current.fontOptions.join(" ") let fontOptions = this.current.fontOptions.join(" ")
const barcodeContent = this.current.text ? this.current.text : "Example 1234" JsBarcode("#barcode", this.current.text, {
JsBarcode(this.$refs.barcode, barcodeContent, { format: this.current.format,//选择要使用的条形码类型
format: this.current.format,
width: this.current.width, width: this.current.width,
height: this.current.height, height: this.current.height,
margin: this.current.margin, margin: this.current.margin,
background: this.current.background, background: this.current.background.hex,
lineColor: this.current.lineColor, lineColor: this.current.lineColor.hex,
displayValue: this.showText, displayValue: this.current.showText,//是否在条形码下方显示文字
textPosition: this.current.textPosition, textPosition: "bottom",//设置文本的垂直位置
textAlign: this.current.textAlign, textAlign: this.current.textAlign,
font: this.current.font, font: this.current.font,
fontOptions: fontOptions, fontOptions: fontOptions,
fontSize: this.current.fontSize, fontSize: this.current.fontSize,
textMargin: this.current.textMargin, textMargin: this.current.textMargin,
valid: (valid) => { valid: function (valid) {
this.validStr = !valid ? `"${barcodeContent}" ${this.$t('barcode_invalid_content').toString()}` : ""; // 显示条码内容无效
if (!this.validStr && this.current.text) { if (!valid) {
this.$saveToolData(this.current) _this.validStr = "无效的条码内容"
} else {
_this.validStr = ""
} }
} }
}) })
}, },
saveImage() {
if (!this.validStr && this.current.text) {
this.$clipboardCopyImages(this.$refs.barcode.toDataURL("image/png"), true)
}
}
}, },
data() { data() {
return { return {
current: { current: {
text: "", text: "Test 123456789",
format: "CODE128", format: "CODE128",
width: 2, width: 2,
height: 50, height: 50,
margin: 10, margin: 10,
background: "#FFFFFF", background: {
lineColor: "#000000", hex: '#FFFFFF',
},
lineColor: {
hex: '#000000',
},
showText: "true",
textAlign: "center", textAlign: "center",
textPosition: "bottom",
font: "monospace", font: "monospace",
fontOptions: [], fontOptions: [],
fontSize: 20, fontSize: 20,
textMargin: 0 textMargin: 0
}, },
validStr: '', validStr: '',
// 背景色选择器控制开关
showBackgroundPicker: false,
// 线条颜色选择器控制开关
showLineColoePicker: false,
// 条码格式 // 条码格式
barcodeFormat: [ barcodeFormat: [
"CODE128", "CODE128",
...@@ -246,8 +297,8 @@ export default { ...@@ -246,8 +297,8 @@ export default {
"Serif", "Serif",
"Fantasy", "Fantasy",
"Cursive" "Cursive"
], ]
barcodeBase64: "",
} }
}, },
} }
...@@ -255,7 +306,7 @@ export default { ...@@ -255,7 +306,7 @@ export default {
<style scoped> <style scoped>
/**iview原来的formitem太高了,在浏览器直接使用插件时会被撑开,因此需要压缩下高度**/ /**iview原来的formitem太高了,在浏览器直接使用插件时会被撑开,因此需要压缩下高度**/
#barcode-setting .ivu-form-item { .line-item {
margin-bottom: 2px; margin-top: -20px;
} }
</style> </style>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册