Browse Source

流水号

master
han\hanst 7 months ago
parent
commit
6e4f4da0ba
  1. 20
      src/utils/zplGenerator.js
  2. 110
      src/views/modules/labelSetting/LabelDesigner.vue
  3. 16
      src/views/modules/labelSetting/components/DataSourceDialog.vue
  4. 41
      src/views/modules/labelSetting/components/DesignCanvas.vue
  5. 46
      src/views/modules/labelSetting/components/DesignElement.vue
  6. 6
      src/views/modules/labelSetting/components/HorizontalToolbar.vue
  7. 97
      src/views/modules/labelSetting/components/PropertyForm.vue
  8. 8
      src/views/modules/labelSetting/components/ToolItem.vue

20
src/utils/zplGenerator.js

@ -101,6 +101,8 @@ export class ZPLGenerator {
return this.generateHorizontalLineZPL(element, x, y)
case 'vLine':
return this.generateVerticalLineZPL(element, x, y)
case 'serialNumber':
return this.generateSerialNumberZPL(element, x, y)
default:
return ''
}
@ -201,6 +203,24 @@ export class ZPLGenerator {
return `^FO${x},${y}^GB1,${element.height},${element.width},B^FS`
}
}
/**
* 生成流水号ZPL代码
*/
generateSerialNumberZPL(element, x, y) {
const zpl = []
const bold = element.bold || false // 加粗(可选)
const serialStr = '流水号'
const base = `^FO${x},${y}^FD${element.data}^FS`
zpl.push(base)
// 可选:加粗效果(重复打印)
if (bold) {
zpl.push(`^FO${x+1},${y}^FD${serialStr}^FS`)
zpl.push(`^FO${x},${y+1}^FD${serialStr}^FS`)
zpl.push(`^FO${x+1},${y+1}^FD${serialStr}^FS`)
}
return zpl.join('\n')
}
}
/**

110
src/views/modules/labelSetting/LabelDesigner.vue

@ -133,6 +133,7 @@
:visible="dataSourceVisible"
:data-keys="dataKeys"
:current-text="currentElementText"
:source-type="sourceType"
@update:visible="dataSourceVisible = $event"
@confirm="handleDataSourceConfirm"
/>
@ -172,6 +173,7 @@ export default {
},
data() {
return {
sourceType: 'text', //
labelNo: '',
showGrid: true,
snapToGrid: true,
@ -440,6 +442,8 @@ export default {
},
handleDrop(dropData) {
console.log('主设计器接收到拖拽数据:', dropData) //
if (!this.labelNo) {
this.$alert('标签编号不可为空!', '错误', {
confirmButtonText: '确定'
@ -448,10 +452,17 @@ export default {
}
const newElement = this.createNewElement(dropData)
console.log('创建的新元素:', newElement) //
this.elements.push(newElement)
//
this.selectedIndex = this.elements.length - 1
},
createNewElement({ type, x, y }) {
console.log('创建新元素:', { type, x, y }) //
const baseElement = {
type,
x,
@ -461,24 +472,65 @@ export default {
bold: false,
newline: false,
lineRows: 2,
lineWidth: 200
lineWidth: 200,
digits: 6,
step: 1,
}
//
//
const sizeConfig = {
text: { width: 100, height: 30 },
barcode: { width: 3, height: 50 },
onecode: { width: 3, height: 50 },
qrcode: { width: 10, height: 10 },
pic: { width: 100, height: 100 },
hLine: { width: 400, height: 3 },
vLine: { width: 3, height: 400 }
text: {
width: 100,
height: 30,
data: '文本元素'
},
barcode: {
width: 3,
height: 50,
data: '123456789'
},
onecode: {
width: 3,
height: 50,
data: '123456789'
},
qrcode: {
width: 10,
height: 10,
data: 'QR Code'
},
pic: {
width: 100,
height: 100
},
hLine: {
width: 400,
height: 3
},
vLine: {
width: 3,
height: 400
},
serialNumber: {
width: 120,
height: 30,
digits: 6,
step: 1,
data: '流水号', //
fontSize: 30
}
}
return {
const config = sizeConfig[type] || { width: 100, height: 30 }
const newElement = {
...baseElement,
...sizeConfig[type]
...config
}
console.log('新元素配置:', newElement) //
return newElement
},
handleElementSelect(index) {
@ -639,7 +691,7 @@ export default {
// PropertyPanel
},
async handleDataSource(currentText) {
async handleDataSource(inData) {
const response = await getViewFieldsByLabelType({
labelType: this.labelSettings.labelType,
site: this.$store.state.user.site
@ -650,42 +702,18 @@ export default {
...field,
fieldDescription: field.fieldDescription || ''
}));
this.currentElementText = currentText || ''
this.currentElementText = inData.data || ''
this.sourceType = inData.type || 'text'
this.dataSourceVisible = true
} else {
this.$message.error(response.data.msg || '获取字段信息失败');
}
/* if (this.elements.length > 0) {
this.dataKeys = Object.keys(this.elements[0])
this.currentElementText = currentText || ''
this.dataSourceVisible = true
}*/
},
async loadViewFields() {
try {
const response = await getViewFieldsByLabelType({
labelType: this.labelSettings.labelType,
site: this.$store.state.user.site
});
if (response.data && response.data.code === 200) {
this.viewFields = response.data.data.map(field => ({
...field,
fieldDescription: field.fieldDescription || ''
}));
} else {
this.$message.error(response.data.msg || '获取字段信息失败');
}
} catch (error) {
console.error('获取字段信息失败:', error);
}
},
handleDataSourceConfirm(selectedKeys) {
handleDataSourceConfirm(selectedKeys, sourceType) {
if (this.selectedElement) {
this.selectedElement.data = selectedKeys.map(key => `#{${key}}`).join('')
this.selectedElement.data = sourceType==='serialNumber'?selectedKeys.map(key => `${key}`).join('+'):
selectedKeys.map(key => `#{${key}}`).join('')
}
},

16
src/views/modules/labelSetting/components/DataSourceDialog.vue

@ -47,6 +47,10 @@ export default {
currentText: {
type: String,
default: ''
},
sourceType: {
type: String,
default: 'text' //
}
},
emits: ['update:visible', 'confirm'],
@ -81,7 +85,17 @@ export default {
foundKeys.push(key.fieldName)
}
})
if (this.sourceType==='serialNumber'){
this.dataKeys.forEach(key => {
//
const pattern = new RegExp(`\\b${key.fieldName}\\b`, 'g')
if (pattern.test(this.currentText)) {
foundKeys.push(key.fieldName)
}
})
}
this.selectedKeys = foundKeys
},
@ -90,7 +104,7 @@ export default {
},
handleConfirm() {
this.$emit('confirm', this.selectedKeys)
this.$emit('confirm', this.selectedKeys, this.sourceType)
this.handleClose()
}
}

