zhou zhou
6 天以前 029559f7cedded183bd1fbd09a5ebb576a9fa21d
#条码自定义
4个文件已修改
452 ■■■■ 已修改文件
rsf-design/src/views/basic-info/wh-mat/matnrPrintTemplate.helpers.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/wh-mat/modules/matnr-print-canvas.vue 416 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-print-dialog.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocTypeController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/wh-mat/matnrPrintTemplate.helpers.js
@@ -473,6 +473,10 @@
    }
    normalized.columns = normalizeTableColumns(element?.columns, normalized.w)
    normalized.rows = normalizeTableRows(element?.rows)
    normalized.w = Math.max(
      normalizeNumber(normalized.w, 0),
      normalized.columns.reduce((total, column) => total + normalizeNumber(column?.width, 0), 0)
    )
    normalized.h = Math.max(
      normalizeNumber(normalized.h, 0),
      normalized.rows.reduce((total, row) => total + normalizeNumber(row?.height, 0), 0)
rsf-design/src/views/basic-info/wh-mat/modules/matnr-print-canvas.vue
@@ -17,7 +17,8 @@
        class="matnr-print-element"
        :class="{
          'is-selected': interactive && selectedElementId === element.id,
          'is-hidden': element.visible === false
          'is-hidden': element.visible === false,
          'is-table': element.type === 'table'
        }"
        :style="getElementBoxStyle(element)"
        @mousedown.stop="handleElementMouseDown($event, element)"
@@ -69,44 +70,44 @@
          :style="getRectStyle(element)"
        ></div>
        <table
        <div
          v-else-if="element.type === 'table'"
          class="matnr-print-element__table"
          :style="getTableStyle(element)"
        >
          <colgroup>
            <col
              v-for="(column, columnIndex) in element.columns"
              :key="`${element.id}_col_${columnIndex}`"
              :style="{ width: getUnitValue(column.width || 10) }"
            />
          </colgroup>
          <tbody>
            <tr
              v-for="(row, rowIndex) in element.rows"
              :key="`${element.id}_row_${rowIndex}`"
              :style="{ height: getUnitValue(row.height || 6) }"
          <div
            v-for="cell in element.resolvedCells"
            :key="`${element.id}_${cell.row}_${cell.col}`"
            class="matnr-print-element__table-cell"
            :style="getTableCellStyle(cell, element)"
          >
            <div
              class="matnr-print-element__table-cell-content"
              :style="getTableCellContentStyle()"
            >
              <template
                v-for="cell in getTableCellsForRow(element, rowIndex)"
                :key="`${element.id}_${rowIndex}_${cell.col}`"
              >
                <td
                  :colspan="cell.colspan || 1"
                  :rowspan="cell.rowspan || 1"
                  :style="getTableCellStyle(cell, element)"
                >
                  <div
                    class="matnr-print-element__table-cell-content"
                    :style="getTableCellContentStyle(cell, element)"
                  >
                    {{ cell.resolvedText }}
                  </div>
                </td>
              </template>
            </tr>
          </tbody>
        </table>
              {{ cell.resolvedText }}
            </div>
          </div>
        </div>
        <template
          v-if="interactive && selectedElementId === element.id && element.type === 'table'"
        >
          <span
            v-for="handle in getTableColumnHandles(element)"
            :key="`${element.id}_col_handle_${handle.index}`"
            class="matnr-print-element__table-divider is-column"
            :style="getTableDividerStyle(element, 'column', handle)"
            @mousedown.stop="handleTableResizeMouseDown($event, element, 'column', handle.index)"
          ></span>
          <span
            v-for="handle in getTableRowHandles(element)"
            :key="`${element.id}_row_handle_${handle.index}`"
            class="matnr-print-element__table-divider is-row"
            :style="getTableDividerStyle(element, 'row', handle)"
            @mousedown.stop="handleTableResizeMouseDown($event, element, 'row', handle.index)"
          ></span>
        </template>
        <template v-if="interactive && selectedElementId === element.id && element.type !== 'line'">
          <span
