maxiaoxiao 1 天之前
父節點
當前提交
601d212bc9
共有 2 個文件被更改,包括 71 次插入9 次删除
  1. 4 3
      task-service/src/index.js
  2. 67 6
      task-service/src/renderer.js

+ 4 - 3
task-service/src/index.js

@@ -10,11 +10,12 @@ const cfg = {
     token: process.env.PORTAL_TOKEN || "",
     sceneUrl:
       process.env.SCENE_URL ||
-      "http://{s}/iserver/services/3D-QingXie/rest/realspace",
+      "http://{s}/iserver/services/3D-SanYaQingXieMoXing/rest/realspace",
     terrainUrl:
       process.env.TERRAIN_URL ||
-      "http://192.168.60.2:8090/iserver/services/3D-local3DCache-SanYaShi_GaoCheng_Level_16DataSource/rest/realspace/datas/%E4%B8%89%E4%BA%9A%E5%B8%82_%E9%AB%98%E7%A8%8B_Level_16%40DataSource",
-    iserverHost: process.env.ISERVER_HOST || "192.168.60.2:8090",
+      "http://192.168.60.87:8090/iserver/services/3D-local3DCache-SanYaDSM2mDataSource/rest/realspace/datas/%E4%B8%89%E4%BA%9ADSM@DataSource",
+    backendUrl: process.env.BACKEND_URL || "http://192.168.60.87:8080",
+    iserverHost: process.env.ISERVER_HOST || "192.168.60.87:8090",
     chromePath:
       process.env.CHROME_PATH ||
       "C:/Program Files/Google/Chrome/Application/chrome.exe",

+ 67 - 6
task-service/src/renderer.js

@@ -1,6 +1,7 @@
 const puppeteer = require("puppeteer-core");
 const fs = require("fs");
 const path = require("path");
+const http = require("http");
 
 const CHROME_DEFAULT =
   "C:/Program Files/Google/Chrome/Application/chrome.exe";
@@ -20,10 +21,54 @@ async function renderScene(opts) {
     params = {},
     terrainUrl = "",
     sceneUrl = "",
-    iserverHost = "192.168.60.2:8090",
+    backendUrl = "",
+    iserverHost = "192.168.60.87:8090",
     chromePath = CHROME_DEFAULT,
   } = opts;
 
+  // 从后端 API 获取 DSM 地形 URL
+  async function fetchTerrainUrl() {
+    if (!backendUrl) return terrainUrl;
+    return new Promise((resolve) => {
+      const postData = JSON.stringify({ id: 0, jscType: "t_zhd_server" });
+      const reqUrl = new URL(backendUrl + "/apply/jsc/QueryOne");
+      const headers = { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) };
+      if (token) headers["Admin-Token"] = token;
+      const options = {
+        hostname: reqUrl.hostname,
+        port: reqUrl.port,
+        path: reqUrl.pathname,
+        method: "POST",
+        headers,
+      };
+      const req = http.request(options, (res) => {
+        let data = "";
+        res.on("data", (chunk) => (data += chunk));
+        res.on("end", () => {
+          try {
+            const json = JSON.parse(data);
+            if (json.data && json.data.url) {
+              console.log("[renderer] DSM URL from API:", json.data.url);
+              resolve(json.data.url);
+            } else {
+              console.warn("[renderer] API 未返回 DSM URL,使用默认值");
+              resolve(terrainUrl);
+            }
+          } catch (e) {
+            console.warn("[renderer] 解析 DSM API 响应失败:", e.message);
+            resolve(terrainUrl);
+          }
+        });
+      });
+      req.on("error", (e) => {
+        console.warn("[renderer] 获取 DSM URL 失败:", e.message);
+        resolve(terrainUrl);
+      });
+      req.write(postData);
+      req.end();
+    });
+  }
+
   function evalTimeout(page, fn, ...args) {
     return Promise.race([
       page.evaluate(fn, ...args),
@@ -77,8 +122,8 @@ async function renderScene(opts) {
       /* 画布 0 尺寸则走兜底截图 */
     }
     await new Promise((r) => setTimeout(r, 8000));
-
     // 注入自动化钩子(仅天际线需要;日照的钩子在 SunlightAnalysis.vue mounted 中)
+    // 天际线:page-hooks.js 注入主页面(纯 Cesium,不需要 Vue 组件)
     if (analysisType !== "sunlight") {
       const hooksSource = fs.readFileSync(
         path.join(__dirname, "page-hooks.js"),
@@ -163,9 +208,10 @@ async function renderScene(opts) {
       await new Promise((r) => setTimeout(r, 5000));
     }
 
-    // 自己加载 DSM 高程
-    if (terrainUrl) {
-      console.log("[renderer] 加载 DSM 高程:", terrainUrl.slice(0, 90));
+    // 自己加载 DSM 高程(从后端 API 动态获取 URL)
+    const resolvedTerrainUrl = await fetchTerrainUrl();
+    if (resolvedTerrainUrl) {
+      console.log("[renderer] 加载 DSM 高程:", resolvedTerrainUrl.slice(0, 90));
       try {
         await evalTimeout(page, async (u) => {
           if (typeof Cesium === "undefined" || !window.viewer) return;
@@ -185,7 +231,7 @@ async function renderScene(opts) {
           } catch (e) {
             console.warn("terrain ready error", e);
           }
-        }, terrainUrl);
+        }, resolvedTerrainUrl);
         console.log("[renderer] 地形已加载");
       } catch (e) {
         console.warn("[renderer] 地形加载失败", e.message);
@@ -193,6 +239,21 @@ async function renderScene(opts) {
       await new Promise((r) => setTimeout(r, 3000));
     }
 
+    // 等待数据源 + 3D瓦片稳定,确保日照分析时模型已渲染(之前 poly=0 根因)
+    await evalTimeout(page, async () => {
+      var start = Date.now();
+      var lastDs = 0, stable = 0;
+      while (stable < 5 && Date.now() - start < 30000) {
+        var ds = window.viewer.dataSources ? window.viewer.dataSources.length : 0;
+        if (ds > 0 && ds === lastDs) { stable++; } else { stable = 0; lastDs = ds; }
+        await new Promise(r => setTimeout(r, 1000));
+      }
+      console.log("[renderer] 数据源稳定 ds=" + lastDs + " 用时=" + (Date.now() - start) + "ms");
+      // 额外等2秒让瓦片渲染
+      await new Promise(r => setTimeout(r, 2000));
+    });
+    console.log("[renderer] 瓦片就绪,开始分析");
+
     if (range && hasHook) {
       if (analysisType === "skyline") {
         // 天际线:range 为 LineString(两点),调 __skylineRun({start,end,faceH,faceW})