41
src/views/modules/labelSetting/components/DesignCanvas.vue

@ -3,7 +3,8 @@
class="design-canvas"
:class="{ 'show-grid': showGrid }"
:style="canvasStyle"
@dragover.prevent
@dragover="handleDragOver"
@dragenter="handleDragEnter"
@drop="handleDrop"
>
<!-- 空状态提示 -->
@ -134,14 +135,35 @@ export default {
}
},
methods: {
handleDragOver(e) {
e.preventDefault()
e.stopPropagation()
e.dataTransfer.dropEffect = 'copy'
},
handleDragEnter(e) {
e.preventDefault()
e.stopPropagation()
},
handleDrop(e) {
const type = e.dataTransfer.getData('type')
if (!type) return
e.preventDefault()
e.stopPropagation()
const type = e.dataTransfer.getData('type') || e.dataTransfer.getData('text/plain')
console.log('画布接收到拖拽类型:', type) //
if (!type) {
console.warn('未获取到拖拽类型数据')
return
}
const rect = e.currentTarget.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
console.log('拖拽位置:', { x, y }) //
this.$emit('drop', { type, x, y })
},
@ -335,6 +357,19 @@ export default {
}
}
//
if (element.type === 'serialNumber') {
const fontSize = element.fontSize || 30
const prefix = element.prefix || ''
const digits = parseInt(element.digits) || 6
const estimatedWidth = Math.max((prefix.length + digits) * (fontSize * 0.6), 80)
return {
width: Math.min(estimatedWidth + 16, 200), // padding
height: Math.max(fontSize + 8, 30) // padding30px
}
}
return baseSize
}
}

