123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- <template>
- <div class="page adffcacjc">
- <div class="content">
- <div class="c_pdf">
- <div id="pdf-content" style="width: 630px;" ref="pdfRef">
- <pdf :reportData="reportData" @optionsMaps="optionsMaps" v-if="isTeam"></pdf>
- <pdf-user :reportData="reportData" @optionsMaps="optionsMaps" v-else></pdf-user>
- </div>
- </div>
- <div class="c_footer adfac">
- <el-button type="defalut" @click="cancel">取消</el-button>
- <el-button type="primary" style="margin-left: 20px;" @click="exportToPDF">生成PDF</el-button>
- </div>
- </div>
- <div class="cus_dialog adffcacjc" v-if="reportShow" @click.prevent="closeReportAlert">
- <div class="cus_dialog_content adffcac">
- <div class="cdc_title">生成PDF</div>
- <i class="el-icon-close cdc_close" style="font-size: 20px;color: #393939;" @click.stop="closeReportAlert"></i>
- <img src="@/assets/images/agent/report.gif">
- <p>{{ reportData.enterpriseName }} - {{ reportData.teamName }}</p>
- <p>pdf正在后台生成中,预计需要时间<span>3-5分钟</span>,在此期间可进行其他操作,成功后将在上方出现提示。</p>
- <p>生成后可点击对应报告操作中的<span>导出报告</span>进行查看</p>
- <div class="zt_btn" @click.stop="closeReportAlert">我知道了</div>
- </div>
- </div>
- </div>
- </template>
- <script lang="ts" setup name="">
- import * as echarts from "echarts";
- import { exportPDF } from './exportPDF';
- import pdf from './pdf.vue'
- import pdfUser from './pdfUser.vue'
- const props = defineProps({
- isTeam: {
- type: Boolean,
- default: true
- },
- reportData:{
- type: Object,
- default: () => {}
- },
- reportId:{
- type: String,
- default: ''
- },
- reportName:{
- type: String,
- default: ''
- }
- })
- import _this from '@/main.js'
- import { ref, getCurrentInstance, onMounted, nextTick, inject } from 'vue'
- const { proxy } = getCurrentInstance();
- const reportData = ref(props.reportData);
- const reportId = ref(props.reportId);
- const reportName = ref(props.reportName);
- const reportShow = ref(false);
- const pdfRef = ref(null);
- const echartsOptions = ref(new Map())
- const isTeam = ref(props.isTeam)
- import useCommonStore from "@/store_v3/modules/common";
- const emit = defineEmits(['cancel','refreshReportList']);
- import { updateReportPdfUrl } from '@/api/agent/index.js';
- const refreshReportTeamList = inject('refreshTeamList')
- const refreshReportPersonList = inject('refreshPersonList')
- const cancel = () => {
- emit('cancel');
- }
- const exportToPDF = async () => {
- const clonedEl = cloneEl();
- await reinitClonedCharts(clonedEl);
- try {
- reportShow.value = true;
- // 滚动到顶部确保完整渲染
- window.scrollTo(0, 0);
- // 避免异步渲染问题
- await new Promise(resolve => setTimeout(resolve, 500));
- // const res = await exportPDF('pdf-content', reportName.value+'.pdf');
- const res = await exportPDF(clonedEl, reportName.value+'.pdf');
- if(res.data && res.data.code === 0) {
- updateReportPdfUrl({id:reportId.value, fileUrl:res.data.data}).then(async resu => {
- if(resu.code!==0) return proxy.$message.error(res.msg)
- proxy.$message.success('生成成功!');
- reportShow.value = false;
- if(isTeam.value){
- refreshReportTeamList(reportData.value.relationId,useCommonStore().$state.teamIndex)
- }else{
- refreshReportPersonList(reportData.value.relationId,useCommonStore().$state.personIndex)
- }
- nextTick(()=>{
- cancel();
- })
- })
- }
- } catch (error) {
- proxy.$message.error('报告生成失败!请稍后再试!');
- reportShow.value = false;
- cancel();
- }
- };
- const cloneEl = () => {
- const targetEl = proxy.$refs.pdfRef; // 通过 ref 获取
- // 2. 克隆元素并插入到 body 末尾(不触发 Vue 更新)
- const clonedEl = targetEl.cloneNode(true);
- clonedEl.style.position = "fixed";
- clonedEl.style.left = "-9999px"; // 移出屏幕外
- clonedEl.style.visibility = "visible"; // 强制显示
- clonedEl.style.display = "block"; // 覆盖原隐藏样式
- document.body.appendChild(clonedEl);
- return clonedEl
- }
- const optionsMaps = (optionsMap) => {
- echartsOptions.value = optionsMap;
- }
- const reinitClonedCharts = async (clonedEl) => {
- // 1. 查找所有图表容器(通过 class 或 data-* 标识)
- const chartContainers = clonedEl.querySelectorAll('.pdfEchart');
- // 2. 并行重新渲染
- await Promise.all(
- Array.from(chartContainers).map(async container => {
- container.id = container.id+'_copy';
- const chartId = container.id;
- const originalOptions = echartsOptions.value.get(chartId);
-
- const existingChart = echarts.getInstanceByDom(container);
- if (existingChart) existingChart.dispose();
- // 5. 重新初始化 ECharts
- const chart = echarts.init(container);
- chart.setOption(originalOptions);
- if(container.id=='zttdznRef_copy'&&echartsOptions.value.get('zttdznRef_copy2')){
- chart.setOption(echartsOptions.value.get('zttdznRef_copy2'));
- }
-
- await new Promise(resolve => {
- chart.on('finished', resolve); // ECharts 3.0+ 支持
- setTimeout(resolve, 500); // 双保险
- });
- })
- );
- }
- const closeReportAlert = () => {
- reportShow.value = false;
- nextTick(()=>{
- cancel();
- })
- }
-
- onMounted(() => {
-
- });
- </script>
- <style scoped lang="scss">
- .page{
- width: 100%;
- height: 100vh;
- position: fixed;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- z-index: 99999;
- background: rgba($color: #000000, $alpha: .4);
- .content{
- width: 685px;
- height: calc(100% - 100px);
- background: #FFFFFF;
- padding: 0 20px;
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- .c_pdf{
- width: 645px;
- flex: 1;
- padding-bottom: 20px;
- box-sizing: border-box;
- overflow-y: auto;
- #pdf-content {
- width: 100%;
- background-color: white;
- word-break: break-all;
- .cd_box{
- width: 100%;
- height: 891px;
- font-size: 30px;
- font-weight: bold;
- }
- }
- }
- .c_footer{
- justify-content: flex-end;
- padding: 20px 0;
- border-top: 1px solid #E5E7EB;
- }
- }
- }
- .cus_dialog_content{
- width: 500px;
- background: linear-gradient( 180deg, #FDF2FB 0%, #FFFFFF 100%);
- border-radius: 6px;
- padding: 36px 68px;
- box-sizing: border-box;
- position: relative;
- .cdc_title{
- font-family: PingFang-SC, PingFang-SC;
- font-weight: bold;
- font-size: 16px;
- color: #252525;
- line-height: 16px;
- text-align: center;
- }
- .cdc_close{
- position: absolute;
- right: 30px;
- top: 36px;
- cursor: pointer;
- }
- img{
- width: 100%;
- }
- p{
- font-family: PingFangSC, PingFang SC;
- font-weight: 400;
- font-size: 14px;
- color: #393939;
- line-height: 24px;
- text-align: center;
- span{
- color: #F31616;
- }
- }
- .zt_btn{
- margin-top: 40px;
- }
- }
- </style>
|