Unity之webgl端通过vue3接入腾讯云联络中心SDK

腾讯云联络中心SDK:云联络中心 Web-SDK 开发指南-文档中心-腾讯云 (tencent.com)

1 首先下载Demo

 1.1 对其进行解压

 1.2根据文档操作

查看README.md,根据说明设置server下的dev.js里的相关参数。

然后打开电脑终端,cd到项目的路径:

安装依赖

 

运行

​ 

1.3 运行demo

复制http://127.0.0.1:5173/在浏览器里输入,这时候会显示如下画面:

输入电话号码,点击拨打就会把电话打出去。

​ 

 2 在Unity端的操作

2.1 创建Unity工程

 新建一个Unity工程,在Assets/Plugins/WebGl下创建一个后缀为jslib的文件,记事本打开编写脚本如下:

mergeInto(LibraryManager.library, {
	ReportReady: function () {
		window.ReportReady()
	},
         
        TellPhone:function(typeName, phone){
             SendPhone(UTF8ToString(typeName), UTF8ToString(phone))
        }

});

 2.2 编写挂载对象UIPanel上的脚本

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class UIPanel : MonoBehaviour
{ 
    [DllImport("__Internal")]
    private static extern string ReportReady();
    [DllImport("__Internal")]
    private static extern string TellPhone(string type,string phone);
    public TextMeshProUGUI text;
    public TMP_InputField inputField;
    void Start()
    {
        ReportReady();//向vue报告脚本初始化完成
    }
    public void OpenPhone()
    {
        TellPhone("tellphone",inputField.text);
    }
    public void receiveMsgFromVue(string token) {
        text.text = token;
        Debug.Log("接受来自vue的消息 == " + token);
    }
}

2.3 Unity的UI界面

2.4最后打包webgl的包

放在tccc-demo-vue\src\路径下,如下图所示:

 

2.5改写index.html

打开index.html:

SendPhone是Unity发送给网页的方法,sendMsgToUnity方法是网页发送个Unity的方法。

index.html完整代码如下:

<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | Web731</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
  </head>
  <body>
    <div id="unity-container" class="unity-desktop">
      <canvas id="unity-canvas" width=1920 height=1080></canvas>
      <div id="unity-loading-bar">
        <div id="unity-logo"></div>
        <div id="unity-progress-bar-empty">
          <div id="unity-progress-bar-full"></div>
        </div>
      </div>
      <div id="unity-warning"> </div>
      <div id="unity-footer">
        <div id="unity-webgl-logo"></div>
        <div id="unity-fullscreen-button"></div>
        <div id="unity-build-title">Web731</div>
      </div>
    </div>
    <script>
      var container = document.querySelector("#unity-container");
      var canvas = document.querySelector("#unity-canvas");
      var loadingBar = document.querySelector("#unity-loading-bar");
      var progressBarFull = document.querySelector("#unity-progress-bar-full");
      var fullscreenButton = document.querySelector("#unity-fullscreen-button");
      var warningBanner = document.querySelector("#unity-warning");

      // Shows a temporary message banner/ribbon for a few seconds, or
      // a permanent error message on top of the canvas if type=='error'.
      // If type=='warning', a yellow highlight color is used.
      // Modify or remove this function to customize the visually presented
      // way that non-critical warnings and error messages are presented to the
      // user.
      function unityShowBanner(msg, type) {
        function updateBannerVisibility() {
          warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
        }
        var div = document.createElement('div');
        div.innerHTML = msg;
        warningBanner.appendChild(div);
        if (type == 'error') div.style = 'background: red; padding: 10px;';
        else {
          if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
          setTimeout(function() {
            warningBanner.removeChild(div);
            updateBannerVisibility();
          }, 5000);
        }
        updateBannerVisibility();
      }

      var buildUrl = "Build";
      var loaderUrl = buildUrl + "/web0803.loader.js";
      var config = {
        dataUrl: buildUrl + "/web0803.data.unityweb",
        frameworkUrl: buildUrl + "/web0803.framework.js.unityweb",
        codeUrl: buildUrl + "/web0803.wasm.unityweb",
        streamingAssetsUrl: "StreamingAssets",
        companyName: "DefaultCompany",
        productName: "Web731",
        productVersion: "0.1",
        showBanner: unityShowBanner,
      };

      // By default Unity keeps WebGL canvas render target size matched with
      // the DOM size of the canvas element (scaled by window.devicePixelRatio)
      // Set this to false if you want to decouple this synchronization from
      // happening inside the engine, and you would instead like to size up
      // the canvas DOM size and WebGL render target sizes yourself.
      // config.matchWebGLToCanvasSize = false;

      if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
        container.className = "unity-mobile";
        // Avoid draining fillrate performance on mobile devices,
        // and default/override low DPI mode on mobile browsers.
        config.devicePixelRatio = 1;
        unityShowBanner('WebGL builds are not supported on mobile devices.');
      } else {
        canvas.style.width = "1920px";
        canvas.style.height = "1080px";
      }
      loadingBar.style.display = "block";

      var script = document.createElement("script");
      script.src = loaderUrl;
      script.onload = () => {
        createUnityInstance(canvas, config, (progress) => {
          progressBarFull.style.width = 100 * progress + "%";
        }).then((unityInstance) => {
          loadingBar.style.display = "none";
          fullscreenButton.onclick = () => {
            unityInstance.SetFullscreen(1);
          };
          unityInstanceV = unityInstance;
        }).catch((message) => {
          alert(message);
        });
      };
      document.body.appendChild(script);

  var unityInstanceV;
  function ReportReady() {
    window.parent.postMessage({guid:"",event:"ReportReady"}, "*");
  }
  function SendPhone(_type,_phone)
  {
    // alert(s);
    if (_type == "tellphone"){
      window.parent.postMessage({guid:"",event:_type,phone:_phone}, "*");
    }else {
      window.parent.postMessage({guid:_type,event:"guid"}, "*");
    }
  }

  function sendMsgToUnity(obj) {
    unityInstanceV.SendMessage('UIPanel','receiveMsgFromVue',JSON.stringify(obj))
  }

    </script>
  </body>
