diff --git a/Jenkinsfile b/Jenkinsfile index c80b947f..9a398fc0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -70,7 +70,7 @@ pipeline { docker build \ --build-arg NODE_IMAGE="$NODE_BASE_IMAGE" \ --build-arg NGINX_IMAGE="$NGINX_BASE_IMAGE" \ - --build-arg VITE_CLIENT_WEB_URL=http://8.163.49.32:9002 \ + --build-arg VITE_CLIENT_WEB_URL="${CLIENT_WEB_URL:-https://dev-app.buggoglobal.com/}" \ -t "$image" . export IMAGE_TAG="$SOURCE_TAG" docker compose -p "$DEVELOPMENT_COMPOSE_PROJECT" -f "$DEVELOPMENT_COMPOSE_FILE" up -d --remove-orphans --pull never diff --git a/README.md b/README.md index 0e8eca94..3cb6f085 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ VITE_CLIENT_WEB_URL=http://localhost:5174 切换开发或测试环境时,只修改未提交的 `.env.local` 中 `API_PROXY_TARGET`、`OVERSEAS_API_PROXY_TARGET` 和 `VITE_CLIENT_WEB_URL`,然后重启 `pnpm dev`;无需修改业务代码。真实环境地址不写入受版本控制的配置模板或说明。 -客户代登录打开的工作台地址是运行时配置,不需要为每个环境重新构建镜像。Docker 部署时设置容器环境变量 `CLIENT_WEB_URL`;容器启动时会生成 `/runtime-config.js`。本地 Vite 开发使用 `VITE_CLIENT_WEB_URL` 作为兜底。 +客户代登录打开的工作台地址是运行时配置,不需要为每个环境重新构建镜像。Docker 部署时为 Admin 容器设置当前环境的 `CLIENT_WEB_URL`;容器启动时会生成 `/runtime-config.js`。开发、测试和生产分别在各自部署任务中注入自己的 Client 根地址,禁止复用其他环境的域名。本地 Vite 开发使用 `VITE_CLIENT_WEB_URL` 作为兜底。部署后可读取 `/runtime-config.js` 核对最终生效值。 认证请求使用 `/api/auth/**`,平台 IAM 请求使用 `/api/platform/v1/iam/**`。登录后只从 JWT 读取平台身份,菜单和操作权限通过当前用户授权接口实时加载,不从 JWT 携带或解析角色权限。企业审核调用 `/reviews`,打开审核详情后按租户调用 `/tenants/{tenantId}/qualifications`;营业执照通过 `/api/platform/v1/files/qualifications/{tenantId}/{fileName}` 携带平台 Token 临时读取,关闭预览后释放本地对象地址。客户端自主注册企业审核通过后继续使用注册账号作为管理员,不展示新凭据;Admin 代建企业并由后端创建管理员时,页面必须展示不可通过遮罩、Esc 或关闭按钮跳过的一次性凭据弹窗,运营人员确认保存后才清除账号密码。平台角色查询、新增、编辑、启停、删除和权限全量保存均已按 `RbacController` 接入真实 `/roles` 契约,角色返回的 `permissionIds` 用于授权回显;系统内置角色及仍被成员使用的角色继续由服务端保护。权限资源查询和新增调用 `/permissions`,尚未提供的权限编辑、删除和启停不会模拟成功。一期真实权限资源只创建 `MENU` 与 `BUTTON`,不创建 `PAGE` 或 `API` 类型。其余业务页面需在对应服务契约确认后逐项替换,生产逻辑不得静默回退到模拟数据。 diff --git a/docker-compose.development.yml b/docker-compose.development.yml index f39efb2b..a677b495 100644 --- a/docker-compose.development.yml +++ b/docker-compose.development.yml @@ -6,7 +6,7 @@ services: ports: - "127.0.0.1:9001:80" environment: - CLIENT_WEB_URL: "http://8.163.49.32:9002" + CLIENT_WEB_URL: "${CLIENT_WEB_URL:-https://dev-app.buggoglobal.com/}" API_UPSTREAM: "http://firstleg-development-gateway:9000" OVERSEAS_API_UPSTREAM: "http://firstleg-development-gateway-overseas:9300" networks: diff --git a/docker-compose.test.yml b/docker-compose.test.yml index c8c35400..f522117c 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -12,8 +12,8 @@ services: ports: - "${HOST_PORT:-9001}:80" environment: - # The test client is exposed on the same host through port 9002. Allow - # deployments to override this, but never fall back to the server IP. - CLIENT_WEB_URL: "${CLIENT_WEB_URL:-http://test-admin.buggoglobal.com:9002}" + # Runtime URL used by the secure customer-workbench handoff. Each + # environment may override it without rebuilding the Admin image. + CLIENT_WEB_URL: "${CLIENT_WEB_URL:-https://test-app.buggoglobal.com/}" API_UPSTREAM: "http://test-api-cn.buggoglobal.com" OVERSEAS_API_UPSTREAM: "http://test-api-global.buggoglobal.com" diff --git a/src/deployment/nginxConfig.test.ts b/src/deployment/nginxConfig.test.ts index 2fb21fba..a26cf17b 100644 --- a/src/deployment/nginxConfig.test.ts +++ b/src/deployment/nginxConfig.test.ts @@ -40,8 +40,9 @@ describe('admin nginx deployment config', () => { it('declares an explicit overseas gateway upstream in container deployments', () => { expect(testCompose).toContain('API_UPSTREAM: "http://test-api-cn.buggoglobal.com"') expect(testCompose).toContain('OVERSEAS_API_UPSTREAM: "http://test-api-global.buggoglobal.com"') - expect(testCompose).toContain('CLIENT_WEB_URL: "${CLIENT_WEB_URL:-http://test-admin.buggoglobal.com:9002}"') + expect(testCompose).toContain('CLIENT_WEB_URL: "${CLIENT_WEB_URL:-https://test-app.buggoglobal.com/}"') expect(testCompose).not.toContain('CLIENT_WEB_URL: "http://8.163.') + expect(developmentCompose).toContain('CLIENT_WEB_URL: "${CLIENT_WEB_URL:-https://dev-app.buggoglobal.com/}"') expect(developmentCompose).toContain('OVERSEAS_API_UPSTREAM: "http://firstleg-development-gateway-overseas:9300"') expect(config).toContain('proxy_set_header Host $proxy_host;') }) @@ -64,5 +65,6 @@ describe('admin nginx deployment config', () => { expect(jenkinsfile).toContain("NGINX_BASE_IMAGE = '172.31.198.7:10082/java-project/nginx:1.27-alpine'") expect(jenkinsfile).toContain('withCredentials([usernamePassword(') expect(jenkinsfile).toContain('export DOCKER_CONFIG="${WORKSPACE}@tmp/docker-auth"') + expect(jenkinsfile).toContain('--build-arg VITE_CLIENT_WEB_URL="${CLIENT_WEB_URL:-https://dev-app.buggoglobal.com/}"') }) }) diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts index 91ab3e26..7a230e81 100644 --- a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts +++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts @@ -252,7 +252,7 @@ describe('GlobalSmartLoadingView', () => { const groupedPlan = { ...plan, items } const group = { groupId: '2093539779795795969', groupNo: 'CLG-2093539779795795969', status: 'LOCKED' as const, warehouseId: '8', channelCode: 'ZBYHK', lockedPlanId: '99', version: 1, - members: items.map((item) => ({ tenantId: item.accountId, orderId: item.orderId, inboundId: item.inboundId, fullPackageCount: item.packageCount })), fullPackageCount: 13, createdAt: '2026-08-29T10:00:00', updatedAt: '2026-08-29T10:30:00', + members: items.map((item) => ({ tenantId: item.accountId, orderId: item.orderId, inboundId: item.inboundId, inboundCode: item.inboundCode, fullPackageCount: item.packageCount })), fullPackageCount: 13, createdAt: '2026-08-29T10:00:00', updatedAt: '2026-08-29T10:30:00', } vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValueOnce(groupedPlan).mockResolvedValue({ ...groupedPlan, version: 3, items: [] }) vi.mocked(batchQueryPlatformCoLoadGroups).mockResolvedValue([...new Set(items.map((item) => item.orderId))].map((orderId) => ({ orderId, group }))) diff --git a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts index 4028d614..532429b3 100644 --- a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts +++ b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts @@ -189,7 +189,7 @@ describe('SmartLoadingWorkbenchView', () => { vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue({ ...planResponse, items }) vi.mocked(batchQueryPlatformCoLoadGroups).mockResolvedValue([...new Set(items.map((item) => item.orderId))].map((orderId) => ({ orderId, group: { groupId: '9900', groupNo: 'CLG-9900', status: 'LOCKED', warehouseId: '8', channelCode: 'ZBYHK', lockedPlanId: '99', version: 1, - members: items.map((member) => ({ tenantId: member.accountId, orderId: member.orderId, inboundId: member.inboundId, fullPackageCount: member.packageCount })), fullPackageCount: 13, createdAt: '2026-08-29T10:00:00', updatedAt: '2026-08-29T10:30:00', + members: items.map((member) => ({ tenantId: member.accountId, orderId: member.orderId, inboundId: member.inboundId, inboundCode: member.inboundCode, fullPackageCount: member.packageCount })), fullPackageCount: 13, createdAt: '2026-08-29T10:00:00', updatedAt: '2026-08-29T10:30:00', } }))) vi.mocked(removeSmartLoadingGroup).mockResolvedValue({ ...planResponse, version: 3, items: [] }) vi.spyOn(ElMessageBox, 'confirm').mockResolvedValue('confirm' as never)