| <template> | 
|     <el-row :gutter="8" style="margin-bottom: 5px"> | 
|         <el-col :span="4"> | 
|             <!-- 流程下拉 模板选择 --> | 
|             <el-select v-model="state.mode" showSearch @change="changeMode" :defaultValue="0" option-label-prop="label" class="w100"> | 
|                 <el-option v-for="(opt, idx) in state.modeList" :key="idx" :label="opt.name" :value="idx"> | 
|                     {{ opt.name }} | 
|                 </el-option> | 
|             </el-select> | 
|         </el-col> | 
|   | 
|         <el-col :span="20"> | 
|             <!-- 纸张设置 --> | 
|             <el-button-group style="margin: 0 2px"> | 
|                 <el-button v-for="(value, type) in state.paperTypes" :type="curPaperType === type ? 'primary' : ''" @click="setPaper(type, value)" :key="type"> | 
|                     {{ type }} | 
|                 </el-button> | 
|                 <el-popover v-model="state.paperPopVisible" placement="bottom" width="300" title="设置纸张宽高(mm)"> | 
|                     <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px"> | 
|                         <el-input type="number" v-model="state.paperWidth" style="width: 100px; text-align: center" place="宽(mm)"></el-input>~ | 
|                         <el-input type="number" v-model="state.paperHeight" style="width: 100px; text-align: center" place="高(mm)"></el-input> | 
|                     </div> | 
|                     <div> | 
|                         <el-button type="primary" style="width: 100%" @click="otherPaper">确定</el-button> | 
|                     </div> | 
|                     <template #reference> | 
|                         <el-button :type="'other' == curPaperType ? 'primary' : ''" style="margin: 0 10px">自定义宽高</el-button> | 
|                     </template> | 
|                 </el-popover> | 
|             </el-button-group> | 
|             <el-input-number style="margin-right: 8px" v-model="state.scaleValue" :precision="2" :step="0.1" :min="state.scaleMin" :max="state.scaleMax" @change="changeScale"></el-input-number> | 
|   | 
|             <el-button-group> | 
|                 <el-tooltip content="左对齐" placement="bottom"> | 
|                     <el-button icon="ele-Back" @click="setElsAlign('left')"> </el-button> | 
|                 </el-tooltip> | 
|                 <el-tooltip content="居中" placement="bottom"> | 
|                     <el-button icon="ele-FullScreen" @click="setElsAlign('vertical')"> </el-button> | 
|                 </el-tooltip> | 
|                 <el-tooltip content="右对齐" placement="bottom"> | 
|                     <el-button icon="ele-Right" @click="setElsAlign('right')"> </el-button> | 
|                 </el-tooltip> | 
|                 <el-tooltip content="顶对齐" placement="bottom"> | 
|                     <el-button icon="ele-Top" @click="setElsAlign('top')"> </el-button> | 
|                 </el-tooltip> | 
|                 <el-tooltip content="垂直居中" placement="bottom"> | 
|                     <el-button icon="ele-DCaret" @click="setElsAlign('horizontal')"> </el-button> | 
|                 </el-tooltip> | 
|                 <el-tooltip content="底对齐" placement="bottom"> | 
|                     <el-button icon="ele-Bottom" @click="setElsAlign('bottom')"> </el-button> | 
|                 </el-tooltip> | 
|                 <el-tooltip content="横向分散" placement="bottom"> | 
|                     <el-button icon="ele-Sort" @click="setElsAlign('distributeHor')"> </el-button> | 
|                 </el-tooltip> | 
|                 <el-tooltip content="纵向分散" placement="bottom"> | 
|                     <el-button icon="ele-Switch" @click="setElsAlign('distributeVer')"> </el-button> | 
|                 </el-tooltip> | 
|             </el-button-group> | 
|   | 
|             <!-- 预览/打印 --> | 
|             <el-button-group style="margin-left: 8px"> | 
|                 <el-button type="primary" icon="ele-RefreshRight" @click="rotatePaper"> 旋转 </el-button> | 
|                 <el-button type="primary" icon="ele-View" @click="preView"> 预览 </el-button> | 
|                 <el-button type="primary" icon="ele-Printer" @click="print"> 直接打印 </el-button> | 
|                 <el-button type="primary" icon="ele-CircleCheck" @click="viewJson"> 模板JSON </el-button> | 
|                 <el-button type="danger" icon="ele-Delete" @click="clearPaper"> 清空模板 </el-button> | 
|             </el-button-group> | 
|         </el-col> | 
|     </el-row> | 
|   | 
|     <el-row :gutter="8"> | 
|         <el-col :span="4"> | 
|             <el-card style="height: 100%" shadow="never"> | 
|                 <el-row> | 
|                     <el-col :span="24" id="hiprintEpContainer" class="rect-printElement-types hiprintEpContainer"> </el-col> | 
|                 </el-row> | 
|             </el-card> | 
|         </el-col> | 
|         <el-col :span="14"> | 
|             <el-card shadow="never" class="card-design"> | 
|                 <div id="hiprint-printTemplate" class="hiprint-printTemplate"></div> | 
|             </el-card> | 
|         </el-col> | 
|         <el-col :span="6" class="params_setting_container"> | 
|             <el-card shadow="never"> | 
|                 <el-row class="hinnn-layout-sider"> | 
|                     <div id="PrintElementOptionSetting"></div> | 
|                 </el-row> | 
|             </el-card> | 
|         </el-col> | 
|     </el-row> | 
|   | 
|     <el-drawer title="打印模板" v-model="state.templateDialogVisible"> | 
|         <vue-json-pretty :data="state.templateContent" showLength showIcon showLineNumber showSelectController /> | 
|     </el-drawer> | 
|   | 
|     <!-- 预览 --> | 
|     <PrintPreview ref="preViewRef" /> | 
| </template> | 
|   | 
| <script lang="ts" setup name="hiprintDesign"> | 
| import { computed, onMounted, ref, reactive } from 'vue'; | 
| import { ElMessage, ElMessageBox } from 'element-plus'; | 
| import VueJsonPretty from 'vue-json-pretty'; | 
| import 'vue-json-pretty/lib/styles.css'; | 
|   | 
| import { hiprint } from 'vue-plugin-hiprint'; | 
| import providers from './providers'; | 
| import PrintPreview from './preview.vue'; | 
| import printData from './print-data'; | 
|   | 
| let hiprintTemplate = ref(); | 
|   | 
| const preViewRef = ref(); | 
| const state = reactive({ | 
|     // 模板选择 | 
|     mode: 0, | 
|     modeList: [] as any, | 
|     // 当前纸张 | 
|     curPaper: { | 
|         type: 'A4', | 
|         width: 220, | 
|         height: 296.6, | 
|     }, | 
|     // 纸张类型 | 
|     paperTypes: { | 
|         A3: { | 
|             width: 420, | 
|             height: 296.6, | 
|         }, | 
|         A4: { | 
|             width: 210, | 
|             height: 296.6, | 
|         }, | 
|         A5: { | 
|             width: 210, | 
|             height: 147.6, | 
|         }, | 
|         B3: { | 
|             width: 500, | 
|             height: 352.6, | 
|         }, | 
|         B4: { | 
|             width: 250, | 
|             height: 352.6, | 
|         }, | 
|         B5: { | 
|             width: 250, | 
|             height: 175.6, | 
|         }, | 
|     }, | 
|     scaleValue: 1, | 
|     scaleMax: 5, | 
|     scaleMin: 0.5, | 
|     // 自定义纸张 | 
|     paperPopVisible: false, | 
|     paperWidth: 220, | 
|     paperHeight: 80, | 
|   | 
|     templateDialogVisible: false, | 
|     templateContent: '', | 
| }); | 
|   | 
| // 计算当前纸张类型 | 
| const curPaperType = computed(() => { | 
|     let type = 'other'; | 
|     let types: any = state.paperTypes; | 
|     for (const key in types) { | 
|         let item = types[key]; | 
|         let { width, height } = state.curPaper; | 
|         if (item.width === width && item.height === height) { | 
|             type = key; | 
|         } | 
|     } | 
|     return type; | 
| }); | 
|   | 
| // 选择模板 | 
| const changeMode = () => { | 
|     let provider = providers[state.mode]; | 
|     hiprint.init({ | 
|         providers: [provider.f], | 
|     }); | 
|   | 
|     // 渲染自定义选项 | 
|     const hiprintEpContainerEl = document.getElementById('hiprintEpContainer'); | 
|     if (hiprintEpContainerEl) { | 
|         hiprintEpContainerEl.innerHTML = ''; | 
|     } | 
|     hiprint.PrintElementTypeManager.build('.hiprintEpContainer', provider.value); | 
|   | 
|     // 渲染绘画模板 | 
|     const hiprintPrintTemplate = document.getElementById('hiprint-printTemplate'); | 
|     if (hiprintPrintTemplate) { | 
|         hiprintPrintTemplate.innerHTML = ''; | 
|     } | 
|     // 初始化打印模板设计器 | 
|     let template = {}; | 
|     hiprintTemplate.value = new hiprint.PrintTemplate({ | 
|         template: template, | 
|         settingContainer: '#PrintElementOptionSetting', | 
|         paginationContainer: '.hiprint-printPagination', | 
|         fontList: [ | 
|             { title: '微软雅黑', value: 'Microsoft YaHei' }, | 
|             { title: '黑体', value: 'STHeitiSC-Light' }, | 
|             { title: 'Arial', value: 'Arial' }, | 
|             { title: '宋体', value: 'SimSun' }, | 
|             { title: '华为楷体', value: 'STKaiti' }, | 
|             { title: 'cursive', value: 'cursive' }, | 
|             { title: 'Vector', value: 'Vector' }, | 
|         ], | 
|     }); | 
|     hiprintTemplate.value.design('#hiprint-printTemplate'); | 
|     // 获取当前放大比例, 当zoom时传true才会有 | 
|     state.scaleValue = hiprintTemplate.value.editingPanel.scale || 1; | 
| }; | 
|   | 
| /** | 
|  * 设置纸张大小 | 
|  * @param type [A3, A4, A5, B3, B4, B5, other] | 
|  * @param value {width,height} mm | 
|  */ | 
| const setPaper = (type: string, value: { width: number; height: number }) => { | 
|     try { | 
|         if (Object.keys(state.paperTypes).includes(type)) { | 
|             state.curPaper = { type: type, width: value.width, height: value.height }; | 
|             hiprintTemplate.value.setPaper(value.width, value.height); | 
|         } else { | 
|             state.curPaper = { type: 'other', width: value.width, height: value.height }; | 
|             hiprintTemplate.value.setPaper(value.width, value.height); | 
|         } | 
|     } catch (error) { | 
|         ElMessage.error(`操作失败: ${error}`); | 
|     } | 
| }; | 
|   | 
| // 改变缩放比例 | 
| const changeScale = (currentValue: number, oldValue: number) => { | 
|     let big = false; | 
|     currentValue <= oldValue ? (big = false) : (big = true); | 
|   | 
|     let scaleVal = state.scaleValue; | 
|     if (big) { | 
|         if (scaleVal > state.scaleMax) scaleVal = 5; | 
|     } else { | 
|         if (scaleVal < state.scaleMin) scaleVal = 0.5; | 
|     } | 
|     if (hiprintTemplate.value) { | 
|         // scaleVal: 放大缩小值, false: 不保存(不传也一样), 如果传 true, 打印时也会放大 | 
|         hiprintTemplate.value.zoom(scaleVal); | 
|         state.scaleValue = scaleVal; | 
|     } | 
| }; | 
|   | 
| // 旋转模板 | 
| const rotatePaper = () => { | 
|     if (hiprintTemplate.value) { | 
|         hiprintTemplate.value.rotatePaper(); | 
|     } | 
| }; | 
|   | 
| // 对齐模板 | 
| const setElsAlign = (e: any) => { | 
|     hiprintTemplate.value.setElsAlign(e); | 
| }; | 
|   | 
| // 清空模板 | 
| const clearPaper = () => { | 
|     ElMessageBox.confirm('是否确认清空模板信息?', '警告', { | 
|         confirmButtonText: '确定', | 
|         cancelButtonText: '取消', | 
|         type: 'warning', | 
|     }) | 
|         .then(() => { | 
|             try { | 
|                 hiprintTemplate.value.clear(); | 
|             } catch (error) { | 
|                 ElMessage.error(`操作失败: ${error}`); | 
|             } | 
|         }) | 
|         .catch((err) => { | 
|             console.log(err); | 
|         }); | 
| }; | 
|   | 
| // 自定义纸张 | 
| const otherPaper = () => { | 
|     let value = { | 
|         width: 0, | 
|         height: 0, | 
|     }; | 
|     value.width = state.paperWidth; | 
|     value.height = state.paperHeight; | 
|     state.paperPopVisible = false; | 
|     setPaper('other', value); | 
| }; | 
|   | 
| // 预览 | 
| const preView = () => { | 
|     let { width } = state.curPaper; | 
|     preViewRef.value.showDialog(hiprintTemplate.value, printData, width); | 
| }; | 
| // 直接打印 | 
| const print = () => { | 
|     console.log('直接打印'); | 
| }; | 
|   | 
| // 查看模板JSON | 
| const viewJson = () => { | 
|     if (hiprintTemplate.value) { | 
|         var templateJson = JSON.stringify(hiprintTemplate.value.getJson() || {}); | 
|         state.templateContent = JSON.parse(templateJson); | 
|         state.templateDialogVisible = true; | 
|     } | 
| }; | 
|   | 
| onMounted(() => { | 
|     state.modeList = providers.map((e) => { | 
|         return { type: e.type, name: e.name, value: e.value }; | 
|     }); | 
|     changeMode(); | 
|     // otherPaper(); // 默认纸张 | 
| }); | 
|   | 
| // 导出对象 | 
| defineExpose({ hiprintTemplate }); | 
| </script> | 
|   | 
| <style lang="scss" scoped> | 
| :deep(.rect-printElement-types .hiprint-printElement-type > li > ul > li > a) { | 
|     // padding: 4px 4px; | 
|     //color: #1296db; | 
|     // line-height: 1; | 
|     height: auto; | 
|     text-overflow: ellipsis; | 
|     color: var(--el-color-primary); | 
|     box-shadow: none !important; | 
|     border: 1px dashed var(--el-color-primary); | 
| } | 
|   | 
| // 默认图片 | 
| :deep(.hiprint-printElement-image-content) { | 
|     img { | 
|         content: url('~@/assets/logo.png'); | 
|     } | 
| } | 
|   | 
| // 设计容器 | 
| .card-design { | 
|     overflow: hidden; | 
|     overflow-x: auto; | 
|     overflow-y: auto; | 
| } | 
|   | 
| :deep(.hiprint-option-item-submitBtn) { | 
|     background: var(--el-color-primary); | 
| } | 
| :deep(.hiprint-option-item-deleteBtn) { | 
|     background: var(--el-color-danger); | 
| } | 
| :deep(.prop-tabs .prop-tab-items li.active) { | 
|     color: var(--el-color-primary); | 
|     border-bottom: 2px solid var(--el-color-primary); | 
| } | 
| </style> |