</html>

2.6 修改Container.vue脚本

增加和Unity交互的方法

 把原先显示的界面代码删除掉<div class="container"> </div>

 style 部分也删掉

对Vue不熟悉,我的理解是这样的(理解不对请留言指正)

其中 

onMounted(()=>{
        window.addEventListener('message', unityWatch,true)
    }) 

是事件,对Unity发送来的消息进行监听。

function  vueSendToUnity(){
      console.log(statusMap[status.value])
      unityIframe.value.contentWindow.sendMsgToUnity({userId:'****',状态:status.value|| '加载中...'})  
}

是vue把消息发送到Unity端。

<template>
  <div >
<iframe id="iframe" ref="unityIframe" src="/src/unity/index.html" style="width:100%;height:100vh" frameborder="0" scrolling="auto" /> 
  </div>
</template>

是Unity部分进行显示(其中stytle的height:100% 不起作用,有知道的请留言,谢谢,所以我改为了height:100vh)。

Container.vue修改后代码如下:

<script setup>
import { ref, onMounted } from 'vue'
const wechatGroupImg = 'https://tccc.qcloud.com/assets/wechatGroup.png';
const arrowImg = 'https://tccc.qcloud.com/assets/arrow.png';

const seat = ref('')
const status = ref('')
const number = ref('')
const loading = ref(false)
const isError = ref(false)
const errorField = ref('')

const statusMap = {
  offline: '已下线',
  disconnect: '网络断开,重连中',
  free: '空闲中',
  busy: '忙碌中',
  rest: '小休中',
  countdown: '话后倒计时',
  arrange: '话后整理中',
  notReady: '示忙中',
}

const errorFieldMap = {
  'InvalidParameterValue.InstanceNotExist': 'sdkAppId',
  'InvalidParameterValue.AccountNotExist': 'userId',
  'AuthFailure.SignatureFailure': 'secretKey或secretId',
  'AuthFailure.SecretIdNotFound': 'secretId',
};

