chenlu
3 天以前 e5ea2c30e33f280ffc8a0ce78224ef99fb6679b1
north-glass-erp/northglass-erp/src/components/pp/PrintCustomLabelTwo.vue
New file
@@ -0,0 +1,452 @@
<script setup>
import request from "@/utils/request"
import {ElDatePicker, ElMessage} from "element-plus"
import {nextTick, onMounted, onUnmounted, reactive, ref, watch} from "vue"
import {Search} from "@element-plus/icons-vue"
import {useRouter} from 'vue-router'
import {changeFilterEvent, filterChanged} from "@/hook"
import {useI18n} from 'vue-i18n'
import deepClone from "@/utils/deepClone";
import companyInfo from "@/stores/sd/companyInfo"
const company = companyInfo()
//语言获取
const {t} = useI18n()
let router = useRouter()
let produceList = ref([])
let labelList = ref([])
let titleList = ref([])
let dataList = ref([])
let list = ref([])
let lastList = ref([])
let filterData = ref({})
const data = ref({
  printList: [],
  isRepeat:false
})
let props = defineProps({
  list:null,//勾选的数据
  faceOrientation:null,//内外面
  type:null,//标签模板
  lableType:null,//标签类型
  switch:null,//判断是否为新打印
  lastList:[],
})
const {currentRoute} = useRouter()
const route = currentRoute.value
let type = props.type
let faceOrientation = props.faceOrientation
if (type.indexOf("英文")>-1 && faceOrientation==="此面为室内面"){
  faceOrientation='INSIDE'
}
else if (type.indexOf("英文")>-1 && faceOrientation==="此面为室外面"){
  faceOrientation='OUTSIDE'
}
let lableType = props.lableType
data.value.printList = JSON.parse(props.list)
onMounted(() => {
      request.post(`/processCard/getSelectPrintCustomLabel/${type}/${lableType}`, data.value).then((res) => {
        if (res.code == 200) {
          produceList.value = deepClone(res.data.title)
          list.value = deepClone(res.data.data)
          const data = produceList.value[0].value
          dataList = JSON.parse(`[${data}]`);
          const printElements = dataList[0].panels[0].printElements;
          let a = []
          printElements.forEach(element => {
            if(element.options.field==='table'){
              element.options.columns[0].forEach(elements => {
                if(elements.field){
                  a.push({
                        title: elements.title,
                        name: elements.field
                      }
                  )
                }
              })
            }else{
              a.push({
                title: element.options.title,
                name: element.options.field
              })
            }
          })
          labelList = a
          props.lastList.length = 0;
          // 遍历列表(替换 i 为更语义化的变量名)
          for (const group of list.value) {
            // 遍历每组中的数据(替换 j)
            for (const item of group.data) {
              const { quantity, newList } = item;
              // 跳过 quantity 为 0 或无效的情况
              if (!quantity || quantity <= 0) continue;
              // 处理 newList:确保是数组,不足时用空对象兜底
              const safeNewList = Array.isArray(newList) ? newList : [];
              // 循环 quantity 次,添加数据到 lastList
              for (let k = 0; k < quantity; k++) {
                // 深拷贝 item,避免重复引用(关键!)
                const newItem = JSON.parse(JSON.stringify(item));
                // 若 newList 有对应索引数据,填充字段;否则置空
                const listItem = safeNewList[k];
                if (listItem) {
                  newItem.heat_layout_sort = listItem.glass_id || ''; // 兜底空字符串
                  newItem.stockPolysId = `${listItem.stock_id || ''}/${listItem.polys_id || ''}`; // 避免 undefined/
                } else {
                  // 无对应数据时,字段置空(避免保留原始值)
                  newItem.heat_layout_sort = '';
                  newItem.stockPolysId = '';
                }
                // 添加到目标列表
                props.lastList.push(newItem);
              }
            }
          }
        } else {
          ElMessage.warning(res.msg)
        }
      })
    }
)
const isComposing = ref(false)
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
  const preRange = range.cloneRange()
  preRange.selectNodeContents(el)
  preRange.setEnd(range.startContainer, range.startOffset)
  return preRange.toString().length
}
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()
  }
  // 超出长度则放到末尾
  range.collapse(false)
  sel.removeAllRanges()
  sel.addRange(range)
}
// =============================================
//修改相同产品名称标签
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)
}
//修改相同产品名称标签
// 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);
//
//   // 根据 index 获取对应的属性名
//   const propertyName = keys[index];
//   // 如果映射中没有该 index,直接返回
//   if (!propertyName) {
//     console.warn('Unsupported index:', index);
//     return;
//   }
//
//   // 遍历 lastList 并更新对应的属性
//   props.lastList.forEach(obj => {
//     // 获取前缀和 orderId
//     const prefix = props.lastList[id].processId.substring(0, 11);
//     const orderId = obj.orderId;
//     const glassNumber=props.lastList[id].glassNumber
//     // 根据 propertyName 更新属性
//     if (propertyName === 'productAbbreviation' && prefix === obj.processId.substring(0, 11)) {
//       obj.productAbbreviation = result;
//     }
//
//     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;
//     }
//     if (propertyName === 'orderId' && orderId === obj.orderId){
//       obj.orderId = result;
//     }
//     if (propertyName === 'glassNumber' && glassNumber === obj.glassNumber){
//       obj.glassNumber = result;
//     }
//     if (propertyName === 'width' && glassNumber === obj.glassNumber){
//       obj.width = result;
//     }
//     if (propertyName === 'height' && glassNumber === obj.glassNumber){
//       obj.height = result;
//     }
//     if (propertyName === 'custom1' && orderId === obj.orderId){
//       obj.custom1 = result;
//     }
//     if (propertyName === 'custom2' && orderId === obj.orderId){
//       obj.custom2 = result;
//     }
//     if (propertyName === 'custom3' && orderId === obj.orderId){
//       obj.custom3 = result;
//     }
//     if (propertyName === 'custom4' && orderId === obj.orderId){
//       obj.custom4 = result;
//     }
//     if (propertyName === 'custom5' && orderId === obj.orderId){
//       obj.custom5 = result;
//     }
//   });
// }
</script>
<template>
  <div id="print" class="printFlowCard_semi">
      <template v-for="(item1,index) in props.lastList">
        <div class="entirety_semi">
      <div class="row4">{{ faceOrientation }}</div>
      <div  v-for="(item,id) in labelList" class="contentRow">
        <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.customSemi(item1)"></div>
        </div>
        <div v-if="(id + 1) % 2 === 0" class="pagebreak"></div>
      </template>
  </div>
