优化
This commit is contained in:
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
VITE_API_BASE_URL=/api
|
VITE_API_BASE_URL=/api
|
||||||
API_PROXY_TARGET=http://8.163.30.128:9000
|
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
|
||||||
|
|||||||
@@ -31,6 +31,18 @@
|
|||||||
|
|
||||||
依赖方向保持为 `app -> modules/core/shared`、`modules -> core/shared`、`core -> shared`、`shared -> 无上层依赖`。模块间确需调用时只能引用对方根入口公开的 API 或契约,不得引用其他模块的页面、内部组件或内部目录。
|
依赖方向保持为 `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 不把“租户”作为用户可见概念,不新增租户选择器、目标租户文案或依赖租户上下文才能使用的页面流程。多租户产品能力后续单独设计。
|
- 当前产品层级只有平台和客户(企业)两级;Admin 不把“租户”作为用户可见概念,不新增租户选择器、目标租户文案或依赖租户上下文才能使用的页面流程。多租户产品能力后续单独设计。
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ RUN pnpm build
|
|||||||
FROM nginx:1.27-alpine
|
FROM nginx:1.27-alpine
|
||||||
|
|
||||||
COPY nginx/default.conf.template /etc/nginx/templates/default.conf.template
|
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
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ VITE_API_BASE_URL=/api
|
|||||||
API_PROXY_TARGET=http://8.163.30.128:9000
|
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` 类型。其余业务页面需在对应服务契约确认后逐项替换,生产逻辑不得静默回退到模拟数据。
|
认证请求使用 `/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 仓和海外仓,支持按租户筛选、详情、新增、编辑和启停,并在更新时保留后端返回的地址、能力和截单时间等完整字段。停用仓库保留历史数据,但不再提供给新业务选择;订单详情使用下单时保存的仓库编码、名称和地址快照,仓库主数据后续修改不改变历史展示。库存和出入库作业由对应业务模块管理,不在仓库主数据页面中模拟。
|
仓库管理已接入真实平台 Warehouse API,统一维护国内收货仓、FBA 仓和海外仓,支持按租户筛选、详情、新增、编辑和启停,并在更新时保留后端返回的地址、能力和截单时间等完整字段。停用仓库保留历史数据,但不再提供给新业务选择;订单详情使用下单时保存的仓库编码、名称和地址快照,仓库主数据后续修改不改变历史展示。库存和出入库作业由对应业务模块管理,不在仓库主数据页面中模拟。
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
|
||||||
VITE_CLIENT_WEB_URL: "${VITE_CLIENT_WEB_URL:-http://8.163.30.128:9002}"
|
|
||||||
image: admin-web-test:local
|
image: admin-web-test:local
|
||||||
container_name: admin-web-test
|
container_name: admin-web-test
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -13,6 +11,7 @@ services:
|
|||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "host.docker.internal:host-gateway"
|
- "host.docker.internal:host-gateway"
|
||||||
environment:
|
environment:
|
||||||
|
CLIENT_WEB_URL: "${CLIENT_WEB_URL:-http://8.163.30.128:9002}"
|
||||||
# Gateway 与前端容器在同一台测试服务器,通过宿主机内部地址访问。
|
# Gateway 与前端容器在同一台测试服务器,通过宿主机内部地址访问。
|
||||||
# 测试环境固定走 Docker 宿主机网关,避免 Jenkins 全局环境变量或
|
# 测试环境固定走 Docker 宿主机网关,避免 Jenkins 全局环境变量或
|
||||||
# 工作区残留配置把上游覆盖成公网 IP,造成容器回连公网端口失败。
|
# 工作区残留配置把上游覆盖成公网 IP,造成容器回连公网端口失败。
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
<meta name="description" content="柏悦物流管理后台" />
|
<meta name="description" content="柏悦物流管理后台" />
|
||||||
<link rel="icon" type="image/png" href="/src/assets/brand/baiyue-favicon.png" />
|
<link rel="icon" type="image/png" href="/src/assets/brand/baiyue-favicon.png" />
|
||||||
<title>柏悦物流管理后台</title>
|
<title>柏悦物流管理后台</title>
|
||||||
|
<script src="/runtime-config.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ server {
|
|||||||
return 200 "ok\n";
|
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。
|
# 前端代码中的 API 前缀为 /api;保持原始路径转给 Gateway。
|
||||||
location /api/ {
|
location /api/ {
|
||||||
client_max_body_size 12m;
|
client_max_body_size 12m;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
window.__CHONGCHONG_RUNTIME_CONFIG__ = window.__CHONGCHONG_RUNTIME_CONFIG__ || { clientWebUrl: '' }
|
||||||
@@ -13,6 +13,14 @@
|
|||||||
- 服务端字段变化先核对 Controller、DTO 和 OpenAPI,再更新本应用的类型、API 适配层和测试;本包不反向定义服务端行为。
|
- 服务端字段变化先核对 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)源码复用。
|
||||||
|
|
||||||
## 兼容性与验证
|
## 兼容性与验证
|
||||||
|
|
||||||
- 修改导出名称、字段类型、枚举值或常量语义前,搜索当前应用内全部消费者。
|
- 修改导出名称、字段类型、枚举值或常量语义前,搜索当前应用内全部消费者。
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -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 QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||||
import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog'
|
import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog'
|
||||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||||
|
import { getClientWebUrl } from '@/core/config/runtimeConfig'
|
||||||
|
|
||||||
type CustomerFilters = QueryModel & { keyword: string; status: PlatformTenantStatus | '' }
|
type CustomerFilters = QueryModel & { keyword: string; status: PlatformTenantStatus | '' }
|
||||||
type QualificationDraft = {
|
type QualificationDraft = {
|
||||||
@@ -701,7 +702,7 @@ async function submitImpersonation() {
|
|||||||
if (!impersonationTenant.value || impersonationSubmitting.value || !impersonationFormRef.value) return
|
if (!impersonationTenant.value || impersonationSubmitting.value || !impersonationFormRef.value) return
|
||||||
const valid = await impersonationFormRef.value.validate().then(() => true).catch(() => false)
|
const valid = await impersonationFormRef.value.validate().then(() => true).catch(() => false)
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
const clientUrl = String(import.meta.env.VITE_CLIENT_WEB_URL || '').trim()
|
const clientUrl = getClientWebUrl()
|
||||||
if (!clientUrl) {
|
if (!clientUrl) {
|
||||||
impersonationError.value = getApiErrorDetails(new Error('未配置客户工作台地址'), '暂未配置客户工作台地址,无法安全跳转登录')
|
impersonationError.value = getApiErrorDetails(new Error('未配置客户工作台地址'), '暂未配置客户工作台地址,无法安全跳转登录')
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user