|
|
<template> <div class="property-form"> <!-- 文本属性 --> <div v-if="element.type === 'text'" class="form-section"> <el-form label-position="top" size="small"> <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)"> 数据源 </el-button> </div> </el-form-item>
<el-form-item label="字体大小"> <div class="font-size-row"> <el-input style="margin-right: 36px" v-model="element.fontSize" :min="8" :max="200" controls-position="right" size="mini" class="font-size-input" /> <el-checkbox v-model="element.bold" size="small" class="inline-checkbox">加粗</el-checkbox> <el-checkbox v-model="element.newline" size="small" class="inline-checkbox">自动换行</el-checkbox> </div> </el-form-item>
<template v-if="element.newline"> <div class="form-row"> <el-form-item label="文本宽度" class="form-item-half"> <el-input v-model="element.lineWidth" :min="50" :max="1000" controls-position="right" size="mini" /> </el-form-item>
<el-form-item label="文本行数" class="form-item-half"> <el-input v-model="element.lineRows" :min="1" :max="10" controls-position="right" size="mini" /> </el-form-item> </div> </template> </el-form> </div>
<!-- 条码/一维码属性 --> <div v-else-if="['barcode', 'onecode'].includes(element.type)" class="form-section"> <el-form label-position="top" size="small"> <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)"> 数据源 </el-button> </div> </el-form-item>
<div class="form-row"> <el-form-item label="宽度" class="form-item-half"> <el-input v-model="element.width" :min="1" :max="10" controls-position="right" size="mini" /> </el-form-item>
<el-form-item label="高度" class="form-item-half"> <el-input v-model="element.height" :min="10" :max="500" controls-position="right" size="mini" /> </el-form-item> </div> </el-form> </div>
<!-- 二维码属性 --> <div v-else-if="element.type === 'qrcode'" class="form-section"> <el-form label-position="top" size="small"> <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)"> 数据源 </el-button> </div> </el-form-item>
<el-form-item label="尺寸"> <el-input v-model="element.height" :min="1" :max="10" controls-position="right" @change="validateQRSize" /> <div class="form-tip">二维码最大尺寸为10</div> </el-form-item> </el-form> </div>
<!-- 图片属性 --> <div v-else-if="element.type === 'pic'" class="form-section"> <el-form label-position="top" size="small"> <el-form-item label="图片上传"> <div class="image-upload"> <input ref="fileInput" type="file" accept="image/*" @change="handleImageUpload" style="display: none;" /> <el-button type="primary" icon="el-icon-upload" @click="handleSelectImage" > 选择图片 </el-button> </div> </el-form-item>
<div v-if="element.previewUrl" class="image-preview"> <img :src="element.previewUrl" alt="预览" /> </div> </el-form> </div>
<!-- 线条属性 --> <div v-else-if="['hLine', 'vLine'].includes(element.type)" 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.width" :min="1" :max="1000" controls-position="right" size="mini" /> </el-form-item>
<el-form-item label="高度" class="form-item-half"> <el-input v-model="element.height" :min="1" :max="1000" controls-position="right" size="mini" /> </el-form-item> </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: { element: { type: Object, required: true } }, emits: ['data-source', 'image-upload'], /*组件*/ components: { comShowLabelSerialInfo,/*标签内容流水号信息的組件*/ }, watch: { // 监听元素变化,确保文件输入框状态正确
'element.id'() { // 当切换到不同元素时,重置文件输入框
this.$nextTick(() => { if (this.$refs.fileInput) { this.$refs.fileInput.value = '' } }) } }, methods: { handleSelectImage() { // 确保文件输入框被重置,然后触发点击
if (this.$refs.fileInput) { this.$refs.fileInput.value = '' this.$refs.fileInput.click() } }, /*流水号信息的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') this.element.height = 10 } },
async handleImageUpload(event) { const file = event.target.files[0] if (!file) return
try { const imageData = await this.processImage(file) this.$emit('image-upload', imageData) // 重置文件输入框的值,确保下次选择相同文件时也能触发change事件
event.target.value = '' } catch (error) { this.$message.error('图片处理失败') // 即使出错也要重置文件输入框
event.target.value = '' } },
processImage(file) { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = (e) => { const img = new Image() img.onload = () => { try { const { zplData, previewUrl } = this.convertImageToZPL(img) resolve({ zplData, previewUrl }) } catch (error) { reject(error) } } img.onerror = reject img.src = e.target.result } reader.onerror = reject reader.readAsDataURL(file) }) },
convertImageToZPL(img) { const targetWidth = 200 const scale = targetWidth / img.width
const canvas = document.createElement('canvas') canvas.width = targetWidth canvas.height = Math.round(img.height * scale)
const ctx = canvas.getContext('2d') ctx.fillStyle = '#fff' ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
// 转换为ZPL格式
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) const { width, height, data } = imageData const bytesPerRow = Math.ceil(width / 8) const totalBytes = bytesPerRow * height
let binaryData = '' for (let y = 0; y < height; y++) { for (let byteIdx = 0; byteIdx < bytesPerRow; byteIdx++) { let byteStr = '' for (let bit = 0; bit < 8; bit++) { const x = byteIdx * 8 + bit if (x >= width) { byteStr += '0' } else { const i = (y * width + x) * 4 const r = data[i], g = data[i + 1], b = data[i + 2] const grayscale = (r + g + b) / 3 byteStr += grayscale < 128 ? '1' : '0' } } const hex = parseInt(byteStr, 2).toString(16).padStart(2, '0').toUpperCase() binaryData += hex } }
return { 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}` } }}</script>
<style scoped>.property-form { overflow-y: auto;}
.property-form::-webkit-scrollbar { width: 4px;}
.property-form::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 2px;}
.property-form::-webkit-scrollbar-thumb { //background: #409eff;
border-radius: 2px;}
.form-section { padding: 10px; background: #fafafa; border-radius: 4px; border: 1px solid #e8e8e8;}
.input-with-button { display: flex; gap: 6px; align-items: flex-start;}
.input-with-button .el-input { flex: 1;}
.input-with-button .el-button { font-size: 11px; padding: 5px 8px; height: 28px;}
.form-tip { font-size: 11px; color: #909399; margin-top: 3px; padding: 3px 6px; background: #f8f9fa; border-radius: 3px; border-left: 2px solid #409eff;}
.image-upload { margin-bottom: 8px;}
.image-upload .el-button { width: 100%; height: 60px; border: 1px dashed #d9d9d9; border-radius: 4px; background: #fafafa; font-size: 12px;}
.image-upload .el-button:hover { border-color: #409eff; background: #f0f9ff;}
.image-preview { text-align: center; padding: 8px; background: #f8f9fa; border-radius: 4px; border: 1px solid #e8e8e8;}
.image-preview img { max-width: 80px; max-height: 80px; border-radius: 4px; border: 1px solid #ddd;}
/* Element UI 表单项紧凑化 */.el-form-item { margin-bottom: 2px;}
.el-form-item:last-child { margin-bottom: 0;}
.el-form-item__label { font-size: 12px !important; padding-bottom: 6px !important; line-height: 1.2 !important; color: #606266 !important; font-weight: 500 !important;}
.el-input__inner { height: 32px !important; font-size: 13px !important; border-radius: 6px !important; border: 1px solid #dcdfe6 !important; padding: 0 12px !important; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;}
.el-input__inner:hover { border-color: #c0c4cc !important;}
.el-input__inner:focus { border-color: #409eff !important; outline: none !important; box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;}
.el-input { width: 100% !important;}
.el-input .el-input__inner { text-align: left !important; height: 32px !important; padding: 0 35px 0 12px !important;}
.el-checkbox { font-size: 12px !important; height: 20px !important; line-height: 20px !important;}
.el-checkbox__label { font-size: 12px !important; padding-left: 6px !important;}
.el-checkbox__inner { width: 12px !important; height: 12px !important;}
.el-checkbox__inner::after { height: 5px !important; left: 3px !important; top: 1px !important; width: 2px !important;}
/* 行布局样式 */.form-row { display: flex; gap: 2px; align-items: flex-start; margin-bottom: 2px;}
.form-row:last-child { margin-bottom: 0;}
.form-item-half { flex: 1; margin-bottom: 0 !important;}
.form-item-half .el-form-item__label { margin-bottom: 2px !important;}
/* 数字输入框统一样式 */.form-item-half .el-input { width: 100% !important;}
.form-item-half .el-input .el-input__inner { height: 32px !important; font-size: 13px !important; padding: 0 35px 0 12px !important; border: 1px solid #dcdfe6 !important; border-radius: 6px !important; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;}
.form-item-half .el-input .el-input__inner:hover { border-color: #c0c4cc !important;}
.form-item-half .el-input .el-input__inner:focus { border-color: #409eff !important; outline: none !important; box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;}
.form-item-half .el-input .el-input__increase,.form-item-half .el-input .el-input__decrease { position: absolute !important; right: 1px !important; width: 32px !important; height: 15px !important; line-height: 15px !important; background: #f5f7fa !important; color: #606266 !important; cursor: pointer !important; font-size: 12px !important; border: none !important; border-radius: 0 !important; transition: all 0.2s !important;}
.form-item-half .el-input .el-input__increase { top: 1px !important; border-radius: 0 5px 0 0 !important;}
.form-item-half .el-input .el-input__decrease { bottom: 1px !important; border-radius: 0 0 5px 0 !important;}
.form-item-half .el-input .el-input__increase:hover,.form-item-half .el-input .el-input__decrease:hover { background: #e6a23c !important; color: #fff !important;}
.form-item-half .el-input .el-input__increase:active,.form-item-half .el-input .el-input__decrease:active { background: #cf9236 !important;}
/* 复选框在行中的样式 */.form-item-half .el-checkbox { display: block !important; margin-bottom: 1px !important; margin-right: 0 !important; padding-top: 5px; padding-left: 1px;}
.form-item-half .el-checkbox:last-child { margin-bottom: 0 !important;}
/* 复选框组样式 */.checkbox-group { position: relative; display: flex; flex-direction: column; justify-content: flex-start; align-items: flex-start;}
.checkbox-label { font-size: 12px !important; color: #606266; margin-bottom: 4px !important; font-weight: 500; line-height: 1.2 !important; height: 14px; padding-bottom: 4px !important; display: block;}
.checkbox-group .el-checkbox { margin-bottom: 2px !important; align-self: flex-start; height: 16px !important; line-height: 16px !important; display: flex !important; align-items: center !important;}
.checkbox-group .el-checkbox:last-child { margin-bottom: 0 !important;}
.checkbox-group .el-checkbox .el-checkbox__input { line-height: 1 !important;}
.checkbox-group .el-checkbox .el-checkbox__label { line-height: 1 !important; padding-left: 4px !important;}
/* 字体大小行布局 */.font-size-row { display: flex; align-items: center; gap: 12px;}
.font-size-input { width: 120px !important; flex-shrink: 0;}
.font-size-input .el-input__inner { height: 32px !important; font-size: 13px !important; border: 1px solid #dcdfe6 !important; border-radius: 6px !important; padding: 0 35px 0 12px !important; background-color: #fff !important; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;}
.font-size-input .el-input__inner:hover { border-color: #c0c4cc !important;}
.font-size-input .el-input__inner:focus { border-color: #409eff !important; outline: none !important; box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;}
.font-size-input .el-input__increase,.font-size-input .el-input__decrease { position: absolute !important; right: 1px !important; width: 32px !important; height: 15px !important; line-height: 15px !important; background: #f5f7fa !important; color: #606266 !important; cursor: pointer !important; font-size: 12px !important; border: none !important; border-radius: 0 !important; transition: all 0.2s !important;}
.font-size-input .el-input__increase { top: 1px !important; border-radius: 0 5px 0 0 !important;}
.font-size-input .el-input__decrease { bottom: 1px !important; border-radius: 0 0 5px 0 !important;}
.font-size-input .el-input__increase:hover,.font-size-input .el-input__decrease:hover { background: #e6a23c !important; color: #fff !important;}
.font-size-input .el-input__increase:active,.font-size-input .el-input__decrease:active { background: #cf9236 !important;}
.inline-checkbox { margin: 0 !important; height: 28px !important; line-height: 28px !important; display: flex !important; align-items: center !important;}
.inline-checkbox .el-checkbox__label { font-size: 12px !important; padding-left: 6px !important; line-height: 1 !important;}
.inline-checkbox .el-checkbox__input { line-height: 1 !important;}
/* 统一所有输入框样式 */.form-section .el-input { width: 150px !important;}
.form-section .el-input .el-input__inner { height: 32px !important; font-size: 13px !important; border: 1px solid #dcdfe6 !important; border-radius: 6px !important; padding: 0 35px 0 12px !important; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;}
.form-section .el-input .el-input__inner:hover { border-color: #c0c4cc !important;}
.form-section .el-input .el-input__inner:focus { border-color: #409eff !important; outline: none !important; box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;}
.form-section .el-input .el-input__increase,.form-section .el-input .el-input__decrease { position: absolute !important; right: 1px !important; width: 32px !important; height: 15px !important; line-height: 15px !important; background: #f5f7fa !important; color: #606266 !important; cursor: pointer !important; font-size: 12px !important; border: none !important; border-radius: 0 !important; transition: all 0.2s !important;}
.form-section .el-input .el-input__increase { top: 1px !important; border-radius: 0 5px 0 0 !important;}
.form-section .el-input .el-input__decrease { bottom: 1px !important; border-radius: 0 0 5px 0 !important;}
.form-section .el-input .el-input__increase:hover,.form-section .el-input .el-input__decrease:hover { background: #e6a23c !important; color: #fff !important;}
.form-section .el-input .el-input__increase:active,.form-section .el-input .el-input__decrease:active { background: #cf9236 !important;}</style>
|