移动端浏览器的扫描二维码实现(vue-qrcode-reader与jsQR方式)

news2024/11/18 23:30:39

1. 实现功能

类似扫一扫的功能,自动识别到画面中的二维码并进行识别,也可以选择从相册中上传。
在这里插入图片描述
在这里插入图片描述

2. 涉及到的一些插件介绍

vue-qrcode-reader
一组用于检测和解码二维码的Vue.js组件

jsQR
一个纯粹的javascript二维码阅读库,该库接收原始图像,并将定位、提取和解析在其中找到的任何二维码。

zxing-wasm
ZXing-C++ WebAssembly 作为带有类型的 ES/CJS 模块。读/写 web、node、bun 和 deno 中的条形码。

2. vite项目配置本地开发使用https访问

安装basicSsl

pnpm i @vitejs/plugin-basic-ssl
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import basicSsl from '@vitejs/plugin-basic-ssl'
 
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), basicSsl()],
  server: {
    host: '0.0.0.0',
    https: true
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  }
})

3. 方式一:vue-qrcode-reader实现

npm install vue-qrcode-reader

🔍vue-qrcode-reader Api 介绍

<template>
  <div>
    <qrcode-stream
      class="qrcode-wrap"
      :torch="torch"
      v-memo="[torch]"
      :constraints="selectedConstraints"
      :track="paintBoundingBox"
      @error="onError"
      @detect="onDetect"
      @camera-on="onCameraReady"
    >
      <div v-if="isSupportTorch" class="torch-wrap">
        <div class="torch" @click="() => (torch = !torch)">
          <div class="flash-light" v-if="torch">
            <MdiFlashlightOff style="width: 36px; height: 36px" />
          </div>
          <div class="flash-light" v-else>
            <MdiFlashlight style="width: 36px; height: 36px" />
          </div>
          {{ torch ? "关闭闪光灯" : "打开闪光灯" }}
        </div>
      </div>
      <div class="photo-wrap">
        <div class="photo" @click="handleOpenFile">
          <el-icon size="20">
            <PictureFilled />
          </el-icon>
        </div>
        <div class="color-[#fff]">相册</div>
      </div>
    </qrcode-stream>
  </div>
</template>
<script setup lang="ts">
// https://gruhn.github.io/vue-qrcode-reader/api/QrcodeStream.html
import { QrcodeStream } from "vue-qrcode-reader";
import { PictureFilled } from "@element-plus/icons-vue";
import MdiFlashlight from "~icons/mdi/flashlight";
import MdiFlashlightOff from "~icons/mdi/flashlight-off";
import { ElMessage } from "element-plus";
import { fileOpen } from "browser-fs-access";
import _ from "lodash";

const error = ref("");
const cameraIsReady = ref(false);
const isSupportTorch = ref(false); // 是否支持闪光灯
const torch = ref(false); // 闪光灯状态
// 相机配置选项: 'user'|'environment' (默认:environment)
const selectedConstraints = ref({ facingMode: "environment" });

// 检测到二维码后绘制画布类型
function paintBoundingBox(detectedCodes: any, ctx: CanvasRenderingContext2D) {
  for (const detectedCode of detectedCodes) {
    const {
      boundingBox: { x, y, width, height },
    } = detectedCode;

    ctx.lineWidth = 2;
    ctx.strokeStyle = "#007bff";
    // 绘制边框矩形
    ctx.strokeRect(x, y, width, height);
  }
}

