From bc14ec7bd22b0da102ce991326b63af9885313f6 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 8 Aug 2026 11:33:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 3 ++- AGENTS.md | 12 ++++++++++++ Dockerfile | 2 ++ README.md | 2 ++ docker-compose.test.yml | 3 +-- docker/runtime-config.sh | 7 +++++++ index.html | 1 + nginx/default.conf.template | 7 +++++++ public/runtime-config.js | 1 + shared/AGENTS.md | 8 ++++++++ src/core/config/runtimeConfig.ts | 14 ++++++++++++++ src/modules/customers/pages/CustomersView.vue | 3 ++- 12 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 docker/runtime-config.sh create mode 100644 public/runtime-config.js create mode 100644 src/core/config/runtimeConfig.ts diff --git a/.env.example b/.env.example index 30f7bb32..3ebc6ad4 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ VITE_API_BASE_URL=/api API_PROXY_TARGET=http://8.163.30.128:9000 -VITE_CLIENT_WEB_URL=http://localhost:5176 +# Local Vite fallback. Container deployments should use CLIENT_WEB_URL instead. +VITE_CLIENT_WEB_URL=http://localhost:5174 diff --git a/AGENTS.md b/AGENTS.md index 742ae602..1b7e0e93 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,6 +31,18 @@ 依赖方向保持为 `app -> modules/core/shared`、`modules -> core/shared`、`core -> shared`、`shared -> 无上层依赖`。模块间确需调用时只能引用对方根入口公开的 API 或契约,不得引用其他模块的页面、内部组件或内部目录。 +## 一期/二期/三期 Admin 快速索引 + +按阶段处理需求时,先核对仓库根目录对应阶段文档,再进入下列模块;阶段范围高于原型中的全量菜单。模块代码均从 `src/` 起算。 + +| 阶段 | Admin 范围与入口 | 当前边界 | +|---|---|---| +| 一期:头程订单闭环 | `modules/auth/` 登录;`customers/` 客户与企业审核;`iam/` 内部用户、角色、权限;`warehouses/` 平台收货仓;`master-data/` 快递公司、往来单位;`first-leg-orders/` 头程订单;`dashboard/` 工作台 | 功能基本完成,处于测试环境部署、样本补齐和验收收口;企业审核已合并客户列表,平台 RBAC 仅维护平台员工与平台权限资源 | +| 二期:到仓与头程计费 | `modules/inbounds/` 入库预报、收货、测量/OCR、审核、差异与费用快照;`warehouse-resources/pallets/` 托盘;`warehouse-resources/locations/` 库位;`fba-pricing/`、`dimension-config/` 计费规则与尺寸配置;`unified-orders/` 订单工作流编排 | 技术闭环完成,验收终点为 `WAIT_SPLIT + APPROVED + CONFIRMED`(等待三期分柜);海外仓阶梯费用仅后端契约已具备,前端联调仍需单独确认;不得把内部备注、文件或租户上下文泄露给 Client | +| 三期:国内出仓 | 当前无正式三期模块;规划复用 `first-leg-orders/`、`unified-orders/`、`inbounds/` 的订单与入库工作流页面,新增出仓能力时按稳定契约拆分模块 | 当前 NO-GO。先解除 `../../docs/三期/三期需求确认表.md` 的 P3-Q1/Q2/Q5/Q9/Q11/Q12/Q13 等阻断项;不得把原型中的分柜、装柜、报关、港务或完整 WMS 菜单提前展示 | + +阶段文档入口(路径相对本文件所在目录):一期读 `../../docs/一期/一期开发进度表.md` 与 `../../docs/一期/一期头程订单闭环设计.md`;二期读 `../../docs/二期/README.md`、`../../docs/二期/二期需求优化版-v2-测量计费入库主流程.md` 及联调报告;三期读 `../../docs/三期/README.md`、`../../docs/三期/三期开发规划.md`、`../../docs/三期/三期需求确认表.md` 和页面清单。阶段状态与代码现状冲突时,以需求确认和验收证据为准,并在改动说明中记录。 + ## 业务与安全约束 - 当前产品层级只有平台和客户(企业)两级;Admin 不把“租户”作为用户可见概念,不新增租户选择器、目标租户文案或依赖租户上下文才能使用的页面流程。多租户产品能力后续单独设计。 diff --git a/Dockerfile b/Dockerfile index a1ecea6e..b3ecd31c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,6 +27,8 @@ RUN pnpm build FROM nginx:1.27-alpine COPY nginx/default.conf.template /etc/nginx/templates/default.conf.template +COPY docker/runtime-config.sh /docker-entrypoint.d/40-runtime-config.sh +RUN chmod +x /docker-entrypoint.d/40-runtime-config.sh COPY --from=build /app/dist /usr/share/nginx/html EXPOSE 80 diff --git a/README.md b/README.md index 79fa4c41..3b816d10 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ VITE_API_BASE_URL=/api API_PROXY_TARGET=http://8.163.30.128:9000 ``` +客户代登录打开的工作台地址是运行时配置,不需要为每个环境重新构建镜像。Docker 部署时设置容器环境变量 `CLIENT_WEB_URL`,例如 `http://8.163.30.128:9002`;容器启动时会生成 `/runtime-config.js`。本地 Vite 开发才使用 `VITE_CLIENT_WEB_URL` 作为兜底,当前 Client 默认端口为 `5174`。 + 认证请求使用 `/api/auth/**`,平台 IAM 请求使用 `/api/platform/v1/iam/**`。登录后从 JWT 读取平台身份和授权快照,再与 IAM 返回的启用权限资源取交集。企业审核调用 `/reviews`,打开审核详情后按租户调用 `/tenants/{tenantId}/qualifications`;营业执照通过 `/api/platform/v1/files/qualifications/{tenantId}/{fileName}` 携带平台 Token 临时读取,关闭预览后释放本地对象地址。客户端自主注册企业审核通过后继续使用注册账号作为管理员,不展示新凭据;Admin 代建企业并由后端创建管理员时,页面必须展示不可通过遮罩、Esc 或关闭按钮跳过的一次性凭据弹窗,运营人员确认保存后才清除账号密码。平台角色查询、新增、编辑、启停、删除和权限全量保存均已按 `RbacController` 接入真实 `/roles` 契约,角色返回的 `permissionIds` 用于授权回显;系统内置角色及仍被成员使用的角色继续由服务端保护。权限资源查询和新增调用 `/permissions`,尚未提供的权限编辑、删除和启停不会模拟成功。一期真实权限资源只创建 `MENU` 与 `BUTTON`,不创建 `PAGE` 或 `API` 类型。其余业务页面需在对应服务契约确认后逐项替换,生产逻辑不得静默回退到模拟数据。 仓库管理已接入真实平台 Warehouse API,统一维护国内收货仓、FBA 仓和海外仓,支持按租户筛选、详情、新增、编辑和启停,并在更新时保留后端返回的地址、能力和截单时间等完整字段。停用仓库保留历史数据,但不再提供给新业务选择;订单详情使用下单时保存的仓库编码、名称和地址快照,仓库主数据后续修改不改变历史展示。库存和出入库作业由对应业务模块管理,不在仓库主数据页面中模拟。 diff --git a/docker-compose.test.yml b/docker-compose.test.yml index c71d0652..23ad5bdc 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -3,8 +3,6 @@ services: build: context: . dockerfile: Dockerfile - args: - VITE_CLIENT_WEB_URL: "${VITE_CLIENT_WEB_URL:-http://8.163.30.128:9002}" image: admin-web-test:local container_name: admin-web-test restart: unless-stopped @@ -13,6 +11,7 @@ services: extra_hosts: - "host.docker.internal:host-gateway" environment: + CLIENT_WEB_URL: "${CLIENT_WEB_URL:-http://8.163.30.128:9002}" # Gateway 与前端容器在同一台测试服务器,通过宿主机内部地址访问。 # 测试环境固定走 Docker 宿主机网关,避免 Jenkins 全局环境变量或 # 工作区残留配置把上游覆盖成公网 IP,造成容器回连公网端口失败。 diff --git a/docker/runtime-config.sh b/docker/runtime-config.sh new file mode 100644 index 00000000..9b699f84 --- /dev/null +++ b/docker/runtime-config.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu + +runtime_file=/usr/share/nginx/html/runtime-config.js +client_web_url=${CLIENT_WEB_URL:-} +escaped_url=$(printf '%s' "$client_web_url" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r/\\r/g; s/\n/\\n/g') +printf "window.__CHONGCHONG_RUNTIME_CONFIG__ = { clientWebUrl: \"%s\" }\n" "$escaped_url" > "$runtime_file" diff --git a/index.html b/index.html index 47c0ca33..7a610ec4 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,7 @@ 柏悦物流管理后台 +
diff --git a/nginx/default.conf.template b/nginx/default.conf.template index 0cf33330..4bbf5ed5 100644 --- a/nginx/default.conf.template +++ b/nginx/default.conf.template @@ -12,6 +12,13 @@ server { return 200 "ok\n"; } + location = /runtime-config.js { + add_header Cache-Control "no-cache, no-store, must-revalidate" always; + add_header Pragma "no-cache" always; + add_header Expires "0" always; + try_files $uri =404; + } + # 前端代码中的 API 前缀为 /api;保持原始路径转给 Gateway。 location /api/ { client_max_body_size 12m; diff --git a/public/runtime-config.js b/public/runtime-config.js new file mode 100644 index 00000000..9a482f5d --- /dev/null +++ b/public/runtime-config.js @@ -0,0 +1 @@ +window.__CHONGCHONG_RUNTIME_CONFIG__ = window.__CHONGCHONG_RUNTIME_CONFIG__ || { clientWebUrl: '' } diff --git a/shared/AGENTS.md b/shared/AGENTS.md index 5efe933f..08e71d0d 100644 --- a/shared/AGENTS.md +++ b/shared/AGENTS.md @@ -13,6 +13,14 @@ - 服务端字段变化先核对 Controller、DTO 和 OpenAPI,再更新本应用的类型、API 适配层和测试;本包不反向定义服务端行为。 - 避免建立宽泛的万能类型或引入重量级依赖。 +## 一期/二期/三期共享模型索引 + +- 一期消费者主要是 `customers`、`iam`、`warehouses`、`master-data`、`first-leg-orders`;`CurrentUser`、`NavigationItem`、`ApiResponse`、平台收货仓快照及头程订单状态常量由 `src/index.ts` 统一导出。共享导出只描述前端数据形状,不替代 Java 服务端权限或状态机。 +- 二期消费者主要是 `inbounds`、`warehouse-resources`、`fba-pricing`、`dimension-config` 与 `unified-orders`。测量、费用、托盘、库位等类型若只被单一模块使用,应留在模块内;确需跨模块复用时,先核对 `baiyue-firstleg` Controller/DTO/OpenAPI,再以兼容方式新增导出。 +- 三期当前 NO-GO,暂无正式三期共享契约。不要为了复用原型中的分柜、装柜、报关或 PDA 字段提前扩展本包;待 `../../../docs/三期/三期需求确认表.md` 阻断项解除并锁定后端契约,再评估新增类型并同步全部 Admin 消费者。 + +阶段依据(路径相对本文件所在目录):一期 `../../../docs/一期/`,二期 `../../../docs/二期/`,三期 `../../../docs/三期/`;共享包不保存阶段进度,也不承载跨应用(Client)源码复用。 + ## 兼容性与验证 - 修改导出名称、字段类型、枚举值或常量语义前,搜索当前应用内全部消费者。 diff --git a/src/core/config/runtimeConfig.ts b/src/core/config/runtimeConfig.ts new file mode 100644 index 00000000..004704d4 --- /dev/null +++ b/src/core/config/runtimeConfig.ts @@ -0,0 +1,14 @@ +export type AdminRuntimeConfig = { + clientWebUrl?: string +} + +declare global { + interface Window { + __CHONGCHONG_RUNTIME_CONFIG__?: AdminRuntimeConfig + } +} + +export function getClientWebUrl(): string { + const runtimeUrl = window.__CHONGCHONG_RUNTIME_CONFIG__?.clientWebUrl + return String(runtimeUrl || import.meta.env.VITE_CLIENT_WEB_URL || '').trim() +} diff --git a/src/modules/customers/pages/CustomersView.vue b/src/modules/customers/pages/CustomersView.vue index a26ad1f9..4538d897 100644 --- a/src/modules/customers/pages/CustomersView.vue +++ b/src/modules/customers/pages/CustomersView.vue @@ -39,6 +39,7 @@ import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.v import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue' import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog' import { useAccessPreviewStore } from '@/core/access/accessPreview' +import { getClientWebUrl } from '@/core/config/runtimeConfig' type CustomerFilters = QueryModel & { keyword: string; status: PlatformTenantStatus | '' } type QualificationDraft = { @@ -701,7 +702,7 @@ async function submitImpersonation() { if (!impersonationTenant.value || impersonationSubmitting.value || !impersonationFormRef.value) return const valid = await impersonationFormRef.value.validate().then(() => true).catch(() => false) if (!valid) return - const clientUrl = String(import.meta.env.VITE_CLIENT_WEB_URL || '').trim() + const clientUrl = getClientWebUrl() if (!clientUrl) { impersonationError.value = getApiErrorDetails(new Error('未配置客户工作台地址'), '暂未配置客户工作台地址,无法安全跳转登录') return