@@ -168,6 +169,8 @@
  const canvasRef = ref(null)
  const interactionState = ref(null)
  const TABLE_MIN_COLUMN_WIDTH = 6
  const TABLE_MIN_ROW_HEIGHT = 4
  const resizeHandles = [
    { direction: 'top-left' },
    { direction: 'top' },
@@ -259,8 +262,17 @@
    return {
      fontSize: editorMode.value ? mmToPx(style.fontSize, props.scale) : `${style.fontSize}mm`,
      color: style.color,
      tableLayout: 'fixed'
      position: 'relative'
    }
  }
  function getTableColumnSpanWidth(element, cell) {
    const columns = Array.isArray(element?.columns) ? element.columns : []
    const startCol = Number(cell?.col) || 0
    const colspan = Math.max(1, Number(cell?.colspan) || 1)
    return columns
      .slice(startCol, startCol + colspan)
      .reduce((total, column) => total + (Number(column?.width) || 6), 0)
  }
  function getTableCellSpanHeight(element, cell) {
@@ -274,23 +286,44 @@
  function getTableCellStyle(cell, element) {
    const style = cell.style || {}
    const borderWidth = editorMode.value
      ? mmToPx(style.borderWidth || 0.2, props.scale)
      : `${style.borderWidth || 0.2}mm`
    const borderColor = style.borderColor || '#111111'
    const columns = Array.isArray(element?.columns) ? element.columns : []
    const rows = Array.isArray(element?.rows) ? element.rows : []
    const left = columns
      .slice(0, Math.max(0, Number(cell?.col) || 0))
      .reduce((total, column) => total + (Number(column?.width) || 6), 0)
    const top = rows
      .slice(0, Math.max(0, Number(cell?.row) || 0))
      .reduce((total, row) => total + (Number(row?.height) || 6), 0)
    return {
      border: `${editorMode.value ? mmToPx(style.borderWidth || 0.2, props.scale) : `${style.borderWidth || 0.2}mm`} solid ${style.borderColor || '#111111'}`,
      position: 'absolute',
      left: getUnitValue(left),
      top: getUnitValue(top),
      width: getUnitValue(getTableColumnSpanWidth(element, cell)),
      height: getUnitValue(getTableCellSpanHeight(element, cell)),
      borderTop: Number(cell?.row) === 0 ? `${borderWidth} solid ${borderColor}` : 'none',
      borderLeft: Number(cell?.col) === 0 ? `${borderWidth} solid ${borderColor}` : 'none',
      borderRight: `${borderWidth} solid ${borderColor}`,
      borderBottom: `${borderWidth} solid ${borderColor}`,
      backgroundColor: style.backgroundColor || '#FFFFFF',
      textAlign: style.textAlign || 'left',
      fontWeight: style.fontWeight || 400,
      height: getUnitValue(getTableCellSpanHeight(element, cell)),
      boxSizing: 'border-box',
      padding: 0,
      overflow: 'hidden'
    }
  }
  function getTableCellContentStyle(cell, element) {
  function getTableCellContentStyle() {
    const paddingY = editorMode.value ? `${0.4 * props.scale}px` : '0.4mm'
    const paddingX = editorMode.value ? `${0.8 * props.scale}px` : '0.8mm'
    return {
      width: '100%',
      height: getUnitValue(getTableCellSpanHeight(element, cell)),
      height: '100%',
      boxSizing: 'border-box',
      padding: `${paddingY} ${paddingX}`,
      overflow: 'hidden',
@@ -301,10 +334,36 @@
    }
  }
  function getTableCellsForRow(element, rowIndex) {
    return (Array.isArray(element?.resolvedCells) ? element.resolvedCells : []).filter(
      (cell) => Number(cell?.row) === rowIndex
    )
  function getTableColumnHandles(element) {
    const columns = Array.isArray(element?.columns) ? element.columns : []
    let offset = 0
    return columns.slice(0, -1).map((column, index) => {
      offset += Number(column?.width) || 0
      return {
        index,
        offset
      }
    })
  }
  function getTableRowHandles(element) {
    const rows = Array.isArray(element?.rows) ? element.rows : []
    let offset = 0
    return rows.slice(0, -1).map((row, index) => {
      offset += Number(row?.height) || 0
      return {
        index,
        offset
      }
    })
  }
  function getTableDividerStyle(element, axis, handle) {
    const baseOffset = Number(handle?.offset) || 0
    return axis === 'column'
      ? { left: getUnitValue(baseOffset) }
      : { top: getUnitValue(baseOffset) }
  }
  function getQrcodeSize(element) {
@@ -338,10 +397,44 @@
      return
    }
    emit('select-element', element.id)
    startInteraction(event, element, 'resize', direction)
    startInteraction(event, element, 'resize', direction, {
      tableColumns:
        element.type === 'table' && Array.isArray(element?.columns)
          ? element.columns.map((column) => ({
              width: Number(column?.width) || TABLE_MIN_COLUMN_WIDTH
            }))
          : [],
      tableRows:
        element.type === 'table' && Array.isArray(element?.rows)
          ? element.rows.map((row) => ({
              height: Number(row?.height) || TABLE_MIN_ROW_HEIGHT
            }))
          : [],
      elementType: element?.type || ''
    })
  }
  function startInteraction(event, element, type, direction = '') {
  function handleTableResizeMouseDown(event, element, axis, index) {
    if (!props.interactive) {
      return
    }
    emit('select-element', element.id)
    startInteraction(event, element, `table-${axis}-resize`, '', {
      index,
      columns: Array.isArray(element?.columns)
        ? element.columns.map((column) => ({
            width: Number(column?.width) || TABLE_MIN_COLUMN_WIDTH
          }))
        : [],
      rows: Array.isArray(element?.rows)
        ? element.rows.map((row) => ({
            height: Number(row?.height) || TABLE_MIN_ROW_HEIGHT
          }))
        : []
    })
  }
  function startInteraction(event, element, type, direction = '', extra = {}) {
    interactionState.value = {
      type,
      direction,
@@ -353,7 +446,8 @@
        y: Number(element.y) || 0,
        w: Number(element.w) || 0,
        h: Number(element.h) || 0
      }
      },
      ...extra
    }
    window.addEventListener('mousemove', handleWindowMouseMove)
    window.addEventListener('mouseup', stopInteraction)
@@ -374,7 +468,29 @@
        y: Math.max(0, origin.y + dy)
      }
    } else if (interactionState.value.type === 'resize') {
      patch = buildResizePatch(origin, dx, dy, interactionState.value.direction)
      patch =
        interactionState.value.elementType === 'table'
          ? buildTableElementResizePatch(
              origin,
              dx,
              dy,
              interactionState.value.direction,
              interactionState.value.tableColumns,
              interactionState.value.tableRows
            )
          : buildResizePatch(origin, dx, dy, interactionState.value.direction)
    } else if (interactionState.value.type === 'table-column-resize') {
      patch = buildTableColumnResizePatch(
        interactionState.value.columns,
        interactionState.value.index,
        dx
      )
    } else if (interactionState.value.type === 'table-row-resize') {
      patch = buildTableRowResizePatch(
        interactionState.value.rows,
        interactionState.value.index,
        dy
      )
    }
    emit('update-element', {
@@ -414,6 +530,149 @@
    }
    return next
  }
  function buildTableElementResizePatch(origin, dx, dy, direction, columns, rows) {
    const basePatch = buildResizePatch(origin, dx, dy, direction)
    const nextColumns = scaleTableTracks(columns, 'width', basePatch.w, TABLE_MIN_COLUMN_WIDTH)
    const nextRows = scaleTableTracks(rows, 'height', basePatch.h, TABLE_MIN_ROW_HEIGHT)
    const nextWidth = Number(
      nextColumns.reduce((total, column) => total + (Number(column?.width) || 0), 0).toFixed(2)
    )
    const nextHeight = Number(
      nextRows.reduce((total, row) => total + (Number(row?.height) || 0), 0).toFixed(2)
    )
    return {
      ...basePatch,
      x: direction.includes('left') ? Math.max(0, origin.x + origin.w - nextWidth) : basePatch.x,
      y: direction.includes('top') ? Math.max(0, origin.y + origin.h - nextHeight) : basePatch.y,
      w: nextWidth,
      h: nextHeight,
      columns: nextColumns,
      rows: nextRows
    }
  }
  function scaleTableTracks(tracks, key, targetTotal, minValue) {
    const source = Array.isArray(tracks)
      ? tracks.map((track) => ({
          [key]: Number(track?.[key]) || minValue
        }))
      : []
    if (!source.length) {
      return []
    }
    const minimumTotal = minValue * source.length
    const effectiveTarget = Math.max(minimumTotal, Number(targetTotal) || minimumTotal)
    const sourceTotal = source.reduce((total, track) => total + (Number(track?.[key]) || 0), 0)
    let nextTracks =
      sourceTotal > 0
        ? source.map((track) => ({
            [key]: Math.max(
              minValue,
              Number((((Number(track?.[key]) || 0) / sourceTotal) * effectiveTarget).toFixed(2))
            )
          }))
        : source.map(() => ({
            [key]: Number((effectiveTarget / source.length).toFixed(2))
          }))
    let remainder = Number(
      (
        effectiveTarget -
        nextTracks.reduce((total, track) => total + (Number(track?.[key]) || 0), 0)
      ).toFixed(2)
    )
    if (Math.abs(remainder) < 0.01) {
      return nextTracks
    }
    if (remainder > 0) {
      nextTracks[nextTracks.length - 1] = {
        ...nextTracks[nextTracks.length - 1],
        [key]: Number((nextTracks[nextTracks.length - 1][key] + remainder).toFixed(2))
      }
      return nextTracks
    }
    let remaining = Math.abs(remainder)
    for (let index = nextTracks.length - 1; index >= 0 && remaining > 0.009; index -= 1) {
      const currentValue = Number(nextTracks[index]?.[key]) || minValue
      const adjustable = Number(Math.max(0, currentValue - minValue).toFixed(2))
      if (adjustable <= 0) {
        continue
      }
      const deduction = Math.min(adjustable, remaining)
      nextTracks[index] = {
        ...nextTracks[index],
        [key]: Number((currentValue - deduction).toFixed(2))
      }
      remaining = Number((remaining - deduction).toFixed(2))
    }
    return nextTracks
  }
  function buildTableColumnResizePatch(columns, index, delta) {
    const nextColumns = Array.isArray(columns)
      ? columns.map((column) => ({
          width: Number(column?.width) || TABLE_MIN_COLUMN_WIDTH
        }))
      : []
    if (!nextColumns[index] || !nextColumns[index + 1]) {
      return {}
    }
    const leftWidth = nextColumns[index].width
    const rightWidth = nextColumns[index + 1].width
    const boundedDelta = Math.min(
      Math.max(delta, TABLE_MIN_COLUMN_WIDTH - leftWidth),
      rightWidth - TABLE_MIN_COLUMN_WIDTH
    )
    nextColumns[index] = {
      ...nextColumns[index],
      width: Number((leftWidth + boundedDelta).toFixed(2))
    }
    nextColumns[index + 1] = {
      ...nextColumns[index + 1],
      width: Number((rightWidth - boundedDelta).toFixed(2))
    }
    return {
      columns: nextColumns,
      w: Number(
        nextColumns.reduce((total, column) => total + (Number(column?.width) || 0), 0).toFixed(2)
      )
    }
  }
  function buildTableRowResizePatch(rows, index, delta) {
    const nextRows = Array.isArray(rows)
      ? rows.map((row) => ({
          height: Number(row?.height) || TABLE_MIN_ROW_HEIGHT
        }))
      : []
    if (!nextRows[index]) {
      return {}
    }
    const currentHeight = nextRows[index].height
    const boundedDelta = Math.max(delta, TABLE_MIN_ROW_HEIGHT - currentHeight)
    nextRows[index] = {
      ...nextRows[index],
      height: Number((currentHeight + boundedDelta).toFixed(2))
    }
    return {
      rows: nextRows,
      h: Number(nextRows.reduce((total, row) => total + (Number(row?.height) || 0), 0).toFixed(2))
    }
  }
  function stopInteraction() {
@@ -466,6 +725,10 @@
    box-sizing: border-box;
    overflow: hidden;
    user-select: none;
  }
  .matnr-print-element.is-table {
    overflow: visible;
  }
  .matnr-print-element.is-selected {
@@ -541,10 +804,11 @@
  }
  .matnr-print-element__table {
    border-collapse: collapse;
    position: relative;
    overflow: hidden;
  }
  .matnr-print-element__table td {
  .matnr-print-element__table-cell {
    box-sizing: border-box;
    vertical-align: middle;
  }
@@ -553,6 +817,60 @@
    box-sizing: border-box;
  }
  .matnr-print-element__table-divider {
    position: absolute;
    z-index: 2;
    background: transparent;
    color: rgba(37, 99, 235, 0.7);
    transition:
      color 0.15s ease,
      opacity 0.15s ease;
    opacity: 0.95;
  }
  .matnr-print-element__table-divider::before {
    position: absolute;
    content: '';
    background: currentColor;
    border-radius: 999px;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.92);
  }
  .matnr-print-element__table-divider.is-column {
    top: 0;
    bottom: 0;
    width: 12px;
    transform: translateX(-6px);
    cursor: ew-resize;
  }
  .matnr-print-element__table-divider.is-column::before {
    top: calc(50% - 12px);
    left: calc(50% - 2px);
    width: 4px;
    height: 24px;
  }
  .matnr-print-element__table-divider.is-row {
    left: 0;
    right: 0;
    height: 12px;
    transform: translateY(-6px);
    cursor: ns-resize;
  }
  .matnr-print-element__table-divider.is-row::before {
    top: calc(50% - 2px);
    left: calc(50% - 12px);
    width: 24px;
    height: 4px;
  }
  .matnr-print-element__table-divider:hover {
    color: rgba(37, 99, 235, 1);
    opacity: 1;
  }
  .matnr-print-element__handle {
    position: absolute;
    width: 10px;
rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-print-dialog.vue
@@ -421,6 +421,9 @@
        position: absolute;
        overflow: hidden;
      }
      .matnr-print-element.is-table {
        overflow: visible;
      }
      .matnr-print-element__text,
      .matnr-print-element__barcode,
      .matnr-print-element__qrcode,
