Przeglądaj źródła

pdf预览页面优化

htc 2 tygodni temu
rodzic
commit
2f861163b5

+ 15 - 24
src/components/reportPdf/exportPDF.js

@@ -11,8 +11,6 @@ export const exportPDF = async (elementId, fileName = 'document.pdf') => {
   // 获取元素原始尺寸
   const originalWidth = element.scrollWidth;
   const originalHeight = element.scrollHeight;
-  console.log(originalWidth,'originalWidth');
-  console.log(originalHeight,'originalHeight');
   
   // 设置PDF参数
   const PDF_WIDTH = 210; // A4纸宽(单位:mm)
@@ -23,14 +21,11 @@ export const exportPDF = async (elementId, fileName = 'document.pdf') => {
   
   // 计算缩放比例
   const scale = PDF_WIDTH / originalWidth;
-  console.log(scale,'scale');
   const canvasWidth = originalWidth;
   const canvasHeight = PDF_HEIGHT / scale;
-  console.log(canvasHeight,'canvasHeight');
   
   // 计算总页数
   const pageCount = Math.ceil(originalHeight / canvasHeight);
-  console.log(pageCount,'pageCount');
   
   // 循环渲染每一页
   for (let i = 0; i < pageCount; i++) {
@@ -63,25 +58,21 @@ export const exportPDF = async (elementId, fileName = 'document.pdf') => {
     );
     }
 
-    const pdfBlob = pdf.output('blob');
-    const formData = new FormData();
-    formData.append('file', pdfBlob, 'report.pdf'); // 参数名按接口要求
-    // 3. 调用上传接口
-    const response = await axios.post(
-        `${window.SITE_CONFIG["apiURL"]}/sys/oss/uploadFile`,
-        formData,
-        {
-            headers: {
-                'Content-Type': 'multipart/form-data',
-                'token': Cookies.get('token') || ''
-            }
-        }
-    );
-    console.log(response,'response');
-    if(response.data && response.data.code === 0) {
-        console.log(response.data.data,'response.data.data');
-    }
+    // const pdfBlob = pdf.output('blob');
+    // const formData = new FormData();
+    // formData.append('file', pdfBlob, 'report.pdf');
+    // const response = await axios.post(
+    //     `${window.SITE_CONFIG["apiURL"]}/sys/oss/uploadFile`,
+    //     formData,
+    //     {
+    //         headers: {
+    //             'Content-Type': 'multipart/form-data',
+    //             'token': Cookies.get('token') || ''
+    //         }
+    //     }
+    // );
+    // return response
 
   // 保存PDF
-//   pdf.save(fileName);
+  pdf.save(fileName);
 };

+ 18 - 5
src/components/reportPdf/index.vue

@@ -3,7 +3,7 @@
         <div class="content">
             <div class="c_pdf">
                 <div id="pdf-content">
-                    <div class="cd_box adffcacjc" v-for="(item,index) in 8" :key="index">{{ item }}</div>
+                    <pdf></pdf>
                 </div>
             </div>
             <div class="c_footer adfac">
@@ -16,6 +16,7 @@
 
 <script setup name="">
     import { exportPDF } from './exportPDF';
+    import pdf from './pdf.vue'
     const props = defineProps({
       show:{
         type: Boolean,
@@ -36,14 +37,26 @@
 
     const exportToPDF = async () => {
         try {
+            const loading = proxy.$loading({
+                lock: true,
+                text: '生成pdf中...',
+                spinner: 'el-icon-loading',
+                background: 'rgba(0, 0, 0, 0.7)'
+            });
             // 滚动到顶部确保完整渲染
             window.scrollTo(0, 0);
             // 避免异步渲染问题
             await new Promise(resolve => setTimeout(resolve, 500));
-            await exportPDF('pdf-content', '员工信息表.pdf');
+            const res = await exportPDF('pdf-content', '员工信息表.pdf');
+            console.log(res,'res');
+            if(res.data && res.data.code === 0) {
+                console.log(res.data.data,'res.data.data');
+                loading.close();
+                proxy.$message.success('生成成功!');
+                cancel();
+            }
         } catch (error) {
             console.error('导出失败:', error);
-            alert('导出失败,请重试');
         }
     };
 
@@ -70,7 +83,7 @@
             height: calc(100% - 100px);
             background: #FFFFFF;
             border-radius: 10px;
-            padding: 20px;
+            padding: 0 20px;
             box-sizing: border-box;
             display: flex;
             flex-direction: column;
@@ -96,7 +109,7 @@
 
             .c_footer{
                 justify-content: flex-end;
-                padding-top: 20px;
+                padding: 20px 0;
                 border-top: 1px solid #E5E7EB;
             }
         }

+ 124 - 0
src/components/reportPdf/pdf.scss

@@ -0,0 +1,124 @@
+.cd_box{
+    padding: 20px 0 30px;
+    box-sizing: border-box;
+    .cb_db{
+        .cb_db_l{
+            width: 120px;
+            font-size: 14px;
+            color: #000;
+        }
+        .cb_db_r{
+            width: calc(100% - 120px);
+            font-size: 14px;
+            color: #000;
+            text-align: center;
+        }
+    }
+
+    .mddj_title{
+        font-size: 28px;
+        color: #000000;
+    }
+    .mddj_tip{
+        font-size: 12px;
+        margin-top: 30px;
+    }
+    .mddj_top{
+        justify-content: space-between;
+        margin-top: 50px;
+        .tt_pre{
+            width: calc(100% / 3 - 10px);
+            .ttp_l{
+                width: 30px;
+                height: 80px;
+                &.tl1{
+                    background: #EBA1A7;
+                }
+                &.tl2{
+                    background: #FBD999;
+                }
+                &.tl3{
+                    background: #D7E5A5;
+                }
+            }
+            .ttp_r{
+                width: calc(100% - 30px);
+                padding-left: 10px;
+                box-sizing: border-box;
+                font-size: 12px;
+                line-height: 20px;
+            }
+        }
+    }
+    .mddj_table{
+        margin-top: 20px;
+        border-radius: 0 20px 0 20px;
+        overflow: auto;
+        .mt_l{
+            padding-left: 20px;
+            flex: 1;
+            box-sizing: border-box;
+        }
+        .mt_r{
+            .mr_pre{
+                font-size: 14px;
+                color: #FFFFFF;
+                width: 50px;
+                height: 200px;
+                padding: 10px 20px;
+            }
+        }
+        .mt_top{
+            background: #007EC1;
+            .mt_l{
+                font-size: 26px;
+                color: #FFFFFF;
+            }
+        }
+        .mt_list{
+            border: 3px solid #007EC1;
+            border-radius: 0 0 0 20px;
+            .ml_pre{
+                border-bottom: 1px solid #E5E7EB;
+                &:last-child{
+                    border: none;
+                    border-radius: 0 0 0 20px;
+                }
+                &:nth-child(odd){
+                    background: #DAECF6;
+                }
+                &:nth-child(even){
+                    background: #FFFFFF;
+                }
+
+                .mt_l{
+                    padding: 20px 0 20px 20px;
+                    color: #777;
+                }
+
+                .mp_pre{
+                    width: 50px;
+                    font-size: 14px;
+                    font-weight: bold;
+                    padding: 20px 0;
+                    color: #000;
+                    &.mp1{
+                        background: #EBA1A7;
+                    }
+                    &.mp2{
+                        background: #FBD999;
+                    }
+                    &.mp3{
+                        background: #D7E5A5; 
+                    }
+                }
+            }
+        }
+    }
+
+    .pjgx_title{
+        font-size: 32px;
+        color: #F09216;
+        margin-top: 20px;
+    }
+}

+ 313 - 0
src/components/reportPdf/pdf.vue

@@ -0,0 +1,313 @@
+<template>
+    <div>
+        <!-- 封面 -->
+        <div class="cd_box">
+            <div class="cb_db adf">
+                <div class="cb_db_l">{{ datetime }}</div>
+                <div class="cb_db_r">欢迎使用CCMI的PERILL</div>
+            </div>
+        </div>
+        <!-- 团队成员评分目的和动机 -->
+        <div class="cd_box">
+            <div class="mddj_title">团队成员评分目的和动机</div>
+            <div class="mddj_tip">下表显示了每个团队成员对每个问题的得分,以及最终的总分和方差。</div>
+            <div class="mddj_top adf">
+                <div class="tt_pre adf">
+                    <div class="ttp_l tl1"></div>
+                    <div class="ttp_r">在个体和总分下,这表示功能得分较低。在方差下,这表示个体得分之间的差异较大。</div>
+                </div>
+                <div class="tt_pre adf">
+                    <div class="ttp_l tl2"></div>
+                    <div class="ttp_r">在个体和总分下,这表明一个中等功能的分数。在方差下,这表明个体分数之间的中等方差。</div>
+                </div>
+                <div class="tt_pre adf">
+                    <div class="ttp_l tl3"></div>
+                    <div class="ttp_r">在个体和总分下,这表示高功能得分。在方差下,这表示个体得分之间的低方差。</div>
+                </div>
+            </div>
+            <div class="mddj_table">
+                <div class="mt_top adf">
+                    <div class="mt_l adfac">问题</div>
+                    <div class="mt_r adf">
+                        <div class="mr_pre">玛丽</div>
+                        <div class="mr_pre">千斤顶</div>
+                        <div class="mr_pre">汤姆</div>
+                        <div class="mr_pre">阿尔法</div>
+                        <div class="mr_pre">总评分</div>
+                        <div class="mr_pre">Variance</div>
+                    </div>
+                </div>
+                <div class="mt_list">
+                    <div class="ml_pre adf" v-for="(item,index) in mddjTableDatas.slice(0,7)" :key="index">
+                        <div class="mt_l adfac">{{ item.title }}</div>
+                        <div class="mt_r adfac">
+                            <div class="mp_pre adffcacjc" :class="{'mp1':pre.status==1,'mp2':pre.status==2,'mp3':pre.status==3}" v-for="(pre,idx) in item.datas" :key="idx">{{ pre.score }}</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="cd_box" v-if="mddjTableDatas.length>7">
+            <div class="mddj_table" style="margin-top: 0;">
+                <div class="mt_top adf">
+                    <div class="mt_l adfac">问题</div>
+                    <div class="mt_r adf">
+                        <div class="mr_pre">玛丽</div>
+                        <div class="mr_pre">千斤顶</div>
+                        <div class="mr_pre">汤姆</div>
+                        <div class="mr_pre">阿尔法</div>
+                        <div class="mr_pre">总评分</div>
+                        <div class="mr_pre">Variance</div>
+                    </div>
+                </div>
+                <div class="mt_list">
+                    <div class="ml_pre adf" v-for="(item,index) in mddjTableDatas.slice(7,mddjTableDatas.length)" :key="index">
+                        <div class="mt_l adfac">{{ item.title }}</div>
+                        <div class="mt_r adfac">
+                            <div class="mp_pre adffcacjc" :class="{'mp1':pre.status==1,'mp2':pre.status==2,'mp3':pre.status==3}" v-for="(pre,idx) in item.datas" :key="idx">{{ pre.score }}</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!-- 绩效评级关系 -->
+        <div class="cd_box">
+            <div class="mddj_title">绩效评级关系</div>
+            <div class="pjgx_title">按主题列出的功能评级</div>
+            <div class="pjgx_chart">
+                <div ref="pjgxRef" style="width: 100%; height: 250px;margin-top: 20px;"></div>
+            </div>
+            <div class="pjgx_title">高/低性能指标</div>
+
+        </div>
+    </div>
+</template>
+
+<script setup name="">
+    import * as echarts from "echarts";
+    import { ref, getCurrentInstance, onMounted } from 'vue'
+    const { proxy } = getCurrentInstance();
+    const pjgxRef = ref(null);
+    const datetime = proxy.parseTime(new Date(), '{yy}-{mm}-{dd} {hh}:{ii}');
+    
+    const mddjTableDatas = ref([
+        {
+            title: '我们可以集体明确地表达我们的共同目标',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 16, status:2 },
+                { name: '汤姆', score: 16, status:2 },
+                { name: '阿尔法', score: 20, status:2 },
+                { name: '总评分', score: 13, status:1 },
+                { name: 'Variance', score: 19, status:2 }
+            ]
+        },
+        {
+            title: '我们对团队在这里要做的事情高度一致',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 9, status:1 },
+                { name: '汤姆', score: 12, status:1 },
+                { name: '阿尔法', score: 16, status:2 },
+                { name: '总评分', score: 10, status:1 },
+                { name: 'Variance', score: 15, status:2 }
+            ]
+        },
+        {
+            title: '我们善于将团队优先事项置于个人优先事项之前',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 12, status:1 },
+                { name: '汤姆', score: 36, status:3 },
+                { name: '阿尔法', score: 18, status:2 },
+                { name: '总评分', score: 17, status:2 },
+                { name: 'Variance', score: 35, status:1 }
+            ]
+        },
+        {
+            title: '我们可以集体明确地表达我们的共同目标',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 16, status:2 },
+                { name: '汤姆', score: 16, status:2 },
+                { name: '阿尔法', score: 20, status:2 },
+                { name: '总评分', score: 13, status:1 },
+                { name: 'Variance', score: 19, status:2 }
+            ]
+        },
+        {
+            title: '我们对团队在这里要做的事情高度一致',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 9, status:1 },
+                { name: '汤姆', score: 12, status:1 },
+                { name: '阿尔法', score: 16, status:2 },
+                { name: '总评分', score: 10, status:1 },
+                { name: 'Variance', score: 15, status:2 }
+            ]
+        },
+        {
+            title: '我们善于将团队优先事项置于个人优先事项之前',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 12, status:1 },
+                { name: '汤姆', score: 36, status:3 },
+                { name: '阿尔法', score: 18, status:2 },
+                { name: '总评分', score: 17, status:2 },
+                { name: 'Variance', score: 35, status:1 }
+            ]
+        },
+        {
+            title: '我们可以集体明确地表达我们的共同目标',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 16, status:2 },
+                { name: '汤姆', score: 16, status:2 },
+                { name: '阿尔法', score: 20, status:2 },
+                { name: '总评分', score: 13, status:1 },
+                { name: 'Variance', score: 19, status:2 }
+            ]
+        },
+        {
+            title: '我们对团队在这里要做的事情高度一致',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 9, status:1 },
+                { name: '汤姆', score: 12, status:1 },
+                { name: '阿尔法', score: 16, status:2 },
+                { name: '总评分', score: 10, status:1 },
+                { name: 'Variance', score: 15, status:2 }
+            ]
+        },
+        {
+            title: '我们善于将团队优先事项置于个人优先事项之前',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 12, status:1 },
+                { name: '汤姆', score: 36, status:3 },
+                { name: '阿尔法', score: 18, status:2 },
+                { name: '总评分', score: 17, status:2 },
+                { name: 'Variance', score: 35, status:1 }
+            ]
+        },
+        {
+            title: '我们可以集体明确地表达我们的共同目标',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 16, status:2 },
+                { name: '汤姆', score: 16, status:2 },
+                { name: '阿尔法', score: 20, status:2 },
+                { name: '总评分', score: 13, status:1 },
+                { name: 'Variance', score: 19, status:2 }
+            ]
+        },
+        {
+            title: '我们对团队在这里要做的事情高度一致',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 9, status:1 },
+                { name: '汤姆', score: 12, status:1 },
+                { name: '阿尔法', score: 16, status:2 },
+                { name: '总评分', score: 10, status:1 },
+                { name: 'Variance', score: 15, status:2 }
+            ]
+        },
+        {
+            title: '我们善于将团队优先事项置于个人优先事项之前',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 12, status:1 },
+                { name: '汤姆', score: 36, status:3 },
+                { name: '阿尔法', score: 18, status:2 },
+                { name: '总评分', score: 17, status:2 },
+                { name: 'Variance', score: 35, status:1 }
+            ]
+        },
+        {
+            title: '我们可以集体明确地表达我们的共同目标',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 16, status:2 },
+                { name: '汤姆', score: 16, status:2 },
+                { name: '阿尔法', score: 20, status:2 },
+                { name: '总评分', score: 13, status:1 },
+                { name: 'Variance', score: 19, status:2 }
+            ]
+        },
+        {
+            title: '我们对团队在这里要做的事情高度一致',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 9, status:1 },
+                { name: '汤姆', score: 12, status:1 },
+                { name: '阿尔法', score: 16, status:2 },
+                { name: '总评分', score: 10, status:1 },
+                { name: 'Variance', score: 15, status:2 }
+            ]
+        },
+        {
+            title: '我们善于将团队优先事项置于个人优先事项之前',
+            datas: [
+                { name: '玛丽', score: 1, status:1 },
+                { name: '千斤顶', score: 12, status:1 },
+                { name: '汤姆', score: 36, status:3 },
+                { name: '阿尔法', score: 18, status:2 },
+                { name: '总评分', score: 17, status:2 },
+                { name: 'Variance', score: 35, status:1 }
+            ]
+        },
+    ])
+
+    const initPlgxChart = () => {
+        let myChart = echarts.init(pjgxRef.value);
+        let option = {
+            color:['#F9CE7F'],
+            legend: {
+                data: ['Allocated Budget']
+            },
+            radar: {
+                indicator: [
+                    { name: 'Sales', max: 6500,
+                        axisLabel : {
+                            show: true
+                        }
+                     },
+                    { name: 'Administration', max: 16000 },
+                    { name: 'Information Technology', max: 30000 },
+                    { name: 'Customer Support', max: 38000 },
+                    { name: 'Development', max: 52000 },
+                    { name: 'Marketing', max: 25000 }
+                ],
+                radius:'55%',
+            },
+            series: [
+                {
+                name: 'Budget vs spending',
+                type: 'radar',
+                areaStyle: {},
+                data: [
+                    {
+                    value: [4200, 3000, 20000, 35000, 50000, 18000],
+                    name: 'Allocated Budget'
+                    }
+                ]
+                }
+            ]
+        }
+        myChart.setOption(option)
+    }
+
+    onMounted(() => {
+        initPlgxChart();
+    })
+</script>
+
+<style scoped lang="scss">
+    @import url(./pdf.scss);
+
+    .cd_box{
+        width: 100%;
+        height: 891px;
+        color: #A1A1A1;
+    }
+</style>