数通互联化工云平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

437 lines
12 KiB

<script lang="ts" setup>
import QRCode from 'qrcode';
import logourl from "@/assets/logo_text.png";
import { useUserStore } from '@/store/modules/user';
export interface fieldTree{
field?:string;
name?:string;
type:string;
checked?:number;
data?:[];
child?:fieldTree[]
}
export interface PageConfig{
width:string;
height:string;
horizontal:string;//横向
pagesize:string;
//页脚页眉
pagebrow:string[];
founder:string;
founderTime:string;
deptOrg:string;
masters_key:string;
qrcode:boolean;
}
const props = withDefaults(defineProps<{
name:string,
pageConfig:PageConfig,
fieldTree:fieldTree[],
flowList:any[],
qrcode?:string,
}>(),{})
const qrdata=ref("")
const userName=useUserStore().nickname;
function parseDataPicker(val:string){
let str:string;
if(typeof(val)=="number"){
str=new Date(val).toISOString()
}else{
if(val==""|| val.match(/[a-z]/) ) return val;
str=new Date(parseInt(val)).toISOString()
}
return str.slice(0,10)+" "+str.slice(11,16)
}
const generateQrCode= ()=>{
var opts = {
errorCorrectionLevel: 'M',
type: 'image/png',
quality: 0.3,
margin: 1,
color: {
dark:"#000",
light:"#fff"
}
}
QRCode.toDataURL(props.qrcode, opts, function (err, url) {
if (err) throw err
qrdata.value=url
})
}
const getStateText=(val:number)=>{
if(val==1) return "未操作"
if(val==2) return "已同意"
if(val==3) return "已驳回"
if(val==4) return "已查看"
return "未操作"
}
</script>
<template>
<div id="printPageAll" :style="{width: props.pageConfig.width}">
<div id="printHeader" class="page_brow">
<img height="50px" :src="logourl" />
<span v-if="props.pageConfig.pagebrow.includes('masters_key')">表单编号: {{ props.pageConfig.masters_key }}</span>
</div>
<div id="printContainer">
<h3>{{props.name}}</h3>
<div style="display: flex;justify-content: space-between; margin-bottom: 10px;">
<span v-if="props.pageConfig.pagebrow.includes('founder')">创建人: {{ props.pageConfig.founder }}</span>
<span v-if="props.pageConfig.pagebrow.includes('founderTime')">创建时间: {{ props.pageConfig.founderTime }}</span>
<span v-if="props.pageConfig.pagebrow.includes('deptOrg')">所属部门: {{ props.pageConfig.deptOrg }}</span>
</div>
<div v-for="group in props.fieldTree">
<div v-if="Array.isArray(group) && group.length>0" class="auto_table">
<template v-for="item in group" >
<div v-if="item.checked!=2" class="cell_box">
<span class="box_name">
{{item.name}}
</span>
<span v-if="item.type !=='datePicker'" class="content">{{item.field}}</span>
<span v-else class="content">{{parseDataPicker(item.field)}}</span>
</div>
</template>
</div>
<div v-else-if="group.type=='divider'" class="title" v-if="group.checked!=2">{{ group.name }}</div>
<div v-else-if="group.type=='textarea'" class="section" v-if="group.checked!=2">
<h5>{{ group.name }}</h5>
<div class="text_area">{{ group.field }}</div>
</div>
<div v-else-if="group.type=='table'" class="section_table" v-if="group.checked!=2">
<table class="bder_table">
<caption >{{ group.name }}</caption>
<thead>
<tr>
<template v-for="child in group.child">
<th v-if="child.checked!=2" >{{ child.name }}</th>
</template>
</tr>
</thead>
<tbody>
<tr v-for="(dd, index) in group.data" :key="dd">
<template v-for="child in group.child">
<td v-if="child.checked!=2" >{{ dd[child.field]}}</td>
</template>
</tr>
</tbody>
</table>
</div>
<div v-else-if="group.type=='tabs'" class="section_tabs" v-if="group.checked!=2">
<h5>{{ group.name }}</h5>
<div v-for="tabs in group.child" class="tabs_item">
<div v-if="Array.isArray(tabs)" class="auto_table">
<template v-for="item in tabs" >
<div v-if="item.checked!=2" class="tabs_cell_box" style="width: auto;">
<span class="box_name">
{{item.name}}
</span>
<span v-if="item.type !=='datePicker'" class="content">{{item.field}}</span>
<span v-else class="content">{{parseDataPicker(item.field)}}</span>
</div>
</template>
</div>
<div v-else-if="tabs.type=='divider'" class="title" v-if="tabs.checked!=2"
style="font-size: 12px; margin-top: 20px;">{{ tabs.name }}</div>
<div v-else-if="tabs.type=='textarea'" class="section" v-if="tabs.checked!=2">
<h5>{{ tabs.name }}</h5>
<div class="text_area">{{ tabs.field }}</div>
</div>
<div v-else-if="tabs.type=='table'" class="section" v-if="tabs.checked!=2">
<h5>{{ tabs.name }}</h5>
<table class="bder_table">
<thead>
<tr>
<template v-for="child in tabs.child">
<th v-if="child.checked!=2" >{{ child.name }}</th>
</template>
</tr>
</thead>
<tbody>
<tr v-for="(dd, index) in tabs.data" :key="dd">
<template v-for="child in tabs.child">
<td v-if="child.checked!=2" >{{ dd[child.field]}}</td>
</template>
</tr>
</tbody>
</table>
</div>
<div v-else class="tabs_cell_box" v-if="tabs.checked!=2">
<span class="box_name">
{{tabs.name}}
</span>
<span v-if="tabs.type !=='datePicker'" class="content">{{tabs.field}}</span>
<span v-else class="content">{{parseDataPicker(tabs.field??'')}}</span>
</div>
</div>
</div>
<div v-else v-if="group.checked!=2">{{ group }}</div>
</div>
<div v-if="props.flowList && props.flowList.length>0" class="section_table">
<table class="bder_table">
<caption >审批流程</caption>
<thead>
<tr>
<th >审批节点</th>
<th >处理人</th>
<th >操作记录</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in props.flowList" :key="dd">
<template v-if="item.step>1">
<td >
<div style="line-height: 22px;">{{ item.nodeName}}
<span v-if="item.examinemode==1">(依次审批)</span>
<span v-if="item.examinemode==2">(会签)</span>
<span v-if="item.examinemode==3">(或签)</span>
<br><span v-if="item.status==2">已同意</span>
<span v-else-if="item.status==3">已驳回</span>
<span v-else>未处理</span>
</div>
</td>
<td >
<template v-for="oper in item.operator" >
<span v-if="oper.log" class="operate_log" >
<template v-for="log in oper.log">
{{ oper.name }}--{{ oper.departmentname }}--{{ oper.postname }}
</template>
</span>
</template>
</td>
<td >
<template v-for="oper in item.operator" >
<span v-if="oper.log" class="operate_log" >
<template v-for="log in oper.log">
({{ getStateText(log.state) }}) {{ log.cause }} {{ log.time.slice(0,16) }}
</template>
</span>
</template>
</td>
</template>
</tr>
</tbody>
</table>
</div>
<div v-if="props.pageConfig.qrcode" style="display: flex; justify-content: space-between;margin-top: 20px; ">
{{ generateQrCode() }}
<div style="display: inherit; align-items: center;">
<img id="qrcode" width="100px" :src="qrdata"/>
<div style="text-align: left;padding-left: 5px;">使用手机企业微信<br>扫一扫</div>
</div>
<div style="display: flex;flex-direction: column;text-align: left;justify-content: center;">
<p>打印日期{{ new Date().toLocaleString() }}</p>
<p>打印人 {{userName}}</p>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
#printContainer{
padding: 0px 57px 30px 57px;
text-align: center;
display: flex;
flex-direction: column;
overflow-y: scroll;
scrollbar-width: none;
}
//没有元素时,隐藏
div:empty {
display: none;
}
.page_brow{
padding: 24px 57px 0 57px;
display: flex;
justify-content: space-between;
align-items: center;
}
.auto_table{
display: grid;
grid-template-columns: 1fr 1fr;
border: 1px solid rgb(226, 226, 226);
}
.operate_log{
display: block;
border-bottom: 1px solid rgb(182, 181, 181);
}
td > .operate_log:last-child{
border-bottom: none;
}
h3{
width: 100%;
font-size: 22px;
font-weight: bold;
}
h5{
font-weight: bold;
width: 100%;
margin: 5px;
}
.title{
margin-left:10px;
text-align: left;
font-size: 15px;
font-weight: bold;
}
.el-descriptions {
margin-top: 20px;
}
.cell-item {
display: flex;
align-items: center;
}
.margin-top {
margin: 10px;
}
.section_title{
width:100%
}
.normal_cell,.normal_cell_field{
width: 23%;
height: 20px;
}
.section{
display: flex;
flex-direction: column;
}
.section_tabs{
margin: 10px 0;
display: flex;
flex-wrap: wrap;
}
.text_area{
border: 1px solid rgb(182, 181, 181);
border-radius: 3px;
min-height: 40px;
margin: 5px 0px 10px 0px;
}
//////////////自动伸缩
.tabs_item {
display: inline-flex;
min-height: 30px;
min-width: 50%; /* 默认最小宽度 */
margin-right: -1px;/* 解决边框重合问题*/
/* 默认情况:没有 title/section 时宽度 50% */
width: 50%;
.section{
width: 100%;
}
}
/* 当直接子元素包含 title 或 section 时,宽度变为 100% */
.tabs_item:has(> .title),
.tabs_item:has(> .section) {
width: 100%;
}
.bder_table{
border: 1px solid rgb(182, 181, 181);
margin:5px 0px 10px 0px;
width: 100% !important; /* 确保表格不超出父容器 */
overflow-x: hidden;
}
/* 原有样式(稍作优化) */
.cell_box, .tabs_cell_box {
border: 1px solid rgb(182, 181, 181);
margin-right: -1px; /* 水平排列时用右负margin */
margin-bottom: -1px; /* 垂直排列时用下负margin */
display: inline-flex;
.box_name {
text-align: center;
align-content: center;
width: 30%;
min-height: 30px;
text-wrap: wrap;
max-height: 80px;
overflow: hidden; /* 配合 ellipsis 需要 */
}
.content {
text-align: center;
align-content: center;
width: 70%;
min-height: 30px;
text-wrap: wrap;
word-break: break-all;
border-left: 1px solid rgb(182, 181, 181);
}
}
.tabs_cell_box{
width: 100%;
}
</style>
<style>
#printContainer table{
border: 0px solid;
border-spacing: 1px;
border-collapse: collapse;
overflow-y: visible !important;
}
#printContainer thead{
border: 1px solid rgb(182, 181, 181);
}
#printContainer table caption{
text-align: center;
caption-side: top;
color: black;
font-weight: bold;
width: 100%;
margin: 5px;
}
#printContainer .el-table th.el-table__cell{
background: none !important;
word-wrap: break-word;
}
#printContainer .el-table .cell{
padding: 0 5px;
text-align: center;
max-width: max-content;
}
#printContainer table th{
font-weight: normal;
border-right: 1px solid rgb(182, 181, 181);
text-align: center;
line-height: 28px;
}
#printContainer table td{
border: 1px solid rgb(182, 181, 181);
line-height: 28px;
}
.el-scrollbar__view {
display: block !important;
width: 100% !important;
}
</style>