async function onCameraReady(capabilities: any) {
  // NOTE: on iOS we can't invoke `enumerateDevices` before the user has given
  // camera access permission. `QrcodeStream` internally takes care of
  // requesting the permissions. The `camera-on` event should guarantee that this
  // has happened.
  try {
    isSupportTorch.value = !!capabilities.torch;
    cameraIsReady.value = true;
    error.value = "";
  } catch (error) {
    onError(error);
    cameraIsReady.value = false;
  }
}
// 错误提示
function onError(err: any) {
  error.value = `[${err.name}]: `;
  if (err.name === "NotAllowedError") {
    error.value += "you need to grant camera access permission";
  } else if (err.name === "NotFoundError") {
    error.value += "no camera on this device";
  } else if (err.name === "NotSupportedError") {
    error.value += "secure context required (HTTPS, localhost)";
  } else if (err.name === "NotReadableError") {
    error.value += "is the camera already in use?";
  } else if (err.name === "OverconstrainedError") {
    error.value += "installed cameras are not suitable";
  } else if (err.name === "StreamApiNotSupportedError") {
    error.value += "Stream API is not supported in this browser";
  } else if (err.name === "InsecureContextError") {
    error.value +=
      "Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP.";
  } else {
    error.value += err.message;
  }
  ElMessage.warning(error.value);
}
// 用户摄像头的流后
function onDetect(detectedCodes: any) {
  if (detectedCodes.length > 0) {
    onDecode(detectedCodes[0]?.rawValue);
  }
}

const emit = defineEmits(["on-success"]);

// 解码(交给父组件处理:进行网络请求)
function onDecode(text: string) {
  emit("on-success", text);
}
// 文件转成base64
const processFile = async (file: any) => {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (e) => {
      let base64String = e.target?.result as string ||'';
      // 此处可对该base64进行获取赋值传入后端, 如果有直接上传文件的接口就可以直接传文件
      onDecode(base64String)
    };
};
// 打开图片选择
async function handleOpenFile() {
  try {
    const file = await fileOpen({ mimeTypes: ["image/*"] }).catch(() => null);
    if (!file) return;
    // 计算文件的大小
    const fileSizeMb = _.round(file.size / 1024 / 1024, 2);
    // 文件大小不能超过 10MB
    const limitSizeMb = 10;
    if (fileSizeMb > limitSizeMb) {
      return ElMessage.warning(`图片大小限制 ${limitSizeMb}MB`);
    }
    processFile(file)
  } catch (error) {
    console.log(`[log] - handleOpenUploadIcon - error:`, error);
  }
}
</script>
<style scoped>
.qrcode-wrap {
  position: fixed !important;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 1 !important;
  background: rgba(0, 0, 0, 0.5);
}
.torch-wrap {
  width: 18.75rem;
  height: 12.5rem;
  position: fixed !important;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -30%);
  z-index: 20;
}