const injectTCCC = ({ token, sdkAppId, userId, sdkUrl }) => {
  const scriptDom = document.createElement('script')
  scriptDom.setAttribute('crossorigin', 'anonymous')
  scriptDom.dataset.token = token
  scriptDom.dataset.sdkAppId = sdkAppId
  scriptDom.dataset.userid = userId
  scriptDom.src = sdkUrl
  document.body.appendChild(scriptDom)
  scriptDom.addEventListener('load', () => {
    // ready事件必须监听,否则容易发生tccc不存在的错误,所有呼入呼出的逻辑必须在ready事件触发后才可以调用
    window.tccc.on('ready', () => {
      // 以下为Demo逻辑,非业务必须。业务代码主要实现都在这个部分
      const statusVal = window.tccc.Agent.getStatus()
      status.value = statusVal;
      seat.value = userId;
    })
    // 以下为Demo逻辑,非接入必须
    setInterval(() => {
      const statusVal = window.tccc.Agent.getStatus()
      status.value = statusVal;
    }, 200)
  })
}

onMounted(() => {
  // 获取Token的方法必须在页面初始化时第一优先级调用
  fetch('/loginTCCC')
    .then((res) => res.json())
    .then((res) => {
      // 以下为Demo逻辑,需要替换为业务逻辑
      if (res.code) {
        if (res.type) {
          isError.value = true;
          errorField.value = errorFieldMap[res.code]
        } else {
          isError.value = true;
          if (errorFieldMap[res.code]) {
            errorField.value = errorFieldMap[res.code]
          } else {
            alert(res.errMsg);
          }
          return;
        }
      }
      // 调用成功后才可以开始执行TCCC的注入
      injectTCCC({
        token: res.token,
        userId: res.userId,
        sdkUrl: res.sdkUrl,
        sdkAppId: res.sdkAppId,
      })
    })
    .catch((error) => {
      console.error(`获取Token失败:${error.message}`)
    })
})

const handleCallout = async () => {
  if (loading.value) {
    return
  }
  loading.value = true
  // 调用呼出方法的核心代码
  try {
    await window.tccc.Call.startOutboundCall({ phoneNumber: number.value })
  } catch (error) {
    console.error(`呼出失败:${error.message}`)
  } finally {
    loading.value = false
  }
}


 onMounted(()=>{
        window.addEventListener('message', unityWatch,true)
    }) 
  function unityWatch(e){
      console.log('unityWatch方法调用 e==' + e.data.guid + '    event=' + e.data.event)
      if(e.data.event=='tellphone'){
            handleCalloutByUnity(e.data.phone)  
            vueSendToUnity()  
      }
} 
  //Unity端调用vue里的打电话功能
const handleCalloutByUnity = async (phone) => {
  if (loading.value) {
    return
  }
  loading.value = true
  // 调用呼出方法的核心代码
  try {
    await window.tccc.Call.startOutboundCall({ phoneNumber: phone })
  } catch (error) {
    console.error(`呼出失败:${error.message}`)
  } finally {
    loading.value = false
  }
}

const unityIframe = ref('unityIframe')
function  vueSendToUnity(){
      console.log(statusMap[status.value])
      unityIframe.value.contentWindow.sendMsgToUnity({userId:'****',状态:status.value|| '加载中...'})      
}

</script>

<template>
  <div >
<iframe id="iframe" ref="unityIframe" src="/src/unity/index.html" style="width:100%;height:100vh" frameborder="0" scrolling="auto" /> 
  </div>
</template>

2.7 测试运行

测试运行时得保证终端npm run dev在运行中

 在Unity 的界面上输入手机号点击拨打,电话打了出去,同时Unity端收到了vue发送过来的消息。

2.8 网页内全屏

这时候如果需要Unity在网页内全屏,且不显示滚动条,需要打开Unity的index.html进行再次修改:

 

 

 

 

 index.html的修改后如下:

<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | Web731</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
  </head>
  <body>
    <div id="unity-container" style="width: 100%;height:100%">
      <canvas id="unity-canvas" width=auto height=auto></canvas>
      <div id="unity-loading-bar">
        <div id="unity-logo"></div>
        <div id="unity-progress-bar-empty">
          <div id="unity-progress-bar-full"></div>
        </div>
      </div>
      <div id="unity-warning"> </div>
     
    </div>
    <script>
      var container = document.querySelector("#unity-container");
      var canvas = document.querySelector("#unity-canvas");
      var loadingBar = document.querySelector("#unity-loading-bar");
      var progressBarFull = document.querySelector("#unity-progress-bar-full");
      //var fullscreenButton = document.querySelector("#unity-fullscreen-button");
      var warningBanner = document.querySelector("#unity-warning");

      // Shows a temporary message banner/ribbon for a few seconds, or
      // a permanent error message on top of the canvas if type=='error'.
      // If type=='warning', a yellow highlight color is used.
      // Modify or remove this function to customize the visually presented
      // way that non-critical warnings and error messages are presented to the
      // user.
      function unityShowBanner(msg, type) {
        function updateBannerVisibility() {
          warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
        }
        var div = document.createElement('div');
        div.innerHTML = msg;
        warningBanner.appendChild(div);
        if (type == 'error') div.style = 'background: red; padding: 10px;';
        else {
          if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
          setTimeout(function() {
            warningBanner.removeChild(div);
            updateBannerVisibility();
          }, 5000);
        }
        updateBannerVisibility();
      }

      var buildUrl = "Build";
      var loaderUrl = buildUrl + "/web0803.loader.js";
      var config = {
        dataUrl: buildUrl + "/web0803.data.unityweb",
        frameworkUrl: buildUrl + "/web0803.framework.js.unityweb",
        codeUrl: buildUrl + "/web0803.wasm.unityweb",
        streamingAssetsUrl: "StreamingAssets",
        companyName: "DefaultCompany",
        productName: "Web731",
        productVersion: "0.1",
        showBanner: unityShowBanner,
      };

      // By default Unity keeps WebGL canvas render target size matched with
      // the DOM size of the canvas element (scaled by window.devicePixelRatio)
      // Set this to false if you want to decouple this synchronization from
      // happening inside the engine, and you would instead like to size up
      // the canvas DOM size and WebGL render target sizes yourself.
      // config.matchWebGLToCanvasSize = false;

      if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
        var meta = document.createElement('meta');
           meta.name = 'viewport';
           meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
           document.getElementsByTagName('head')[0].appendChild(meta);
           container.className = "unity-mobile";
         
           canvas.style.width = window.innerWidth + 'px';
           canvas.style.height = window.innerHeight + 'px';


       unityShowBanner('暂不支持移动端...');
     } else {	  
      canvas.style.height= document.documentElement.clientHeight+"px";
      canvas.style.width = document.documentElement.clientWidth+"px"; 	  
     }
      loadingBar.style.display = "block";

      var script = document.createElement("script");
      script.src = loaderUrl;
      script.onload = () => {
        createUnityInstance(canvas, config, (progress) => {
          progressBarFull.style.width = 100 * progress + "%";
        }).then((unityInstance) => {
          loadingBar.style.display = "none";
          //fullscreenButton.onclick = () => {
          //  unityInstance.SetFullscreen(1);
          //};
          unityInstanceV = unityInstance;
        }).catch((message) => {
          alert(message);
        });
      };
      document.body.appendChild(script);

  var unityInstanceV;
  function ReportReady() {
    window.parent.postMessage({guid:"",event:"ReportReady"}, "*");
  }
  function SendPhone(_type,_phone)
  {
    // alert(s);
    if (_type == "tellphone"){
      window.parent.postMessage({guid:"",event:_type,phone:_phone}, "*");
    }else {
      window.parent.postMessage({guid:_type,event:"guid"}, "*");
    }
  }

  function sendMsgToUnity(obj) {
    unityInstanceV.SendMessage('UIPanel','receiveMsgFromVue',JSON.stringify(obj))
  }

    </script>
  </body>
</html>

打开Unity\TemplateData路径下的style.css增加:

html,body{width:100%;height:100%;margin:0;padding:0;overflow:hidden;}
.webgl-content{width: 100%; height: 100%;}
.unityContainer{width: 100%; height: 100%;}

style.css完整脚本如下:

body { padding: 0; margin: 0 }
#unity-container { position: absolute }
#unity-container.unity-desktop { left: 50%; top: 50%; transform: translate(-50%, -50%) }
#unity-container.unity-mobile { width: 100%; height: 100% }
#unity-canvas { background: #231F20 }
.unity-mobile #unity-canvas { width: 100%; height: 100% }
#unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none }
#unity-logo { width: 154px; height: 130px; background: url('unity-logo-dark.png') no-repeat center }
#unity-progress-bar-empty { width: 141px; height: 18px; margin-top: 10px; background: url('progress-bar-empty-dark.png') no-repeat center }
#unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png') no-repeat center }
#unity-footer { position: relative }
.unity-mobile #unity-footer { display: none }
#unity-webgl-logo { float:left; width: 204px; height: 38px; background: url('webgl-logo.png') no-repeat center }
#unity-build-title { float: right; margin-right: 10px; line-height: 38px; font-family: arial; font-size: 18px }
#unity-fullscreen-button { float: right; width: 38px; height: 38px; background: url('fullscreen-button.png') no-repeat center }
#unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }


html,body{width:100%;height:100%;margin:0;padding:0;overflow:hidden;}
.webgl-content{width: 100%; height: 100%;}
.unityContainer{width: 100%; height: 100%;}

 但是vue的这个右侧还是有滚动条,还没找到隐藏的方法,有知道的同学请留言,谢谢。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ 智能指针

C 智能指针 为什么需要智能指针&#xff1f;auto_ptrunique_ptrshared_ptrweak_ptr智能指针的核心实现unique_ptr的简单实现Counter的简单实现share_ptr的简单实现weak_ptr简单实现 shared_ptr的线程安全性多线程无保护读写 shared_ptr 可能出现的问题make_shared()share_ptr/u…

类文件一些内容

1、类加载 将类的字节码加载到JVM中&#xff0c;并转换为可以被JVM运行的数据结构的过程 类文件结构

8月3日上课内容 LNMP精讲

LNMP&#xff1a;目前成熟的企业网站的应用模式之一&#xff0c;指的是一套协作工作的系统和相关文件 能够提供静态页面服务&#xff0c;也可以提供动态web服务。 这是一个缩写 L linux系统&#xff0c;操作系统。 N nginx网站服务&#xff0c;前端&#xff0c;提供前端的静…

【NLP概念源和流】 01-稀疏文档表示(第 1/20 部分)

一、介绍 自然语言处理(NLP)是计算方法的应用,不仅可以从文本中提取信息,还可以在其上对不同的应用程序进行建模。所有基于语言的文本都有系统的结构或规则,通常被称为形态学,例如“跳跃”的过去时总是“跳跃”。对于人类来说,这种形态学的理解是显而易见的。 在这篇介…

maven下载安装及初次使用相关配置

maven下载按照及初次使用相关配置 一、下载 与安装 下载完解压放在文件夹中即可&#xff01; 依赖Java&#xff0c;需要配置JAVA_HOME设置MAVEN自身的运行环境&#xff0c;需要配置MAVEN_HOME&#xff08;参考安装java&#xff09;测试环境配置结果 MVN测试成功&#xff01…

Eureka增加账号密码认证登录

一、业务背景 注册中心Eureka在微服务开发中经常使用到&#xff0c;用来管理发布的微服务&#xff0c;供前端或者外部调用。但是如果放到生产环境&#xff0c;我们直接通过URL访问的话&#xff0c;这显然是不安全的。 所以需要给注册中心加上登录认证。 通过账号和密码认证进行…

iMX6ULL应用移植 | 移植 infoNES 模拟器(重玩经典NES游戏)

没玩过NES游戏的童年&#xff0c;可能不是80后的童年。我们小时候是从玩FC开始接触游戏机的&#xff0c;那时真的是红极一时啊&#xff0c;我上初中时还省吃俭用买了一台小霸王&#xff0c;暑假里把电视机都给打爆了&#xff01;那时任天堂单是FC机的主机的发售收入就超过全美的…

性能测试jmeter连接数据库jdbc(sql server举例)

一、下载第三方工具包驱动数据库 1. 因为JMeter本身没有提供链接数据库的功能&#xff0c;所以我们需要借助第三方的工具包来实现。 &#xff08;有这个jar包之后&#xff0c;jmeter可以发起jdbc请求&#xff0c;没有这个jar包&#xff0c;也有jdbc取样器&#xff0c;但不能发起…

Sketch打不开AI文件?转换方法在这里

1、对比设计软件 Sketch 与 AI 软件功能 Sketch 与 Illustrator 都是行业内优秀的矢量图形设计软件&#xff0c;各有千秋。Sketch 从 2010 年面世&#xff0c;专注 APP 界面设计&#xff0c;深受初学者与专业人士喜爱。Illustrator 拥有更悠久的历史&#xff0c;是处理复杂图标…

基于dockerfile构建sshd、httpd、nginx、tomcat、mysql、lnmp、redis镜像

