<script lang="ts" setup>
|
import type { TreeActionItem } from '@jnpf/ui';
|
|
import { computed, getCurrentInstance, h, onMounted, reactive, ref, toRaw, toRefs, watch } from 'vue';
|
import { hiprint } from 'vue-plugin-hiprint';
|
|
import { useGlobSetting, useMessage, useRedo } from '@jnpf/hooks';
|
import { BasicLeftTree, ScrollContainer } from '@jnpf/ui';
|
import { useModal } from '@jnpf/ui/modal';
|
|
import { DeleteOutlined, FormOutlined } from '@ant-design/icons-vue';
|
import { onKeyStroke, useClipboard } from '@vueuse/core';
|
import dayjs from 'dayjs';
|
import $ from 'jquery';
|
import { cloneDeep, omit } from 'lodash-es';
|
import draggable from 'vuedraggable';
|
|
import { ConvertModal, DataSetModal } from '#/components/CommonModal';
|
import { HistoryPopover } from '#/components/CommonPopover';
|
import { $t } from '#/locales';
|
|
import Preview from '../Preview.vue';
|
import {
|
formatter,
|
imageHeight,
|
imageWidth,
|
paperNumberContinue,
|
paperNumberDisabled,
|
paperNumberFormat,
|
tableBarcodeMode,
|
tableColumnH,
|
tableQRCodeLevel,
|
tableTextType,
|
} from './properties';
|
import provider from './provider';
|
import SliceConfig from './SliceConfig.vue';
|
import {
|
basicComponents,
|
businessComponents,
|
distributeList,
|
horizontalAlignList,
|
paperTypes,
|
seniorComponents,
|
subComponents,
|
systemComponents,
|
verticalAlignList,
|
} from './utils/define';
|
import { newHiprintPrintTemplate } from './utils/template-helper';
|
|
defineOptions({ name: 'PrintDesign' });
|
|
const props = defineProps({
|
conf: { type: String, default: '' },
|
dataSetList: { type: Array, default: () => [] },
|
convertConfig: { type: Array, default: () => [] },
|
versionState: { type: Number, default: 0 },
|
fullName: { type: String, default: '' },
|
globalConfig: { type: String },
|
});
|
|
interface State {
|
leftDragList: any[];
|
templateKey: any;
|
activeKey: string;
|
curPaper: any;
|
paperPopVisible: boolean;
|
paperCustomWidth: number;
|
paperCustomHeight: number;
|
scaleValue: number;
|
scaleMax: number;
|
scaleMin: number;
|
leftActiveKey: string[];
|
configActiveKey: string[];
|
dataSetListCopy: any[];
|
convertConfig: any[];
|
drag: boolean;
|
mouseOffSet: any;
|
copyTempData: any;
|
isAuto: boolean;
|
globalConfigCopy: any;
|
}
|
|
const defaultGlobalConfig = {
|
sliceConfig: [],
|
};
|
const defaultPaper = { type: 'A4', width: 210, height: 297 };
|
const defaultPanelConfig = {
|
optionItems: [
|
paperNumberDisabled,
|
paperNumberContinue,
|
paperNumberFormat,
|
tableTextType,
|
tableBarcodeMode,
|
tableQRCodeLevel,
|
tableColumnH,
|
imageWidth,
|
imageHeight,
|
formatter,
|
],
|
panel: {
|
supportOptions: [
|
{ name: 'firstPaperFooter', hidden: true },
|
{ name: 'evenPaperFooter', hidden: true },
|
{ name: 'oddPaperFooter', hidden: true },
|
{ name: 'lastPaperFooter', hidden: true },
|
{ name: 'panelLayoutOptions', hidden: true },
|
],
|
},
|
text: {
|
tabs: [
|
{ options: [] },
|
{ options: [] },
|
{ options: [] },
|
{
|
options: [
|
{ name: 'textType', hidden: true },
|
{ name: 'tableTextType', hidden: true },
|
{ name: 'barcodeMode', hidden: true },
|
{ name: 'barWidth', hidden: true },
|
{ name: 'barAutoWidth', hidden: true },
|
{ name: 'qrCodeLevel', hidden: true },
|
],
|
},
|
],
|
},
|
qrcode: {
|
tabs: [{ options: [{ name: 'qrcodeType', hidden: true }] }],
|
},
|
html: {
|
tabs: [
|
{
|
name: '基础',
|
replace: true,
|
options: [
|
{ name: 'field', hidden: false },
|
{ name: 'imageWidth', hidden: false },
|
{ name: 'imageHeight', hidden: false },
|
{ name: 'coordinate', hidden: false },
|
{ name: 'widthHeight', hidden: false },
|
{ name: 'showInPage', hidden: false },
|
{ name: 'unShowInPage', hidden: false },
|
{ name: 'fixed', hidden: false },
|
],
|
},
|
],
|
supportOptions: [
|
{ name: 'imageWidth', hidden: false },
|
{ name: 'imageHeight', hidden: false },
|
],
|
},
|
};
|
/**
|
* 变量集合
|
*/
|
let hiprintTemplate: any = null;
|
const state = reactive<State>({
|
leftDragList: [
|
{ id: '1', title: '辅助组件', list: subComponents },
|
{ id: '2', title: '基础组件', list: basicComponents },
|
{ id: '3', title: '系统组件', list: systemComponents },
|
],
|
templateKey: undefined,
|
activeKey: '1',
|
curPaper: {
|
type: 'A4',
|
width: 210,
|
height: 297,
|
},
|
// 自定义纸张
|
paperPopVisible: false,
|
paperCustomWidth: 150,
|
paperCustomHeight: 150,
|
// 缩放
|
scaleValue: 1,
|
scaleMax: 5,
|
scaleMin: 0.5,
|
leftActiveKey: ['1', '2', '3', '4', '5'],
|
configActiveKey: ['1'],
|
dataSetListCopy: [],
|
convertConfig: [],
|
drag: false,
|
mouseOffSet: { offsetX: 0, offsetY: 0 },
|
copyTempData: null,
|
isAuto: false,
|
globalConfigCopy: {},
|
});
|
const { leftDragList, activeKey, leftActiveKey, configActiveKey, drag, dataSetListCopy, globalConfigCopy } = toRefs(state);
|
// ref 创建的模板json
|
const templateRef = ref();
|
const dataSetTreeRef = ref();
|
const globSetting = useGlobSetting();
|
const { createMessage, createConfirm } = useMessage();
|
const [registerPreview, { openModal: openPreviewModal }] = useModal();
|
const [registerDataSetModal, { openModal: openDataSetModal }] = useModal();
|
const [registerConvertModal, { openModal: openConvertModal }] = useModal();
|
const { initRedo, addRecord, handleUndo, handleRedo, getCanUndo, getCanRedo, recordList, currentRecordIndex, jumpToRecord } = useRedo();
|
const actionList: TreeActionItem[] = [
|
{
|
render: (node) => {
|
if (!node.children) return null;
|
return h(FormOutlined, {
|
class: 'mr-[4px]',
|
title: '编辑',
|
onClick: (e) => {
|
e.stopPropagation();
|
handleEditDataSet(node);
|
},
|
});
|
},
|
},
|
{
|
render: (node) => {
|
if (!node.children) return null;
|
return h(DeleteOutlined, {
|
class: 'mr-[4px]',
|
title: '删除',
|
onClick: (e) => {
|
e.stopPropagation();
|
handleDeleteDataSet(node);
|
},
|
});
|
},
|
},
|
];
|
const { copy } = useClipboard({ legacy: true });
|
|
const getCustomPaperButtonType = computed(() => {
|
return state.curPaper?.type === 'other' ? 'primary' : undefined;
|
});
|
|
watch(
|
() => state.paperPopVisible,
|
(val) => {
|
if (!val) return;
|
state.paperCustomHeight = state.curPaper.height;
|
state.paperCustomWidth = state.curPaper.width;
|
},
|
);
|
|
/**
|
* 旋转纸张
|
*/
|
function rotatePaper() {
|
hiprintTemplate.rotatePaper();
|
}
|
/**
|
* 清空所有元素
|
*/
|
function clearPaper() {
|
hiprintTemplate.clear();
|
}
|
/**
|
* 元素对齐
|
*/
|
function handleAlign(e) {
|
setElsAlign(e.key);
|
}
|
/**
|
* 对齐方式
|
*/
|
function setElsAlign(type) {
|
hiprintTemplate.setElsAlign(type);
|
addLocalRecord('移动组件');
|
}
|
/**
|
* 获取预设尺寸按钮状态
|
*/
|
function getPresetPaperButtonType(type) {
|
return state.curPaper?.type === type ? 'primary' : undefined;
|
}
|
/**
|
* 修改预设纸张
|
*/
|
function setPresetPaper(item) {
|
const { type, width, height } = item || {};
|
const paperTypesCache = paperTypes || [];
|
|
try {
|
const matchResult = paperTypesCache?.find((option) => option?.type === type);
|
state.curPaper = { ...item, type: matchResult === undefined ? 'other' : matchResult?.type };
|
hiprintTemplate.setPaper(width, height);
|
} catch {}
|
}
|
/**
|
* 修改自定义纸张
|
*/
|
function setCustomPaper() {
|
state.paperPopVisible = false;
|
|
const { paperCustomWidth: width, paperCustomHeight: height } = state || {};
|
setPresetPaper({ type: 'other', width, height });
|
}
|
/**
|
* 设置初始化纸张
|
*/
|
function setCurPaper() {
|
if (!templateRef.value) return (state.curPaper = cloneDeep(defaultPaper));
|
const panel = templateRef.value.panels[0];
|
const { height, width } = panel;
|
let curPaper: any = null;
|
for (const paperType of paperTypes) {
|
if (paperType.height === height && paperType.width === width) {
|
curPaper = paperType;
|
break;
|
}
|
}
|
state.curPaper = curPaper || { type: 'other', width, height };
|
}
|
/**
|
* 修改缩放比例
|
*/
|
function changeScale(grow) {
|
const { scaleMax, scaleMin } = state || {};
|
|
let scaleValue = state.scaleValue || 1;
|
|
if (grow) {
|
scaleValue += 0.1;
|
scaleValue = Math.min(scaleValue, scaleMax);
|
} else {
|
scaleValue -= 0.1;
|
scaleValue = Math.max(scaleValue, scaleMin);
|
}
|
|
hiprintTemplate.zoom(scaleValue);
|
state.scaleValue = scaleValue;
|
}
|
/**
|
* 格式化比例值
|
*/
|
function formatScaleValue(value) {
|
return `${(value * 100)?.toFixed(0)}%`;
|
}
|
/**
|
* 解析比例值
|
*/
|
function parserScaleValue(value) {
|
return value?.replace('%', '');
|
}
|
/**
|
* 确认清空设计
|
*/
|
function handleClear() {
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: '确定要清空所有设计吗?',
|
onOk: () => {
|
try {
|
clearPaper();
|
templateRef.value.panels[0].printElements = [];
|
} catch {}
|
},
|
});
|
}
|
|
/**
|
* 选中字段
|
*/
|
function handleTreeNodeClick(_, node) {
|
const { id = '', children, fullName = '' } = node?.dataRef || {};
|
const text = children ? fullName : id;
|
copy(text);
|
createMessage.success('复制成功');
|
}
|
function handleEditDataSet(node: any) {
|
const data: any = omit(node, ['fullName_title', 'children']);
|
handleOpenDataSetModal(data);
|
}
|
function handleDeleteDataSet(node: any) {
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: '确定要删除该数据集吗?',
|
onOk: () => {
|
state.dataSetListCopy = state.dataSetListCopy.filter((o) => o.jnpfId !== node.jnpfId);
|
reBuildDesign();
|
},
|
});
|
}
|
/**
|
* 暴露数据
|
*/
|
function getData() {
|
return new Promise((resolve) => {
|
if (!existSliceConfig()) return;
|
const data = {
|
dataSetList: state.dataSetListCopy.map((o) => omit(o, ['fullName_title', 'children'])),
|
convertConfig: state.convertConfig,
|
globalConfig: state.globalConfigCopy,
|
printTplPanels: JSON.stringify(hiprintTemplate.getJson() || {}),
|
};
|
resolve(data);
|
});
|
}
|
function existSliceConfig() {
|
if (!state.globalConfigCopy.sliceConfig.length) return true;
|
let isOk = true;
|
for (let i = 0; i < state.globalConfigCopy.sliceConfig.length; i++) {
|
const e = state.globalConfigCopy.sliceConfig[i];
|
if (!e.dataSet) {
|
createMessage.error('多联打印设置中数据集不能为空');
|
isOk = false;
|
break;
|
}
|
if (!e.limit) {
|
createMessage.error('多联打印设置中每页条数不能为空');
|
isOk = false;
|
break;
|
}
|
}
|
return isOk;
|
}
|
/**
|
* 设计预览
|
*/
|
function handlePreview() {
|
openPreviewModal(true, { printTplPanels: JSON.stringify(hiprintTemplate.getJson() || {}), fullName: props.fullName });
|
}
|
/**
|
* 添加复合型组件
|
*/
|
function handleAddComplex(templateJson) {
|
if (!templateJson) return;
|
if (!templateRef.value) templateRef.value = hiprintTemplate.getJson() || {};
|
templateRef.value.panels[0].printElements = hiprintTemplate.getJson()?.panels[0]?.printElements?.concat(templateJson) || [];
|
buildDesignModel();
|
}
|
// 添加业务套件
|
function handleAddBusiness(templateJson) {
|
function addBusiness(isClear = true) {
|
if (!templateRef.value) templateRef.value = hiprintTemplate.getJson() || {};
|
try {
|
if (isClear) {
|
state.isAuto = true;
|
clearPaper();
|
templateRef.value.panels[0].printElements = [];
|
}
|
if (!templateJson) return;
|
templateRef.value.panels[0].printElements = hiprintTemplate.getJson()?.panels[0]?.printElements?.concat(templateJson) || [];
|
hiprintTemplate.update(templateRef.value);
|
addLocalRecord('新增套件');
|
} catch {}
|
}
|
if (!hiprintTemplate.getJson()?.panels[0]?.printElements.length) return addBusiness(false);
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: '确定后覆盖当前页面设计内容,是否继续?',
|
onOk: () => {
|
addBusiness();
|
},
|
});
|
}
|
/**
|
* 构建左侧可拖拽元素
|
*/
|
function buildDragElement() {
|
const items = $('.ep-draggable-item');
|
hiprint.PrintElementTypeManager.buildByHtml(items);
|
}
|
/**
|
* 构建中间设计器
|
*/
|
function buildDesignModel(isInit = false) {
|
// 先清空, 避免重复构建
|
$('#hiprintPrintTemplate').empty();
|
$('#PrintElementOptionSetting').empty();
|
|
const fields = convertField();
|
hiprintTemplate = newHiprintPrintTemplate(state.templateKey, {
|
template: toRaw(templateRef.value),
|
fields,
|
qtDesigner: true,
|
settingContainer: '#PrintElementOptionSetting', // 元素参数容器
|
onImageChooseClick: (target) => {
|
// 创建input,模拟点击,然后 target.refresh 更新
|
const input = document.createElement('input');
|
input.setAttribute('type', 'file');
|
input.setAttribute('accept', 'image/*');
|
input.click();
|
input.addEventListener('change', function () {
|
const file = (this as any).files[0];
|
if (!file) return;
|
const isAccept = /image\/*/.test(file.type);
|
if (!isAccept) {
|
createMessage.error($t('component.upload.uploadImg'));
|
return;
|
}
|
if (file.size / 1024 > 500) {
|
createMessage.error('操作失败,图片大小超出500K');
|
return;
|
}
|
const reader = new FileReader();
|
// 通过文件流行文件转换成Base64字行串
|
reader.readAsDataURL(file);
|
// 转换成功后
|
reader.onloadend = function () {
|
// 通过 target.refresh 更新图片元素
|
target.refresh(reader.result);
|
};
|
});
|
input.remove();
|
},
|
onDataChanged: (type) => {
|
if (['清空', '调整大小'].includes(type) && state.isAuto) return (state.isAuto = false);
|
if (type === '缩放' || (type === '框选移动' && !hiprintTemplate?.getSelectEls()?.length)) return;
|
const fullName = getRealFullName(type);
|
addLocalRecord(fullName);
|
},
|
});
|
|
hiprintTemplate.design('#hiprintPrintTemplate');
|
|
setCurPaper();
|
if (isInit) addLocalRecord('初始化');
|
}
|
function getRealFullName(type) {
|
// 新增、移动、删除、修改(参数调整)、大小、旋转
|
if (type.includes('移动')) return '移动组件';
|
if (['元素修改', '大小', '旋转'].includes(type)) return '修改组件';
|
if (['模板调整', '调整大小'].includes(type)) return '模板调整';
|
return `${type}组件`;
|
}
|
// 转换hiprint需要的字段
|
function convertField() {
|
let list = [
|
{ text: 'systemPrintTime(打印时间)', field: 'systemInfo.printTime' },
|
{ text: 'systemPrinter(打印人员)', field: 'systemInfo.printer' },
|
{ text: 'systemSlicePageNo(多联页码)', field: 'systemSlicePageNo' },
|
];
|
for (let i = 0; i < state.dataSetListCopy.length; i++) {
|
const e = state.dataSetListCopy[i];
|
const { children = [], fullName = '' } = e;
|
const fields = children.map((o) => ({ text: `${fullName}.${o?.fullName}`, field: o?.jnpfId }));
|
list = [...list, ...fields];
|
}
|
return list;
|
}
|
// 数据转换配置
|
function handleConvertConfig() {
|
const fieldOptions = state.dataSetListCopy.map((o) => ({
|
...o,
|
id: o.id || o.jnpfId,
|
disabled: true,
|
children: o.children ? o.children.map((c) => ({ ...c, fullName: `${o.fullName}.${c.fullName}`, id: `${o.fullName}.${c.id}` })) : [],
|
}));
|
openConvertModal(true, { list: state.convertConfig, fieldOptions });
|
}
|
function updateConvertConfig(data) {
|
state.convertConfig = data;
|
}
|
// 添加数据集
|
function handleAddDataSet() {
|
handleOpenDataSetModal();
|
}
|
function handleOpenDataSetModal(data = null) {
|
openDataSetModal(true, { data, list: state.dataSetListCopy });
|
}
|
function onDataSetConfirm(data) {
|
state.dataSetListCopy = data.map((o) => ({ ...o, children: o.children ? o.children.map((c) => ({ ...c, jnpfId: `${o.fullName}.0.${c.id}` })) : [] }));
|
reBuildDesign();
|
}
|
function reBuildDesign() {
|
templateRef.value = hiprintTemplate.getJson() || {};
|
buildDesignModel();
|
}
|
function onDragStart(e) {
|
state.mouseOffSet.offsetX = e.originalEvent.offsetX;
|
state.mouseOffSet.offsetY = e.originalEvent.offsetY;
|
state.drag = true;
|
}
|
function onDragEnd(e) {
|
const item = seniorComponents[e.oldIndex];
|
if (!item || !item.templateJson) return;
|
const x = e.originalEvent.clientX + $('.hiprint-printTemplate').scrollLeft() - $('#hiprintPrintTemplate').offset().left - state.mouseOffSet.offsetX - 15;
|
const y = e.originalEvent.clientY + $('.hiprint-printTemplate').scrollTop() - $('#hiprintPrintTemplate').offset().top - state.mouseOffSet.offsetY - 15;
|
if (!(window as any).hinnn) return buildInsertedTemplate(x, y, item.templateJson);
|
const firstItemX = (window as any).hinnn.px.toPt(Math.max(x, 0));
|
const firstItemY = (window as any).hinnn.px.toPt(Math.max(y, 0));
|
buildInsertedTemplate(firstItemX, firstItemY, item.templateJson);
|
state.drag = false;
|
}
|
function buildInsertedTemplate(firstItemX, firstItemY, templateJson) {
|
if (!templateJson) return;
|
templateRef.value = hiprintTemplate.getJson() || {};
|
let minY = Infinity;
|
for (const e of templateJson) {
|
if (e.options.top < minY) minY = e.options.top;
|
}
|
const minYList: any[] = templateJson.filter((o) => o.options.top === minY);
|
let minX = Infinity;
|
let elementWithMinX: any = null;
|
for (const e of minYList) {
|
if (e.options.left < minX) {
|
minX = e.options.left;
|
elementWithMinX = e;
|
}
|
}
|
const distanceX = firstItemX - elementWithMinX?.options?.left || 0;
|
const distanceY = firstItemY - elementWithMinX?.options?.top || 0;
|
for (const element of templateJson) {
|
element.options.left += distanceX;
|
element.options.top += distanceY;
|
}
|
handleAddComplex(templateJson);
|
}
|
// 重写hinnn
|
function initHinnn() {
|
if (!(window as any).hinnn) return;
|
(window as any).hinnn.apiUrl = globSetting.apiURL;
|
(window as any).hinnn.dateFormat = function (date, format) {
|
if (!date) return '';
|
if (!Number.isNaN(date) && typeof date === 'string') date = Number(date);
|
format = format.replaceAll('y', 'Y').replaceAll('d', 'D');
|
return dayjs(date).format(format);
|
};
|
}
|
function addLocalRecord(fullName: string = '') {
|
const copyTempData = JSON.stringify(hiprintTemplate.getJson() || {});
|
if (copyTempData != state.copyTempData) {
|
state.copyTempData = copyTempData;
|
addRecord(copyTempData, fullName);
|
}
|
}
|
// 更新打印设计器模板
|
function updateTemp(data) {
|
templateRef.value = JSON.parse(data);
|
hiprintTemplate.update(JSON.parse(data));
|
$('.hiprint-printPaper').click();
|
setCurPaper();
|
state.isAuto = true;
|
setPresetPaper(state.curPaper);
|
}
|
// 快捷键监听
|
function handleListen() {
|
// 取消绑定事件处理器
|
$(document).off('keydown');
|
|
onKeyStroke(true, (e: any) => {
|
if (e?.target?.tagName == 'INPUT') return;
|
// ctrl/command + z 撤销 / ctrl/command + shift + z 重做
|
if ((e.ctrlKey || e.metaKey) && e.keyCode == 90) {
|
e.shiftKey ? handleRedo(updateTemp) : handleUndo(updateTemp);
|
e.preventDefault();
|
}
|
});
|
}
|
function init() {
|
initHinnn();
|
// 初始化 provider
|
hiprint.init({ providers: [provider()] });
|
// 还原配置
|
hiprint.setConfig();
|
// 替换配置
|
hiprint.setConfig(defaultPanelConfig);
|
|
state.drag = false;
|
try {
|
templateRef.value = props?.conf ? JSON.parse(props.conf) : null;
|
} catch {
|
templateRef.value = null;
|
}
|
state.dataSetListCopy = (props.dataSetList as any[]).map((o) => ({
|
...o,
|
jnpfId: o.id,
|
children: o.children ? o.children.map((c) => ({ ...c, jnpfId: `${o.fullName}.0.${c.id}` })) : [],
|
}));
|
state.convertConfig = props.convertConfig;
|
state.globalConfigCopy = { ...defaultGlobalConfig, ...(props.globalConfig ? JSON.parse(props.globalConfig) : {}) };
|
|
const templateKey = getCurrentInstance()?.type?.name; // 存储模板对象的 key
|
if (templateKey === undefined) return;
|
state.templateKey = templateKey;
|
buildDragElement();
|
buildDesignModel(true);
|
}
|
|
onMounted(() => {
|
initRedo();
|
init();
|
handleListen();
|
});
|
|
/**
|
* 暴露方法
|
*/
|
defineExpose({ getData });
|
</script>
|
|
<template>
|
<div class="jnpf-print-designer">
|
<div class="design-wrap">
|
<div class="flex-row">
|
<div class="left-side">
|
<a-tabs class="average-tabs" v-model:active-key="activeKey" :tab-bar-gutter="11">
|
<a-tab-pane key="1" tab="组件" />
|
<a-tab-pane key="2" tab="数据源" />
|
<a-tab-pane key="3" tab="全局设置" />
|
</a-tabs>
|
<div class="tabs-content">
|
<ScrollContainer v-show="activeKey === '1'">
|
<a-collapse v-model:active-key="leftActiveKey" expand-icon-position="end" ghost>
|
<a-collapse-panel v-for="item in leftDragList" :key="item.id" class="components-list" id="providerContainer">
|
<template #header>
|
<div class="components-list-title">{{ item.title }}</div>
|
</template>
|
<div class="components-item ep-draggable-item" v-for="child in item.list" :key="child.id" :tid="`providerModule.${child.id}`">
|
<div class="components-body">
|
<i :class="child.icon"></i>
|
{{ child.label }}
|
</div>
|
</div>
|
</a-collapse-panel>
|
<a-collapse-panel key="4" class="components-list" v-if="seniorComponents.length">
|
<template #header>
|
<div class="components-list-title">复合组件</div>
|
</template>
|
<draggable
|
class="components-draggable"
|
v-model="seniorComponents"
|
item-key="id"
|
:sort="false"
|
draggable=".components-item"
|
@start="onDragStart"
|
@end="onDragEnd">
|
<template #item="{ element }">
|
<div class="components-item">
|
<div class="components-body">
|
<i :class="element.icon"></i>
|
{{ element.label }}
|
</div>
|
</div>
|
</template>
|
</draggable>
|
</a-collapse-panel>
|
<a-collapse-panel key="5" class="components-list" v-if="businessComponents.length">
|
<template #header>
|
<div class="components-list-title">业务套件<span class="title-tip">(点击添加)</span></div>
|
</template>
|
<div class="components-item ep-click-item" v-for="item in businessComponents" :key="item.id" @click="handleAddBusiness(item.templateJson)">
|
<div class="components-body">
|
<i :class="item.icon"></i>
|
{{ item.label }}
|
</div>
|
</div>
|
</a-collapse-panel>
|
</a-collapse>
|
</ScrollContainer>
|
<div class="dataSet-content" v-show="activeKey === '2'">
|
<div class="dataSet-content-header">
|
<a-button type="primary" size="small" pre-icon="icon-ym icon-ym-btn-add" @click="handleAddDataSet">数据集</a-button>
|
<a-button type="link" size="small" @click="handleConvertConfig" class="!p-0">数据转换</a-button>
|
</div>
|
<div class="dataSet-content-main">
|
<BasicLeftTree
|
ref="dataSetTreeRef"
|
:show-search="false"
|
:tree-data="dataSetListCopy"
|
:field-names="{ key: 'jnpfId', title: 'fullName' }"
|
@select="handleTreeNodeClick"
|
:action-list="actionList" />
|
</div>
|
</div>
|
<ScrollContainer v-show="activeKey === '3'">
|
<a-collapse v-model:active-key="configActiveKey" expand-icon-position="end" ghost>
|
<a-collapse-panel class="components-list" key="1">
|
<template #header>
|
<div class="components-list-title">多联打印设置</div>
|
</template>
|
<SliceConfig :list="globalConfigCopy.sliceConfig" :data-set-list="dataSetListCopy" />
|
</a-collapse-panel>
|
</a-collapse>
|
</ScrollContainer>
|
</div>
|
</div>
|
<div class="center-side">
|
<div class="center-side-tool-wrap">
|
<div class="left-handle-tool-wrap">
|
<a-space-compact>
|
<a-dropdown placement="bottom">
|
<template #overlay>
|
<a-menu @click="handleAlign">
|
<a-menu-item v-for="item in verticalAlignList" :key="item?.type">
|
<a-tooltip placement="right" :title="item.title">
|
<i :class="item.preIcon"></i>
|
</a-tooltip>
|
</a-menu-item>
|
</a-menu>
|
</template>
|
<a-button pre-icon="icon-ym icon-ym-flow-align-left" />
|
</a-dropdown>
|
<a-dropdown placement="bottom">
|
<template #overlay>
|
<a-menu @click="handleAlign">
|
<a-menu-item v-for="item in horizontalAlignList" :key="item?.type">
|
<a-tooltip placement="right" :title="item.title">
|
<i :class="item.preIcon"></i>
|
</a-tooltip>
|
</a-menu-item>
|
</a-menu>
|
</template>
|
<a-button pre-icon="icon-ym icon-ym-flow-align-top" />
|
</a-dropdown>
|
<a-tooltip :title="item.title" v-for="item in distributeList" :key="item.type">
|
<a-button @click="setElsAlign(item.type)" :title="item.title" :pre-icon="item.preIcon" />
|
</a-tooltip>
|
</a-space-compact>
|
<a-space-compact class="size-tool-wrap">
|
<a-button v-for="item in paperTypes" :key="item?.type" :type="getPresetPaperButtonType(item?.type)" @click="setPresetPaper(item)">
|
{{ item?.type }}
|
</a-button>
|
<a-popover overlay-class-name="custom-print-size-popover" v-model:open="state.paperPopVisible" title="设置纸张宽高(mm)" trigger="click">
|
<template #content>
|
<a-input-group class="custom-size-input-group" compact>
|
<a-input-number class="custom-size-input" v-model:value="state.paperCustomWidth" min="1" step="1" :precision="0" placeholder="宽" />
|
<a-input class="custom-size-input-range" placeholder="X" disabled />
|
<a-input-number class="custom-size-input" v-model:value="state.paperCustomHeight" min="1" step="1" :precision="0" placeholder="高" />
|
</a-input-group>
|
<a-button type="primary" block @click="setCustomPaper">确定</a-button>
|
</template>
|
<a-button class="custom-size-button" :type="getCustomPaperButtonType">自定义</a-button>
|
</a-popover>
|
<a-button class="custom-size-button" @click="rotatePaper">旋转</a-button>
|
</a-space-compact>
|
<a-input-group class="scale-tool-wrap" compact>
|
<a-button @click="changeScale(false)" pre-icon="icon-ym icon-ym-flow-minus" />
|
<a-input-number
|
class="scale-value-input"
|
disabled
|
:value="state.scaleValue"
|
:min="state.scaleMin"
|
:max="state.scaleMax"
|
:step="0.1"
|
:formatter="(value) => formatScaleValue(value)"
|
:parser="(value) => parserScaleValue(value)" />
|
<a-button @click="changeScale(true)" pre-icon="icon-ym icon-ym-flow-plus" />
|
</a-input-group>
|
</div>
|
<div class="right-handle-tool-wrap">
|
<a-tooltip :title="$t('common.undoText')">
|
<a-button type="text" class="action-bar-btn" :disabled="!getCanUndo" @click="handleUndo(updateTemp)">
|
<i class="icon-ym icon-ym-undo"></i>
|
</a-button>
|
</a-tooltip>
|
<a-tooltip :title="$t('common.redoText')">
|
<a-button type="text" class="action-bar-btn" :disabled="!getCanRedo" @click="handleRedo(updateTemp)">
|
<i class="icon-ym icon-ym-redo"></i>
|
</a-button>
|
</a-tooltip>
|
<HistoryPopover :record-list="recordList" :active-index="currentRecordIndex" @jump="jumpToRecord($event, updateTemp)" class="ml-[10px]" />
|
<a-divider type="vertical" class="action-bar-divider" />
|
<a-tooltip :title="$t('common.cleanText')">
|
<a-button type="text" class="action-bar-btn" @click="handleClear">
|
<i class="icon-ym icon-ym-clean"></i>
|
</a-button>
|
</a-tooltip>
|
<a-tooltip :title="$t('common.previewText')">
|
<a-button type="text" class="action-bar-btn" @click="handlePreview">
|
<i class="icon-ym icon-ym-video-play"></i>
|
</a-button>
|
</a-tooltip>
|
</div>
|
</div>
|
<!-- 设计器的 容器 -->
|
<div id="hiprintPrintTemplate"></div>
|
<draggable tag="div" class="draggable-box h-full w-full" :animation="300" group="componentsGroup" item-key="id" v-show="drag">
|
<template #item></template>
|
</draggable>
|
</div>
|
<div class="right-side">
|
<!-- 元素参数的 容器 -->
|
<div id="PrintElementOptionSetting"></div>
|
</div>
|
</div>
|
</div>
|
</div>
|
<Preview @register="registerPreview" />
|
<DataSetModal type="print" @register="registerDataSetModal" @confirm="onDataSetConfirm" />
|
<ConvertModal @register="registerConvertModal" @confirm="updateConvertConfig" />
|
</template>
|
|
<style lang="scss">
|
@use './style/index.scss' as *;
|
</style>
|