@@ -458,12 +461,15 @@
        display: block;
      }
      .matnr-print-element__table {
        border-collapse: collapse;
        table-layout: fixed;
        position: relative;
        overflow: hidden;
      }
      .matnr-print-element__table td {
        padding: 0.4mm 0.8mm;
      .matnr-print-element__table-cell {
        box-sizing: border-box;
        vertical-align: middle;
      }
      .matnr-print-element__table-cell-content {
        box-sizing: border-box;
        word-break: break-word;
      }
      </style>
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocTypeController.java
@@ -31,7 +31,7 @@
    @Autowired
    private LocTypeService locTypeService;
    @PreAuthorize("hasAuthority('manager:locType:list')")
    @PreAuthorize("hasAuthority('manager:loc:list')")
    @PostMapping("/locType/page")
    public R page(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
@@ -40,25 +40,25 @@
        return R.ok().add(buildPageRowsUtils.rowsMap(page));
    }
    @PreAuthorize("hasAuthority('manager:locType:list')")
    @PreAuthorize("hasAuthority('manager:loc:list')")
    @PostMapping("/locType/list")
    public R list(@RequestBody Map<String, Object> map) {
        return R.ok().add(buildPageRowsUtils.rowsMap(locTypeService.list()));
    }
    @PreAuthorize("hasAuthority('manager:locType:list')")
    @PreAuthorize("hasAuthority('manager:loc:list')")
    @PostMapping({"/locType/many/{ids}", "/locTypes/many/{ids}"})
    public R many(@PathVariable Long[] ids) {
        return R.ok().add(buildPageRowsUtils.rowsMap(locTypeService.listByIds(Arrays.asList(ids))));
    }
    @PreAuthorize("hasAuthority('manager:locType:list')")
    @PreAuthorize("hasAuthority('manager:loc:list')")
    @GetMapping("/locType/{id}")
    public R get(@PathVariable("id") Long id) {
        return R.ok().add(buildPageRowsUtils.rowsMap(locTypeService.getById(id)));
    }
    @PreAuthorize("hasAuthority('manager:locType:save')")
    @PreAuthorize("hasAuthority('manager:loc:save')")
    @OperationLog("Create loc type")
    @PostMapping("/locType/save")
    public R save(@RequestBody LocType locType) {
@@ -91,7 +91,7 @@
        return R.ok("Save Success").add(buildPageRowsUtils.rowsMap(locType));
    }
    @PreAuthorize("hasAuthority('manager:locType:update')")
    @PreAuthorize("hasAuthority('manager:loc:update')")
    @OperationLog("Update loc type")
    @PostMapping("/locType/update")
    @Transactional(rollbackFor = Exception.class)
@@ -126,7 +126,7 @@
        return R.ok("Update Success").add(buildPageRowsUtils.rowsMap(locType));
    }
    @PreAuthorize("hasAuthority('manager:locType:remove')")
    @PreAuthorize("hasAuthority('manager:loc:remove')")
    @OperationLog("Delete loc type")
    @PostMapping("/locType/remove/{ids}")
    public R remove(@PathVariable Long[] ids) {
@@ -136,7 +136,7 @@
        return R.ok("Delete Success").add(buildPageRowsUtils.rowsMap(ids));
    }
    @PreAuthorize("hasAuthority('manager:locType:list')")
    @PreAuthorize("hasAuthority('manager:loc:list')")
    @PostMapping("/locType/query")
    public R query(@RequestParam(required = false) String condition) {
        List<KeyValVo> vos = new ArrayList<>();
@@ -150,7 +150,7 @@
        return R.ok().add(buildPageRowsUtils.rowsMap(vos));
    }
    @PreAuthorize("hasAuthority('manager:locType:list')")
    @PreAuthorize("hasAuthority('manager:loc:list')")
    @PostMapping("/locType/export")
    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
        ExcelUtil.build(ExcelUtil.create(buildPageRowsUtils.rowsMap(locTypeService.list()), LocType.class), response);