</template>
<style scoped>
* {
  margin: 0;
  padding: 0;
}
body{
  overflow: hidden;
  font-family: Arial;
}
#printButton {
  margin-top: -20px;
  width: 100px;
}
/*半*/
.printFlowCard_semi {
  flex-wrap: wrap;
  font-size: 10px;
  display: flex;
  justify-content:space-between;
}
/*半*/
.entirety_semi {
  width: 45%;
  display: flex;
  text-align: center;
  flex-direction:column;
  margin: 8px;
}
.row3{
  text-align: center;
}
.contentRow{
  display: flex;
  text-align: center;
}
label{
  font-weight: bolder;
}
.contentRow .row1{
  width: 100%;
}
.entirety_semi .row4{
  text-align: right;
}
.contentRow .row1,.contentRow .row2{
  text-align: left;
}
@media print {
  @page {
    size: auto;  /* auto is the initial value */
    margin: 13mm 5mm 0mm 7mm;  /* this affects the margin in the printer settings */
  }
  div {
    page-break-inside: avoid;
  }
  .pagebreak {
    page-break-after: always;
  }
}
.printFlowCard_semi1 {
  flex-wrap: wrap;
  font-size: 8pt;
  display: flex;
}
/*成*/
.entirety_semi1 {
  width: 50%;
  display: flex;
  text-align: center;
  flex-direction: column;
  margin-left: -10px;
  height: 80px;
}
.contentRow1 {
  font-weight: bolder;
  display: flex;
  text-align: center;
  width: 100%;
}
.contentRow1 .row1 {
  width: 30%;
  font-weight: bolder;
}
.entirety_finished1 .row4 {
  font-weight: bolder;
  text-align: right;
  margin-right: 10px;
}
.contentRow1 .row1, .contentRow1 .row2 {
  text-align: left;
  font-weight: bolder;
}
</style>