Quellcode durchsuchen

chore: 项目初始化

chenlei vor 2 Jahren
Ursprung
Commit
7fd13d804a

+ 3 - 0
.vscode/settings.json

@@ -0,0 +1,3 @@
+{
+  "typescript.tsdk": "node_modules\\typescript\\lib"
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 29400
package-lock.json


+ 6 - 0
package.json

@@ -10,8 +10,10 @@
     "@types/node": "^16.18.38",
     "@types/react": "^18.2.14",
     "@types/react-dom": "^18.2.6",
+    "classnames": "^2.3.2",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
+    "react-router-dom": "^6.14.1",
     "react-scripts": "5.0.1",
     "typescript": "^4.9.5",
     "web-vitals": "^2.1.4"
@@ -39,5 +41,9 @@
       "last 1 firefox version",
       "last 1 safari version"
     ]
+  },
+  "devDependencies": {
+    "node-sass": "6.x",
+    "sass-loader": "^13.3.2"
   }
 }

+ 10 - 22
public/index.html

@@ -1,30 +1,18 @@
 <!DOCTYPE html>
 <html lang="en">
   <head>
-    <meta charset="utf-8" />
-    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
-    <meta name="viewport" content="width=device-width, initial-scale=1" />
-    <meta name="theme-color" content="#000000" />
+    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
     <meta
-      name="description"
-      content="Web site created using create-react-app"
+      content="width=device-width,initial-scale=1,user-scalable=no"
+      name="viewport"
     />
-    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
-    <!--
-      manifest.json provides metadata used when your web app is installed on a
-      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-    -->
-    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
-    <!--
-      Notice the use of %PUBLIC_URL% in the tags above.
-      It will be replaced with the URL of the `public` folder during the build.
-      Only files inside the `public` folder can be referenced from the HTML.
-
-      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
-      work correctly both with client-side routing and a non-root public URL.
-      Learn how to configure a non-root public URL by running `npm run build`.
-    -->
-    <title>React App</title>
+    <meta name="apple-mobile-web-app-capable" content="yes" />
+    <meta name="apple-touch-fullscreen" content="yes" />
+    <meta name="format-detection" content="telephone=no,address=no" />
+    <meta name="apple-mobile-web-app-status-bar-style" content="white" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+    <title>上海市工业博物馆</title>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>

Datei-Diff unterdrückt, da er zu groß ist
+ 8692 - 0
public/js/4dage.js


BIN
public/logo192.png


BIN
public/logo512.png


+ 0 - 25
public/manifest.json

@@ -1,25 +0,0 @@
-{
-  "short_name": "React App",
-  "name": "Create React App Sample",
-  "icons": [
-    {
-      "src": "favicon.ico",
-      "sizes": "64x64 32x32 24x24 16x16",
-      "type": "image/x-icon"
-    },
-    {
-      "src": "logo192.png",
-      "type": "image/png",
-      "sizes": "192x192"
-    },
-    {
-      "src": "logo512.png",
-      "type": "image/png",
-      "sizes": "512x512"
-    }
-  ],
-  "start_url": ".",
-  "display": "standalone",
-  "theme_color": "#000000",
-  "background_color": "#ffffff"
-}

+ 53 - 0
public/model.html

@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <script src="./js/4dage.js"></script>
+    <title>Document</title>
+    <style>
+      html {
+        overflow: hidden;
+      }
+
+      .bacBox {
+        opacity: 1;
+        pointer-events: auto;
+        position: absolute;
+        z-index: 998;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        transition: all 1s;
+      }
+    </style>
+  </head>
+
+  <body>
+    <div id="ui"></div>
+    <div class="bacBox"></div>
+    <script>
+      let loaded = false;
+      const number = getQueryVariable("m");
+
+      window.autoRotate = true; // 是否自动旋转
+
+      function initModel(isDev) {
+        if (loaded) return;
+        fdage.embed(isDev ? "https://hnbwg.4dage.com" + number : number, {
+          transparentBackground: true,
+          width: 800,
+          height: 600,
+          autoStart: true,
+          fullFrame: true,
+          pagePreset: false,
+        });
+        loaded = true;
+      }
+
+      window.parent.postMessage("modelPageLoaded", location.origin);
+    </script>
+  </body>
+</html>

+ 0 - 3
public/robots.txt

@@ -1,3 +0,0 @@
-# https://www.robotstxt.org/robotstxt.html
-User-agent: *
-Disallow:

+ 35 - 31
src/App.css

@@ -1,38 +1,42 @@
-.App {
-  text-align: center;
+body,
+ol,
+ul,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+th,
+td,
+dl,
+dd,
+form,
+fieldset,
+legend,
+input,
+textarea,
+select {
+  margin: 0;
+  padding: 0;
 }
 
-.App-logo {
-  height: 40vmin;
-  pointer-events: none;
+body {
+  font-family: Source Han Sans CN-Bold, Source Han Sans CN;
+  font-size: 16px;
 }
 
-@media (prefers-reduced-motion: no-preference) {
-  .App-logo {
-    animation: App-logo-spin infinite 20s linear;
-  }
+.limit-line {
+  display: -webkit-box;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+  word-break: break-all;
+  word-wrap: break-word;
 }
 
-.App-header {
-  background-color: #282c34;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  font-size: calc(10px + 2vmin);
-  color: white;
-}
-
-.App-link {
-  color: #61dafb;
-}
-
-@keyframes App-logo-spin {
-  from {
-    transform: rotate(0deg);
-  }
-  to {
-    transform: rotate(360deg);
-  }
+.line-2 {
+  -webkit-line-clamp: 2;
 }

+ 0 - 9
src/App.test.tsx

@@ -1,9 +0,0 @@
-import React from 'react';
-import { render, screen } from '@testing-library/react';
-import App from './App';
-
-test('renders learn react link', () => {
-  render(<App />);
-  const linkElement = screen.getByText(/learn react/i);
-  expect(linkElement).toBeInTheDocument();
-});

+ 7 - 17
src/App.tsx

@@ -1,24 +1,14 @@
-import React from 'react';
-import logo from './logo.svg';
-import './App.css';
+import React from "react";
+import "./App.css";
+import { Route, Routes } from "react-router-dom";
+import ModelInfoPage from "./pages/model-info";
 
 function App() {
   return (
     <div className="App">
-      <header className="App-header">
-        <img src={logo} className="App-logo" alt="logo" />
-        <p>
-          Edit <code>src/App.tsx</code> and save to reload.
-        </p>
-        <a
-          className="App-link"
-          href="https://reactjs.org"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Learn React
-        </a>
-      </header>
+      <Routes>
+        <Route path="/model" element={<ModelInfoPage />} />
+      </Routes>
     </div>
   );
 }

+ 0 - 13
src/index.css

@@ -1,13 +0,0 @@
-body {
-  margin: 0;
-  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
-    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
-    sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-code {
-  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
-    monospace;
-}

+ 10 - 8
src/index.tsx

@@ -1,19 +1,21 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import './index.css';
-import App from './App';
-import reportWebVitals from './reportWebVitals';
+import React from "react";
+import ReactDOM from "react-dom/client";
+import { BrowserRouter } from "react-router-dom";
+import App from "./App";
+// import reportWebVitals from './reportWebVitals';
 
 const root = ReactDOM.createRoot(
-  document.getElementById('root') as HTMLElement
+  document.getElementById("root") as HTMLElement
 );
 root.render(
   <React.StrictMode>
-    <App />
+    <BrowserRouter>
+      <App />
+    </BrowserRouter>
   </React.StrictMode>
 );
 
 // If you want to start measuring performance in your app, pass a function
 // to log results (for example: reportWebVitals(console.log))
 // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-reportWebVitals();
+// reportWebVitals();

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 1
src/logo.svg


BIN
src/pages/model-info/images/header-bd.png


BIN
src/pages/model-info/images/icon_circle@2x.png


BIN
src/pages/model-info/images/icon_fullscreen@2x.png


BIN
src/pages/model-info/images/icon_screen@2x.png


+ 100 - 0
src/pages/model-info/index.scss

@@ -0,0 +1,100 @@
+.model-info-page {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  overflow: hidden;
+  background: #14191d;
+
+  &::after {
+    content: "";
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    height: 60vh;
+    background: linear-gradient(
+      180deg,
+      #d9d9d9 0%,
+      rgba(217, 217, 217, 0) 100%
+    );
+    opacity: 0.1;
+    filter: blur(24px);
+  }
+  &-header {
+    position: relative;
+    margin: 0 20px;
+    padding: 20px 0;
+    color: #ffffff;
+    font-size: 24px;
+    font-weight: bold;
+
+    .border {
+      position: absolute;
+      left: 0;
+      bottom: 0;
+      width: 100%;
+    }
+  }
+
+  &-iframe {
+    position: relative;
+    margin: 3px 0 35px 0;
+    flex: 0 0 43vh;
+    z-index: 1;
+
+    iframe {
+      width: 100%;
+      height: 100%;
+      border: 0;
+    }
+  }
+
+  &-info {
+    flex: 1;
+    position: relative;
+    padding: 0 30px;
+    color: #ffffff;
+    line-height: 19px;
+    z-index: 1;
+
+    &__line {
+      display: flex;
+
+      &:not(:first-child) {
+        margin-top: 30px;
+      }
+      span {
+        opacity: 0.8;
+      }
+      img {
+        position: relative;
+        top: 1px;
+        margin-right: 15px;
+        width: 16px;
+        height: 16px;
+      }
+    }
+  }
+
+  &__btn {
+    position: fixed;
+    right: 25px;
+    bottom: 46vh;
+    width: 40px;
+    height: 40px;
+    z-index: 1;
+  }
+
+  &.fullscreen {
+    .model-info-page {
+      &-iframe {
+        flex: 1;
+        margin-bottom: 0;
+      }
+      &__btn {
+        bottom: 0;
+        padding-bottom: 20px;
+      }
+    }
+  }
+}

+ 95 - 0
src/pages/model-info/index.tsx

@@ -0,0 +1,95 @@
+import HeaderBdImage from "./images/header-bd.png";
+import IconScreen from "./images/icon_screen@2x.png";
+import IconFullScreen from "./images/icon_fullscreen@2x.png";
+import IconCircle from "./images/icon_circle@2x.png";
+import "./index.scss";
+import { useCallback, useEffect, useRef, useState } from "react";
+import classNames from "classnames";
+
+const INFO_LIST = [
+  {
+    label: "厂家",
+    key: "航天八院",
+  },
+  {
+    label: "尺寸",
+    key: "3.22m×2.87m×4.12m",
+  },
+  {
+    label: "简介",
+    key: "风云四号气象卫星是我国第二代静止轨道气象卫星,获取地球表面和云的多光谱、高精度定量观测数据和图像,全面提高对地球表面和大气物理参数的多光谱、高频次、定量探测能力;实现大气温度和湿度参数垂直结构观测,提高探测精度;实现观测区内闪电成像观测;监测空间高能粒子、空间充放电效应、地磁场强度等空间环境。",
+  },
+];
+
+const ModelInfoPage = () => {
+  // 控制模型放大缩小和复位
+  const ifrBoxRef = useRef<HTMLIFrameElement>(null);
+  const [isFullScreen, setIsFullScreen] = useState(false);
+
+  useEffect(() => {
+    const init = (e: MessageEvent<any>) => {
+      if (
+        e.origin === window.location.origin &&
+        e.data === "modelPageLoaded" &&
+        !!ifrBoxRef.current &&
+        !!ifrBoxRef.current.contentWindow
+      ) {
+        // @ts-ignore
+        ifrBoxRef.current.contentWindow.initModel(
+          process.env.NODE_ENV === "development"
+        );
+      }
+    };
+    window.addEventListener("message", init);
+
+    return () => {
+      window.removeEventListener("message", init);
+    };
+  }, []);
+
+  const handleScreen = useCallback(() => {
+    setIsFullScreen(!isFullScreen);
+  }, [isFullScreen]);
+
+  return (
+    <div
+      className={classNames("model-info-page", isFullScreen && "fullscreen")}
+    >
+      <div className="model-info-page-header">
+        <span>风云四号模型</span>
+        <img className="border" src={HeaderBdImage} alt="" />
+      </div>
+
+      {/* 模型 */}
+      <div className="model-info-page-iframe">
+        <iframe
+          ref={ifrBoxRef}
+          title="模型"
+          src="model.html?m=/goods/base/model/hnbwy263.4dage"
+        />
+      </div>
+
+      <img
+        className="model-info-page__btn"
+        src={isFullScreen ? IconScreen : IconFullScreen}
+        alt={isFullScreen ? "缩小" : "放大"}
+        onClick={handleScreen}
+      />
+
+      {!isFullScreen && (
+        <div className="model-info-page-info">
+          {INFO_LIST.map((item) => (
+            <div key={item.key} className="model-info-page-info__line">
+              <img src={IconCircle} alt="" />
+              <span>
+                {item.label}:{item.key}
+              </span>
+            </div>
+          ))}
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default ModelInfoPage;

+ 0 - 5
src/setupTests.ts

@@ -1,5 +0,0 @@
-// jest-dom adds custom jest matchers for asserting on DOM nodes.
-// allows you to do things like:
-// expect(element).toHaveTextContent(/react/i)
-// learn more: https://github.com/testing-library/jest-dom
-import '@testing-library/jest-dom';

Datei-Diff unterdrückt, da er zu groß ist
+ 10306 - 0
yarn.lock