一、镜像概述 Docker 镜像是Docker容器技术中的核心&#xff0c;也是应用打包构建发布的标准格式。一个完整的镜像可以支撑多个容器的运行&#xff0c;在Docker的整个使用过程中&#xff0c;进入一个已经定型的容器之后&#xff0c;就可以在容器中进行操作&#xff0c;最常见的…

JVM面试题--JVM组成

JVM是什么 Java Virtual Machine Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 运行流程 什么是程序计数器&#xff1f; 程序计数器&#xff1a;线程私有的&#xff0c;内部保存的字节码的行号。用于记录正在执行的字节码指令的地址。 我们知道ja…

16.M端事件和JS插件

16.1移动端 移动端也有自己独特的地方 ●触屏事件touch (也称触摸事件)&#xff0c;Android 和I0S都有。 ●touch对象代表一个触摸点。触摸点可能是一根手指&#xff0c;也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。 ●常见的触屏事件如下: …

读书笔记-《ON JAVA 中文版》-摘要21第十九章 类型信息-2]

文章目录 第十九章 类型信息7. 动态代理8. Optional类9. 接口和类型10. 本章小结 第十九章 类型信息 7. 动态代理 代理是基本的设计模式之一。一个对象封装真实对象&#xff0c;代替其提供其他或不同的操作—这些操作通常涉及到与“真实”对象的通信&#xff0c;因此代理通常…

IOS看书最终选择|源阅读转换|开源阅读|IOS自签

环境&#xff1a;IOS想使用 换源阅读 问题&#xff1a;换新手机&#xff0c;源阅读下架后&#xff0c;没有好的APP阅读小说 解决办法&#xff1a;自签APP 转换源仓库书源 最终预览 &#xff1a;https://rc.real9.cn/ 背景&#xff1a;自从我换了新iPhone手机&#xff0c;就无法…

单价20块蓝牙耳机卖爆越南市场,现象级爆款出现?

以儒道为文化底蕴的越南&#xff0c;是与中国最为相近的东南亚国家&#xff0c;"快速增长的劳动人口相对年轻的社会群体"是很多人对越南这个国家的基本认知。背靠庞大的Z世代用户群体&#xff0c;越南社会年轻化消费需求暴涨&#xff0c;手机与数码品类商品作为“年轻…

Maven依赖爆红的几种解决思路

说明&#xff1a;本文介绍Maven依赖爆红&#xff0c;排查错误的几种思路&#xff1b; 思路一&#xff1a;删除本地仓库.lastupdate文件&#xff1b; 找到本地maven仓库&#xff0c;全局搜索.lastupdate文件&#xff0c;把搜索出来的文件全部删除。.lastupdate后缀名的文件&am…

将word每页页眉单独设置

在进行论文排版的时候&#xff0c;总是会出现页眉的页码设置问题&#xff0c;比如出现奇数或偶数页码一致&#xff0c;尝试将前面页码改掉&#xff0c;后面再修改前面也进行了变动&#xff0c;将每页页眉单独设置&#xff1a; &#xff08;1&#xff09;在第一页的最后一行输入…

完全背包(从二维到一维)

图片来源活动 - AcWing 有 N件物品和一个容量为 V 的背包&#xff0c;每件物品有各自的价值且能被选择无数次&#xff0c;要求在有限的背包容量下&#xff0c;装入的物品总价值最大。 一&#xff0c;暴力解法&#xff08;容易超时&#xff09; #include<iostream> usi…

37.利用linprog解 有约束条件多元变量函数最小值(matlab程序)

1.简述 linprog函数主要用来求线型规划中的最小值问题&#xff08;最大值的镜像问题&#xff0c;求最大值只需要加个“-”&#xff09; 2. 算法结构及使用方法 针对约束条件为Axb或Ax≤b的问题 2.1 linprog函数 xlinprog(f,A,b) xlinprog(f,A,b,Aeq,beq) xlinprog(f,A,b,Aeq,…

C语言每日一题:13《数据结构》环形链表。

题目链接&#xff1a; 一.环形链表运动基础。 使用快慢指针利用相对移动的思想&#xff1a; 1.第一种情况&#xff1a; 1,令快指针&#xff08;fast&#xff09;速度为2. 2.慢指针&#xff08;slow&#xff09;速度为1. 3.以慢指针进入环中开始。 4。假设slow刚刚进入环中fast…