art:条形码生成并打印的组件
Some checks failed
Release / lint (push) Successful in 29s
Release / Release (push) Failing after 35s

This commit is contained in:
my_ong 2024-12-13 13:11:26 +08:00
parent 861b77aa93
commit d089737967
5 changed files with 222 additions and 20 deletions

View File

@ -4027,6 +4027,63 @@
}
]
},
{
"description": "批量生成条形码",
"name": "generateBarcodes",
"method": "post",
"path": "/material/{id}/generate-barcodes",
"response": {
"typeArgs": [
{
"typeArgs": [],
"typeName": "string",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
],
"typeName": "Array",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
},
"parameters": [
{
"description": "物料id",
"required": true,
"in": "path",
"name": "id",
"dataType": {
"typeArgs": [],
"typeName": "number",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
},
{
"description": "条形码数量",
"required": true,
"in": "query",
"name": "count",
"dataType": {
"typeArgs": [],
"typeName": "number",
"isDefsType": false,
"templateIndex": -1,
"compileTemplateKeyword": "#/definitions/",
"enum": [],
"typeProperties": []
}
}
]
},
{
"description": "分页查询物料列表",
"name": "materials",

View File

@ -0,0 +1,29 @@
/**
* @desc
*/
import { defaultSuccess, defaultError, http } from '@/plugins/axios'
import type { AxiosResponse } from 'axios'
export interface Params {
/** 条形码数量 */
count: number
}
export default async function (
/** 物料id */
id: number,
params: Params,
success: (data: Array<string>) => void = defaultSuccess,
fail: (error: { code: string; error?: string }) => void = defaultError,
): Promise<void> {
return http({
method: 'post',
url: `/material/${id}/generate-barcodes`,
params,
})
.then((data: AxiosResponse<Array<string>, unknown>) => {
success(data.data)
})
.catch((error: { code: string; error?: string }) => fail(error))
}

View File

@ -2,16 +2,18 @@
* @description
*
*/
import saveOrUpdateMaterial from './saveOrUpdateMaterial';
import all from './all';
import detail from './detail';
import deleteMaterial from './deleteMaterial';
import materials from './materials';
import saveOrUpdateMaterial from './saveOrUpdateMaterial'
import all from './all'
import detail from './detail'
import deleteMaterial from './deleteMaterial'
import generateBarcodes from './generateBarcodes'
import materials from './materials'
export default {
saveOrUpdateMaterial,
all,
detail,
deleteMaterial,
materials,
};
saveOrUpdateMaterial,
all,
detail,
deleteMaterial,
generateBarcodes,
materials,
}

11
src/components.d.ts vendored
View File

@ -13,15 +13,15 @@ declare module 'vue' {
ACard: typeof import('ant-design-vue/es')['Card']
ACol: typeof import('ant-design-vue/es')['Col']
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
ADivider: typeof import('ant-design-vue/es')['Divider']
ADrawer: typeof import('ant-design-vue/es')['Drawer']
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
AFlex: typeof import('ant-design-vue/es')['Flex']
AFloatButton: typeof import('ant-design-vue/es')['FloatButton']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AImage: typeof import('ant-design-vue/es')['Image']
AInput: typeof import('ant-design-vue/es')['Input']
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
ALayout: typeof import('ant-design-vue/es')['Layout']
@ -35,25 +35,18 @@ declare module 'vue' {
AModal: typeof import('ant-design-vue/es')['Modal']
APageHeader: typeof import('ant-design-vue/es')['PageHeader']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
AResult: typeof import('ant-design-vue/es')['Result']
ARow: typeof import('ant-design-vue/es')['Row']
ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASpace: typeof import('ant-design-vue/es')['Space']
AStatistic: typeof import('ant-design-vue/es')['Statistic']
ASteps: typeof import('ant-design-vue/es')['Steps']
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
ASwitch: typeof import('ant-design-vue/es')['Switch']
ATable: typeof import('ant-design-vue/es')['Table']
ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATransfer: typeof import('ant-design-vue/es')['Transfer']
ATree: typeof import('ant-design-vue/es')['Tree']
ATypographyLink: typeof import('ant-design-vue/es')['TypographyLink']
ATypographyParagraph: typeof import('ant-design-vue/es')['TypographyParagraph']
ATypographyTitle: typeof import('ant-design-vue/es')['TypographyTitle']

View File

@ -0,0 +1,121 @@
<template>
<div>
<a-flex gap="middle" horizontal>
<span class="ant-form-text">请输入打印的条码数量:</span>
<a-form-item name="input-number" no-style>
<a-input-number v-model:value="inputRef" :min="1" :max="10" @change="fetchAndPrintBarcodes(inputRef)" />
</a-form-item>
<button @click="printCode">打印条形码</button>
</a-flex>
<div id="barcodes-container">
<!-- 条形码将被动态插入到这里 -->
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import JsBarcode from 'jsbarcode'
import printJS from 'print-js'
import api from '@/api'
const props = defineProps({
//
materialId: {
type: Number,
default: 1,
},
})
const inputRef = ref(0)
const printCode = () => {
const container = document.getElementById('barcodes-container')
if (!container) {
window.console.log('条形码容器未找到')
return
}
// 40mm x 30mm
const widthInches = (40 * 0.0393701).toFixed(3) // 1.575
const heightInches = (30 * 0.0393701).toFixed(3) // 1.181
//
const printOptions: printJS.Configuration = {
printable: 'barcodes-container',
type: 'html',
scanStyles: false,
honorMarginPadding: false,
targetStyles: ['*'],
style: `
@page {
size: ${widthInches}in ${heightInches}in;
margin: 0;
}
body {
margin: 0;
padding: 0;
font-size: 6px;
}
#barcodes-container canvas {
display: block;
margin-bottom: 2mm; /* 调整条形码之间的间距 */
}
`,
onLoadingStart: () => console.log('开始加载'),
onLoadingEnd: () => console.log('加载完成'),
onError: (err) => console.error('打印出错:', err),
}
// 便
container.style.display = 'block'
// printJS
printJS(printOptions)
}
//
const fetchAndPrintBarcodes = async (count: number) => {
//
const container = document.getElementById('barcodes-container')
if (!container) throw new Error('条形码容器未找到')
container.innerHTML = ''
//
api.materialApi.material.generateBarcodes(props.materialId, { count: count }, (res: Array<string>) => {
res.forEach((barcodeString: string, index: number) => {
const canvasId = `barcode-${index}`
const canvasElement = document.createElement('canvas')
//
canvasElement.width = 472 // 40mm
canvasElement.height = 354 // 30mm
canvasElement.id = canvasId
container.appendChild(canvasElement)
// 使JsBarcode
JsBarcode(`#${canvasId}`, barcodeString, {
// format: "EAN13", //
width: 1, // 线
height: 70, //
displayValue: true, //
// fontOptions: "italic", //
fontSize: 10, //
textMargin: 5, //
margin: 10, //
})
})
})
}
//
// onMounted(fetchAndPrintBarcodes);
</script>
<style scoped>
/* 针对打印样式的样式 */
@media print {
#barcodes-container {
display: block;
}
}
</style>