前端vue2-完全前端生成pdf->pdf-lib,html2canvas+jspdf,原生打印,三种方式(打印带有echarts图的pdf)

news2025/12/15 13:14:01

pdf-lib:优点是可以控制输出内容,缺点是麻烦

html2canvas:优点是直接把html页面转成图片之后插入pdf很方便,不用过多的代码,缺点是不好控制图片大小,容易被戒断,可以把想打印的内容藏在页面外面(postion:absoult;left:-9999)

原生打印:原生浏览器打印,完全无法控制

pdfkit:尝试了一下pdfkit,一直在报错,不好用目前只有0.12.1版本能打印,但是echarts好像也放不上去,格式要求很多(字体,图片)

依赖下载

npm包下载

npm install pdf-lib
npm install jspdf
npm install html2canvas
npm install echarts
npm install @pdf-lib/fontkit

字体下载(pdf-lib使用,ttf的会用不了,得用otf的格式,第二个链接)

https://github.com/adobe-fonts/source-han-sans/tree/release/OTC
https://github.com/adobe-fonts/source-han-sans/tree/release/SubsetOTF/CN

<template>
  <div class="pdf-container">
    <el-button type="primary" @click="downloadPdf">导出 PDF</el-button>
    <el-button type="primary" @click="nativePrint">原生打印</el-button>
    <el-button type="primary" @click="downloadPdfLib"
      >导出 PDF(PDFKit)</el-button
    >
    <div ref="pdfContent" class="pdf-content">
      <div class="pdf-page">
        <div>测试</div>
        <div>测试</div>
        <div>
          测试。
        </div>
        <div ref="chartRef" id="chart" style="width: 600px; height: 280px" />
        <div>测试测试测试测试测试测试。</div>
        <div>测试测试测试测试测试测试。</div>
        <div>
         测试测试测试测试测试测试。
        </div>
        <div ref="chartRef2" id="chart" style="width: 600px; height: 280px" />
      </div>
      <div class="pdf-page">
        <div>测试测试测试测试测试测试。</div>
        <div>
          测试测试测试测试测试测试。
        </div>
        <div ref="chartRef3" id="chart" style="width: 600px; height: 280px" />
        <div>测试测试测试测试测试测试。</div>
        <div>测试测试测试测试测试测试。</div>
        <div>
         测试测试测试测试测试测试。
        </div>
        <div ref="chartRef4" id="chart" style="width: 600px; height: 280px" />
      </div>
      <div class="pdf-page">
        <div>(测试测试测试测试测试测试。</div>
        <div>
          测试测试测试测试测试测试。
        </div>
        <div ref="chartRef5" id="chart" style="width: 600px; height: 280px" />
      </div>
    </div>
  </div>
</template>

<script>
import html2canvas from "html2canvas";
import jsPDF from "jspdf";
// import PDFDocument from "pdfkit"; // 新增
import "@fontsource/noto-sans-sc";
// const PDFDocument = require("pdfkit/js/pdfkit.standalone");
export default {
  mounted() {
    this.initChart();
  },
  methods: {
    initChart() {
      const chart = this.$echarts.init(this.$refs.chartRef, "", {
        renderer: "svg", // 强制使用 SVG
        devicePixelRatio: window.devicePixelRatio || 1, // 通常设为 2(Retina 屏)或更高,这样在页面上图片不会变糊了
      });
      chart.setOption({
        title: { text: "示例 ECharts 图表" },
        tooltip: {},
        xAxis: { data: ["A", "B", "C", "D", "E"] },
        yAxis: {},
        series: [
          {
            name: "数量",
            type: "bar",
            data: [5, 20, 36, 10, 10],
          },
        ],
      });
      const chart2 = this.$echarts.init(this.$refs.chartRef2, "", {
        renderer: "svg", // 强制使用 SVG
        devicePixelRatio: window.devicePixelRatio || 1, // 通常设为 2(Retina 屏)或更高,这样在页面上图片不会变糊了
      });
      chart2.setOption({
        title: { text: "示例 ECharts 图表" },
        tooltip: {},
        xAxis: { data: ["A", "B", "C", "D", "E"] },
        yAxis: {},
        series: [
          {
            name: "数量",
            type: "bar",
            data: [5, 20, 36, 10, 10],
          },
        ],
      });

      const chart3 = this.$echarts.init(this.$refs.chartRef3, "", {
        renderer: "svg", // 强制使用 SVG
        devicePixelRatio: window.devicePixelRatio || 1, // 通常设为 2(Retina 屏)或更高,这样在页面上图片不会变糊了
      });
      chart3.setOption({
        title: { text: "示例 ECharts 图表" },
        tooltip: {},
        xAxis: { data: ["A", "B", "C", "D", "E"] },
        yAxis: {},
        series: [
          {
            name: "数量",
            type: "bar",
            data: [5, 20, 36, 10, 10],
          },
        ],
      });

      const chart4 = this.$echarts.init(this.$refs.chartRef4, "", {
        renderer: "svg", // 强制使用 SVG
        devicePixelRatio: window.devicePixelRatio || 1, // 通常设为 2(Retina 屏)或更高,这样在页面上图片不会变糊了
      });
      chart4.setOption({
        title: { text: "示例 ECharts 图表" },
        tooltip: {},
        xAxis: { data: ["A", "B", "C", "D", "E"] },
        yAxis: {},
        series: [
          {
            name: "数量",
            type: "bar",
            data: [5, 20, 36, 10, 10],
          },
        ],
      });

      const chart5 = this.$echarts.init(this.$refs.chartRef5, "", {
        renderer: "svg", // 强制使用 SVG
        devicePixelRatio: window.devicePixelRatio || 1, // 通常设为 2(Retina 屏)或更高,这样在页面上图片不会变糊了
      });
      chart5.setOption({
        title: { text: "示例 ECharts 图表" },
        tooltip: {},
        xAxis: { data: ["A", "B", "C", "D", "E"] },
        yAxis: {},
        series: [
          {
            name: "数量",
            type: "bar",
            data: [5, 20, 36, 10, 10],
          },
        ],
      });
    },
    downloadPdf() {
      const content = this.$refs.pdfContent;
      // 设置 A4 页面尺寸(宽度 210mm, 高度 297mm),以 pt 为单位(1mm ≈ 2.8346pt)
      // 使用 html2canvas 渲染时保持原始内容
      html2canvas(content, {
        allowTaint: false, // 是否允许跨域图像。会污染画布,导致无法使用canvas.toDataURL 方法
        backgroundColor: "#fff", // 画布背景色(如果未在DOM中指定)。设置null为透明
        useCORS: true, // 是否尝试使用CORS从服务器加载图像
        scale: 2, // 300 DPI = 3 × 96 DPI
        dpi: 300,
      }).then((canvas) => {
        const imgData = canvas.toDataURL("image/png");

        // 创建 jsPDF 实例并设置页面尺寸为 A4
        const pdf = new jsPDF("p", "px", "a4"); // 直接修改页面宽高

        // 获取页面宽高
        const pageWidth = pdf.internal.pageSize.getWidth();
        const pageHeight = pdf.internal.pageSize.getHeight();

        const imgWidth = pageWidth; // 设置图片宽度为 PDF 页面宽度
        const imgHeight = (canvas.height * imgWidth) / canvas.width;
        console.log(canvas, "canvas");
        console.log(pdf.internal.pageSize, "pdf.internal.pageSize");
        console.log(pageHeight, "pageHeight");
        console.log(imgHeight, "imgHeight");

        let heightLeft = imgHeight;
        let position = 0;
        let pageNum = 1;
        const totalPages = Math.ceil(imgHeight / pageHeight);

        while (heightLeft > 0) {
          if (pageNum > 1) pdf.addPage();

          // 关键修复:跳过微小残余高度
          if (heightLeft < 5) break;

          const posY = -(pageHeight * (pageNum - 1));
          pdf.addImage(imgData, "PNG", 0, posY, imgWidth, imgHeight);

          // 页码(保持原样)
          pdf.setFontSize(10);
          pdf.setTextColor(150);
          pdf.text(`${pageNum}/${totalPages}`, pageWidth / 2, pageHeight - 20, {
            align: "center",
          });

          heightLeft -= pageHeight;
          pageNum++;
        }

        pdf.save("export.pdf");
      });
    },
    nativePrint() {
      // 1. 克隆打印内容(避免影响原DOM)
      const printContent = this.$refs.pdfContent.cloneNode(true);

      // 2. 创建隐藏的打印容器
      const printContainer = document.createElement("div");
      printContainer.id = "print-container";
      printContainer.appendChild(printContent);

      // 3. 添加到DOM(隐藏状态)
      document.body.appendChild(printContainer);

      // 4. 调用打印
      window.print();

      // 5. 打印后移除临时容器
      document.body.removeChild(printContainer);
    },
    async downloadPdfLib() {
      const { PDFDocument, rgb } = await import("pdf-lib");
      const fontkit = await import("@pdf-lib/fontkit");

      const pdfDoc = await PDFDocument.create();
      pdfDoc.registerFontkit(fontkit.default);

      const fontBytes = await fetch("/SourceHanSansCN-Regular.otf").then(
        (res) => res.arrayBuffer()
      );
      const customFont = await pdfDoc.embedFont(fontBytes);
      const fontBytesBlod = await fetch("/SourceHanSansCN-Bold.otf").then(
        (res) => res.arrayBuffer()
      );
      const customFontBlod = await pdfDoc.embedFont(fontBytesBlod);
      const pageWidth = 595.28;
      const pageHeight = 841.89;
      const marginLeft = 50;
      const marginTop = pageHeight - 50;
      const fontSize = 12;
      const lineHeight = fontSize * 1.5;
      const maxTextWidth = pageWidth - marginLeft * 2;

      function splitTextToLines(text, font, size, maxWidth) {
        let lines = [];
        let currentLine = "";
        for (let i = 0; i < text.length; i++) {
          const testLine = currentLine + text[i];
          const width = font.widthOfTextAtSize(testLine, size);
          if (width < maxWidth) {
            currentLine = testLine;
          } else {
            if (currentLine) {
              lines.push(currentLine);
            }
            currentLine = text[i];
          }
        }
        if (currentLine) {
          lines.push(currentLine);
        }
        return lines;
      }

      function drawTextBlock(
        page,
        text,
        x,
        yStart,
        alignCenter = false,
        options = {}
      ) {
        const {
          fontSize = 12,
          lineHeight = fontSize * 1.5,
          color = rgb(0, 0, 0),
          font = customFont,
        } = options;

        const lines = splitTextToLines(text, font, fontSize, maxTextWidth);
        let y = yStart;
        for (const line of lines) {
          let drawX = x;
          if (alignCenter) {
            const textWidth = font.widthOfTextAtSize(line, fontSize);
            drawX = (pageWidth - textWidth) / 2;
          }

          page.drawText(line, {
            x: drawX,
            y,
            size: fontSize,
            font,
            color,
          });
          y -= lineHeight;
        }
        return y;
      }

      function addPageNumber(page, pageNumber, totalPages) {
        const fontSize = 10;
        const margin = 20;
        const pageNumberText = `${pageNumber} / ${totalPages}`;
        const textWidth = customFont.widthOfTextAtSize(
          pageNumberText,
          fontSize
        );
        page.drawText(pageNumberText, {
          x: (pageWidth - textWidth) / 2,
          y: margin,
          size: fontSize,
          font: customFont,
          color: rgb(0, 0, 0),
        });
      }

      let _this = this;
      async function drawImage(page, base64Img, x, y, width, height) {
        const canvas = await _this.convertSvgToCanvas(base64Img, 3);
        const imgData = canvas.toDataURL("image/png");
        const imgBytes = await fetch(imgData).then((res) => res.arrayBuffer());
        const pngImage = await pdfDoc.embedPng(imgBytes);
        page.drawImage(pngImage, {
          x,
          y: y - height,
          width,
          height,
        });
      }

      const generateDirectory = true;
      let y = 0;
      let directoryPage;
      if (generateDirectory) {
        directoryPage = pdfDoc.addPage([pageWidth, pageHeight]);
        let y = pageHeight - 100;

        directoryPage.drawText("目录", {
          x: marginLeft,
          y: y,
          size: 16,
          font: customFont,
          color: rgb(0, 0, 0),
        });

        y -= lineHeight;
        directoryPage.drawText(
          "一、测试测试测试测试测试测试。 .......................................... 1",
          {
            x: marginLeft,
            y: y,
            size: fontSize,
            font: customFont,
            color: rgb(0, 0, 0),
          }
        );

        y -= lineHeight;
        directoryPage.drawText(
          "二、测试测试测试测试测试测试。 .......................................... 2",
          {
            x: marginLeft,
            y: y,
            size: fontSize,
            font: customFont,
            color: rgb(0, 0, 0),
          }
        );
      }

      const page1 = pdfDoc.addPage([pageWidth, pageHeight]);
      y = marginTop;

      y = drawTextBlock(
        page1,
        "测试测试测试测试测试测试。",
        marginLeft,
        y,
        true,
        { fontSize: 16, font: customFontBlod }
      );
      y -= lineHeight / 2;
      y = drawTextBlock(page1, "一、贸易总体情况", marginLeft, y, false, {
        fontSize: 14,
      });
      y -= lineHeight / 2;
      y = drawTextBlock(
        page1,
        "    测试测试测试测试测试测试。",
        marginLeft,
        y
      );

      const chart1 = this.$echarts.getInstanceByDom(this.$refs.chartRef);
      const svgData1 = chart1.getDataURL({ type: "svg" });
      y -= lineHeight * 1.5;
      await drawImage(page1, svgData1, marginLeft, y, 495, 250);
      y -= 250 + lineHeight;

      y = drawTextBlock(page1, "二、产品结构情况", marginLeft, y, false, {
        fontSize: 14,
      });
      y -= lineHeight / 2;
      y = drawTextBlock(page1, "(一)出口商品结构", marginLeft, y);
      y -= lineHeight / 2;
      y = drawTextBlock(
        page1,
        "测试测试测试测试测试测试。",
        marginLeft,
        y
      );

      y -= lineHeight * 1.5;
      const chart2 = this.$echarts.getInstanceByDom(this.$refs.chartRef2);
      const svgData2 = chart2.getDataURL({ type: "svg" });
      await drawImage(page1, svgData2, marginLeft, y, 495, 250);
      addPageNumber(page1, 1, 3);

      const page2 = pdfDoc.addPage([pageWidth, pageHeight]);
      y = marginTop;

      y = drawTextBlock(page2, "(二)进口商品结构", marginLeft, y);
      y -= lineHeight / 2;
      y = drawTextBlock(
        page2,
        "测试测试测试测试测试测试。",
        marginLeft,
        y
      );
      const chart3 = this.$echarts.getInstanceByDom(this.$refs.chartRef3);
      const svgData3 = chart3.getDataURL({ type: "svg" });
      y -= lineHeight * 1.5;
      await drawImage(page2, svgData3, marginLeft, y, 495, 250);
      y -= 250 + lineHeight;

      y = drawTextBlock(page2, "测试测试测试测试测试测试。", marginLeft, y, false, {
        fontSize: 14,
      });
      y -= lineHeight / 2;
      y = drawTextBlock(page2, "测试测试测试测试测试测试。", marginLeft, y);
      y -= lineHeight / 2;
      y = drawTextBlock(
        page2,
        "测试测试测试测试测试测试。",
        marginLeft,
        y,
        false,
        {
          fontSize: 12,
          color: rgb(0.2, 0.2, 0.6),
          lineHeight: 20,
        }
      );

      const chart4 = this.$echarts.getInstanceByDom(this.$refs.chartRef4);
      const svgData4 = chart4.getDataURL({ type: "svg" });
      y -= lineHeight * 1.5;
      await drawImage(page2, svgData4, marginLeft, y, 495, 250);
      addPageNumber(page2, 2, 3);

      const page3 = pdfDoc.addPage([pageWidth, pageHeight]);
      y = marginTop;

      y = drawTextBlock(page3, "(二)进口商品结构", marginLeft, y);
      y -= lineHeight / 2;
      y = drawTextBlock(
        page3,
        "测试测试测试测试测试测试。",
        marginLeft,
        y
      );
      const chart5 = this.$echarts.getInstanceByDom(this.$refs.chartRef5);
      const svgData5 = chart5.getDataURL({ type: "svg" });
      y -= lineHeight * 1.5;
      await drawImage(page3, svgData5, marginLeft, y, 495, 250);
      addPageNumber(page3, 3, 3);

      const pdfBytes = await pdfDoc.save();
      const blob = new Blob([pdfBytes], { type: "application/pdf" });
      const link = document.createElement("a");
      link.href = URL.createObjectURL(blob);
      link.download = "测试测试测试测试测试测试.pdf";
      link.click();
    },

    // 将文本分割为多行
    splitTextIntoLines(text, maxWidth, font, fontSize) {
      const lines = [];
      let line = "";

      for (let i = 0; i < text.length; i++) {
        const testLine = line + text[i];
        const width = font.widthOfTextAtSize(testLine, fontSize);

        if (width < maxWidth) {
          line = testLine;
        } else {
          lines.push(line);
          line = text[i];
        }
      }

      if (line) lines.push(line);
      return lines;
    },

    // 使用 html2canvas 将 SVG 转换为 Canvas
    convertSvgToCanvas(svgData, scale = 4) {
      return new Promise((resolve, reject) => {
        const img = new Image();
        img.src = svgData;
        img.onload = () => {
          const canvas = document.createElement("canvas");
          const ctx = canvas.getContext("2d");
          // 设置canvas尺寸,使用scale来增加渲染分辨率
          canvas.width = img.width * scale;
          canvas.height = img.height * scale;
          ctx.scale(scale, scale); // 拉伸canvas,提升图像分辨率
          ctx.drawImage(img, 0, 0);
          resolve(canvas);
        };
        img.onerror = reject;
      });
    },
  },
};
</script>

<style scoped>
.pdf-container {
  background: white;
  padding: 20px;
}
.pdf-content {
  width: 794px;
  background: #fff;
  /* padding: 20px; */
  /* margin-top: 20px; */
  /* border: 1px solid #eee; */
}
.pdf-page {
  height: 1123px;
  /* border: 1px solid #eee; */
  /* margin: 10px 0; */
  padding: 20px;
}
.pdf-page:last-child {
  height: 1100px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文阅读笔记——Emerging Properties in Unified Multimodal Pretraining

BAGEL 论文 商业闭源系统与学术/开源模型的差距很大&#xff0c;BAGEL 旨在通过开源统一架构大规模交错数据主要解决&#xff1a; 架构割裂&#xff1a;理解/生成分属两条网络&#xff0c;信息被压缩在少量条件 token 中&#xff0c;长上下文推理受限。数据贫乏&#xff1a;主…

JAVA批量发送邮件(含excel内容)

EmailSenderHtmlV1 是读取配置文件《批量发送邮件.xlsx》&#xff0c;配置sheet获取 发件人邮箱 邮箱账号 口令&#xff0c;发送excel数据sheet获取收件人邮箱 抄送人邮箱 邮件标题 第N行开始(N>1,N0默认表头) 第M行结束(M>1,M0默认表头) 附件文件夹…

Linux(Ubuntu)新建文件权限继承问题

当你在一个工作目权限为777的文件下&#xff0c;新建一个文件的时候&#xff0c;就有可能发生&#xff0c;新建的这个文件&#xff0c;权限和其他文件&#xff0c;或者工作目录不一致的问题&#xff0c;我们不可能每次新建一个文件&#xff0c;就要 sudo chmod -R 777 /PATH 所…

Java中的String的常用方法用法总结

1.1 String &#xff08;1&#xff09;声明 &#xff08;2&#xff09;字符串常量 存储字符串数据的容器&#xff1a;private final char value[] 字符串常量都存储在字符串常量池&#xff08;StringTable&#xff09;中 字符串常量池不允许存放两个相同的字符串常量 &#xff…

QGIS如何打开 ARCGIS的mxd工程文件

“SLYR”是一款由著名开源组织“北路开源”开发的一套QGIS兼容和转换ARCGIS样式、工程、设置信息的插件&#xff01;其主要功能为&#xff1a; 最近项目需要&#xff0c;我使用了一些功能&#xff0c;发现其对中文环境及中文信息支持不太好&#xff0c;还有一些其它BUG&#xf…

基于微信小程序的智能问卷调查系统设计与实现(源码+定制+解答)基于微信生态的问卷管理与数据分析系统设计

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

React 如何封装一个可复用的 Ant Design 组件

文章目录 前言一、为什么需要封装组件&#xff1f;二、 仿antd组件的Button按钮三、封装一个可复用的表格组件 (实战)1. 明确需求2. 设计组件 API3. 实现组件代码4. 使用组件 三、封装组件的最佳实践四、进阶优化 总结 前言 作为一名前端开发工程师&#xff0c;在日常项目中&a…

Canvas SVG BpmnJS编辑器中Canvas与SVG职能详解

Canvas详解与常见API 一、Canvas基础 核心特性 • 像素级绘图&#xff1a;Canvas是基于位图的绘图技术&#xff0c;通过JavaScript操作像素实现图形渲染&#xff0c;适合动态、高性能场景&#xff08;如游戏、数据可视化&#xff09;。 • 即时模式&#xff1a;每次绘制需手动…

dify多实例部署,一台机器部署多个dify实例

dify多实例部署 目的 实现在一台机器上&#xff0c;部署多个dify的实例。比如一个部署1.2版本&#xff0c;一个部署1.3版本。废话没有&#xff0c;直接上干货。 前提 你的电脑已经部署了一个dify实例&#xff0c;并成功运行。比如已经部署成功0.15.3版本。 步骤如下&#…

ML 48.机器学习之临床生存树(rpartSurv)

简介机器学习中生存树&#xff08;Survival Tree&#xff09;的原理详解 生存树是结合决策树与生存分析的机器学习模型&#xff0c;主要用于处理带有时间-事件数据&#xff08;包含删失数据&#xff09;的预测问题。其核心目标是&#xff1a;通过树状结构对数据进行递归分割&am…

HarmonyOS 应用开发,如何引入 Golang 编译的第三方 SO 库

本指南基于笔者临时修复的 ohos_golang_go 项目fork&#xff0c;解决HO 应用导入 cgo编译产物时的 crash 问题。 1. 下载 ohos_golang_go git clone https://gitcode.com/deslord/ohos_golang_go.git&#x1f4cc; 该仓库为笔者临时修复版本&#xff0c;修复了 CGO 编译模式下…

一体化雷达波明渠流量计简介

一、技术定义与核心原理 一体化雷达波明渠流量计是基于微波技术的全自动流量监测设备&#xff0c;采用 24G K 波段平面雷达技术&#xff0c;通过非接触式测量方式实现对明渠、河道、排水管网等场景的水位、流速及流量监测。其核心原理是利用雷达发射高频电磁波&#xff0c;经水…

Pr -- 耳机没有Pr输出的声音

问题 很久没更新视频号了&#xff0c;想用pr剪辑一下&#xff0c;结果使用Pr打开后发现耳机没有Pr输出的声音 解决方法 在编辑--首选项-音频硬件中设置音频硬件的输出为当前耳机设备

白皮精读:2024年国家数据基础设施建设指引【附全文阅读】

《国家数据基础设施建设指引》提出建设覆盖数据采集至安全全链条的新型基础设施,目标到 2029 年形成横向联通、纵向贯通的格局,聚焦数据可信流通、算力协同、高速传输、安全保障四大功能,明确技术架构与重点方向,强调政府与市场协同,分阶段推进试点及规模化部署,为数字中…

穿屏技巧:Mac-Windows一套鼠标键盘控制多台设备 (sharemouse6.0-Keygen)| KM-401A

文章目录 引言I sharemouse6.0介绍功能介绍关闭自动更新安装包II 安装系统对应的sharemouse软件Windowsmac版本III 知识扩展:SCP、FTP、SSH文件传输SCP配置SSH密钥免密登录FTP(File Transfer Protocal,文件传输协议)引言 基于USB进行同步键盘和鼠标事件,更流畅。 基于局域…

【写在创作纪念日】基于SpringBoot和PostGIS的各省东西南北四至极点区县可视化

目录 前言 一、空间检索简介 1、空间表结构 2、四至空间检索 二、前后端实现 1、后端实现 2、前端集成 三、成果展示 1、东部省份 2、西部省份 3、南部省份 4、北部省份 5、中部省份 四、总结 前言 在当今数字化时代&#xff0c;地理信息数据的分析与可视化对于众…

如何制作可以本地联网搜索的MCP,并让本地Qwen3大模型调用搜索回答用户问题?

环境: SearXNG Qwen3-32B-FP8 vllm 0.8.5 问题描述: 如何制作可以本地联网搜索的MCP,并让本地Qwen3大模型调用搜索回答用户问题? 解决方案: 一、安装searxng 1.按需新建模型相关文件夹 mkdir MCP chmod 777 /mnt/program/MCP2.配置conda源 nano ~/.condarc nano…

服务器硬盘虚拟卷的处理

目前的情况是需要删除逻辑卷&#xff0c;然后再重新来弄一遍。 数据已经备份好了&#xff0c;所以不用担心数据会丢失。 查看服务器的具体情况 使用 vgdisplay 操作查看服务器的卷组情况&#xff1a; --- Volume group ---VG Name vg01System IDFormat …

一个国债交易策略思路

该国债交易策略的核心在于通过分析历史价格数据来识别市场趋势&#xff0c;并在趋势确认时进行开仓操作。策略的设计思路结合了价格波动范围的计算和市场波动性的评估&#xff0c;旨在捕捉市场的短期趋势并控制风险。 首先&#xff0c;策略通过对过去5根K线的最高价和最低价进行…

【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之如何形成高斯椭球

【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之如何形成高斯椭球 文章目录 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之如何形成高斯椭球前言高斯函数一维高斯多维高斯 椭球基本定义一般二次形式 3D高斯椭球3D高斯与椭球的关系各向同性(Isotropic)和…