From 92a3cae781b9cc06758e5d1a65c9ad360436ae56 Mon Sep 17 00:00:00 2001
From: vincentlu <t1341870251@gmail.com>
Date: 星期六, 21 三月 2026 16:15:55 +0800
Subject: [PATCH] #

---
 /dev/null                                     |   75 ---
 zy-acs-flow/package.json                      |    3 
 zy-acs-flow/package-lock.json                 |  279 +++++++++++++
 zy-acs-flow/src/map/insight/index.jsx         |    6 
 zy-acs-flow/src/map/insight/code/CodeQr.jsx   |   68 +++
 zy-acs-flow/src/map/insight/code/CodeMain.jsx |  658 ++++++++++++++++++++++++++++++++
 zy-acs-common/pom.xml                         |    8 
 zy-acs-flow/src/map/insight/code/index.jsx    |   93 ++++
 8 files changed, 1,108 insertions(+), 82 deletions(-)

diff --git a/zy-acs-common/pom.xml b/zy-acs-common/pom.xml
index 5ab1a1d..d29f5cf 100644
--- a/zy-acs-common/pom.xml
+++ b/zy-acs-common/pom.xml
@@ -64,6 +64,14 @@
                     <encoding>UTF-8</encoding>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>17</source>
+                    <target>17</target>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/zy-acs-flow/package-lock.json b/zy-acs-flow/package-lock.json
index b000d2c..a053e5e 100644
--- a/zy-acs-flow/package-lock.json
+++ b/zy-acs-flow/package-lock.json
@@ -17,6 +17,7 @@
         "lodash": "^4.17.21",
         "papaparse": "^5.4.1",
         "pixi.js": "^7.4.0",
+        "qrcode": "^1.5.4",
         "react": "^18.3.0",
         "react-admin": "^5.1.0",
         "react-dom": "^18.3.0",
@@ -2369,7 +2370,6 @@
       "version": "5.0.1",
       "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-      "dev": true,
       "engines": {
         "node": ">=8"
       }
@@ -2692,6 +2692,15 @@
         "node": ">=6"
       }
     },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/caniuse-lite": {
       "version": "1.0.30001651",
       "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz",
@@ -2763,6 +2772,17 @@
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
       }
     },
     "node_modules/clsx": {
@@ -2962,6 +2982,15 @@
         }
       }
     },
+    "node_modules/decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/decode-uri-component": {
       "version": "0.2.2",
       "resolved": "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
@@ -3016,6 +3045,12 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/dijkstrajs": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
+      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
+      "license": "MIT"
+    },
     "node_modules/dir-glob": {
       "version": "3.0.1",
       "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -3064,6 +3099,12 @@
       "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz",
       "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==",
       "dev": true
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "license": "MIT"
     },
     "node_modules/error-ex": {
       "version": "1.3.2",
@@ -3904,6 +3945,15 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
     "node_modules/get-intrinsic": {
       "version": "1.2.4",
       "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
@@ -4397,6 +4447,15 @@
       },
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
       }
     },
     "node_modules/is-generator-function": {
@@ -5083,6 +5142,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/papaparse": {
       "version": "5.4.1",
       "resolved": "https://registry.npmmirror.com/papaparse/-/papaparse-5.4.1.tgz",
@@ -5137,7 +5205,6 @@
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
       "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "dev": true,
       "engines": {
         "node": ">=8"
       }
@@ -5229,6 +5296,15 @@
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/pixijs"
+      }
+    },
+    "node_modules/pngjs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
+      "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.13.0"
       }
     },
     "node_modules/possible-typed-array-names": {
@@ -5334,6 +5410,23 @@
       "dev": true,
       "engines": {
         "node": ">=6"
+      }
+    },
+    "node_modules/qrcode": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
+      "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
+      "license": "MIT",
+      "dependencies": {
+        "dijkstrajs": "^1.0.1",
+        "pngjs": "^5.0.0",
+        "yargs": "^15.3.1"
+      },
+      "bin": {
+        "qrcode": "bin/qrcode"
+      },
+      "engines": {
+        "node": ">=10.13.0"
       }
     },
     "node_modules/qs": {
@@ -5759,6 +5852,21 @@
       "resolved": "https://registry.npmmirror.com/remove-accents/-/remove-accents-0.4.4.tgz",
       "integrity": "sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg=="
     },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "license": "ISC"
+    },
     "node_modules/resolve": {
       "version": "2.0.0-next.5",
       "resolved": "https://registry.npmmirror.com/resolve/-/resolve-2.0.0-next.5.tgz",
@@ -5923,6 +6031,12 @@
         "node": ">=10"
       }
     },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "license": "ISC"
+    },
     "node_modules/set-function-length": {
       "version": "1.2.2",
       "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -6055,6 +6169,20 @@
         "node": ">=4"
       }
     },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/string.prototype.matchall": {
       "version": "4.0.11",
       "resolved": "https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
@@ -6144,7 +6272,6 @@
       "version": "6.0.1",
       "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz",
       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-      "dev": true,
       "dependencies": {
         "ansi-regex": "^5.0.1"
       },
@@ -6598,6 +6725,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/which-module": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
+      "license": "ISC"
+    },
     "node_modules/which-typed-array": {
       "version": "1.1.15",
       "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.15.tgz",
@@ -6644,6 +6777,53 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "license": "MIT"
+    },
     "node_modules/wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
@@ -6679,6 +6859,12 @@
         "node": ">=0.4"
       }
     },
+    "node_modules/y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "license": "ISC"
+    },
     "node_modules/yallist": {
       "version": "3.1.1",
       "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",
@@ -6693,6 +6879,93 @@
         "node": ">= 6"
       }
     },
+    "node_modules/yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "license": "ISC",
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/yargs/node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "license": "MIT",
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/yargs/node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/yocto-queue": {
       "version": "0.1.0",
       "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/zy-acs-flow/package.json b/zy-acs-flow/package.json
index 77bdb38..c284a30 100644
--- a/zy-acs-flow/package.json
+++ b/zy-acs-flow/package.json
@@ -21,6 +21,7 @@
     "lodash": "^4.17.21",
     "papaparse": "^5.4.1",
     "pixi.js": "^7.4.0",
+    "qrcode": "^1.5.4",
     "react": "^18.3.0",
     "react-admin": "^5.1.0",
     "react-dom": "^18.3.0",
@@ -47,4 +48,4 @@
     "vite": "^5.3.5"
   },
   "name": "cool-admin-flow"
-}
\ No newline at end of file
+}
diff --git a/zy-acs-flow/src/map/insight/code/CodeMain.jsx b/zy-acs-flow/src/map/insight/code/CodeMain.jsx
new file mode 100644
index 0000000..6719584
--- /dev/null
+++ b/zy-acs-flow/src/map/insight/code/CodeMain.jsx
@@ -0,0 +1,658 @@
+import React, { useMemo } from 'react';
+import { useTranslate, useRedirect } from 'react-admin';
+import {
+    Box,
+    Paper,
+    Typography,
+    Stack,
+    Grid,
+    Chip,
+    Button,
+    Skeleton,
+    useTheme,
+} from '@mui/material';
+import { alpha } from '@mui/material/styles';
+import OpenInNewIcon from '@mui/icons-material/OpenInNew';
+import BoolValueIcon from '../BoolValueIcon';
+import { rotationToNum } from '../../tool';
+import CodeQr from './CodeQr';
+
+const DIR_RULE_ANGLES = [0, 90, 180, 270];
+const MAX_RELATION_ITEMS = 8;
+
+const CodeMain = ({ sprite, codeInfo, loading, code }) => {
+    const translate = useTranslate();
+    const redirect = useRedirect();
+    const theme = useTheme();
+
+    const info = codeInfo || {};
+
+    const displayCode = info?.data ?? info?.code ?? sprite?.data?.no ?? code;
+    const zoneName = info?.zoneName ?? info?.zoneId$ ?? sprite?.data?.zoneName;
+    const statusBool = detectBoolean(info?.statusBool ?? info?.status);
+    const statusLabel = info?.status$ || translate(statusBool ? 'common.enums.statusTrue' : 'common.enums.statusFalse');
+    const cornerBool = detectBoolean(info?.cornerBool ?? info?.corner ?? sprite?.data?.corner);
+    const spinText = getSpinText(info?.spin, translate);
+    const mapMetrics = useMemo(() => {
+        if (!sprite) {
+            return null;
+        }
+        const posX = sprite.position?.x;
+        const posY = sprite.position?.y;
+        const rotation = rotationToNum(sprite.rotation || 0);
+        const scaleX = sprite.scale?.x;
+        const scaleY = sprite.scale?.y;
+        return {
+            posX: isFiniteNumber(posX) ? posX : null,
+            posY: isFiniteNumber(posY) ? posY : null,
+            rotation: isFiniteNumber(rotation) ? rotation : null,
+            scaleX: isFiniteNumber(scaleX) ? scaleX : null,
+            scaleY: isFiniteNumber(scaleY) ? scaleY : null,
+        };
+    }, [sprite]);
+
+    const routeRelations = useMemo(
+        () => extractRelationItems(info, ['routeList', 'routes', 'routeRefs']),
+        [info]
+    );
+    const funcStaBool = detectBoolean(
+        info?.funcStaBool ?? info?.isFuncSta ?? info?.funcStation ?? info?.funcStaFlag
+    );
+    const funcStaText = info?.funcSta$ || info?.funcStaName || info?.funcStaType || info?.funcStaCode || info?.funcStaUuid || info?.funcSta;
+
+    const ruleList = useMemo(() => normalizeDirRule(info?.dirRule), [info?.dirRule]);
+
+    const spatialItems = [
+        { label: translate('table.field.code.x'), value: formatNumber(info?.x, 0), hideWhenEmpty: true },
+        { label: translate('table.field.code.y'), value: formatNumber(info?.y, 0), hideWhenEmpty: true },
+        {
+            label: translate('page.map.insight.code.fields.mapPosition', { _: '鍦板浘鍧愭爣' }),
+            render: () => (
+                <CoordinatePair
+                    x={formatNumber(mapMetrics?.posX, 0)}
+                    y={formatNumber(mapMetrics?.posY, 0)}
+                />
+            ),
+            always: mapMetrics?.posX != null || mapMetrics?.posY != null,
+            hideWhenEmpty: true,
+        },
+        {
+            label: translate('page.map.insight.code.fields.rotation', { _: '鏃嬭浆瑙掑害(掳)' }),
+            value: mapMetrics?.rotation != null ? `${formatNumber(mapMetrics.rotation, 1)}掳` : null,
+            hideWhenEmpty: true
+        },
+        {
+            label: translate('table.field.code.corner', { _: '鎷愯' }),
+            render: () => (
+                <BooleanDisplay
+                    value={cornerBool}
+                    label={
+                        cornerBool == null
+                            ? translate('common.enums.na')
+                            : translate(cornerBool ? 'common.enums.true' : 'common.enums.false')
+                    }
+                />
+            ),
+            always: true,
+        },
+    ];
+
+    const handleOpenDetail = () => {
+        if (info?.id) {
+            redirect('edit', 'code', info.id);
+        }
+    };
+
+    const funcStaLabel = funcStaBool == null
+        ? translate('common.enums.na')
+        : translate(funcStaBool ? 'common.enums.true' : 'common.enums.false');
+
+    return (
+        <Box sx={{ pr: 1, pb: 3 }}>
+            <Grid container spacing={3} alignItems="flex-start">
+                <Grid item xs={12} md={5}>
+                    <Stack spacing={3}>
+                        <QrPreview
+                            translate={translate}
+                            value={displayCode}
+                            loading={loading}
+                            statusLabel={statusLabel}
+                            statusBool={statusBool}
+                        />
+                        <Paper
+                            sx={{
+                                borderRadius: 4,
+                                border: '1px solid',
+                                borderColor: 'divider',
+                                backgroundColor: theme.palette.background.paper,
+                                p: { xs: 2.5, md: 3 },
+                            }}
+                        >
+                            <Stack spacing={2}>
+                                {zoneName && (
+                                    <Chip
+                                        label={zoneName}
+                                        variant="outlined"
+                                        size="small"
+                                        color="primary"
+                                        sx={{ alignSelf: 'flex-start' }}
+                                    />
+                                )}
+                                <FieldGrid items={spatialItems} loading={loading} />
+                                <Button
+                                    variant="contained"
+                                    color="primary"
+                                    startIcon={<OpenInNewIcon />}
+                                    onClick={handleOpenDetail}
+                                    disabled={!info?.id}
+                                    sx={{ alignSelf: 'flex-start', textTransform: 'none', px: 3 }}
+                                >
+                                    {translate('page.map.insight.code.actions.openDetail', { _: '杩涘叆 Code 椤甸潰' })}
+                                </Button>
+                            </Stack>
+                        </Paper>
+                    </Stack>
+                </Grid>
+                <Grid item xs={12} md={7}>
+                    <Paper
+                        sx={{
+                            borderRadius: 4,
+                            border: '1px solid',
+                            borderColor: 'divider',
+                            backgroundColor: theme.palette.background.paper,
+                            p: { xs: 2.5, md: 3 },
+                        }}
+                    >
+                        <Stack spacing={3}>
+                            <InfoPanel title={translate('page.map.insight.code.sections.rules', { _: '閫氳瑙勫垯' })}>
+                                <RulesSection
+                                    loading={loading}
+                                    cornerBool={cornerBool}
+                                    spinText={spinText}
+                                    rules={ruleList}
+                                    translate={translate}
+                                />
+                            </InfoPanel>
+                            <InfoPanel title={translate('page.map.insight.code.relations.routes', { _: '鍏宠仈璺嚎' })}>
+                                <RelationsChips
+                                    items={routeRelations}
+                                    emptyLabel={translate('page.map.insight.code.relations.empty', { _: '鏆傛棤鍏宠仈淇℃伅' })}
+                                />
+                            </InfoPanel>
+                            <InfoPanel title={translate('menu.funcSta', { _: '鍔熻兘绔�' })}>
+                                <Stack spacing={1}>
+                                    <BooleanDisplay
+                                        value={funcStaBool}
+                                        label={funcStaLabel}
+                                    />
+                                    {funcStaText && funcStaText !== funcStaLabel && (
+                                        <Typography variant="body2" color="text.secondary">
+                                            {funcStaText}
+                                        </Typography>
+                                    )}
+                                </Stack>
+                            </InfoPanel>
+                        </Stack>
+                    </Paper>
+                </Grid>
+            </Grid>
+        </Box>
+    );
+};
+
+const InfoPanel = ({ title, children }) => (
+    <Box
+        sx={{
+            border: '1px solid',
+            borderColor: 'divider',
+            borderRadius: 3,
+            p: { xs: 2, sm: 2.5 },
+            backgroundColor: 'background.paper',
+        }}
+    >
+        <Typography variant="subtitle2" color="text.secondary" sx={{ mb: 1 }}>
+            {title}
+        </Typography>
+        {children}
+    </Box>
+);
+
+const RelationsChips = ({ items, emptyLabel }) => {
+    if (!items?.length) {
+        return (
+            <Typography variant="body2" color="text.disabled">
+                {emptyLabel}
+            </Typography>
+        );
+    }
+    return (
+        <Stack direction="row" spacing={1} flexWrap="wrap">
+            {items.slice(0, MAX_RELATION_ITEMS).map((item, index) => (
+                <Chip
+                    key={`${getRelationKey(item)}-${index}`}
+                    label={getRelationLabel(item)}
+                    variant="outlined"
+                    size="small"
+                />
+            ))}
+            {items.length > MAX_RELATION_ITEMS && (
+                <Chip
+                    label={`+${items.length - MAX_RELATION_ITEMS}`}
+                    size="small"
+                />
+            )}
+        </Stack>
+    );
+};
+
+const QrPreview = ({ translate, value, loading, statusLabel, statusBool }) => (
+    <Paper
+        elevation={3}
+        sx={{
+            borderRadius: 4,
+            px: 3,
+            py: 3,
+            width: '100%',
+            maxWidth: 320,
+            alignSelf: { xs: 'center', lg: 'flex-start' },
+            minHeight: 320,
+            display: 'flex',
+            flexDirection: 'column',
+            alignItems: 'center',
+            justifyContent: 'center',
+            gap: 1,
+        }}
+    >
+        <Typography variant="caption" color="text.secondary" sx={{ letterSpacing: 1, textTransform: 'uppercase' }}>
+            {translate('page.map.insight.code.summary.qr', { _: '浜岀淮鐮侀瑙�' })}
+        </Typography>
+        <CodeQr value={value} loading={loading} />
+        <Typography variant="caption" color="text.secondary">
+            QR CODE
+        </Typography>
+        {!loading && (
+            <Stack spacing={0.5} alignItems="center" sx={{ mt: 0.5 }}>
+                <Typography variant="caption" color="text.secondary">
+                    {translate('common.field.status', { _: '鐘舵��' })}
+                </Typography>
+                <Chip
+                    label={statusLabel}
+                    color={statusBool ? 'success' : 'default'}
+                    variant="outlined"
+                    size="small"
+                    sx={{ fontWeight: 500 }}
+                />
+            </Stack>
+        )}
+    </Paper>
+);
+
+const FieldGrid = ({ items, loading }) => {
+    const candidates = (loading ? items : items.filter(item => {
+        if (!item) {
+            return false;
+        }
+        if (item.always) {
+            return true;
+        }
+        if (item.hideWhenEmpty) {
+            return hasDisplayValue(item.value);
+        }
+        return true;
+    })).filter(Boolean);
+
+    if (!candidates.length) {
+        return loading ? <Skeleton width="40%" /> : (
+            <Typography variant="body2" color="text.disabled">
+                -
+            </Typography>
+        );
+    }
+
+    return (
+        <Box
+            sx={{
+                display: 'grid',
+                gap: 2,
+                gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))',
+            }}
+        >
+            {candidates.map((item, index) => (
+                <Stack key={`${item.label}-${index}`} spacing={0.5}>
+                    <Typography variant="caption" color="text.secondary">
+                        {item.label}
+                    </Typography>
+                    <Box>
+                        {item.render
+                            ? item.render({ loading })
+                            : loading
+                                ? <Skeleton width="60%" />
+                                : renderDisplayValue(item.value)}
+                    </Box>
+                </Stack>
+            ))}
+        </Box>
+    );
+};
+
+const renderDisplayValue = (value) => {
+    if (React.isValidElement(value)) {
+        return value;
+    }
+    if (value === null || value === undefined || value === '') {
+        return (
+            <Typography variant="body2" color="text.disabled">
+                -
+            </Typography>
+        );
+    }
+    return (
+        <Typography variant="subtitle1" sx={{ wordBreak: 'break-word', fontWeight: 600 }}>
+            {value}
+        </Typography>
+    );
+};
+
+const hasDisplayValue = (value) => {
+    if (value === 0 || value === false) {
+        return true;
+    }
+    if (typeof value === 'number') {
+        return !Number.isNaN(value);
+    }
+    if (value instanceof Date) {
+        return true;
+    }
+    return value !== null && value !== undefined && String(value).trim() !== '';
+};
+
+const BooleanDisplay = ({ value, label }) => {
+    if (value == null) {
+        return (
+            <Typography variant="body2" color="text.disabled">
+                {label}
+            </Typography>
+        );
+    }
+    return (
+        <Stack direction="row" alignItems="center" spacing={1}>
+            <BoolValueIcon value={value} />
+            <Typography variant="body2">{label}</Typography>
+        </Stack>
+    );
+};
+
+const CoordinatePair = ({ x, y }) => {
+    if (!hasDisplayValue(x) && !hasDisplayValue(y)) {
+        return renderDisplayValue(null);
+    }
+
+    return (
+        <Stack direction="row" spacing={2.5} alignItems="center" flexWrap="wrap">
+            <Stack spacing={0.25}>
+                <Typography variant="caption" color="text.secondary">
+                    X
+                </Typography>
+                <Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
+                    {hasDisplayValue(x) ? x : '-'}
+                </Typography>
+            </Stack>
+            <Stack spacing={0.25}>
+                <Typography variant="caption" color="text.secondary">
+                    Y
+                </Typography>
+                <Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
+                    {hasDisplayValue(y) ? y : '-'}
+                </Typography>
+            </Stack>
+        </Stack>
+    );
+};
+
+const RulesSection = ({ cornerBool, spinText, rules, translate, loading }) => (
+    <Stack spacing={2}>
+        <Box
+            sx={{
+                display: 'grid',
+                gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, minmax(0, 1fr))' },
+                gap: 2,
+            }}
+        >
+            <RuleMetric
+                label={translate('table.field.code.corner')}
+                value={
+                    <BooleanDisplay
+                        value={cornerBool}
+                        label={cornerBool == null
+                            ? translate('common.enums.na')
+                            : translate(cornerBool ? 'common.enums.true' : 'common.enums.false')}
+                    />
+                }
+            />
+            <RuleMetric
+                label={translate('table.field.code.spin')}
+                value={
+                    <Chip
+                        label={spinText}
+                        size="small"
+                        color="primary"
+                        variant="outlined"
+                    />
+                }
+            />
+        </Box>
+        {loading ? (
+            <Skeleton variant="rounded" height={220} />
+        ) : (
+            <DirectionRuleCompass rules={rules} translate={translate} />
+        )}
+    </Stack>
+);
+
+const DirectionRuleCompass = ({ rules, translate }) => {
+    const theme = useTheme();
+    const enabledCount = rules.filter(rule => rule.enabled).length;
+    const placement = {
+        0: { gridColumn: 2, gridRow: 1 },
+        90: { gridColumn: 3, gridRow: 2 },
+        180: { gridColumn: 2, gridRow: 3 },
+        270: { gridColumn: 1, gridRow: 2 },
+    };
+
+    return (
+        <Box
+            sx={{
+                display: 'grid',
+                gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
+                gridTemplateRows: 'repeat(3, minmax(58px, auto))',
+                gap: 1,
+                alignItems: 'stretch',
+            }}
+        >
+            <Box
+                sx={{
+                    gridColumn: 2,
+                    gridRow: 2,
+                    borderRadius: 3,
+                    border: '1px dashed',
+                    borderColor: 'divider',
+                    backgroundColor: alpha(theme.palette.primary.main, 0.04),
+                    px: 1,
+                    py: 0.75,
+                    display: 'flex',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                    textAlign: 'center',
+                }}
+            >
+                <Typography variant="h6" sx={{ lineHeight: 1.1, fontWeight: 700 }}>
+                    {enabledCount}/{rules.length}
+                </Typography>
+            </Box>
+            {rules.map(rule => {
+                const position = placement[rule.angle] || { gridColumn: 'auto', gridRow: 'auto' };
+                const statusText = translate(
+                    rule.enabled ? 'page.code.dirRule.status.enabled' : 'page.code.dirRule.status.disabled'
+                );
+
+                return (
+                    <Box
+                        key={rule.angle}
+                        sx={{
+                            ...position,
+                            borderRadius: 3,
+                            border: '1px solid',
+                            borderColor: rule.enabled ? 'success.light' : 'error.light',
+                            backgroundColor: rule.enabled
+                                ? alpha(theme.palette.success.main, 0.08)
+                                : alpha(theme.palette.error.main, 0.08),
+                            px: 1,
+                            py: 0.75,
+                            minHeight: 60,
+                            display: 'flex',
+                            alignItems: 'center',
+                            justifyContent: 'center',
+                            textAlign: 'center',
+                        }}
+                    >
+                        <Stack spacing={0.35}>
+                            <Typography variant="subtitle2" sx={{ fontWeight: 700, lineHeight: 1 }}>
+                                {rule.angle}掳
+                            </Typography>
+                            <Typography
+                                variant="caption"
+                                sx={{
+                                    lineHeight: 1.1,
+                                    color: rule.enabled ? 'success.dark' : 'error.dark',
+                                    fontWeight: 600,
+                                }}
+                            >
+                                {statusText}
+                            </Typography>
+                        </Stack>
+                    </Box>
+                );
+            })}
+        </Box>
+    );
+};
+
+const RuleMetric = ({ label, value }) => (
+    <Stack spacing={0.5}>
+        <Typography variant="caption" color="text.secondary">
+            {label}
+        </Typography>
+        {value}
+    </Stack>
+);
+
+const normalizeDirRule = (value) => {
+    if (!value) {
+        return DIR_RULE_ANGLES.map(angle => ({ angle, enabled: true }));
+    }
+    let parsed = value;
+    if (typeof parsed === 'string') {
+        try {
+            parsed = JSON.parse(parsed);
+        } catch (error) {
+            parsed = [];
+        }
+    }
+    if (!Array.isArray(parsed)) {
+        parsed = [parsed];
+    }
+    const normalized = DIR_RULE_ANGLES.map(angle => ({ angle, enabled: true }));
+    parsed.forEach(rule => {
+        const angle = typeof rule?.angle === 'number' ? rule.angle : Number(rule?.angle);
+        if (!Number.isFinite(angle)) {
+            return;
+        }
+        const normalizedAngle = ((angle % 360) + 360) % 360;
+        const target = normalized.find(item => item.angle === normalizedAngle);
+        if (target) {
+            const disabled = rule?.enabled === false || rule?.enabled === 'false' || rule?.value === false || rule?.value === 'false';
+            target.enabled = !disabled;
+        }
+    });
+    return normalized;
+};
+
+const getRelationKey = (item) => {
+    if (item && typeof item === 'object') {
+        return item.id || item.uuid || item.code || item.data || item.no || JSON.stringify(item);
+    }
+    return item ?? 'relation';
+};
+
+const getRelationLabel = (item) => {
+    if (item == null) {
+        return '-';
+    }
+    if (typeof item === 'string' || typeof item === 'number') {
+        return item;
+    }
+    if (typeof item === 'object') {
+        return item.name || item.code || item.data || item.no || item.uuid || item.locNo || item.staNo || JSON.stringify(item);
+    }
+    return String(item);
+};
+
+const extractRelationItems = (info, keys) => {
+    if (!info) {
+        return [];
+    }
+    const dataset = keys
+        .map(key => info?.[key])
+        .find(value => Array.isArray(value) && value.length);
+    return Array.isArray(dataset) ? dataset : [];
+};
+
+const detectBoolean = (value) => {
+    if (typeof value === 'boolean') {
+        return value;
+    }
+    if (value === 1 || value === '1') {
+        return true;
+    }
+    if (value === 0 || value === '0') {
+        return false;
+    }
+    if (value === 'true') {
+        return true;
+    }
+    if (value === 'false') {
+        return false;
+    }
+    return null;
+};
+
+const getSpinText = (spin, translate) => {
+    switch (spin) {
+        case 1:
+            return translate('page.code.enums.spin.cw');
+        case 2:
+            return translate('page.code.enums.spin.ccw');
+        case 0:
+            return translate('page.code.enums.spin.na');
+        default:
+            return translate('page.code.enums.spin.na');
+    }
+};
+
+const isFiniteNumber = (value) => Number.isFinite(Number(value));
+
+const formatNumber = (value, precision = 2) => {
+    if (value === null || value === undefined || value === '') {
+        return null;
+    }
+    const num = Number(value);
+    if (!Number.isFinite(num)) {
+        return value;
+    }
+    if (precision === null) {
+        return num;
+    }
+    return num.toFixed(precision);
+};
+
+export default CodeMain;
diff --git a/zy-acs-flow/src/map/insight/code/CodeQr.jsx b/zy-acs-flow/src/map/insight/code/CodeQr.jsx
new file mode 100644
index 0000000..c8a950c
--- /dev/null
+++ b/zy-acs-flow/src/map/insight/code/CodeQr.jsx
@@ -0,0 +1,68 @@
+import React, { useEffect, useState } from 'react';
+import { toDataURL } from 'qrcode';
+import { Box, Skeleton, Typography, useTheme } from '@mui/material';
+
+const CodeQr = ({ value, size = 160, loading }) => {
+    const [dataUrl, setDataUrl] = useState(null);
+    const theme = useTheme();
+
+    useEffect(() => {
+        let ignore = false;
+        if (!value) {
+            setDataUrl(null);
+            return () => { ignore = true; };
+        }
+        const darkColor = theme.palette.mode === 'dark' ? '#f5f6fa' : '#111111';
+        const lightColor = theme.palette.mode === 'dark' ? '#1b1b1b' : '#fafafa';
+        toDataURL(String(value), {
+            width: size,
+            margin: 2,
+            color: {
+                dark: darkColor,
+                light: lightColor
+            },
+        }).then((url) => {
+            if (!ignore) {
+                setDataUrl(url);
+            }
+        }).catch((error) => {
+            console.error('QR render failed', error);
+            if (!ignore) {
+                setDataUrl(null);
+            }
+        });
+        return () => {
+            ignore = true;
+        };
+    }, [value, size, theme.palette.mode]);
+
+    if (loading) {
+        return <Skeleton variant="rectangular" height={size} width={size} sx={{ borderRadius: 2 }} />;
+    }
+
+    if (!value || !dataUrl) {
+        return (
+            <Typography variant="body2" color="text.disabled">
+                -
+            </Typography>
+        );
+    }
+
+    return (
+        <Box
+            component="img"
+            src={dataUrl}
+            alt="Code QR"
+            sx={{
+                width: size,
+                height: size,
+                borderRadius: 2,
+                boxShadow: (theme) => theme.shadows[3],
+                p: 1,
+                backgroundColor: 'background.paper'
+            }}
+        />
+    );
+};
+
+export default CodeQr;
diff --git a/zy-acs-flow/src/map/insight/code/index.jsx b/zy-acs-flow/src/map/insight/code/index.jsx
new file mode 100644
index 0000000..63c651c
--- /dev/null
+++ b/zy-acs-flow/src/map/insight/code/index.jsx
@@ -0,0 +1,93 @@
+import React, { useState, useEffect, useCallback } from 'react';
+import { useTranslate } from 'react-admin';
+import { Box, Tabs, Tab, Divider } from '@mui/material';
+import JsonShow from '../../JsonShow';
+import { getPointInfo } from '../../http';
+import CodeMain from './CodeMain';
+
+const CodeInsight = ({ sprite, setTitle }) => {
+    const translate = useTranslate();
+    const [activeTab, setActiveTab] = useState(0);
+    const [currentCode, setCurrentCode] = useState(null);
+    const [codeInfo, setCodeInfo] = useState(null);
+    const [loading, setLoading] = useState(false);
+
+    const codeLabel = translate('page.map.devices.code', {
+        _: translate('page.map.devices.point', { _: 'Code' })
+    });
+
+    const fetchCodeInfo = useCallback(async (code, options = {}) => {
+        if (!code) {
+            return;
+        }
+        if (!options?.silent) {
+            setLoading(true);
+        }
+        setTitle(`${codeLabel} - ${code}`);
+        setCurrentCode(code);
+        try {
+            await getPointInfo(code, (response) => {
+                setCodeInfo(response || null);
+            });
+        } finally {
+            if (!options?.silent) {
+                setLoading(false);
+            }
+        }
+    }, [codeLabel, setTitle]);
+
+    useEffect(() => {
+        if (sprite?.data?.no) {
+            fetchCodeInfo(sprite.data.no);
+            setActiveTab(0);
+        } else {
+            setCodeInfo(null);
+            setCurrentCode(null);
+            setTitle(null);
+        }
+        return () => {
+            setCodeInfo(null);
+            setCurrentCode(null);
+            setTitle(null);
+        };
+    }, [sprite, fetchCodeInfo, setTitle]);
+
+    const handleTabChange = (_, newValue) => {
+        setActiveTab(newValue);
+    };
+
+    return (
+        <Box sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
+            <Tabs
+                value={activeTab}
+                onChange={handleTabChange}
+                centered
+                sx={{ mb: 0 }}
+            >
+                <Tab label={translate('page.map.insight.title')} />
+                <Tab label={'JSON'} />
+            </Tabs>
+
+            <Divider />
+
+            <Box flex={1} pt={2} sx={{ overflow: 'hidden' }}>
+                {activeTab === 0 && (
+                    <CodeMain
+                        sprite={sprite}
+                        codeInfo={codeInfo}
+                        loading={loading}
+                        code={currentCode}
+                    />
+                )}
+                {activeTab === 1 && (
+                    <JsonShow
+                        data={codeInfo || sprite?.data}
+                        height={550}
+                    />
+                )}
+            </Box>
+        </Box>
+    );
+};
+
+export default CodeInsight;
diff --git a/zy-acs-flow/src/map/insight/index.jsx b/zy-acs-flow/src/map/insight/index.jsx
index 3bc802c..ab4bbdd 100644
--- a/zy-acs-flow/src/map/insight/index.jsx
+++ b/zy-acs-flow/src/map/insight/index.jsx
@@ -9,7 +9,7 @@
 import JsonShow from '../JsonShow';
 import ShelfInsight from './shelf';
 import AgvInsight from './agv';
-import PointInsight from './point';
+import CodeInsight from './code';
 
 const Insight = (props) => {
     const { open, onCancel, sprite, width = PAGE_DRAWER_WIDTH } = props;
@@ -95,7 +95,7 @@
             )
         case DEVICE_TYPE.POINT:
             return (
-                <PointInsight
+                <CodeInsight
                     sprite={sprite}
                     setTitle={setTitle}
                 />
@@ -110,4 +110,4 @@
     }
 }
 
-export default Insight;
\ No newline at end of file
+export default Insight;
diff --git a/zy-acs-flow/src/map/insight/point/index.jsx b/zy-acs-flow/src/map/insight/point/index.jsx
deleted file mode 100644
index 9dcc780..0000000
--- a/zy-acs-flow/src/map/insight/point/index.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import React, { useState, useRef, useEffect } from 'react';
-import { useTranslate } from "react-admin";
-import { Box, Typography, Tabs, Tab, Stack, useTheme, Divider } from '@mui/material';
-import JsonShow from '../../JsonShow';
-import { getPointInfo } from '../../http';
-
-const PointInsight = (props) => {
-    const { sprite, setTitle } = props;
-    const translate = useTranslate();
-    const theme = useTheme();
-
-    const [activeTab, setActiveTab] = useState(0);
-    const [curPoint, setCurPoint] = useState(null);
-    const [curPointInfo, setCurPointInfo] = useState(null);
-
-    const fetchInfo = (param) => {
-        setTitle(translate('page.map.devices.point') + ' - ' + param);
-        setCurPoint(param);
-        getPointInfo(param, (response) => {
-            setCurPointInfo(response);
-        });
-    }
-
-    useEffect(() => {
-        if (sprite) {
-            const param = sprite.data.no;
-            if (param) {
-                fetchInfo(param);
-            }
-        }
-
-        return () => {
-            setTitle(null);
-            setCurPoint(null);
-            setCurPointInfo(null);
-        }
-    }, [sprite])
-
-    const handleTabChange = (event, newValue) => {
-        setActiveTab(newValue);
-    };
-
-    return (
-        <Box sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
-            <Tabs
-                value={activeTab}
-                onChange={handleTabChange}
-                centered
-                sx={{ mb: 0 }}
-            >
-                <Tab label={translate('page.map.insight.title')} />
-                <Tab label={'JSON'} />
-            </Tabs>
-
-            <Divider />
-
-            <Box flex={1} pt={2}>
-                {activeTab === 0 && (
-                    <JsonShow
-                        data={curPointInfo || sprite?.data}
-                        height={550}
-                    />
-                )}
-                {activeTab === 1 && (
-                    <JsonShow
-                        data={curPointInfo || sprite?.data}
-                        height={550}
-                    />
-                )}
-            </Box>
-        </Box>
-    )
-}
-
-export default PointInsight;
\ No newline at end of file

--
Gitblit v1.9.1