写一个Orillusion编辑器(伪)

news2024/11/24 14:42:30

界面效果

在这里插入图片描述

思路

  1. bootstrap控制界面效果
  2. jquery动态修改界面内容
  3. [Add]增加一个box
  4. [Play]导出play.html,打开play.html就可以看到程序运行效果

编辑器代码

<!DOCTYPE html>
<html>
<!-- TODO
1. 序列化数据,保存工程
2. 反序列化数据,打开工程 -->

<head>
	<meta charset="utf-8">
	<title>编辑器</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
	<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
	<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
	<style>
		body {
			margin: 0;
			width: 100%;
			height: 100%;
		}

		#project {
			position: absolute;
			z-index: 100;
		}

		#propertyList {
			position: absolute;
			z-index: 100;
			left: 80%;
			right: 0px;
			top: 25%;
		}

		#canvas {
			position: absolute;
			top: 0px;
			left: 0px;
			width: 100%;
			height: 100%;
			z-index: 0;
			background: transparent;
			touch-action: none;
			object-fit: cover;
		}
	</style>
</head>

<body οnresize="resize_canvas()">
	<div class="panel panel-default" id="project">
		<button type="button" class="btn btn-default" onclick="addBox()">Add</button>
		<button type="button" class="btn btn-default" onclick="startSimulate()">Play</button>
		<br />
		project
		<div class="panel-body">
			<ul class="list-group" id="projectUl">
			</ul>
		</div>
	</div>


	<div class="panel panel-default" id="propertyList">
		property
		<div class="panel-body" id="propertyListBody">
		</div>
	</div>

	<canvas id="canvas"></canvas>

	<!-- 可以定义ES模块的名称和对应地址 -->
	<script type="importmap">
	{
	  "imports": {
		"@orillusion/core": "https://unpkg.com/@orillusion/core/dist/orillusion.es.js",
		"@orillusion/stats": "https://unpkg.com/@orillusion/stats/dist/stats.es.js",
		"dat.gui": "https://npm.elemecdn.com/dat.gui@0.7.9/build/dat.gui.module.js"
	  }
	}
	</script>
	<!-- 可以使用自定义名称引入 -->
	<script type="module">

		import { Engine3D, Scene3D, Object3D, Camera3D, ComponentBase, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from '@orillusion/core'
		import { Stats } from '@orillusion/stats'
		import * as dat from 'dat.gui'

		window.startGame = startGame
		window.continueGame = continueGame
		window.endGame = endGame
		window.showMenu = showMenu
		window.hideMenu = hideMenu
		window.resize_canvas = resize_canvas
		window.initGame = initGame

		window.selectItem = selectItem
		window.startSimulate = startSimulate
		window.serializeGame = serializeGame
		window.saveFile = saveFile
		window.scene2Json = scene2Json

		window.addBox = addBox
		window.addCamera = addCamera
		window.addLight = addLight

		let gameState = 'none'
		let GUIHelp
		let gItemes = new Array()
		let scene3D
		let gCurrentItemIndex = -1
		let gItemsSize = 0
		let dataMap = []

		function startGame() {
			console.log("StartGame")
			if (gameState == 'pause') {
				continueGame()
				return
			}

			hideMenu()
			gameState = 'start'
			initGame()
		}

		function continueGame() {
			console.log("ContinueGame")
			hideMenu()
			if (gameState == 'none') {
				startGame()
			}
		}

		function endGame() {
			console.log("EndGame")
			// gameState = 'none'
		}

		function showMenu() {
			console.log("showMenu")
			// let canvas = document.getElementById('canvas')
			// canvas.setAttribute('style', 'display:none');

			if (gameState == 'start') {
				gameState = 'pause'
				Engine3D.pause()
			}

		}

		function hideMenu() {
			console.log("hideMenu")

			let canvas = document.getElementById('canvas')

			if (gameState == 'pause') {
				gameState = 'start'
				Engine3D.resume()
			}
		}

		function resize_canvas() {
			canvas = document.getElementById("canvas");
			if (canvas.width < window.innerWidth) {
				canvas.width = window.innerWidth;
			}

			if (canvas.height < window.innerHeight) {
				canvas.height = window.innerHeight;
			}
		}

		async function initGame() {

			// initializa engine
			await Engine3D.init({
				canvasConfig: { canvas }
			})
			// create new scene as root node
			scene3D = new Scene3D()
			// add an Atmospheric sky enviroment			
			addSky()
			// create camera
			let camera = addCamera()
			// create light
			addLight()
			// create new object

			// create a view with target scene and camera
			let view = new View3D()
			view.scene = scene3D
			view.camera = camera
			// start render
			Engine3D.startRenderView(view)

			const GUIHelp = new dat.GUI()
			GUIHelp.addFolder('Setting')

			GUIHelp.add({ menu: () => showMenu() }, 'menu')
		}

		function addSky() {
			let sky = scene3D.addComponent(AtmosphericComponent)
			sky.sunY = 0.6
			scene3D.name = 'scene3D'

			gCurrentItemIndex = gItemes.length
			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "scene3D" + "</button> </li>")

			gItemes.push({
				"obj": scene3D,
				"type": 'scene3D',
				"scriptContent": "",
				"scriptClassName": "",
			})
			return sky
		}

		function addBox() {
			gCurrentItemIndex = gItemes.length
			let name = 'box-' + gCurrentItemIndex

			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + name + "</button> </li>")

			const obj = new Object3D()
			obj.name = name
			// add MeshRenderer
			let mr = obj.addComponent(MeshRenderer)
			// set geometry
			mr.geometry = new BoxGeometry(5, 5, 5)
			// set material
			mr.material = new LitMaterial()
			// add object
			scene3D.addChild(obj)

			gItemes.push({
				"obj": obj,
				"type": 'box',
				"scriptContent": "",
				"scriptClassName": "",
			})
		}

		function addCamera() {
			let cameraObj = new Object3D()
			cameraObj.name = "camera"
			let camera = cameraObj.addComponent(Camera3D)
			// adjust camera view
			camera.perspective(60, Engine3D.aspect, 1, 5000.0)
			// set camera controller
			let controller = cameraObj.addComponent(HoverCameraController)
			controller.setCamera(0, 0, 15)
			// add camera node
			scene3D.addChild(cameraObj)

			gCurrentItemIndex = gItemes.length
			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "camera" + "</button> </li>")

			gItemes.push({
				"obj": cameraObj,
				"type": 'camera',
				"scriptContent": "",
				"scriptClassName": "",
			})

			return camera
		}

		function addLight() {
			let light = new Object3D()
			light.name = "light"
			// add direct light component
			let component = light.addComponent(DirectLight)
			// adjust lighting
			light.rotationX = 45
			light.rotationY = 30
			component.intensity = 1
			// add light object
			scene3D.addChild(light)

			gCurrentItemIndex = gItemes.length
			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "light" + "</button> </li>")

			gItemes.push({
				"obj": light,
				"type": 'light',
				"scriptContent": "",
				"scriptClassName": "",
			})
			return light
		}

		function selectItem(index) {
			console.log("selectItemIndex: " + index)
			gCurrentItemIndex = index
			showItemProrperty(gItemes[index])
		}

		function showItemProrperty(item) {
			let name = item['obj'].name
			console.log("showItemProrperty: " + item)
			$("#propertyListBody").empty()

			// let obj = scene3D.getObjectByName(name)
			let obj = item['obj']
			if (!obj) {
				console.warn("scene3D not find: " + name)
				return
			}
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">name</span><input type=\"text\" id=\"objName\" value=" + obj.name + "></input></div><br/>")

			let trans = obj.transform
			$("#propertyListBody").append("<p>transform</p>")
			$("#propertyListBody").append("<p>position</p>")
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">x</span><input type=\"text\" id=\"transX\" value=" + trans.x + "></input></div>")
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">y</span><input type=\"text\" id=\"transY\" value=" + trans.y + "></input></div>")
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">z</span><input type=\"text\" id=\"transZ\" value=" + trans.z + "></input></div>")

			$("#transX").change(function () { obj.x = $("#transX").val() })
			$("#transY").change(function () { obj.y = $("#transY").val() })
			$("#transZ").change(function () { obj.z = $("#transZ").val() })

			$("#propertyListBody").append("<p>script</p>")
			$("#propertyListBody").append("<textarea class=\"form-control\" rows=\"6\" id=\"textareaScript\">" + item.scriptContent + "</textarea>")
			// console.log("----------" + item.scriptContent + "-" + item.scriptClassName)
			$("#textareaScript").change(function () {
				let str = $("#textareaScript").val()

				let className = str.split(/\s* extends/)[0].replace('class', '')
				console.log("className = " + className + ";gCurrentItemIndex=" + gCurrentItemIndex + ";str=" + str)

				if (gCurrentItemIndex > -1) {
					gItemes[gCurrentItemIndex].scriptContent = str
					gItemes[gCurrentItemIndex].scriptClassName = className.trim()
				}
			})


		}

		function startSimulate() {
			serializeGame()
		}

		function serializeGame() {
			saveFile('play.html')
		}

		async function getFile() {
			// Open file picker and destructure the result the first handle
			const [fileHandle] = await window.showOpenFilePicker();
			const file = await fileHandle.getFile();
			return file;
		}

		async function saveFile(path) {
			// create a new handle
			const newHandle = await window.showSaveFilePicker();

			// create a FileSystemWritableFileStream to write to
			const writableStream = await newHandle.createWritable();
			
			dataMap = []
			let data = scene2Json()
			console.log("scene2Json=" + data)

			// write our file
			await writableStream.write("<!DOCTYPE html>");
			await writableStream.write("<html>");
			await writableStream.write("<head>\n");
			await writableStream.write("<meta charset=\"utf-8\">\n");
			await writableStream.write("<title>Play</title>\n");

			await writableStream.write("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
			await writableStream.write("<link rel=\"stylesheet\" href=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css\">\n");
			await writableStream.write("<script src=\"https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js\"><\/script>\n");
			await writableStream.write("<script src=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js\"><\/script>\n");
			await writableStream.write("<style>body {margin: 0;width: 100%;height: 100%;}\n");
			await writableStream.write("#canvas {position: absolute;top: 0px;left: 0px;width: 100%;height: 100%;z-index: 0;background: transparent;touch-action: none;object-fit: cover;}\n");
			await writableStream.write("</style>\n");
			await writableStream.write("</head>\n");
			await writableStream.write("<body οnresize=\"resize_canvas()\">\n");
			await writableStream.write("<canvas id=\"canvas\"></canvas>\n");
			await writableStream.write("<script type=\"importmap\">{\n");
			await writableStream.write(" \"imports\": {\n");
			await writableStream.write("\"@orillusion/core\": \"https://unpkg.com/@orillusion/core/dist/orillusion.es.js\",\n");
			await writableStream.write("\"@orillusion/stats\": \"https://unpkg.com/@orillusion/stats/dist/stats.es.js\",\n");
			await writableStream.write("\"dat.gui\": \"https://npm.elemecdn.com/dat.gui@0.7.9/build/dat.gui.module.js\"}}\n");
			await writableStream.write("<\/script>\n");
			await writableStream.write("<script type=\"module\">\n");
			await writableStream.write("import { Engine3D, Scene3D, Object3D, Camera3D, ComponentBase, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from '@orillusion/core'\n");
			await writableStream.write("import { Stats } from '@orillusion/stats'\n");
			await writableStream.write("import * as dat from 'dat.gui'\n");
			await writableStream.write("import * as localSprite from './localScript.mjs'\n");

			//script generate
			for(var s = 0; s < dataMap.length; s++){
				let strScript = dataMap[s].scriptContent
				if(strScript == "") continue;

				// console.log(s + ": " + strScript)
				await writableStream.write(strScript);
				await writableStream.write("\n");
			}
			

			//main generate
			await writableStream.write("async function initGame() {\n");
			await writableStream.write("await Engine3D.init({ canvasConfig: { canvas } })\n");
			await writableStream.write("let scene3D = new Scene3D()\n");
			await writableStream.write("let view = new View3D()\n");
			await writableStream.write("view.scene = scene3D\n");
			await writableStream.write("localSprite.testlocalScript()\n");

			await writableStream.write("localSprite.loadObj(scene3D, view, " + data + ")\n");
			
			for(var s = 0; s < dataMap.length; s++){		
				if(dataMap[s].scriptClassName != ""){					
					await writableStream.write("{ let obj = scene3D.getObjectByName(\"" + dataMap[s].name + "\"); ");
					await writableStream.write("obj.addComponent(" + dataMap[s].scriptClassName + ") }\n");
				}
			}

			await writableStream.write("Engine3D.startRenderView(view) }\n");
			await writableStream.write("initGame()\n");

			await writableStream.write("<\/script>\n");
			await writableStream.write("</body>\n");
			await writableStream.write("</html>");
			// close the file and write the contents to disk.
			await writableStream.close();
		}

		function scene2Json() {
			for (var i = 0; i < gItemes.length; i++) {
				let item = gItemes[i]
				console.log(item.obj.name)

				let mapobj = {
					name: item.obj.name,
					type: item.type,
					scriptContent: item.scriptContent,
					scriptClassName: item.scriptClassName,
					x: item.obj.x,
					y: item.obj.y,
					z: item.obj.z,
					scaleX: item.obj.scaleX,
					scaleY: item.obj.scaleY,
					scaleZ: item.obj.scaleZ,
					rotationX: item.obj.rotationX,
					rotationY: item.obj.rotationY,
					rotationZ: item.obj.rotationZ,
				}

				let mr = item.obj.getComponent(MeshRenderer)
				if (mr) {
					mapobj.MeshRenderer = {}
					let geometry = mr.geometry
					if (geometry) {
						mapobj.MeshRenderer.geometry = {}
						if (geometry.constructor === BoxGeometry) {
							console.log("===========BoxGeometry======================")
							mapobj.MeshRenderer.geometry.type = 'BoxGeometry'
							mapobj.MeshRenderer.geometry.width = geometry.width
							mapobj.MeshRenderer.geometry.height = geometry.height
							mapobj.MeshRenderer.geometry.depth = geometry.depth
						}
					}

				}

				dataMap.push(mapobj)
			}
			return JSON.stringify(dataMap)
		}

		startGame()

	</script>
</body>

</html>

play.html是编辑器自动生成的不用修改

localScript.mjs是方便play.html动态创建加载Object3D

/**
 * localScript
 * @version 0.1.0
 * @author CC
 * @license MIT
 */

// export const name = 'localScript';

export function testlocalScript() {
    console.log("testlocalScript~~~~~~~~~~~~~")
}

import { Engine3D, Scene3D, Object3D, Camera3D, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from "https://unpkg.com/@orillusion/core/dist/orillusion.es.js"
//Scene3D View3D
export function loadObj(scene3D, view, content) {
    console.log("loadObj~~~~~~~~~~~~~" + content)

    // let data = JSON.parse(content)
    for (var i = 0; i < content.length; i++) {
        let item = content[i]
        console.log("loadObj~~~~~~~~~~~~~" + i + item)

        if (item.type == "scene3D") {
            addSky(item, scene3D)
        }
        else if (item.type == "light") {
            addLight(item, scene3D)
        }
        else if (item.type == "camera") {
            let camera = addCamera(item, scene3D)
            view.camera = camera
        }
        else if (item.type == "box") {
            addBox(item, scene3D)
        }
    }
}


function addBox(item, scene3D) {
    const obj = new Object3D()
    obj.name = item.name
    // add MeshRenderer
    let mr = obj.addComponent(MeshRenderer)
    if (item.MeshRenderer) {
        if (item.MeshRenderer.geometry) {
            // set geometry
            mr.geometry = new BoxGeometry(item.MeshRenderer.geometry.width, 
                item.MeshRenderer.geometry.height, 
                item.MeshRenderer.geometry.depth)
        }
    }

    // set material
    mr.material = new LitMaterial()
    setObjInfo(item, obj)
    // add object
    scene3D.addChild(obj)
}

function addCamera(item, scene3D) {
    let cameraObj = new Object3D()
    cameraObj.name = item.name
    let camera = cameraObj.addComponent(Camera3D)
    // adjust camera view
    camera.perspective(60, Engine3D.aspect, 1, 5000.0)
    // set camera controller
    let controller = cameraObj.addComponent(HoverCameraController)
    controller.setCamera(0, 0, 15)
    // add camera node
    scene3D.addChild(cameraObj)

    return camera
}

function addLight(item, scene3D) {
    let light = new Object3D()
    light.name = item.name
    // add direct light component
    let component = light.addComponent(DirectLight)
    // adjust lighting
    light.rotationX = 45
    light.rotationY = 30
    component.intensity = 1
    // add light object
    scene3D.addChild(light)

    return light
}

function addSky(item, scene3D) {
    let sky = scene3D.addComponent(AtmosphericComponent)
    sky.sunY = 0.6
    return sky
}

function setObjInfo(item, obj){
    obj.x = item.x
    obj.y = item.y
    obj.z = item.z
    obj.rotationX = item.rotationX
    obj.rotationY = item.rotationY
    obj.rotationZ = item.rotationZ
}

物体的脚本也会动态写入play.html,所以支持物体脚本行为

play效果

请添加图片描述

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

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

相关文章

Python实现ACO蚁群优化算法优化随机森林回归模型(RandomForestRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蚁群优化算法(Ant Colony Optimization, ACO)是一种源于大自然生物世界的新的仿生进化算法&#xff0c…

腾讯安全SOC+荣获“鑫智奖”,助力金融业数智化转型

近日&#xff0c;由金科创新社主办&#xff0c;全球金融专业人士协会支持的“2023鑫智奖第五届金融数据智能优秀解决方案评选”榜单正式发布。腾讯安全申报的“SOC基于新一代安全日志大数据平台架构的高级威胁安全治理解决方案”获评“鑫智奖网络信息安全创新优秀解决方案”。 …

大数据分析平台释疑专用帖

大数据分析平台是大数据时代&#xff0c;企业数字化运营决策的一大关键平台&#xff0c;但初次接触大数据分析平台时&#xff0c;大家必然是问题多多的&#xff0c;本文将就几个比较常见的问题进行总结回答&#xff0c;希望对正在了解、选型大数据分析平台的大家有所帮助。 首…

Qt学习08:文本输入类与快捷键

文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 文章目录 QLineEditQTextEditQTextCursor QPlainTextQKeySequenceEdit QLineEdit QLineEdit是最基本的输入控件&#xff0c;常用于短行的文本输入。 构造函数 QLineEdit(const QString &contents, QWidget *parent …

07_scrapy的应用——获取电影数据(通过excel保存静态页面scrapy爬虫数据的模板/通过数据库保存)

0、前言: 一般我们自己创建的一些python项目,我们都需要创建虚拟环境,其中会下载很多包,也叫做依赖。但是我们在给他人分享我们的项目时,不能把虚拟环境打包发送给别人,因为每个人电脑系统不同,我们可以把依赖导出为依赖清单,然后别人有了我们的依赖清单,就可以用一条…

[网络工程师]-网络规划与设计-网络测试运行和维护(二)

4、局域网测试 局域网测试主要是检验网络是否为应用系统提供了稳定、高效的网络平台,如果网络系统不够稳定,网络应用就不可能快速稳定。对于常规的以太网进行系统测试,主要包括系统连通性、链路传输速率、吞吐率、传输时延、丢包率及链路层健康状况测试等基本功能测试。 4.…

用那种方式安装 ThinkPHP 5.0?

简单介绍 ThinkPHP是一个免费开源的&#xff0c;快速、简单的面向对象的轻量级PHP开发框架&#xff0c;是为了敏捷WEB应用开发和简化企业应用开发而诞生的。 ThinkPHP5.0版本是一个颠覆和重构版本&#xff0c;采用全新的架构思想&#xff0c;引入了更多的PHP新特性&#xff0c…

分享几个免费 AI 生成工具 (第一期)

今天来给大家分享几个国外免费的AI视频生成工具 Artflow ai https://app.artflow.ai Artflow.ai 是一款人工智能工具&#xff0c;旨在帮助用户创建自定义头像并让他们的故事栩栩如生。主要特点和优势包括&#xff1a; 自定义创作&#xff1a;从文本中生成角色、场景和声音&…

利用C语言实现十大经典排序算法的方法

排序算法 算法分类 —— 十种常见排序算法可以分为两大类&#xff1a; 比较类排序&#xff1a;通过比较来决定元素间的相对次序&#xff0c;由于其时间复杂度不能突破O(nlogn)&#xff0c;因此也称为非线性时间比较类排序。 非比较类排序&#xff1a;不通过比较来决定元素间…

《实战AI低代码》:一场新的软件工程革命

目录 五十年前的软件危机 二十年前的软件危机 今天的软件危机 革命性的新技术 AI低代码开发宣言 AI低代码开发原则 一场新的软件工程革命 AI低代码开发不仅是继面向过程,面向对象之后的一种新的抽象方式,也是继瀑布开发,敏捷开发之后的一种新的开发方法。 五十年前的…

QT学习07:五种按钮控件

文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 文章目录 抽象类&#xff1a;QAbstractButtonQPushButtonQToolButtonQCommandLinkButtonQRadioButtonQCheckBoxQButtonGroup 抽象类&#xff1a;QAbstractButton 是所有按钮类的祖先。 QAbstractButton的信号&#xff1a…

【appium】appium自动化入门之API(中)

上一篇介绍了在appium上启动app和两个定位元素的小工具使用方法&#xff0c;这篇就从appium的一种小方法&#xff1a;远程控制&#xff0c;以及如何把appium上的输入法调整成中文&#xff0c;算是两个小技巧吧 目录 正文 2.4 Remote 远程控制 前言 2.4.1 设置 IP 2.4.2 访问地址…

OpenMMLab-AI实战营第二期-课程笔记-Class 3:RTMPose关键点检测

Class 3&#xff1a;RTMPose关键点检测 文章目录 Class 3&#xff1a;RTMPose关键点检测概述安装相关库为了方便使用者快速上手 MMPose&#xff0c;这次课程有着丰富的示例代码脚本&#xff0c;以及详细的技术文档&#xff0c;包括安装、数据集准备、使用教程、常见问题解答等。…

Pycharm+pytest+allure打造高逼格的测试报告

目录 前言&#xff1a; 1、安装allure 2、安装allure-pytest 3、一个简单的用例test_simpe.py 4、在pycharm底部打开terminal 5、用allure美化报告 6、查看报告 总结&#xff1a; 前言&#xff1a; 今天分享的内容&#xff1a;在Pycharmpytest基础上使用allure打造高逼格…

Spring注入

前言 向一个普通的类中注入数据有什么方法&#xff1f; set方法 构造方法 依赖注入描述了在容器之间建立bean与bean之间依赖关系的过程&#xff0c;如果bean运行需要的是数字或者字符串呢&#xff1f; 引用类型 基本数据类型与String 依赖注入方式 setter注入 简单类型…

HUAWEI悦盒ec6108v9c 如何刷成海纳思系统(家用低功耗服务器,使用Home Assistant服务)

环境&#xff1a; 1.HW悦盒ec6108v9c一套 2.16G U盘 3.格式化软件USB_format.exe 4.固件 mv100-mdmo1g-usb-flash.zip&#xff08;底层是Ubuntu 20.04系统&#xff09; 5.十字螺丝刀 6.翘片/薄铲子 7.有线网络环境 8.镊子/回形针 问题描述&#xff1a; 最近玩智能家居…

最近我面了15个人,发现这些测试人都有个通病

最近公司离职好几个测试&#xff0c;也是赶上程序员跳槽的多&#xff0c;老板叫我招2个测试进来。4天时间面了15个人&#xff0c;怎么说呢&#xff0c;基本上没有符合要求的&#xff0c; 也没别的意思&#xff0c;因为我们公司小&#xff0c;开的薪水也不高&#xff0c;所以来…

Oracle中xmltype类型toObject函数用法实例

Oracle中xmltype类型toObject函数用法总结。 用法总结 xmltype是oracle中的type object类型。在实际使用中&#xff0c;可以当做xml对象来使用&#xff1a; set serveroutput ondrop type person_typex; create type person_typex is object (name varchar2(32),age number …

每天一道大厂SQL题【Day25】脉脉真题实战(一)每日活跃用户

文章目录 每天一道大厂SQL题【Day25】脉脉真题实战(一)每日活跃用户每日语录第25题&#xff1a;1. 需求列表1. 初级题: 每日活跃用户 思路分析(1) 创建表(2) 思路 答案获取加技术群讨论附表文末SQL小技巧 后记 每天一道大厂SQL题【Day25】脉脉真题实战(一)每日活跃用户 大家好…

【React】路由,Hooks

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录 路由Navigate导航组件 路由的嵌套useNavigate路由传递参数route配置抽取 路由 通过Link组件就可…