|
|
|
@ -12,7 +12,7 @@ |
|
|
|
<div class="combination-content"> |
|
|
|
<!-- 目标元素信息 --> |
|
|
|
<div class="target-element-info" v-if="targetElement"> |
|
|
|
<h4>{{ $t('labelSetting.combination.targetElement', { type: targetElement.type === 'onecode' ? $t('labelSetting.combination.elementBarcode') : $t('labelSetting.combination.elementQrcode') }) }}</h4> |
|
|
|
<h4>{{ $t('labelSetting.combination.targetElement', { type: getElementTypeName(targetElement.type) }) }}</h4> |
|
|
|
<p>{{ $t('labelSetting.combination.currentData', { data: targetElement.data || $t('labelSetting.combination.empty') }) }}</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -46,7 +46,7 @@ |
|
|
|
</div> |
|
|
|
<div |
|
|
|
v-for="(element, index) in selectedElements" |
|
|
|
:key="element.id || index" |
|
|
|
:key="index" |
|
|
|
class="selected-element-card" |
|
|
|
> |
|
|
|
<div class="element-info"> |
|
|
|
@ -74,7 +74,7 @@ |
|
|
|
<el-button |
|
|
|
size="mini" |
|
|
|
icon="el-icon-delete" |
|
|
|
@click="removeElement(element)" |
|
|
|
@click="removeElement(index)" |
|
|
|
class="action-btn remove-btn" |
|
|
|
:title="$t('labelSetting.combination.remove')" |
|
|
|
></el-button> |
|
|
|
@ -127,6 +127,10 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { parseElementCombination } from '@/utils/elementCombination' |
|
|
|
|
|
|
|
let nextElementId = 0 |
|
|
|
|
|
|
|
export default { |
|
|
|
name: 'ElementCombinationDialog', |
|
|
|
props: { |
|
|
|
@ -148,7 +152,10 @@ export default { |
|
|
|
data() { |
|
|
|
return { |
|
|
|
selectedElements: [], |
|
|
|
separator: '-' |
|
|
|
separator: '-', |
|
|
|
originalReferences: [], |
|
|
|
originalCombinationData: '', |
|
|
|
originalSeparator: '-' |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
@ -171,41 +178,81 @@ export default { |
|
|
|
} |
|
|
|
}, |
|
|
|
watch: { |
|
|
|
visible(newVal) { |
|
|
|
if (newVal) { |
|
|
|
this.initializeDialog() |
|
|
|
visible: { |
|
|
|
immediate: true, |
|
|
|
handler(newVal) { |
|
|
|
if (newVal) { |
|
|
|
this.initializeDialog() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
initializeDialog() { |
|
|
|
// 重置为默认状态 |
|
|
|
this.resetToDefaults() |
|
|
|
this.allElements.forEach(element => this.ensureElementId(element)) |
|
|
|
|
|
|
|
const data = (this.targetElement && this.targetElement.data) || '' |
|
|
|
const references = parseElementCombination(data) |
|
|
|
if (!references.length) return |
|
|
|
|
|
|
|
this.originalReferences = references.map(item => item.reference) |
|
|
|
this.originalCombinationData = data.slice(references[0].start, references[references.length - 1].end) |
|
|
|
const config = this.targetElement.combinationConfig |
|
|
|
// 元素内容可能被手工修改,只有仍对应当前组合的缓存配置才可用于恢复身份和分隔符。 |
|
|
|
const savedConfig = config && config.mode === 'sequence' && config.data === this.originalCombinationData |
|
|
|
? config : null |
|
|
|
this.selectedElements = references.map((reference, index) => { |
|
|
|
const savedId = savedConfig && savedConfig.selectedElements && savedConfig.selectedElements[index] |
|
|
|
const candidates = this.allElements.filter(element => element !== this.targetElement && element.type === reference.type) |
|
|
|
const source = (savedId != null && candidates.find(element => element.id === savedId)) || |
|
|
|
candidates.find(element => this.getElementFullName(element) === reference.reference) || |
|
|
|
(reference.data === undefined && candidates[0]) |
|
|
|
// 来源已删除时保留原引用,避免打开后直接确定就悄悄丢失内容。 |
|
|
|
return source || { |
|
|
|
id: `missing_${index}`, |
|
|
|
type: reference.type, |
|
|
|
data: reference.data || '', |
|
|
|
combinationReference: reference.reference |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
if (savedConfig && savedConfig.separator != null) { |
|
|
|
this.separator = String(savedConfig.separator) |
|
|
|
} else if (references.length > 1) { |
|
|
|
this.separator = data.slice(references[0].end, references[1].start) |
|
|
|
} |
|
|
|
this.originalSeparator = this.separator |
|
|
|
}, |
|
|
|
|
|
|
|
resetToDefaults() { |
|
|
|
this.selectedElements = [] |
|
|
|
this.separator = '-' |
|
|
|
this.originalReferences = [] |
|
|
|
this.originalCombinationData = '' |
|
|
|
this.originalSeparator = '-' |
|
|
|
}, |
|
|
|
|
|
|
|
addElement(element) { |
|
|
|
// 为元素添加唯一ID(如果没有的话) |
|
|
|
const elementWithId = { |
|
|
|
...element, |
|
|
|
id: element.id || `element_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` |
|
|
|
ensureElementId(element) { |
|
|
|
if (element.id == null) { |
|
|
|
// ID 放在画布原元素上,不能只给选中项的副本分配 ID。 |
|
|
|
this.$set(element, 'id', `element_${Date.now()}_${++nextElementId}`) |
|
|
|
} |
|
|
|
this.selectedElements.push(elementWithId) |
|
|
|
}, |
|
|
|
|
|
|
|
removeElement(element) { |
|
|
|
const index = this.selectedElements.findIndex(e => e.id === element.id) |
|
|
|
if (index > -1) { |
|
|
|
addElement(element) { |
|
|
|
if (element === this.targetElement || this.selectedElements.some(selected => selected === element)) return |
|
|
|
this.ensureElementId(element) |
|
|
|
if (this.selectedElements.some(selected => selected.id === element.id)) return |
|
|
|
this.selectedElements.push(element) |
|
|
|
}, |
|
|
|
|
|
|
|
removeElement(index) { |
|
|
|
if (index >= 0 && index < this.selectedElements.length) { |
|
|
|
this.selectedElements.splice(index, 1) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 上移元素 |
|
|
|
moveElementUp(index) { |
|
|
|
if (index > 0) { |
|
|
|
@ -224,7 +271,7 @@ export default { |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
getElementDisplayName(element) { |
|
|
|
getElementTypeName(type) { |
|
|
|
const typeNames = { |
|
|
|
text: this.$t('labelSetting.combination.elementText'), |
|
|
|
onecode: this.$t('labelSetting.combination.elementBarcode'), |
|
|
|
@ -232,13 +279,18 @@ export default { |
|
|
|
pic: this.$t('labelSetting.combination.elementImage'), |
|
|
|
serialNumber: this.$t('labelSetting.combination.elementSerial') |
|
|
|
} |
|
|
|
const typeName = typeNames[element.type] || element.type |
|
|
|
return typeNames[type] || type |
|
|
|
}, |
|
|
|
|
|
|
|
getElementDisplayName(element) { |
|
|
|
const typeName = this.getElementTypeName(element.type) |
|
|
|
const content = element.data ? `(${element.data.substring(0, 40)}${element.data.length > 40 ? '...' : ''})` : '' |
|
|
|
return `${typeName}${content}` |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取用于后端匹配的完整元素名称(不截断内容) |
|
|
|
getElementFullName(element) { |
|
|
|
if (element.combinationReference) return element.combinationReference |
|
|
|
const typeNames = { |
|
|
|
text: '文本', |
|
|
|
onecode: '一维码', |
|
|
|
@ -267,15 +319,46 @@ export default { |
|
|
|
generateSequencePreview() { |
|
|
|
if (!this.selectedElements.length) return '' |
|
|
|
|
|
|
|
const parts = this.selectedElements.map(element => |
|
|
|
element.data || `[${this.getElementDisplayName(element)}]` |
|
|
|
) |
|
|
|
const parts = this.selectedElements.map(element => this.getElementPreviewData(element)) |
|
|
|
|
|
|
|
return parts.join(this.separator || '') |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getElementPreviewData(element) { |
|
|
|
const value = element.data == null ? '' : String(element.data) |
|
|
|
if (!value) return `[${this.getElementDisplayName(element)}]` |
|
|
|
|
|
|
|
// 动态字段需要真实数据才能加工;这里保留模板,不能截断 #{字段名} 本身。 |
|
|
|
if (element.type !== 'text' || element.dataType !== 'string' || /#\{[^}]+\}/.test(value)) { |
|
|
|
return value |
|
|
|
} |
|
|
|
|
|
|
|
switch (element.stringProcessType) { |
|
|
|
case 'substring_start': { |
|
|
|
const length = Number(element.substringStartLength) |
|
|
|
return length > 0 ? value.substring(0, length) : value |
|
|
|
} |
|
|
|
case 'substring_end': { |
|
|
|
const length = Number(element.substringEndLength) |
|
|
|
return length > 0 ? value.substring(Math.max(0, value.length - length)) : value |
|
|
|
} |
|
|
|
case 'split': { |
|
|
|
const index = Number(element.splitIndex) - 1 |
|
|
|
if (!element.splitCharacter || !Number.isInteger(index) || index < 0) return value |
|
|
|
const parts = value.split(element.splitCharacter) |
|
|
|
return index < parts.length ? parts[index] : '' |
|
|
|
} |
|
|
|
case 'replace': |
|
|
|
return element.replaceFrom |
|
|
|
? value.split(element.replaceFrom).join(element.replaceTo == null ? '' : String(element.replaceTo)) |
|
|
|
: value |
|
|
|
default: |
|
|
|
return value |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
handleClose() { |
|
|
|
this.$emit('update:visible', false) |
|
|
|
}, |
|
|
|
@ -295,12 +378,15 @@ export default { |
|
|
|
}, |
|
|
|
|
|
|
|
generateSequenceFormat() { |
|
|
|
// 将顺序拼接转换为模板格式 |
|
|
|
const parts = this.selectedElements.map(element => { |
|
|
|
// 使用完整的元素名称,确保后端能精确匹配 |
|
|
|
return `{${this.getElementFullName(element)}}` |
|
|
|
}) |
|
|
|
return parts.join(this.separator || '') |
|
|
|
const references = this.selectedElements.map(element => this.getElementFullName(element)) |
|
|
|
// 未改动时保持原组合字面内容(含手工插入的不同间隔文字),确认不会重写或重复追加。 |
|
|
|
if (this.originalReferences && this.originalReferences.length > 0 && |
|
|
|
this.separator === this.originalSeparator && |
|
|
|
references.length === this.originalReferences.length && |
|
|
|
references.every((reference, index) => reference === this.originalReferences[index])) { |
|
|
|
return this.originalCombinationData |
|
|
|
} |
|
|
|
return references.map(reference => `{${reference}}`).join(this.separator || '') |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|