release/2.19.1.2503.01-业务线个税
parent
ed8f9a056b
commit
15446c6a6b
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
Binary file not shown.
After Width: | Height: | Size: 223 KiB |
Binary file not shown.
After Width: | Height: | Size: 361 KiB |
Binary file not shown.
After Width: | Height: | Size: 398 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 405 B |
Binary file not shown.
@ -0,0 +1,12 @@
|
||||
.threetemplate_container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:global {
|
||||
#TEMPLATE_CONTAINER {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
import Viewer from "@/lib/three/Viewer";
|
||||
import BoxGeometry from "./modules/BoxGeometry";
|
||||
import styles from "./index.less";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const PAGE_ID = "TEMPLATE_CONTAINER";
|
||||
const Template: React.FC<Props> = (props) => {
|
||||
const viewerRef = useRef<Viewer>();
|
||||
let boxGeometry: BoxGeometry;
|
||||
useEffect(() => {
|
||||
init();
|
||||
return () => {};
|
||||
}, []);
|
||||
const init = () => {
|
||||
viewerRef.current = new Viewer(PAGE_ID);
|
||||
const viewer = viewerRef.current;
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
viewer.addAxis();
|
||||
boxGeometry = new BoxGeometry(viewer);
|
||||
// boxGeometry.addBoxGeometry();
|
||||
const fnOnj = {
|
||||
fun: () => {
|
||||
const elapsedTime = clock.getElapsedTime();
|
||||
boxGeometry.cube.rotation.y = elapsedTime * Math.PI;
|
||||
},
|
||||
content: viewer
|
||||
};
|
||||
viewer?.addAnimate("cubeCraze", fnOnj);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.threetemplate_container}>
|
||||
<div id={PAGE_ID} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Template;
|
@ -0,0 +1,24 @@
|
||||
.login_container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
|
||||
.login_ground {
|
||||
position: absolute;
|
||||
z-index: 9998;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background-image: url("../../../../public/images/ground.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
#LOGIN_CONTAINER {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import React, { FC, useEffect, useRef } from "react";
|
||||
import Viewer from "./modules/Viewer";
|
||||
import Earth from "./modules/earth";
|
||||
import styles from "./index.less";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const PAGE_ID = "LOGIN_CONTAINER";
|
||||
const ThreeJSIndex: FC<Props> = (props) => {
|
||||
const viewerRef = useRef<Viewer>();
|
||||
useEffect(() => {
|
||||
init();
|
||||
return () => viewerRef.current?.destroy();
|
||||
}, []);
|
||||
// 加载
|
||||
const init = () => {
|
||||
viewerRef.current = new Viewer(PAGE_ID);
|
||||
const viewer = viewerRef.current;
|
||||
viewer.addStats();
|
||||
viewer.initSphereModal();
|
||||
const earthLoader = new Earth(viewer);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.login_container}>
|
||||
<div id={PAGE_ID} />
|
||||
<div className={styles.login_ground} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThreeJSIndex;
|
@ -0,0 +1,12 @@
|
||||
.threejs_container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:global {
|
||||
#DEMO_CONTAINER {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
import React, { FC, useEffect, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useMobStore } from "@/hooks";
|
||||
import * as THREE from "three";
|
||||
import Viewer from "./modules/Viewer";
|
||||
import ModelLoader from "./modules/ModelLoder";
|
||||
import BoxHelperWrap from "./modules/BoxHelperWrap";
|
||||
import { checkNameIncludes } from "@/utils/three";
|
||||
import Floors from "./modules/Floors";
|
||||
import { Object3DExtends } from "@/types";
|
||||
import styles from "./index.less";
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
type Props = OwnProps;
|
||||
|
||||
const PAGE_ID = "DEMO_CONTAINER";
|
||||
const ThreeJSIndex: FC<Props> = observer((props) => {
|
||||
const store = useMobStore("threeStore");
|
||||
const [rackList, setRackList] = useState<Object3DExtends[]>([]); //架子
|
||||
const [chairList, setChairList] = useState<Object3DExtends[]>([]); //椅子
|
||||
const viewerRef = useRef<Viewer>();
|
||||
let modelLoader: ModelLoader;
|
||||
let boxHelperWrap: BoxHelperWrap;
|
||||
useEffect(() => {
|
||||
init();
|
||||
initModel();
|
||||
return () => viewerRef.current?.destroy();
|
||||
}, []);
|
||||
/** 需要监听rackInfoList更新监听点击事件的函数 */
|
||||
useEffect(() => {
|
||||
if (!viewerRef.current) return;
|
||||
if (_.isEmpty(store?.raycasterObjects)) return;
|
||||
const viewer = viewerRef.current;
|
||||
onMouseClick(store?.raycasterObjects);
|
||||
}, [store?.raycasterObjects, viewerRef, viewerRef.current?.scene]);
|
||||
// 加载
|
||||
const init = () => {
|
||||
viewerRef.current = new Viewer(PAGE_ID);
|
||||
const viewer = viewerRef.current;
|
||||
viewer.addAxis();
|
||||
viewer.addStats();
|
||||
viewer.initRaycaster();
|
||||
|
||||
modelLoader = new ModelLoader(viewer);
|
||||
const floors = new Floors(viewer);
|
||||
floors.addGird(8, 25, 0x004444, 0x004444);
|
||||
// boxHelperWrap = new BoxHelperWrap(viewer);
|
||||
};
|
||||
// 加载模型
|
||||
const initModel = () => {
|
||||
modelLoader.loadModelToScene("/models/datacenter.glb", (baseModel) => {
|
||||
// 设置基础模型的缩放比例
|
||||
baseModel.setScalc(0.15);
|
||||
// 暂时注释掉旋转代码
|
||||
// baseModel.object.rotation.y = Math.PI / 2;
|
||||
// 获取实际的模型对象
|
||||
const model = baseModel.gltf.scene;
|
||||
model.position.set(0, 0, 0.3);
|
||||
// 为模型设置名称
|
||||
model.name = "机房";
|
||||
model.uuid = "机房";
|
||||
// 启用基础模型的投射阴影功能
|
||||
baseModel.openCastShadow();
|
||||
let rackList: Object3DExtends[] = []; // 机架列表
|
||||
let allList: Object3DExtends[] = []; // 所有的物体
|
||||
let chairList: Object3DExtends[] = []; // 椅子列表
|
||||
model.traverse((item) => {
|
||||
if (checkIsRack(item)) {
|
||||
rackList.push(item);
|
||||
}
|
||||
if (checkIsChair(item)) {
|
||||
chairList.push(item);
|
||||
}
|
||||
allList.push(item);
|
||||
if (item instanceof THREE.Mesh) {
|
||||
// 保存原始颜色数据,以及警告颜色
|
||||
if (item.isMesh) {
|
||||
item.material.warningColor = { r: 1, g: 0, b: 0, isColor: true };
|
||||
// 保存旧的材质
|
||||
(item as Object3DExtends).oldMaterial = item.material;
|
||||
}
|
||||
}
|
||||
});
|
||||
// dispatchDeviceListData({ type: "INIT", initData: rackList });
|
||||
setRackList(rackList);
|
||||
setChairList(chairList);
|
||||
const viewer = viewerRef.current;
|
||||
// 将 rackList 中的机架设置为 viewer 的射线检测对象
|
||||
viewer?.setRaycasterObjects([...allList]);
|
||||
});
|
||||
};
|
||||
const checkIsRack = (obj: THREE.Object3D): boolean => {
|
||||
return checkNameIncludes(obj, "rack");
|
||||
};
|
||||
const checkIsChair = (obj: THREE.Object3D): boolean => {
|
||||
return checkNameIncludes(obj, "chair");
|
||||
};
|
||||
const onClickChair = (selectedObject: THREE.Object3D) => {
|
||||
if (!checkNameIncludes(selectedObject, "chair")) return;
|
||||
const viewer = viewerRef.current;
|
||||
|
||||
viewer?.addCameraTween(new THREE.Vector3(0.05, 0.66, -2.54), 1000, () => {
|
||||
console.log("动画完成");
|
||||
console.log(viewer?.scene?.children);
|
||||
const sceneModels = viewer?.scene?.children;
|
||||
// const model = sceneModels?.find((model) => {
|
||||
// return model.name === "机房";
|
||||
// })!;
|
||||
// const floorModel = sceneModels?.find((model) => {
|
||||
// return model.name === "机房";
|
||||
// })
|
||||
viewer?.setRaycasterObjects([]); //
|
||||
sceneModels?.forEach((model) => {
|
||||
viewer?.scene.remove(model);
|
||||
});
|
||||
|
||||
// createRoom("room", new THREE.Vector3(0, 0, 0));
|
||||
});
|
||||
};
|
||||
const onMouseClick = (intersects: THREE.Intersection[]) => {
|
||||
if (!intersects.length) return;
|
||||
const selectedObject = intersects?.[0].object || {};
|
||||
// onClickRack(selectedObject);
|
||||
onClickChair(selectedObject);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.threejs_container}>
|
||||
<div id={PAGE_ID} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ThreeJSIndex;
|
@ -0,0 +1,20 @@
|
||||
import { BoxHelper, Color, Object3D } from "three";
|
||||
import type Viewer from "../Viewer";
|
||||
// 通过 BoxHelper 可以实现简单的鼠标选中的特效。
|
||||
// 也可以通过 OutlinePass 实现发光的特效。
|
||||
export default class BoxHelperWrap {
|
||||
protected viewer: Viewer;
|
||||
public boxHelper: BoxHelper;
|
||||
|
||||
constructor(viewer: Viewer, color?: number) {
|
||||
this.viewer = viewer;
|
||||
const boxColor = color === undefined ? 0x00ffff : color;
|
||||
this.boxHelper = new BoxHelper(new Object3D(), new Color(boxColor));
|
||||
|
||||
this.initBoxHelperWrap(); // 初始化
|
||||
}
|
||||
|
||||
private initBoxHelperWrap() {
|
||||
this.viewer.scene.add(this.boxHelper);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import * as THREE from "three";
|
||||
import type Viewer from "../Viewer";
|
||||
|
||||
export default class Floors {
|
||||
protected viewer: Viewer;
|
||||
public planeWidth = 1000;
|
||||
public planeHeight = 1000;
|
||||
|
||||
constructor(viewer: Viewer) {
|
||||
this.viewer = viewer;
|
||||
this.initFlooer();
|
||||
}
|
||||
|
||||
private initFlooer() {
|
||||
const ground = new THREE.Mesh(new THREE.PlaneGeometry(this.planeWidth, this.planeHeight), new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }));
|
||||
ground.rotation.x = -Math.PI / 2;
|
||||
ground.receiveShadow = true;
|
||||
this.viewer.scene.add(ground);
|
||||
}
|
||||
|
||||
/**网格辅助线 */
|
||||
public addGird(size = 1000, divisions = 20, colorCenterLine = 0x888888, colorGrid = 0x888888) {
|
||||
const grid = new THREE.GridHelper(size, divisions, colorCenterLine, colorGrid);
|
||||
this.viewer.scene.add(grid);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
import type Viewer from "../Viewer";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
|
||||
import BaseModel from "../BaseModel";
|
||||
|
||||
type LoadModelCallbackFn<T = any> = (arg: T) => any;
|
||||
|
||||
/**模型加载器 */
|
||||
export default class ModelLoder {
|
||||
protected viewer: Viewer;
|
||||
private gltfLoader: GLTFLoader;
|
||||
private readonly dracoLoader: DRACOLoader;
|
||||
|
||||
constructor(viewer: Viewer, dracolPath = "/draco/") {
|
||||
this.viewer = viewer;
|
||||
this.gltfLoader = new GLTFLoader();
|
||||
this.dracoLoader = new DRACOLoader();
|
||||
// 提供一个DracLoader实例来解码压缩网格数据
|
||||
// 没有这个会报错 dracolPath 默认放在public文件夹当中
|
||||
this.dracoLoader.setDecoderPath(dracolPath);
|
||||
this.gltfLoader.setDRACOLoader(this.dracoLoader);
|
||||
}
|
||||
|
||||
private loadModel(url: string, callback: LoadModelCallbackFn<BaseModel>) {
|
||||
this.gltfLoader.load(url, (gltf) => {
|
||||
const baseModel = new BaseModel(gltf, this.viewer);
|
||||
callback && callback(baseModel);
|
||||
});
|
||||
}
|
||||
|
||||
/**模型加载到场景 */
|
||||
public loadModelToScene(url: string, callback: LoadModelCallbackFn<BaseModel>) {
|
||||
this.loadModel(url, (model) => {
|
||||
this.viewer.scene.add(model.object);
|
||||
callback && callback(model);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
animate: "animate",
|
||||
dispose: "dispose",
|
||||
orbitChange: "orbitChange",
|
||||
load: {
|
||||
start: "load:start",
|
||||
processing: "load:processing",
|
||||
finish: "load:finish",
|
||||
},
|
||||
click: {
|
||||
raycaster: "click:raycaster",
|
||||
},
|
||||
dblclick: {
|
||||
raycaster: "dblclick:raycaster",
|
||||
},
|
||||
mousemove: {
|
||||
raycaster: "mousemove:raycaster",
|
||||
},
|
||||
resize: "resize",
|
||||
};
|
@ -0,0 +1,13 @@
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
import { Intersection } from "three";
|
||||
|
||||
export class ThreeStore {
|
||||
constructor() {
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@observable raycasterObjects: Intersection[] = [];
|
||||
@action setRaycasterIntersectObjects = (objects: Intersection[]) => (this.raycasterObjects = objects);
|
||||
}
|
||||
|
||||
export const threeStore = new ThreeStore();
|
@ -0,0 +1,18 @@
|
||||
import type { Object3D, Material, Color } from "three";
|
||||
export interface MaterialExtends extends Material {
|
||||
color?: Color;
|
||||
warningColor?: Color;
|
||||
}
|
||||
export type ModelExtendsData = {
|
||||
warn?: boolean;
|
||||
name: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
export interface Object3DExtends extends Object3D {
|
||||
isGroup?: boolean;
|
||||
isMesh?: boolean;
|
||||
material?: MaterialExtends;
|
||||
oldMaterial?: MaterialExtends;
|
||||
addData?: ModelExtendsData;
|
||||
dom?: HTMLElement;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import type { Object3D } from "three";
|
||||
|
||||
export function checkNameIncludes(obj: Object3D, str: string): boolean {
|
||||
return obj.name.includes(str);
|
||||
}
|
Loading…
Reference in New Issue