north-glass-erp/northglass-erp/src/components/pp/PrintCustomLabel.vue
@@ -74,53 +74,105 @@
const isComposing = ref(false)
//修改相同产品名称标签
const updateProductName = (event, index,id) => {
  // 创建映射对象
  const propertyMapping = {};
  labelList.forEach(item => {
    propertyMapping[item.name] = item.title;
  });
  // 输入的值
  const newValue = event.target.innerText;
  const parts = newValue.split(':');
  const result = parts[1]; // 获取冒号后的部分
  // 获取映射中所有的键
  const keys = Object.keys(propertyMapping);
const getCaretOffset = (el) => {
  const sel = window.getSelection()
  if (!sel || sel.rangeCount === 0) return 0
  const range = sel.getRangeAt(0)
  if (!el.contains(range.startContainer)) return 0
  // 根据 index 获取对应的属性名
  const propertyName = keys[index];
  const preRange = range.cloneRange()
  preRange.selectNodeContents(el)
  preRange.setEnd(range.startContainer, range.startOffset)
  return preRange.toString().length
}
  // 如果映射中没有该 index,直接返回
  if (!propertyName) {
    console.warn('Unsupported index:', index);
    return;
const setCaretOffset = (el, offset) => {
  const sel = window.getSelection()
  if (!sel) return
  const range = document.createRange()
  range.selectNodeContents(el)
  let current = 0
  const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null)
  let node = walker.nextNode()
  while (node) {
    const next = current + (node.nodeValue?.length || 0)
    if (offset <= next) {
      range.setStart(node, Math.max(0, offset - current))
      range.collapse(true)
      sel.removeAllRanges()
      sel.addRange(range)
      return
    }
    current = next
    node = walker.nextNode()
  }
  // 遍历 lastList 并更新对应的属性
  lastList.value.forEach(obj => {
    // 获取前缀和 orderId
    const prefix = lastList.value[id].processId.substring(0, 11);
    const orderId = obj.orderId;
    const glassNumber=lastList.value[id].glassNumber
    const customerName = obj.customerName
    // 根据 propertyName 更新属性
    if (propertyName === 'productAbbreviation' && prefix === obj.processId.substring(0, 11)) {
      obj.productAbbreviation = result;
    }
  // 超出长度则放到末尾
  range.collapse(false)
  sel.removeAllRanges()
  sel.addRange(range)
}
// =============================================
    if (propertyName === 'project' && orderId === obj.orderId) {
      obj.project = result;
    }
    if (propertyName === 'productName' && prefix === obj.processId.substring(0, 11)){
      obj.productName = result;
    }
    if (propertyName === 'customerName' && orderId === obj.orderId){
      obj.customerName = result;
    }
  });
//修改相同产品名称标签
const updateProductName = async (event, fieldIndex, rowIndex) => {
  // 输入法组词阶段不要同步,否则会抖动/错乱
  if (isComposing.value) return
  const el = event.target
  //  保存光标
  const caret = getCaretOffset(el)
  //  取“纯值”此时 contenteditable 只包含值,不包含标题:
  const result = (el.innerText ?? '').trim()
  //  映射:fieldIndex -> 字段名
  const propertyMapping = {}
  labelList.forEach(item => {
    propertyMapping[item.name] = item.title
  })
  const keys = Object.keys(propertyMapping)
  const propertyName = keys[fieldIndex]
  if (!propertyName) return
  //更新
  const baseRow = props.lastList?.[rowIndex]
  if (!baseRow) return
  const basePrefix = (baseRow.processId ?? '').substring(0, 11)
  const baseGlassNumber = baseRow.glassNumber
  const baseOrderId = baseRow.orderId
  props.lastList.forEach(obj => {
    const objPrefix = (obj.processId ?? '').substring(0, 11)
    if (propertyName === 'productAbbreviation' && basePrefix === objPrefix) obj.productAbbreviation = result
    if (propertyName === 'project' && baseOrderId === obj.orderId) obj.project = result
    if (propertyName === 'productName' && basePrefix === objPrefix) obj.productName = result
    if (propertyName === 'customerName' && baseOrderId === obj.orderId) obj.customerName = result
    if (propertyName === 'orderId' && baseOrderId === obj.orderId) obj.orderId = result
    if (propertyName === 'glassNumber' && baseGlassNumber === obj.glassNumber) obj.glassNumber = result
    if (propertyName === 'width' && baseGlassNumber === obj.glassNumber) obj.width = result
    if (propertyName === 'height' && baseGlassNumber === obj.glassNumber) obj.height = result
    if (propertyName === 'custom1' && baseOrderId === obj.orderId) obj.custom1 = result
    if (propertyName === 'custom2' && baseOrderId === obj.orderId) obj.custom2 = result
    if (propertyName === 'custom3' && baseOrderId === obj.orderId) obj.custom3 = result
    if (propertyName === 'custom4' && baseOrderId === obj.orderId) obj.custom4 = result
    if (propertyName === 'custom5' && baseOrderId === obj.orderId) obj.custom5 = result
  })
  // 5) 等 Vue patch 完成后,把光标放回去
  await nextTick()
  setCaretOffset(el, caret)
}
@@ -132,9 +184,16 @@
      <div v-for="(item1,index) in lastList" :class="company.printLabel.className.custom.entiretyName()">
        <div class="row4">{{ faceOrientation }}</div>
        <div v-for="(item,id) in labelList" :class="company.printLabel.className.custom.contentRowName()">
          <div v-if="item1[item.name] != null && item1[item.name] !== ''" class="row1"  contenteditable="true" @input="updateProductName($event, id,index)" v-text="item.title+':'+item1[item.name]"></div>
<!--          <div class="row2" style="width: 100%;"><input class="contentRow2" v-model="item1[item.name]"  @keyup="updataProductName()" style="border: none;"/></div>-->
<!--          <div v-if="item1[item.name] != null && item1[item.name] !== ''" class="row2" style="width: 100%;" contenteditable="true" @input="updateProductName($event, id)" v-text="item1[item.name]"></div>-->
          <div class="row1" v-show="item1[item.name] != null && item1[item.name] !== ''">
            <span class="label">{{ item.title }}:</span>
            <span
                class="value"
                contenteditable="true"
                @compositionstart="isComposing.value = true"
                @compositionend="(e) => { isComposing.value = false; updateProductName(e, id, index) }"
                @input="(e) => updateProductName(e, id, index)"
            >{{ item1[item.name] }}</span>
          </div>
        </div>
        <div v-html="company.printLabel.custom(item1)"></div>
      </div>