46
src/views/modules/labelSetting/components/DesignElement.vue

@ -78,6 +78,12 @@
}"
></div>
</div>
<!-- 流水号元素 -->
<div v-else-if="element.type === 'serialNumber'" class="serial-number-element">
<div class="element-label">流水号</div>
</div>
</div>
</template>
@ -169,6 +175,17 @@ export default {
this.isDragging = false
document.removeEventListener('mousemove', this.handleMouseMove)
document.removeEventListener('mouseup', this.handleMouseUp)
},
getSerialNumberDisplay() {
if (this.element.type !== 'serialNumber') return ''
const prefix = this.element.prefix || 'SN'
const startValue = parseInt(this.element.startValue) || 1
const digits = parseInt(this.element.digits) || 6
const paddedNumber = startValue.toString().padStart(digits, '0')
return `${prefix}${paddedNumber}`
}
}
}
@ -341,6 +358,35 @@ export default {
border-color: rgba(46, 204, 113, 0.4);
}
.design-element[data-type="serialNumber"] {
border-color: rgba(114, 46, 209, 0.4);
}
.serial-number-element {
display: flex;
flex-direction: column;
align-items: center;
padding: 4px 6px;
background: linear-gradient(135deg, #f3e8ff, #f3e8ff);
border-radius: 6px;
min-width: 60px;
}
.serial-number-element .serial-display {
font-size: 12px;
font-weight: 600;
color: #2c3e50;
padding: 6px 4px;
background: linear-gradient(135deg, #fff, #f8f9fa);
border: 1px solid rgba(114, 46, 209, 0.3);
border-radius: 4px;
min-width: 70px;
text-align: center;
font-family: 'Courier New', monospace;
letter-spacing: 0.5px;
box-shadow: 0 1px 3px rgba(114, 46, 209, 0.1);
}
/* 响应式调整 */
@media (max-width: 1200px) {
.design-element {

6
src/views/modules/labelSetting/components/HorizontalToolbar.vue

@ -98,6 +98,12 @@ export default {
label: '竖线',
rotate: true,
color: '#909399'
},
{
type: 'serialNumber',
icon: 'el-icon-setting',
label: '流水号',
color: '#909399'
}
]
}

97
src/views/modules/labelSetting/components/PropertyForm.vue

@ -6,7 +6,7 @@
<el-form-item label="文本内容">
<div class="input-with-button">
<el-input v-model="element.data" placeholder="请输入文本" />
<el-button type="primary" size="mini" @click="$emit('data-source', element.data)">
<el-button type="primary" size="mini" @click="$emit('data-source', element)">
数据源
</el-button>
</div>
@ -59,7 +59,7 @@
<el-form-item label="数据内容">
<div class="input-with-button">
<el-input v-model="element.data" placeholder="请输入条码数据" />
<el-button type="primary" size="mini" @click="$emit('data-source', element.data)">
<el-button type="primary" size="mini" @click="$emit('data-source', element)">
数据源
</el-button>
</div>
@ -95,7 +95,7 @@
<el-form-item label="数据内容">
<div class="input-with-button">
<el-input v-model="element.data" placeholder="请输入二维码数据" />
<el-button type="primary" size="mini" @click="$emit('data-source', element.data)">
<el-button type="primary" size="mini" @click="$emit('data-source', element)">
数据源
</el-button>
</div>
@ -168,10 +168,69 @@
</div>
</el-form>
</div>
<!-- 流水号属性 -->
<div v-else-if="element.type === 'serialNumber'" class="form-section">
<el-form label-position="top" size="small">
<div class="form-row">
<el-form-item label="位数" class="form-item-half">
<el-input
v-model="element.digits"
:min="1"
:max="10"
controls-position="right"
size="mini"
placeholder="6"
/>
</el-form-item>
<el-form-item label="步长" class="form-item-half">
<el-input
v-model="element.step"
:min="1"
:max="100"
controls-position="right"
size="mini"
placeholder="1"
/>
</el-form-item>
</div>
<div class="form-row">
<el-form-item label="字体大小" class="form-item-half">
<el-input
v-model="element.fontSize"
:min="8"
:max="200"
controls-position="right"
size="mini"
placeholder="30"
/>
</el-form-item>
<el-form-item label="加粗" class="form-item-half">
<el-checkbox v-model="element.bold" size="middle"></el-checkbox>
</el-form-item>
</div>
<div class="form-row">
<el-form-item label="流水号规则" class="form-item-half">
<el-input v-model="element.data" placeholder="请输入流水号规则" @focus="$emit('data-source', element)"/>
</el-form-item>
<el-form-item label="流水号信息" class="form-item-half">
<el-button type="primary" size="mini" @click="serialInfoModal(element)">
查看
</el-button>
</el-form-item>
</div>
</el-form>
</div>
<!-- 标签内容流水号信息 -->
<comShowLabelSerialInfo ref="comShowLabelSerialInfo" @refreshCurrentPageTable="refreshCurrentPageTable" v-drag></comShowLabelSerialInfo>
</div>
</template>
<script>
import comShowLabelSerialInfo from "../com_show_label_serial_info";
export default {
name: 'PropertyForm',
props: {
@ -181,7 +240,22 @@ export default {
}
},
emits: ['data-source', 'image-upload'],
/*组件*/
components: {
comShowLabelSerialInfo,/*标签内容流水号信息的組件*/
},
methods: {
/*流水号信息的modal*/
serialInfoModal(row){
let rowData = {
labelNo: row.reportId,
itemNo: row.itemNo,
};
//
this.$nextTick(() => {
this.$refs.comShowLabelSerialInfo.init(rowData);
})
},
validateQRSize() {
if (this.element.height > 10) {
this.$message.warning('二维码最大尺寸为10')
@ -265,6 +339,17 @@ export default {
zplData: `${totalBytes},${totalBytes},${bytesPerRow},${binaryData}`,
previewUrl: canvas.toDataURL()
}
},
getSerialNumberPreview() {
if (this.element.type !== 'serialNumber') return ''
const prefix = this.element.prefix || ''
const startValue = parseInt(this.element.startValue) || 1
const digits = parseInt(this.element.digits) || 6
const paddedNumber = startValue.toString().padStart(digits, '0')
return `${prefix}${paddedNumber}`
}
}
}
@ -509,8 +594,10 @@ export default {
/* 复选框在行中的样式 */
.form-item-half .el-checkbox {
display: block !important;
margin-bottom: 4px !important;
margin-bottom: 1px !important;
margin-right: 0 !important;
padding-top: 5px;
padding-left: 1px;
}
.form-item-half .el-checkbox:last-child {
@ -648,7 +735,7 @@ export default {
/* 统一所有输入框样式 */
.form-section .el-input {
width: 120px !important;
width: 150px !important;
}
.form-section .el-input .el-input__inner {

8
src/views/modules/labelSetting/components/ToolItem.vue

@ -30,7 +30,15 @@ export default {
emits: ['dragstart'],
methods: {
handleDragStart(e) {
console.log('开始拖拽工具:', this.tool.type) //
//
e.dataTransfer.setData('type', this.tool.type)
e.dataTransfer.setData('text/plain', this.tool.type) //
//
e.dataTransfer.effectAllowed = 'copy'
this.$emit('dragstart', this.tool.type)
}
}

Loading…
Cancel
Save