<template>
<el-dialog v-model="visible" title="季度诊断" center width="425px" top="0" class="dialog-header-blue-bg">
<canvas :ref="(ref) => ref && canvasRefs(ref)" width="375" height="780" style="margin: auto;"></canvas>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="handleSave">
保存
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue'
import request from "@/utils/request"
import { userHandleRequest } from '@/utils/hooks/userHandleRequest'
// 控制dialog显示隐藏
const visible = ref(false)
const basicData = ref({}) // 基础数据
// 获取canvas实例
let canvasRefs
const canvasRef = ref()
const canvasRefPromise = new Promise((res) => (canvasRefs = res));
(async function () {
canvasRef.value = await canvasRefPromise
draw(canvasRef.value)
})()
// x轴开始位置
const MARGIN_LEFT = 52;
// 最大宽度
const MAX_WIDTH = 280
// 行高
const LINE_HEIGHT = 20
// 开始绘制
const draw = (canvasRef) => {
let ctx = canvasRef?.getContext('2d');
if (!ctx) return
const image = new Image();
image.src = '/src/assets/image/1.png';
image.onload = () => {
ctx.drawImage(image, 0, 0, canvasRef.width, canvasRef.height);
//修改字体
ctx.font = 'bold 22px Arial';
ctx.fillStyle = 'rgb(170,123,68)'
//绘制文本
ctx.fillText(`2022年第三季度`, 108, 105);
//修改字体
ctx.font = 'bold 15px Arial';
ctx.fillStyle = 'rgb(51,51,51)'
//绘制文本
ctx.fillText('您好!', MARGIN_LEFT, 135);
getWarpText(ctx, `公司2022年第三季度的财务已经完成,贵司的财务和经营成果如下:`, MARGIN_LEFT, 160, MAX_WIDTH, 24)
//修改字体
ctx.font = '13px Arial';
ctx.fillStyle = 'rgb(51,51,51)'
const arrText = [
`1、资产总额:1000元,其中预付账款和其他应收款共计1000元,占资产总额1000%。`,
`2、负债总额:1000元,其中预收账款和其他应付款共计1000元,占负债总额1000%。`,
`3、所有者权益总额:1000元。`,
`4、收入总额:1000元。`,
`5、成本费用总额:1000元。`,
`6、利润总额:1000元。`,
`7、纳税总额:1000元,其中企业所得税1000元,增值税1000元,附加税费1000元,其他税额1000元。`
]
getWarpTextMulti(ctx, arrText, 220)
//修改字体
ctx.font = 'bold 15px Arial';
ctx.fillStyle = 'rgb(51,51,51)'
//绘制文本
getWarpText(ctx, `以上是贵公司季度财务报表情况,您有任何问题可以随时咨询您的会。`, MARGIN_LEFT, 624, MAX_WIDTH, 24)
};
}
/**
* 计算多句换行文字
* @param: canvas canvas上下文对象
* @param: arrText 渲染文本数组
* @param y 渲染第一行y轴位置
* @param gap 文字之间的上下间隔
*/
function getWarpTextMulti(canvas, arrText, y, gap = 10) {
for (let index = 0; index < arrText.length; index++) {
const text = arrText[index];
let lineArr = getWarpText(canvas, text, MARGIN_LEFT, y, MAX_WIDTH, LINE_HEIGHT)
y += LINE_HEIGHT * lineArr.length + gap
}
}
/**
* 计算换行文字
* @param canvas canvas上下文对象
* @param text 渲染文本
* @param x 渲染x轴位置
* @param y 渲染第一行y轴位置
* @param maxWidth 最大宽度
* @param lineHeight 行高
* @param maxLine 最大行数 超出隐藏并显示省略号 不传入则代表不限制
*/
function getWarpText(canvas, text, x, y, maxWidth, lineHeight, maxLine) {
// 对入参的类型进行检测
if (typeof text != 'string' || typeof x != 'number' || typeof y != 'number' || typeof lineHeight != 'number') {
throw new Error("参数传入出错")
}
//如果最大宽度未定义 默认为canvas宽度
if (typeof maxWidth == 'undefined') {
maxWidth = (canvas && canvas.width);
}
if (typeof lineHeight == 'undefined') {
lineHeight = (canvas.canvas && parseInt(window.getComputedStyle(canvas.canvas).lineHeight))
|| parseInt(window.getComputedStyle(document.body).lineHeight)
}
let arrText = text.split('');
let line = '';
let lines = [];
let lastLine = ""
let ellipsis = canvas.measureText("...");
let ellipsisWidth = ellipsis.width;
for (let n = 0; n < arrText.length; n++) {
//每个循环累加字符
let testLine = line + arrText[n];
//检测累加字符 获取累加字符的高度和宽度
let metrics = canvas.measureText(testLine);
let testWidth = metrics.width;
let lineWidth = canvas.measureText(line).width;
// 如果当前添加行是最后一行 则替换最后一个字符为"..." 判断长度是否需要删去最后一个字符
if (maxLine && maxLine - 1 === lines.length && ((lineWidth + ellipsisWidth) > maxWidth)) {
line = line.slice(0, line.length - 1) + "...";
testWidth = lineWidth + ellipsisWidth;
}
//如果累加字符的宽度大于定义的绘制文本最大宽度 则绘制累加字符的文本 并且设置换行间距再次进行绘制
if (testWidth > maxWidth && n > 0) {
lastLine = line;
lines.push({
text: line,
x: x,
y: y
})
if (maxLine && maxLine <= lines.length) {
break
}
line = arrText[n];
y += lineHeight;
} else {
line = testLine;
}
}
if (lastLine !== line) {
lines.push({
text: line,
x: x,
y: y
})
}
for (let i = 0; i < lines.length; i++) {
const item = lines[i];
canvas.fillText(item.text, item.x, item.y);
}
return lines;
}
// 保存为图片
const handleSave = () => {
// 获取图像数据
const imageData = canvasRef.value.toDataURL();
// 将图像数据保存到本地文件
const link = document.createElement('a');
link.href = imageData;
link.download = `季度诊断报告.png`;
link.click();
}
// 打开dialog 并请求数据
const open = async (e) => {
visible.value = true
if(canvasRef.value){
draw(canvasRef.value)
}
} catch (error) {}
}
defineExpose({
open
})
</script>