.torch {
  position: fixed;
  bottom: -6.25rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.photo-wrap {
  position: fixed;
  bottom: 2.875rem;
  left: 2.875rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.photo {
  height: 3.125rem;
  width: 3.125rem;
  background-color: rgba(250, 250, 250, 0.8);
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
}
</style>

browser-fs-access 这个包需要提前下载

pnpm i browser-fs-access

如果需要在离线的环境解析二维码,则需要使用zxing-wasm,在上面文件的js部分添加以下代码:

// 该文件由zxing-wasm项目构建而来
import wasmFile from './zxing_reader.wasm?url';

// !为了离线加载
// https://github.com/gruhn/vue-qrcode-reader/issues/354
setZXingModuleOverrides({
  locateFile: (path: string, prefix: any) => {
    if (path.endsWith('.wasm')) {
      return wasmFile;
    }
    return prefix + path;
  },
});

✨ 该部分完整Demo代码在该文件夹下:Demo (二维码实现之vue-qrcode-reader)

4. 方式二:jsQR实现

🔍Canvas的基本介绍与使用

<template>
  <div>
    <div class="canvasBox">
      <div class="box">
        <div class="line"></div>
        <div class="angle"></div>
      </div>
      <div v-if="isUseTorch" class="box2">
        <div class="track" @click="openTrack">
          <div class="flash-light" v-if="trackStatus">
            <MdiFlashlightOff style="width: 36px; height: 36px" />
          </div>
          <div class="flash-light" v-else>
            <MdiFlashlight style="width: 36px; height: 36px" />
          </div>
          {{ trackStatus ? "关闭闪光灯" : "打开闪光灯" }}
        </div>
      </div>

      <div class="photo-wrap">
        <div class="photo" @click="handleClickFile">
          <el-icon size="20">
            <input
              class="hide_file"
              ref="fileRef"
              type="file"
              accept="image/*;"
              @change="getFile"
            />
            <PictureFilled />
          </el-icon>
        </div>
        <div class="color-[#fff]">相册</div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
// https://github.com/cozmo/jsQR
import jsQR from "jsqr";
import { PictureFilled } from "@element-plus/icons-vue";
import MdiFlashlight from "~icons/mdi/flashlight";
import MdiFlashlightOff from "~icons/mdi/flashlight-off";
import { ElMessage } from "element-plus";
import _ from "lodash";

const props = withDefaults(
  defineProps<{
    // environment 后摄像头  user 前摄像头
    exact?: "environment" | "user";
    //  whole 全屏  half 半屏
    size?: "whole" | "half";
    // 清晰度: fasle 正常  true 高清
    definition?: boolean;
  }>(),
  {
    exact: "environment",
    size: "whole",
    definition: false,
  }
);
const video = ref();
const canvas2d = ref();
const canvasWidth = ref(520);
const canvasHeight = ref(500);
const c = ref();
const track = ref();
const isUseTorch = ref(false);
const trackStatus = ref(false);
const fileRef = ref();

onMounted(() => {
  const windowWidth = window.screen.availWidth;
  const windowHeight = window.screen.availHeight;

  canvasWidth.value = windowWidth;
  canvasHeight.value = windowHeight;

  nextTick(() => {
    video.value = document.createElement("video");
    c.value = document.createElement("canvas");
    c.value.id = "c";
    c.value.width = canvasWidth.value;
    c.value.height = canvasHeight.value;
    c.value.style.width = "100%";
    document.querySelector(".canvasBox")?.append(c.value);
    openScan();
  });
});

onUnmounted(() => {
  closeCamera();
});
// 开始扫描
async function openScan() {
  try {
    let width = canvasHeight.value;
    width = props.size === "whole" ? width : width * 0.5;
    width = props.definition ? width * 1.6 : width;
    let height = canvasWidth.value;
    height = props.definition ? height * 1.6 : height;
    const videoParam = {
      audio: false,
      video: {
        facingMode: { exact: props.exact }, //强制使用摄像头类型
        width,
        height,
      },
    };
    // 获取用户摄像头的视频流
    const stream = await navigator.mediaDevices.getUserMedia(videoParam);
    if (stream) {
      video.value.srcObject = stream;
      video.value.setAttribute("playsinline", true); //内联播放
      video.value.play();
      requestAnimationFrame(tick);
      // 返回所有的媒体内容流的轨道列表
      track.value = stream.getVideoTracks()?.[0];
      setTimeout(() => {
        // 检测摄像头是否支持闪光灯
        isUseTorch.value = track.value.getCapabilities().torch || null;
      }, 500);
    }
  } catch (error) {
    ElMessage.warning("设备不支持,请检查是否允许摄像头权限!");
    console.log("获取本地设备(摄像头)---失败", error);
  }
}
function closeCamera() {
  if (video.value.srcObject) {
    video.value.srcObject.getTracks().forEach((track: any) => {
      track.stop();
    });
  }
}
function tick() {
  if (video.value.readyState === video.value.HAVE_ENOUGH_DATA) {
    canvasHeight.value = video.value.videoHeight;
    canvasWidth.value = video.value.videoWidth;
    c.value.width = canvasWidth.value;
    c.value.height = canvasHeight.value;
    if (canvas2d.value === undefined) {
      canvas2d.value = c.value.getContext("2d");
    }

    canvas2d.value.drawImage(
      video.value,
      0,
      0,
      canvasWidth.value,
      canvasHeight.value
    );

    const imageData = canvas2d.value.getImageData(
      0,
      0,
      canvasWidth.value,
      canvasHeight.value
    );
    // 解析二维码数据
    const code = jsQR(imageData.data, imageData.width, imageData.height, {
      inversionAttempts: "dontInvert",
    });

    if (!_.isEmpty(code)) {
      drawLine(
        code.location.topLeftCorner,
        code.location.topRightCorner,
        "#FF3B58"
      );
      drawLine(
        code.location.topRightCorner,
        code.location.bottomRightCorner,
        "#FF3B58"
      );
      drawLine(
        code.location.bottomRightCorner,
        code.location.bottomLeftCorner,
        "#FF3B58"
      );
      drawLine(
        code.location.bottomLeftCorner,
        code.location.topLeftCorner,
        "#FF3B58"
      );
      if (code.data) {
        getData(code.data);
      }
    }
  }
  requestAnimationFrame(tick);
}
function drawLine(begin: any, end: any, color: string) {
  canvas2d.value.beginPath();
  canvas2d.value.moveTo(begin.x, begin.y);
  canvas2d.value.lineTo(end.x, end.y);
  canvas2d.value.lineWidth = 4;
  canvas2d.value.strokeStyle = color;
  canvas2d.value.stroke();
}
const emit = defineEmits(["on-success"]);

function getData(data: string) {
  emit("on-success", data);
  closeCamera();
}

function openTrack() {
  trackStatus.value = !trackStatus.value;
  track.value.applyConstraints({
    advanced: [{ torch: trackStatus.value }],
  });
}
const handleClickFile = () => {
  fileRef.value.click();
};
const getFile = (e: any) => {
  const file = e.target.files[0];
  emit("on-success", file);
  closeCamera();
};
</script>

<style scoped>
.flash-light {
  display: grid;
  place-content: center;
  margin-bottom: 6px;
}

.photo-wrap {
  position: fixed;
  bottom: 2.875rem;
  left: 2.875rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.photo {
  height: 3.125rem;
  width: 3.125rem;
  background-color: rgba(250, 250, 250, 0.8);
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
}

.hide_file {
  display: none;
}

page {
  background-color: #333333;
}

.canvasBox {
  width: 100vw;
  position: relative;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-image: linear-gradient(
      0deg,
      transparent 24%,
      rgba(32, 255, 77, 0.1) 25%,
      rgba(32, 255, 77, 0.1) 26%,
      transparent 27%,
      transparent 74%,
      rgba(32, 255, 77, 0.1) 75%,
      rgba(32, 255, 77, 0.1) 76%,
      transparent 77%,
      transparent
    ),
    linear-gradient(
      90deg,
      transparent 24%,
      rgba(32, 255, 77, 0.1) 25%,
      rgba(32, 255, 77, 0.1) 26%,
      transparent 27%,
      transparent 74%,
      rgba(32, 255, 77, 0.1) 75%,
      rgba(32, 255, 77, 0.1) 76%,
      transparent 77%,
      transparent
    );
  background-size: 3rem 3rem;
  background-position: -1rem -1rem;
  z-index: 10;
  background-color: #1110;
}

.box {
  width: 11.9375rem;
  height: 11.9375rem;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -80%);
  overflow: hidden;
  border: 0.1rem solid rgba(0, 255, 51, 0.2);
  z-index: 11;
}

.line {
  height: calc(100% - 2px);
  width: 100%;
  background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
  border-bottom: 3px solid #00ff33;
  transform: translateY(-100%);
  animation: radar-beam 2s infinite alternate;
  animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
  animation-delay: 1.4s;
}

.box:after,
.box:before,
.angle:after,
.angle:before {
  content: "";
  display: block;
  position: absolute;
  width: 3vw;
  height: 3vw;
  z-index: 12;
  border: 0.2rem solid transparent;
}

.box:after,
.box:before {
  top: 0;
  border-top-color: #00ff33;
}

.angle:after,
.angle:before {
  bottom: 0;
  border-bottom-color: #00ff33;
}

.box:before,
.angle:before {
  left: 0;
  border-left-color: #00ff33;
}

.box:after,
.angle:after {
  right: 0;
  border-right-color: #00ff33;
}

@keyframes radar-beam {
  0% {
    transform: translateY(-100%);
  }

  100% {
    transform: translateY(0);
  }
}

.box2 {
  width: 18.75rem;
  height: 12.5rem;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -80%);
  z-index: 20;
}

.track {
  position: absolute;
  bottom: -6.25rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
}
</style>

✨该部分完整Demo代码在该文件夹下:Demo (二维码实现之jsQR)

5. 总结

方式一结合vue-qrcode-reader的封装性更强且识别二维码速度更快。
方式二接近了vue-qrcode-reader的底层实现过程。
实际项目开发中更推荐方式一,兼容性与稳定性会更好些

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

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

相关文章

基于asp.net大学生健康管理系统功能介绍

项目关键技术 开发工具&#xff1a;Visual Studio 编程语言: .net、JavaScript 数据库: SQL Server 框架&#xff1a;ASP.NET框架 关键技术&#xff1a;ASP.NET、SQL Server 数据库工具&#xff1a;Navicat 1、ASP.NET框架 ASP.NET技术框架是目前在程序开发中广泛应用的一种新…

存储协议入门-UPIU简介

写在前面:本文参考UFS jedec3.1,本文思维导图如下,详细内容关注微信:存储协议探索 ​ 1. UPIU架构 UPIU是UFS协议中的一种数据包格式,用于传输应用层的各种请求和命令,UFS采用的是客户-服务端架构,UFS主机(客户)主动发起请求,UFS设备(服务)执行后并返回相应状态。…

演出门票小程序开发

一、实时票务信息更新的重要性 在演出票务市场&#xff0c;票务信息的实时性对于消费者来说至关重要。一旦票务信息出现滞后或错误&#xff0c;不仅可能导致消费者错过心仪的演出&#xff0c;还可能引发一系列不必要的纠纷和投诉。因此&#xff0c;演出门票小程序通过引入实时…

IMU监测举重作

近日&#xff0c;来自加拿大的科研团队针对举重中因不当举重操作引发的普遍下背痛问题开展了一项开创性研究。团队利用穿戴式惯性测量单元&#xff08;IMU&#xff09;技术&#xff0c;在受控实验室环境中&#xff0c;实时监测并评估了举重动作过程中下背部肌肉与脊柱关节的受力…

The First项目报告:Stargate Finance重塑跨链金融的未来

Stargate Finance是一个基于LayerZero协议的去中心化金融平台&#xff0c;自2022年3月由LayerZero Labs创建以来&#xff0c;一直致力于为不同区块链之间的资产转移提供高效、低成本的解决方案。凭借其独特的跨链技术和丰富的DeFi服务&#xff0c;Stargate Finance已成为连接不…

物联网TCP、UDP、CoAP、LwM2M、MQTT协议简单对比

一、前言 目前物联网行业有TCP、UDP、CoAP、LwM2M、MQTT、Modbus系列、JT808、HTTP、TLINK、ISAPI等协议&#xff0c;本文先对其中的几款协议进行介绍。具体关系见下图&#xff1a; 传输层协议&#xff1a;TCP、UDP&#xff1b;应用层协议&#xff1a;CoAP、LwM2M、MQTT、Modbu…

数据结构之线性表(4)

前面我们了解到线性表中的顺序表、链表等结构&#xff0c;今天我们探讨新的一种线性表——栈。 那么我们开始栈的探讨之旅吧。 1.栈的基本概念 1.1栈&#xff08;Stack&#xff09;&#xff1a; 是只允许在一端进行插入或删除的线性表。首先栈是一种线性表&#xff0c;但限定…

【Mybatis】动态SQL内置参数

配置映射关系的xml文件里&#xff0c;所有的参数都是来自接口方法的传值&#xff0c;但是Mybatis内部&#xff0c;其实还有两个很有作用的内置参数的 ①_databaseId: 在全局变量中配置了多数据库支持的databaseIdProvider属性的前提下&#xff0c;这个内置参数的值就是databas…

【Java】在你上一家公司中是如何如何实现蓝绿发布的?

一、问题解析 随着微服务应用的不断增加&#xff0c;各个微服务之间的依赖关系也变得比较复杂&#xff0c;各个微服务的更新、升级部署给整个服务域的稳定性带来很大挑战。怎么以不停机的方式部署升级微服务呢&#xff1f; 在进行技术方案的设计之前&#xff0c;我们先来了解…

opencv_核心操作

图像基本操作 访问和修改像素值 import numpy as np import cv2 img cv2.imread(c:/Users/HP/Downloads/basketball.png) h,w,c img.shape #图像大小 print(h,w,c)### 841 1494 3# 通过行和列坐标访问像素值 img[100,100]### 231 ### array([231, 140, 146], dtypeuint8)# …

WordPress 站点 Wp-Login.Php 登录页面,防止被机器扫描爆破终极方法

最近好像不少的 WordPress 站点又迎来了一波疯狂的 wp-login.php 登录页面暴力破解,明月使用的 Dragon 主题也迅速的做出了安全防范响应,第一时间就增强了代码上的安全防御能力。明月代运维的几个站点也在这方面加强了防范措施,基本上实现了永久解决这一顽疾的目标,今天明月…

智能编程支持分析本地工程文件,项目级开发效率再度提升!

CodeGeeX的智能问答新增关联本地文件的系列功能&#xff0c;用户在智能问答的输入框中输入&#xff0c;就可以在弹出框中选择需要使用的指令。从而能够针对所关联的文件给出更有针对性的问答和代码建议。 下面我们将分别介绍在编程工作中&#xff0c;如何关联本地文件&#xff…

Shell脚本01

一、shell脚本 脚本就是可运行的代码的集合&#xff0c;脚本语言&#xff08;计算机语言&#xff09;。 脚本的特点&#xff1a;从上到下&#xff0c;按行执行。 shell 脚本就是在shell环境&#xff08;bin/bash&#xff09;bash就是shell解释器&#xff0c;linux环境下的编…

pytest+requests+allure自动化测试接入Jenkins学习

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 最近在这整理知识&#xff0c;发现在pytest的知识文档缺少系统性&#xff0c;这里整理一下&…

MCU为什么上电不启动

相信很多朋友们都遇到过&#xff0c;自信满满的将程序下载到板子上&#xff0c;发现MCU居然没启动。 那这个现象可能有很多问题会导致&#xff0c;让我们来看看会有哪些原因。 1、BOOT引脚电平不对&#xff1a; 在GD32 MCU上&#xff0c;BOOT引脚决定了MCU的启动方式&#x…

zabbix监控深信服AD案例+自动发现虚拟服务和链路

文章目录 前言监控功能告警功能 环境准备操作步骤深信服AD开启SNMPSNMP V2SNMP V3 Zabbix导入模版Zabbix中添加深信服AD 前言 深信服AD&#xff0c;应用交付网关&#xff0c;是较为常见的应用发布、负载均衡设备&#xff0c;常用于网络出口。 本案例是通过zabbix的snmp监控深…

拥抱AI-图片学习中的卷积神经算法详解

一、定义 卷积神经算法&#xff08;Convolutional Neural Networks, CNN&#xff09;是深度学习领域中的一种重要算法&#xff0c;特别适用于处理图像相关的任务。以下是卷积神经算法的详细解释&#xff1a; 1. 基本概念 定义&#xff1a;卷积神经网络是一类包含卷积计算且具…

网络代理加速器:太阳HTTP的新一代解决方案(网络代理IP)

在当今数字化时代&#xff0c;网络速度与稳定性是企业和个人用户最为关注的重要问题之一。面对不稳定的网络连接&#xff0c;延迟高和速度慢等问题&#xff0c;传统的网络代理已经难以满足用户的需求。 为了解决这一问题&#xff0c;太阳HTTP推出了全新一代的网络代理加速器&a…

SQL Server 2016导入.bak文件到数据库里面步骤

1、打开SSMS管理器 选择数据库 右键 然后点击还原数据库。 2、选择设备 然后点击三个点 找到本地bak文件&#xff0c;然后点击确定 3、点击确定&#xff0c;会自动弹出来一个成功的提示。

消费增值模式引领业绩飙升与用户活跃

大家好&#xff0c;我是吴军&#xff0c;致力于为您揭示私域电商领域的独特魅力与机遇。 今日&#xff0c;我很高兴与大家分享一个激动人心的成功案例。我们的客户在短短一个月的时间里&#xff0c;业绩就飙升至上百万级别&#xff0c;其用户活跃度更是居高不下&#xff0c;日…