art:条形码生成并打印的组件
This commit is contained in:
parent
861b77aa93
commit
d089737967
@ -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",
|
||||
|
29
src/api/material/mods/material/generateBarcodes.ts
Normal file
29
src/api/material/mods/material/generateBarcodes.ts
Normal 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))
|
||||
}
|
@ -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
11
src/components.d.ts
vendored
@ -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']
|
||||
|
121
src/views/stock/material/print-code.vue
Normal file
121
src/views/stock/material/print-code.vue
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user