Custom Printing
# Custom Printing
# Background
Normally, the printing template functionality in Fxiaoke can meet most printing requirements. However, for special report printing scenarios, the standard printing templates may not be sufficient.
This article teaches you how to develop custom components to create tailored printing pages.
# Writing the Template
The main content involves using HTML to construct tables.
<template>
<div class="cus-demo" v-if="dData">
<h1 class="text-center">Fund Utilization Approval Form</h1>
<div class="flex bd">
<div class="flex flex-1 flex-col">
<div class="flex">
<div class="w-120 text-center bd">Payee</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_uhcib__c }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Bank Account</div>
<div class="flex-1">
<div class="flex">
<div class="w-60 text-center bd">Bank</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_utckZ__c }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Account</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_oQgRl__c }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Address</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_v82bd__c }}}</div>
</div>
</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Payment Amount</div>
<div class="flex-1">
<div class="flex">
<div class="w-60 text-center bd">In Words</div>
<div class="flex-1 padding-5 bd">{{{ digitUppercase(dData.field_8P18m__c) }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">In Numbers</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_8P18m__c }}}</div>
</div>
</div>
</div>
<div class="flex">
<div class="w-120 text-center bd">Payment Method</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_fJY1p__c }}}</div>
</div>
<div class="flex">
<div class="flex-1 bd">
<div class="text-center">Payment Reason</div>
<div class="text-center padding-5">{{{ dData.field_fwjy1__c }}}</div>
</div>
<div class="flex-1 bd">
<div class="text-center">Department Opinion</div>
<div class="text-center padding-5">{{{ dData.field_36nKK__c }}}</div>
</div>
<div class="flex-1 bd">
<div class="text-center">Project Manager Opinion</div>
<div class="text-center padding-5">{{{ dData.field_J3N26__c }}}</div>
</div>
</div>
</div>
</div>
<div class="text-right no-print">Click the browser's print button to print directly (this text won't be printed)</div>
</div>
</template>
# Writing the Script
Let's outline the approach:
- Get complete detail data of the current record. This relies on
userDatafrom uiaction. - Get field descriptions of the current record's business object. This relies on APIs provided by FxUI.
- With data and descriptions, we can parse human-readable data. This relies on APIs provided by FxUI.
Based on these steps, we organize the logic as follows:
<script>
export default {
props: ['userData'], //Step 1 mentioned above. Custom components receive uiaction data via userData
data() {
return {
dData: null
}
},
created() {
this.getData();
},
mounted() {
//Trigger dialog position recalculation
this.$emit('action', {type: 'resize'});
},
methods: {
getData() {
const userData = this.userData;
//Step 2 mentioned above. Get object description
FxUI.objectApi.fetch_describe(userData.object_describe_api_name).then((data) => {
const {
fields
} = data.objectDescribe;
//Step 3 mentioned above. Parse data
let result = {};
Object.keys(fields).forEach(fApiName => {
result[fApiName] = (FxUI.objectApi.format_field_value || PAAS.format_field_value)(fields[fApiName], userData[fApiName], userData);
})
//Final step. Assign and render
this.dData = result;
this.$nextTick(() => {
//After data renders to page, height changes. We need to recalculate dialog position
this.$emit('action', {type: 'resize'});
})
})
}
}
}
</script>
Additionally, since the requirements involve amount conversion between numeric and Chinese characters, we enhance the code by providing the digitUppercase method in the component:
<script>
export default {
props: ['userData', 'data'],
data() {
return {
dData: null
}
},
created() {
this.getData();
},
mounted() {
this.$emit('action', {type: 'resize'});
},
methods: {
//Convert numeric amount to Chinese characters
digitUppercase(n) {
var fraction = ['角', '分'];
var digit = [
'零', '壹', '贰', '叁', '肆',
'伍', '陆', '柒', '捌', '玖'
];
var unit = [
['元', '万', '亿'],
['', '拾', '佰', '仟']
];
var head = n < 0 ? '欠' : '';
n = Math.abs(n);
var s = '';
for (var i = 0; i < fraction.length; i++) {
s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
}
s = s || '整';
n = Math.floor(n);
for (var i = 0; i < unit[0].length && n > 0; i++) {
var p = '';
for (var j = 0; j < unit[1].length && n > 0; j++) {
p = digit[n % 10] + unit[1][j] + p;
n = Math.floor(n / 10);
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
}
return head + s.replace(/(零.)*零元/, '元')
.replace(/(零.)+/g, '零')
.replace(/^整$/, '零元整');
},
getData() {
const userData = this.userData;
//Get description then parse data
FxUI.objectApi.fetch_describe(userData.object_describe_api_name).then((data) => {
const {
fields
} = data.objectDescribe;
let result = {};
Object.keys(fields).forEach(fApiName => {
result[fApiName] = (FxUI.objectApi.format_field_value || PAAS.format_field_value)(fields[fApiName], userData[fApiName], userData);
})
this.dData = result;
this.$nextTick(() => {
this.$emit('action', {type: 'resize'});
})
})
}
}
}
</script>
# Writing the Style
<style lang="less">
.cus-demo {
.demo {
max-width: 1200px;
}
h1 {
font-size: 28px;
font-weight: bold;
margin-bottom: 15px;
}
div {
box-sizing: border-box;
line-height: 34px;
}
.flex {
display: flex;
}
.flex-1 {
flex: 1;
}
.flex-col {
flex-direction: column;
}
.w-120 {
width: 120px;
}
.w-60 {
width: 60px;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.padding-5 {
padding: 0 10px;
}
.bd {
border: 1px solid #ccc;
}
&--rotate {
transform: rotate(90deg);
}
}
</style>
For printing purposes, we want to print only the custom component content. We achieve this through media queries to hide unnecessary page elements:
Note: This is a temporary solution. @吴敬 will provide a more robust approach.
<style lang="less">
@media print {
body {
height: auto!important;
}
#crm-layout {
display: none;
}
#app-portal {
display: none;
}
.detail-dialog-v3 {
display: none;
}
.el-dialog__header {
display: none!important;
}
.f-qx-container {
display: none;
}
.fx-dialog {
margin-top: 0!important;
}
.no-print {
display: none!important;
}
}
</style>
# Complete Final Code
<template>
<div class="cus-demo" v-if="dData">
<h1 class="text-center">Fund Utilization Approval Form</h1>
<div class="flex bd">
<div class="flex flex-1 flex-col">
<div class="flex">
<div class="w-120 text-center bd">Payee</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_uhcib__c }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Bank Account</div>
<div class="flex-1">
<div class="flex">
<div class="w-60 text-center bd">Bank</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_utckZ__c }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Account</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_oQgRl__c }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Address</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_v82bd__c }}}</div>
</div>
</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">Payment Amount</div>
<div class="flex-1">
<div class="flex">
<div class="w-60 text-center bd">In Words</div>
<div class="flex-1 padding-5 bd">{{{ digitUppercase(dData.field_8P18m__c) }}}</div>
</div>
<div class="flex">
<div class="w-60 text-center bd">In Numbers</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_8P18m__c }}}</div>
</div>
</div>
</div>
<div class="flex">
<div class="w-120 text-center bd">Payment Method</div>
<div class="flex-1 padding-5 bd">{{{ dData.field_fJY1p__c }}}</div>
</div>
<div class="flex">
<div class="flex-1 bd">
<div class="text-center">Payment Reason</div>
<div class="text-center padding-5">{{{ dData.field_fwjy1__c }}}</div>
</div>
<div class="flex-1 bd">
<div class="text-center">Department Opinion</div>
<div class="text-center padding-5">{{{ dData.field_36nKK__c }}}</div>
</div>
<div class="flex-1 bd">
<div class="text-center">Project Manager Opinion</div>
<div class="text-center padding-5">{{{ dData.field_J3N26__c }}}</div>
</div>
</div>
</div>
</div>
<div class="text-right no-print">Click the browser's print button to print directly (this text won't be printed)</div>
</div>
</template>
<script>
export default {
props: ['userData', 'data'],
data() {
return {
dData: null
}
},
created() {
this.getData();
},
mounted() {
this.$emit('action', {type: 'resize'});
},
methods: {
//Convert numeric amount to Chinese characters
digitUppercase(n) {
var fraction = ['角', '分'];
var digit = [
'零', '壹', '贰', '叁', '肆',
'伍', '陆', '柒', '捌', '玖'
];
var unit = [
['元', '万', '亿'],
['', '拾', '佰', '仟']
];
var head = n < 0 ? '欠' : '';
n = Math.abs(n);
var s = '';
for (var i = 0; i < fraction.length; i++) {
s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
}
s = s || '整';
n = Math.floor(n);
for (var i = 0; i < unit[0].length && n > 0; i++) {
var p = '';
for (var j = 0; j < unit[1].length && n > 0; j++) {
p = digit[n % 10] + unit[1][j] + p;
n = Math.floor(n / 10);
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
}
return head + s.replace(/(零.)*零元/, '元')
.replace(/(零.)+/g, '零')
.replace(/^整$/, '零元整');
},
getData() {
const userData = this.userData;
//Get description then parse data
FxUI.objectApi.fetch_describe(userData.object_describe_api_name).then((data) => {
const {
fields
} = data.objectDescribe;
let result = {};
Object.keys(fields).forEach(fApiName => {
result[fApiName] = (FxUI.objectApi.format_field_value || PAAS.format_field_value)(fields[fApiName], userData[fApiName], userData);
})
this.dData = result;
this.$nextTick(() => {
this.$emit('action', {type: 'resize'});
})
})
}
}
}
</script>
<style lang="less">
.cus-demo {
.demo {
max-width: 1200px;
}
h1 {
font-size: 28px;
font-weight: bold;
margin-bottom: