diff --git a/devops/Dockerfile b/devops/Dockerfile index 5bb16b7..fc7ce12 100644 --- a/devops/Dockerfile +++ b/devops/Dockerfile @@ -97,11 +97,14 @@ FROM --platform=$TARGETARCH eclipse-temurin:8-jre WORKDIR /app # 安装字体(用于验证码 Captcha) -# 使用中科大镜像加速(amd64 用 ubuntu,勿用 ubuntu-ports) -RUN echo 'deb http://mirrors.ustc.edu.cn/ubuntu/ noble main restricted universe multiverse' > /etc/apt/sources.list && \ - echo 'deb http://mirrors.ustc.edu.cn/ubuntu/ noble-updates main restricted universe multiverse' >> /etc/apt/sources.list && \ - echo 'deb http://mirrors.ustc.edu.cn/ubuntu/ noble-backports main restricted universe multiverse' >> /etc/apt/sources.list && \ - apt-get update && apt-get install -y --no-install-recommends \ +# 使用中科大镜像加速 +# 彻底删除所有旧源(关键!包括DEB822格式新源)→ 写入中科大arm64专属源 → 安装字体 +RUN rm -rf /etc/apt/sources.list /etc/apt/sources.list.d/* && \ + echo 'deb http://mirrors.ustc.edu.cn/ubuntu-ports/ jammy main restricted universe multiverse' > /etc/apt/sources.list && \ + echo 'deb http://mirrors.ustc.edu.cn/ubuntu-ports/ jammy-updates main restricted universe multiverse' >> /etc/apt/sources.list && \ + echo 'deb http://mirrors.ustc.edu.cn/ubuntu-ports/ jammy-backports main restricted universe multiverse' >> /etc/apt/sources.list && \ + echo 'deb http://mirrors.ustc.edu.cn/ubuntu-ports/ jammy-security main restricted universe multiverse' >> /etc/apt/sources.list && \ + apt-get update -y && apt-get install -y --no-install-recommends \ fontconfig \ fonts-noto-cjk \ && fc-cache -f -v \ @@ -109,7 +112,7 @@ RUN echo 'deb http://mirrors.ustc.edu.cn/ubuntu/ noble main restricted universe && rm -rf /var/lib/apt/lists/* COPY devops/start.sh /app/start.sh -RUN sed -i 's/\r$//' /app/start.sh && chmod +x /app/start.sh +RUN chmod +x /app/start.sh # 复制所有构建产物 COPY --from=builder /build/gateway/target/springboot.jar /app/gateway.jar diff --git a/devops/Dockerfile.test b/devops/Dockerfile.test new file mode 100644 index 0000000..5bb16b7 --- /dev/null +++ b/devops/Dockerfile.test @@ -0,0 +1,131 @@ +# ============================================================ +# 碳信网 - 统一后端构建镜像 +# 支持多平台构建: docker buildx build --platform linux/arm64,linux/amd64 +# 使用方式: docker run -e SERVICE_NAME=gateway txw-all:latest +# ============================================================ + +# Stage 1: Build +# 使用多架构 Maven 镜像,自动选择对应平台版本 +FROM --platform=$BUILDPLATFORM maven:3.6.3-openjdk-8 AS builder + +# Maven 构建参数 +ARG TARGETARCH +ARG BUILDARCH + +WORKDIR /build + +# ------------------------------------------- +# Step 1: 复制所有 pom.xml 和 settings +# ------------------------------------------- + +# 公共模块 +COPY txw-common/pom.xml txw-common/pom.xml +COPY txw-common/src txw-common/src + +# Gateway +COPY txw-gateway/pom.xml gateway/pom.xml +COPY txw-gateway/devops/settings-offline.xml gateway/settings.xml +COPY txw-gateway/src gateway/src + +# SSO +COPY txw-sso/pom.xml sso/pom.xml +COPY txw-sso/devops/settings-offline.xml sso/settings.xml +COPY txw-sso/txw-sso-service-api/pom.xml sso/txw-sso-service-api/pom.xml +COPY txw-sso/txw-sso-service-api/src sso/txw-sso-service-api/src +COPY txw-sso/txw-sso-service-biz/pom.xml sso/txw-sso-service-biz/pom.xml +COPY txw-sso/txw-sso-service-biz/src sso/txw-sso-service-biz/src + +# MHZC +COPY txw-mhzc/pom.xml mhzc/pom.xml +COPY txw-mhzc/devops/settings-offline.xml mhzc/settings.xml +COPY txw-mhzc/txw-mhzc-service-api/pom.xml mhzc/txw-mhzc-service-api/pom.xml +COPY txw-mhzc/txw-mhzc-service-api/src mhzc/txw-mhzc-service-api/src +COPY txw-mhzc/txw-mhzc-service-biz/pom.xml mhzc/txw-mhzc-service-biz/pom.xml +COPY txw-mhzc/txw-mhzc-service-biz/src mhzc/txw-mhzc-service-biz/src + +# YYGL +COPY txw-yygl/pom.xml yygl/pom.xml +COPY txw-yygl/settings.xml yygl/settings.xml +COPY txw-yygl/txw-yygl-service-api/pom.xml yygl/txw-yygl-service-api/pom.xml +COPY txw-yygl/txw-yygl-service-api/src yygl/txw-yygl-service-api/src +COPY txw-yygl/txw-yygl-service-biz/pom.xml yygl/txw-yygl-service-biz/pom.xml +COPY txw-yygl/txw-yygl-service-biz/src yygl/txw-yygl-service-biz/src + +# ------------------------------------------- +# Step 2: 复制 Maven 本地仓库(离线构建) +# 注意:若本地仓库中有编译好的二进制 native 库(非 Java byte code), +# 需要确保这些库是跨平台的,或在 ARM64 上重新构建 +# ------------------------------------------- +COPY script/.m2/repository /root/.m2/repository + +# ------------------------------------------- +# Step 3: 按依赖顺序构建 +# ------------------------------------------- + +# 3.1 构建公共模块 +WORKDIR /build/txw-common +RUN mvn clean install -DskipTests -s ../gateway/settings.xml -o || mvn clean install -DskipTests + +# 3.2 构建 API 模块 +WORKDIR /build/mhzc/txw-mhzc-service-api +RUN mvn clean install -DskipTests -s ../../gateway/settings.xml -o || mvn clean install -DskipTests + +WORKDIR /build/sso/txw-sso-service-api +RUN mvn clean install -DskipTests -s ../../gateway/settings.xml -o || mvn clean install -DskipTests + +WORKDIR /build/yygl/txw-yygl-service-api +RUN mvn clean install -DskipTests -s ../../gateway/settings.xml -o || mvn clean install -DskipTests + +# 3.3 构建 BIZ 模块 +WORKDIR /build/mhzc/txw-mhzc-service-biz +RUN mvn clean package -DskipTests -s ../../gateway/settings.xml -o || mvn clean package -DskipTests + +WORKDIR /build/sso/txw-sso-service-biz +RUN mvn clean package -DskipTests -s ../../gateway/settings.xml -o || mvn clean package -DskipTests + +WORKDIR /build/yygl/txw-yygl-service-biz +RUN mvn clean package -DskipTests -s ../../gateway/settings.xml -o || mvn clean package -DskipTests + +# 3.4 构建 Gateway +WORKDIR /build/gateway +RUN mvn clean package -DskipTests -s settings.xml -o || mvn clean package -DskipTests + +# Stage 2: Package +# 使用多架构 JRE 镜像,指定目标平台 +FROM --platform=$TARGETARCH eclipse-temurin:8-jre + +WORKDIR /app + +# 安装字体(用于验证码 Captcha) +# 使用中科大镜像加速(amd64 用 ubuntu,勿用 ubuntu-ports) +RUN echo 'deb http://mirrors.ustc.edu.cn/ubuntu/ noble main restricted universe multiverse' > /etc/apt/sources.list && \ + echo 'deb http://mirrors.ustc.edu.cn/ubuntu/ noble-updates main restricted universe multiverse' >> /etc/apt/sources.list && \ + echo 'deb http://mirrors.ustc.edu.cn/ubuntu/ noble-backports main restricted universe multiverse' >> /etc/apt/sources.list && \ + apt-get update && apt-get install -y --no-install-recommends \ + fontconfig \ + fonts-noto-cjk \ + && fc-cache -f -v \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +COPY devops/start.sh /app/start.sh +RUN sed -i 's/\r$//' /app/start.sh && chmod +x /app/start.sh + +# 复制所有构建产物 +COPY --from=builder /build/gateway/target/springboot.jar /app/gateway.jar +COPY --from=builder /build/sso/txw-sso-service-biz/target/txw-sso-service-biz.jar /app/sso.jar +COPY --from=builder /build/mhzc/txw-mhzc-service-biz/target/txw-mhzc-service-biz.jar /app/mhzc.jar +COPY --from=builder /build/yygl/txw-yygl-service-biz/target/txw-yygl-service-biz.jar /app/yygl.jar + +# 清理构建缓存 +RUN rm -rf /root/.m2 /root/.mvn + +# 环境变量:指定启动的服务名 +ENV SERVICE_NAME=gateway + +# 激活正式环境 profile +ENV SPRING_PROFILES_ACTIVE=prod + +EXPOSE 9300 9301 9302 9303 20010 + +ENTRYPOINT ["/app/start.sh"] \ No newline at end of file diff --git a/devops/README.md b/devops/README.md index e02a567..b7aab4d 100644 --- a/devops/README.md +++ b/devops/README.md @@ -38,10 +38,11 @@ bash build.sh 1.0.0-BETA 4. 构建前端镜像 `txw-web` #### 构建测试环境 + 仅构建后端 ``` -docker build -t txw-all:1.0.0-BETA -t txw-all:latest -f devops/Dockerfile . +docker build -t txw-all:1.0.0-BETA -t txw-all:latest -f devops/Dockerfile.test . ``` 仅构建前端 @@ -130,16 +131,16 @@ docker-compose -f docker-compose.svc.yml ps ## 服务访问 -| 服务 | 地址 | 说明 | -| ------- | --------------------------- | ----------------------------- | -| Nacos 控制台 | http://localhost:8080/index.html | Nacos 3.x Web 控制台 | -| Nacos API | http://localhost:8848/nacos | 默认账号: nacos / nacos | -| Redis | localhost:6379 | 密码: redis_password | -| MinIO | http://localhost:9000 | 控制台: http://localhost:9001 | -| Gateway | http://localhost:9300 | API 网关 | -| SSO | http://localhost:9301 | 单点登录 | -| MHZC | http://localhost:9302 | 碳资产服务 | -| YYGL | http://localhost:20010 | 运营管理服务 | +| 服务 | 地址 | 说明 | +| ------------ | -------------------------------- | ----------------------------- | +| Nacos 控制台 | http://localhost:8080/index.html | Nacos 3.x Web 控制台 | +| Nacos API | http://localhost:8848/nacos | 默认账号: nacos / nacos | +| Redis | localhost:6379 | 密码: redis_password | +| MinIO | http://localhost:9000 | 控制台: http://localhost:9001 | +| Gateway | http://localhost:9300 | API 网关 | +| SSO | http://localhost:9301 | 单点登录 | +| MHZC | http://localhost:9302 | 碳资产服务 | +| YYGL | http://localhost:20010 | 运营管理服务 | --- @@ -233,10 +234,9 @@ curl http://localhost:8848/nacos/v1/ns/operator/metrics docker exec txw-redis redis-cli -a redis_password ping ``` - ## 参考指令 ``` // 清理缓存 docker buildx prune -``` \ No newline at end of file +``` diff --git a/txw-mhzc-web/src/pages/index/views/tzzx/index.vue b/txw-mhzc-web/src/pages/index/views/tzzx/index.vue index 47dcc6a..cc68f92 100644 --- a/txw-mhzc-web/src/pages/index/views/tzzx/index.vue +++ b/txw-mhzc-web/src/pages/index/views/tzzx/index.vue @@ -33,8 +33,8 @@ export default { heightMode: 'default', resizeObserver: null, heightCheckTimer: null, - _messageHandler: null, - _iframeLoadGeneration: 0, + messageHandler: null, + iframeLoadGeneration: 0, }; }, computed: { @@ -95,14 +95,19 @@ export default { resetIframeMetrics() { this.iframeHeight = 0; this.heightMode = 'default'; - this._iframeLoadGeneration += 1; + this.iframeLoadGeneration += 1; }, onIframeLoad() { + console.log('[tzzx debug] onIframeLoad, iframeUrl=', this.iframeUrl); const iframe = this.$refs.tzzxIframe; - if (!iframe) return; + if (!iframe) { + console.log('[tzzx debug] onIframeLoad: no iframe ref'); + return; + } - const loadGeneration = this._iframeLoadGeneration; + const loadGeneration = this.iframeLoadGeneration; + console.log('[tzzx debug] onIframeLoad: loadGeneration=', loadGeneration); this.cleanupObserversOnly(); const isSameOrigin = this.trySameOrigin(iframe, loadGeneration); @@ -113,23 +118,31 @@ export default { trySameOrigin(iframe, loadGeneration) { try { + console.log('trySameOrigin'); const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; if (!iframeDoc || !iframeDoc.body) { + console.log('[tzzx debug] trySameOrigin: no doc or body'); return false; } const updateHeight = () => { - if (loadGeneration !== this._iframeLoadGeneration) return; + if (loadGeneration !== this.iframeLoadGeneration) { + console.log(`[tzzx debug] loadGeneration: ${loadGeneration}, this.iframeLoadGeneration: ${this.iframeLoadGeneration}`) + console.log('[tzzx debug] updateHeight: generation mismatch, skip'); + return; + } - const height = Math.max( + const height = Math.ceil(Math.max( iframeDoc.body.scrollHeight, iframeDoc.body.offsetHeight, iframeDoc.documentElement.scrollHeight, iframeDoc.documentElement.offsetHeight - ); + )); + console.log('[tzzx debug] updateHeight: height=', height, ', current iframeHeight=', this.iframeHeight); if (height > 0) { - this.iframeHeight = height + 20; + this.iframeHeight = height; this.heightMode = 'same-origin'; + console.log('[tzzx debug] updateHeight: set iframeHeight=', this.iframeHeight); } }; @@ -151,16 +164,19 @@ export default { } }); + console.log('[tzzx debug] trySameOrigin: success, returning true'); return true; } catch (e) { + console.log('[tzzx debug] trySameOrigin: catch error=', e); console.log('[tzzx] 检测到跨域 iframe,将使用 postMessage / 视口降级方案'); return false; } }, setupPostMessage(iframe, loadGeneration) { - this._messageHandler = (event) => { - if (loadGeneration !== this._iframeLoadGeneration) return; + console.log('[tzzx debug] setupPostMessage: loadGeneration=', loadGeneration); + this.messageHandler = (event) => { + if (loadGeneration !== this.iframeLoadGeneration) return; if (!isAllowedIframeMessageOrigin(event.origin)) return; if (event.source !== iframe.contentWindow) return; @@ -168,16 +184,21 @@ export default { if (!data || data.type !== 'iframeHeight') return; const height = Number(data.height); - if (!Number.isFinite(height) || height <= 0) return; + console.log('[tzzx debug] postMessage received: height=', height, ', type=', data && data.type); + if (!Number.isFinite(height) || height <= 0) { + console.log('[tzzx debug] postMessage: invalid height, skip'); + return; + } - this.iframeHeight = height + 20; + this.iframeHeight = Math.ceil(height); this.heightMode = 'post-message'; + console.log('[tzzx debug] postMessage: set iframeHeight=', this.iframeHeight); }; - window.addEventListener('message', this._messageHandler); + window.addEventListener('message', this.messageHandler); const requestHeight = () => { - if (loadGeneration !== this._iframeLoadGeneration) return; + if (loadGeneration !== this.iframeLoadGeneration) return; try { iframe.contentWindow.postMessage({ type: 'REQUEST_HEIGHT' }, '*'); } catch (e) {} @@ -192,7 +213,7 @@ export default { if (retryCount >= 5) { clearInterval(this.heightCheckTimer); this.heightCheckTimer = null; - if (loadGeneration === this._iframeLoadGeneration && this.heightMode === 'default') { + if (loadGeneration === this.iframeLoadGeneration && this.heightMode === 'default') { this.applyViewportFallback(); } } @@ -200,10 +221,12 @@ export default { }, applyViewportFallback() { + console.log('[tzzx debug] applyViewportFallback'); this.heightMode = 'viewport-fallback'; }, cleanupObserversOnly() { + console.log('[tzzx debug] cleanupObserversOnly'); if (this.resizeObserver) { this.resizeObserver.disconnect(); this.resizeObserver = null; @@ -212,9 +235,9 @@ export default { clearInterval(this.heightCheckTimer); this.heightCheckTimer = null; } - if (this._messageHandler) { - window.removeEventListener('message', this._messageHandler); - this._messageHandler = null; + if (this.messageHandler) { + window.removeEventListener('message', this.messageHandler); + this.messageHandler = null; } }, @@ -228,6 +251,7 @@ export default {