Junjie
2 天以前 c3aa006e03eeb0817833cde93ed963c893478792
# Agent数据分析V3.0.1.7
1个文件已修改
120 ■■■■■ 已修改文件
src/main/webapp/views/ai/data_analysis.html 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/ai/data_analysis.html
@@ -110,7 +110,6 @@
      margin-top: 2px;
    }
    .report-summary {
      margin-top: 12px;
      padding: 14px;
      border-radius: 12px;
      border: 1px solid #e4ebf2;
@@ -121,16 +120,27 @@
      font-size: 15px;
      color: #223046;
    }
    .report-summary pre {
      white-space: pre-wrap;
      word-break: break-word;
      font-size: 13px;
      line-height: 1.6;
    .markdown-body {
      font-size: 15px;
      line-height: 1.8;
      color: #333;
      margin: 0;
      max-height: 500px;
      max-height: 600px;
      overflow-y: auto;
    }
    .markdown-body h1 { font-size: 22px; margin: 20px 0 10px; border-bottom: 1px solid #eee; padding-bottom: 6px; }
    .markdown-body h2 { font-size: 19px; margin: 18px 0 8px; color: #223046; }
    .markdown-body h3 { font-size: 17px; margin: 14px 0 6px; }
    .markdown-body p { margin: 8px 0; }
    .markdown-body ul, .markdown-body ol { padding-left: 24px; margin: 8px 0; }
    .markdown-body li { margin: 4px 0; }
    .markdown-body code { background: #f0f2f5; padding: 2px 6px; border-radius: 3px; font-size: 14px; }
    .markdown-body pre { background: #282c34; color: #abb2bf; padding: 14px; border-radius: 6px; overflow-x: auto; margin: 10px 0; }
    .markdown-body pre code { background: none; color: inherit; padding: 0; font-size: 14px; }
    .markdown-body table { border-collapse: collapse; margin: 10px 0; width: 100%; }
    .markdown-body th, .markdown-body td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; font-size: 14px; }
    .markdown-body th { background: #f5f7fa; font-weight: 600; }
    .markdown-body blockquote { border-left: 3px solid #409eff; padding-left: 12px; color: #666; margin: 10px 0; }
    .markdown-body strong { color: #223046; }
  </style>
</head>
<body>
@@ -275,12 +285,15 @@
            {{ periodLabel(selectedReport.periodType) }} · {{ formatTime(selectedReport.createTime) }}
          </div>
        </div>
        <el-button size="mini" @click="selectedReport=null">关闭</el-button>
        <div>
          <el-button size="mini" type="primary" icon="el-icon-download" :loading="pdfLoading" @click="downloadPdf">下载 PDF</el-button>
          <el-button size="mini" @click="selectedReport=null">关闭</el-button>
        </div>
      </div>
      <div class="panel-body">
        <div class="report-summary">
        <div class="report-summary" id="reportContent">
          <h3>分析报告</h3>
          <pre>{{ selectedReport.summary || '暂无报告内容' }}</pre>
          <div class="markdown-body" v-html="renderedSummary"></div>
        </div>
      </div>
    </div>
@@ -290,6 +303,9 @@
<script type="text/javascript" src="../../static/vue/js/vue.min.js"></script>
<script type="text/javascript" src="../../static/vue/element/element.js"></script>
<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
<script type="text/javascript" src="../../static/js/marked.min.js"></script>
<script type="text/javascript" src="../../static/lib/pdf/html2canvas.min.js"></script>
<script type="text/javascript" src="../../static/lib/pdf/jspdf.umd.min.js"></script>
<script>
  new Vue({
    el: '#app',
@@ -300,6 +316,7 @@
        enabled: false,
        config: {},
        enabledLoading: false,
        pdfLoading: false,
        triggerLoading: false,
        triggerPeriod: '',
        reportsLoading: false,
@@ -314,6 +331,15 @@
        if (cron === '0 0 2 * * ?') return '每天凌晨 2:00';
        if (cron === '0 30 0 * * ?') return '每天 0:30';
        return cron;
      },
      renderedSummary: function() {
        var md = this.selectedReport && this.selectedReport.summary;
        if (!md) return '<p style="color:#999;">暂无报告内容</p>';
        try {
          return marked.parse(md);
        } catch (e) {
          return '<pre>' + md.replace(/</g, '&lt;') + '</pre>';
        }
      }
    },
    mounted: function() {
@@ -443,6 +469,78 @@
        var pad = function(n) { return n < 10 ? '0' + n : n; };
        return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
          + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
      },
      downloadPdf: function() {
        var self = this;
        var el = document.getElementById('reportContent');
        if (!el) return;
        self.pdfLoading = true;
        // 临时移除滚动限制,让 html2canvas 捕获完整内容
        var origMaxHeight = el.style.maxHeight;
        var origOverflow = el.style.maxHeight;
        var scrollEl = el.querySelector('.markdown-body');
        if (scrollEl) {
          scrollEl.style.maxHeight = 'none';
          scrollEl.style.overflow = 'visible';
        }
        html2canvas(el, {
          scale: 2,
          useCORS: true,
          backgroundColor: '#ffffff',
          width: el.scrollWidth,
          height: el.scrollHeight,
          windowWidth: el.scrollWidth,
          windowHeight: el.scrollHeight
        }).then(function(canvas) {
          // 恢复滚动限制
          if (scrollEl) {
            scrollEl.style.maxHeight = origMaxHeight || '';
            scrollEl.style.overflow = origOverflow || '';
          }
          var pdf = new jspdf.jsPDF('p', 'mm', 'a4');
          var pdfWidth = pdf.internal.pageSize.getWidth();
          var pdfHeight = pdf.internal.pageSize.getHeight();
          var margin = 15;
          var contentWidth = pdfWidth - margin * 2;
          // 按 A4 页面高度分页
          var pageContentHeight = pdfHeight - margin * 2;
          var imgRatio = canvas.width / contentWidth;
          var totalImgHeightPx = canvas.height;
          var pageImgHeightPx = pageContentHeight * imgRatio;
          var srcY = 0;
          var page = 0;
          while (srcY < totalImgHeightPx) {
            if (page > 0) pdf.addPage();
            var sliceH = Math.min(pageImgHeightPx, totalImgHeightPx - srcY);
            var sliceCanvas = document.createElement('canvas');
            sliceCanvas.width = canvas.width;
            sliceCanvas.height = sliceH;
            var ctx = sliceCanvas.getContext('2d');
            ctx.fillStyle = '#ffffff';
            ctx.fillRect(0, 0, sliceCanvas.width, sliceCanvas.height);
            ctx.drawImage(canvas, 0, srcY, canvas.width, sliceH, 0, 0, canvas.width, sliceH);
            var sliceImgH = sliceH / imgRatio;
            pdf.addImage(sliceCanvas.toDataURL('image/png'), 'PNG', margin, margin, contentWidth, sliceImgH);
            srcY += sliceH;
            page++;
          }
          var fileName = 'WCS数据分析报告_' + (self.selectedReport.periodType || '') + '_' + self.formatTime(self.selectedReport.createTime).replace(/[: ]/g, '-') + '.pdf';
          pdf.save(fileName);
          self.pdfLoading = false;
        }).catch(function() {
          if (scrollEl) {
            scrollEl.style.maxHeight = origMaxHeight || '';
            scrollEl.style.overflow = origOverflow || '';
          }
          self.pdfLoading = false;
          self.$message.error('PDF 生成失败');
        });
      }
    }
  });