chore: 拆分生产 ideship / 测试 nanafa 两套环境配置
All checks were successful
Build and Deploy Front / deploy (push) Successful in 5m39s

生产用 .env.production 与 pnpm build;测试用 .env.nanafa 与 pnpm build:test;本地 pnpm dev / dev:ideship 可切换。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-09-09 12:38:11 +08:00
parent d52e10b09e
commit c0c37a4eac
15 changed files with 154 additions and 38 deletions

View File

@ -1,11 +1,18 @@
# VITE_API_BASE_URL='http://localhost:5173/'
# 本地开发统一走线上 Admin API(与 /rbac、/order 等 Vite 代理一致)
VITE_OMS_ADMIN_URL=http://api.nanafa.com/admin
# =============================================================================
# 本地开发默认 → 测试环境 oms.nanafa.com / api.nanafa.com
# 切换到生产 API:pnpm dev:ideship (加载 .env.ideship)
# 发版构建:pnpm build(生产) / pnpm build:test(测试)
# =============================================================================
VITE_DEPLOY_TARGET=nanafa
VITE_API_ORIGIN=http://api.nanafa.com
VITE_API_ADMIN_URL=http://api.nanafa.com/admin
VITE_OMS_ADMIN_URL=http://api.nanafa.com/admin
VITE_API_ASSET_ORIGIN=http://api.nanafa.com/admin
# 企业微信客服
VITE_WECOM_KF_URL=https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a
# 智谱 AI(接口映射脚本生成)
# 在 https://open.bigmodel.cn 申请 API Key
VITE_ZHIPU_API_KEY=85bbbef6bafd4ca383eef04189decd07.lKVQHcLGtYE8oUn5
VITE_ZHIPU_BASE_URL=/zhipu-api
VITE_ZHIPU_MODEL=glm-5.1

11
.env.ideship Normal file
View File

@ -0,0 +1,11 @@
# =============================================================================
# 本地开发直连生产 API(ideship.com)— pnpm dev:ideship
# 仅用于联调生产;正式发版请用 pnpm build(.env.production)
# =============================================================================
VITE_DEPLOY_TARGET=ideship
VITE_API_ORIGIN=https://api.ideship.com
VITE_API_ADMIN_URL=https://api.ideship.com/admin
VITE_OMS_ADMIN_URL=https://api.ideship.com/admin
VITE_API_ASSET_ORIGIN=https://api.ideship.com/admin
VITE_WECOM_KF_URL=https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a

12
.env.nanafa Normal file
View File

@ -0,0 +1,12 @@
# =============================================================================
# 测试环境(oms.nanafa.com)— pnpm build:test → vite build --mode nanafa
# 三套 API:http://api.nanafa.com/{admin|itfx|track}
# 前端站点:https://oms.nanafa.com
# =============================================================================
VITE_DEPLOY_TARGET=nanafa
VITE_API_ORIGIN=http://api.nanafa.com
VITE_API_ADMIN_URL=http://api.nanafa.com/admin
VITE_API_ASSET_ORIGIN=http://api.nanafa.com/admin
VITE_OMS_ADMIN_URL=http://api.nanafa.com/admin
VITE_WECOM_KF_URL=https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a

View File

@ -0,0 +1,13 @@
# =============================================================================
# 生产环境(ideship.com)— vite build / vite build --mode production
# 三套 API:https://api.ideship.com/{admin|itfx|track}
# 前端站点:https://ideship.com
# =============================================================================
VITE_DEPLOY_TARGET=ideship
VITE_API_ORIGIN=https://api.ideship.com
VITE_API_ADMIN_URL=https://api.ideship.com/admin
VITE_API_ASSET_ORIGIN=https://api.ideship.com/admin
VITE_OMS_ADMIN_URL=https://api.ideship.com/admin
# 企业微信客服
VITE_WECOM_KF_URL=https://work.weixin.qq.com/kfid/kfcae09c206f6c7045a

View File

@ -202,7 +202,15 @@ flowchart TD
## 4. 接口说明
API 前缀:`https://api.nanafa.com/admin`(`ASPNETCORE_PATHBASE=/admin`)
API 前缀:`https://api.ideship.com/admin`(`ASPNETCORE_PATHBASE=/admin`)
生产三套服务:
| 服务 | Swagger / PATHBASE |
|------|-------------------|
| Admin | https://api.ideship.com/admin/index.html |
| Itfx | https://api.ideship.com/itfx/index.html |
| Track | https://api.ideship.com/track/index.html |
### 4.1 获取登录二维码
@ -300,10 +308,10 @@ Content-Type: application/json
**现网配置 URL:**
```
https://oms.nanafa.com/api/apiwechat/verification
https://api.ideship.com/admin/apiwechat/verification
```
Nginx 反代至 `https://api.nanafa.com/admin/apiwechat/verification`。
(旧站曾用 `https://oms.nanafa.com/api/apiwechat/verification` 反代到 Admin。)
| 方法 | 路径 | 说明 |
|------|------|------|
@ -410,7 +418,7 @@ src/SimpleAdmin.Api/
| 项 | 值 |
|----|-----|
| URL | `https://oms.nanafa.com/api/apiwechat/verification` |
| URL | `https://api.ideship.com/admin/apiwechat/verification` |
| Token | 与数据库/AppSettings 一致 |
| 消息加解密 | **明文**(当前实现) |
@ -467,8 +475,9 @@ location ^~ /api/apiwechat/ {
完整 URL 示例:
```
GET https://api.nanafa.com/admin/wechat/mp/login-qrcode?loginUuid=abc123
GET https://api.nanafa.com/admin/rbac/auth/wx-login/status?loginUuid=abc123
POST https://api.nanafa.com/admin/rbac/auth/wx-login
POST https://oms.nanafa.com/api/apiwechat/verification
GET https://api.ideship.com/admin/wechat/mp/login-qrcode?loginUuid=abc123
GET https://api.ideship.com/admin/rbac/auth/wx-login/status?loginUuid=abc123
POST https://api.ideship.com/admin/rbac/auth/wx-login
POST https://api.ideship.com/admin/apiwechat/verification
GET https://api.ideship.com/admin/wechat/oauth/config
```

View File

@ -8,7 +8,8 @@
# /etc/nginx/ssl/oms.nanafa.com.key
# 4. 官网在 /(dist/site/index.html);客户登录 /login;管理端 /admin
# 5. 静态资源使用 /login-assets/,勿使用 /login/ 目录名
# 6. 微信公众号服务器 URL 请使用 https://oms.nanafa.com/api/apiwechat/verification
# 6. 微信公众号服务器 URL 请使用 https://api.ideship.com/admin/apiwechat/verification
# (生产三套:admin / itfx / track,均挂在 https://api.ideship.com/{pathbase})
# ============================================================================
# HTTP → HTTPS

View File

@ -11,7 +11,11 @@
"preinstall": "node -e \"if (!process.env.npm_config_user_agent || !process.env.npm_config_user_agent.includes('pnpm')) { console.error('Please use pnpm to install dependencies.'); process.exit(1); }\"",
"generate:order-template": "node scripts/generate-order-template.js",
"dev": "vite",
"dev:test": "vite --mode nanafa",
"dev:ideship": "vite --mode ideship",
"build": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=1 node --max-old-space-size=4096 node_modules/vite/bin/vite.js build",
"build:prod": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=1 node --max-old-space-size=4096 node_modules/vite/bin/vite.js build --mode production",
"build:test": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=1 node --max-old-space-size=4096 node_modules/vite/bin/vite.js build --mode nanafa",
"postbuild": "node scripts/postbuild-cleanup-dist.js",
"report": "cross-env REPORT=true pnpm run build",
"preview": "npm run build && vite preview --host",

View File

@ -59,7 +59,10 @@ export async function getWeChatOAuthConfig(): Promise<WxOAuthConfigResult> {
const data = unwrapOrSelf<WxOAuthConfigResult & Record<string, unknown>>(body);
const appId = String(data.appId ?? data.AppId ?? '').trim();
const oauthRedirectBase = String(
data.oauthRedirectBase ?? data.OAuthRedirectBase ?? '',
data.oauthRedirectBase ??
data.oAuthRedirectBase ??
data.OAuthRedirectBase ??
'',
).trim();
return {
appId,

View File

@ -0,0 +1,37 @@
/**
* 部署目标(由 Vite mode / env 文件切换,勿在业务里写死域名)
*
* | 目标 | 前端 | API |
* |------|------|-----|
* | ideship(生产) | https://ideship.com | https://api.ideship.com/{admin,itfx,track} |
* | nanafa(测试) | https://oms.nanafa.com | http://api.nanafa.com/{admin,itfx,track} |
*
* 本地:pnpm dev(测试) / pnpm dev:ideship(生产 API)
* 构建:pnpm build(生产) / pnpm build:test(测试)
*/
export type DeployTarget = 'ideship' | 'nanafa'
export const DEPLOY_TARGETS = {
ideship: {
siteOrigin: 'https://ideship.com',
apiOrigin: 'https://api.ideship.com',
adminBase: 'https://api.ideship.com/admin',
itfxBase: 'https://api.ideship.com/itfx',
trackBase: 'https://api.ideship.com/track',
},
nanafa: {
siteOrigin: 'https://oms.nanafa.com',
apiOrigin: 'http://api.nanafa.com',
adminBase: 'http://api.nanafa.com/admin',
itfxBase: 'http://api.nanafa.com/itfx',
trackBase: 'http://api.nanafa.com/track',
},
} as const
export function resolveDeployTarget(): DeployTarget {
const raw = String(import.meta.env.VITE_DEPLOY_TARGET ?? '').trim().toLowerCase()
if (raw === 'nanafa') return 'nanafa'
if (raw === 'ideship') return 'ideship'
// 未显式配置时:生产构建默认 ideship,开发默认 nanafa
return import.meta.env.PROD ? 'ideship' : 'nanafa'
}

2
src/env.d.ts vendored
View File

@ -31,6 +31,8 @@ declare module '*.vue' {
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string;
readonly VITE_OMS_URL?: string;
/** 部署目标:ideship(生产)| nanafa(测试) */
readonly VITE_DEPLOY_TARGET?: 'ideship' | 'nanafa' | string;
/** 生产 Admin 基址,默认 https://api.ideship.com/admin */
readonly VITE_API_ADMIN_URL?: string;
readonly VITE_OMS_ADMIN_URL?: string;

View File

@ -3172,7 +3172,7 @@ export default {
'system.otherConfig.form.remark': 'Remark',
'system.otherConfig.placeholder.input': 'Please enter',
'system.otherConfig.placeholder.configCode': 'e.g. track_service',
'system.otherConfig.placeholder.baseUrl': 'e.g. http://api.idtms.com/track',
'system.otherConfig.placeholder.baseUrl': 'e.g. https://api.ideship.com/track',
'system.otherConfig.placeholder.appSecretEdit': 'Leave blank to keep unchanged',
'system.otherConfig.modal.addTitle': 'Add Config',
'system.otherConfig.modal.editTitle': 'Edit Config',

View File

@ -3220,7 +3220,7 @@ export default {
'system.otherConfig.form.remark': '备注',
'system.otherConfig.placeholder.input': '请输入',
'system.otherConfig.placeholder.configCode': '如 track_service',
'system.otherConfig.placeholder.baseUrl': '如 http://api.idtms.com/track',
'system.otherConfig.placeholder.baseUrl': '如 https://api.ideship.com/track',
'system.otherConfig.placeholder.appSecretEdit': '留空则不修改',
'system.otherConfig.modal.addTitle': '新增配置',
'system.otherConfig.modal.editTitle': '编辑配置',

View File

@ -1,7 +1,8 @@
/**
* Admin API 地址(方案 A)
* - 开发:相对路径,Vite 代理到 Admin
* - 生产:直连 https://api.ideship.com/admin(可用 VITE_API_ADMIN_URL 覆盖)
* - 优先 VITE_API_ADMIN_URL(.env.production / .env.nanafa / .env.ideship 切换)
* - 未配置且开发:相对路径走 Vite 代理
* - 未配置且生产构建:默认 https://api.ideship.com/admin
*/
function normalizeBase(base: string): string {
@ -13,49 +14,58 @@ function ensureLeadingSlash(path: string): string {
}
const DEFAULT_PROD_ADMIN = 'https://api.ideship.com/admin'
const DEFAULT_TEST_ADMIN = 'http://api.nanafa.com/admin'
function prodAdminBase(): string {
function configuredAdminBase(): string | undefined {
const override = import.meta.env.VITE_API_ADMIN_URL as string | undefined
if (override?.trim()) return normalizeBase(override)
return DEFAULT_PROD_ADMIN
return undefined
}
function prodAdminBase(): string {
return configuredAdminBase() ?? DEFAULT_PROD_ADMIN
}
/** 浏览器请求 Admin API(OpenAPI.BASE 或 omsUrl/orderUrl 等) */
export function resolveAdminApiPath(path: string): string {
const p = ensureLeadingSlash(path)
const configured = configuredAdminBase()
if (configured) {
return `${configured}${p}`
}
if (!import.meta.env.DEV) {
return `${prodAdminBase()}${p}`
return `${DEFAULT_PROD_ADMIN}${p}`
}
return p
}
export function resolveOpenApiBase(): string {
const configured = configuredAdminBase()
if (configured) return configured
if (!import.meta.env.DEV) {
return prodAdminBase()
return DEFAULT_PROD_ADMIN
}
return ''
}
/** 桌面 Agent 等直连 Admin 网关 */
export function resolveDirectAdminApiUrl(): string {
const override = import.meta.env.VITE_API_ADMIN_URL as string | undefined
if (override?.trim()) {
return normalizeBase(override)
}
const configured = configuredAdminBase()
if (configured) return configured
if (import.meta.env.DEV) {
return 'http://api.nanafa.com/admin'
return DEFAULT_TEST_ADMIN
}
return DEFAULT_PROD_ADMIN
}
/** 静态资源(uploads)在 Admin wwwroot,须带 `/admin`。
* 生产默认 api 域名;开发空串走 Vite `/uploads` 代理。
*/
/** 静态资源(uploads)在 Admin wwwroot,须带 `/admin`。 */
export function resolveAdminAssetOrigin(): string {
const override = import.meta.env.VITE_API_ASSET_ORIGIN as string | undefined
if (override?.trim()) {
return normalizeBase(override)
}
const configured = configuredAdminBase()
if (configured) return configured
if (!import.meta.env.DEV) {
return DEFAULT_PROD_ADMIN
}

View File

@ -1,5 +1,7 @@
/**
* 方案 A:生产直连 api.ideship.com PATHBASE;开发仍走 Vite 代理旧路径。
* 方案 A:按 VITE_API_ORIGIN 改写到 {admin|itfx|track} PATHBASE。
* 生产默认 https://api.ideship.com;测试用 .env.nanafa → http://api.nanafa.com。
* 开发且未配置 VITE_API_ORIGIN 时不改写(走 Vite 代理)。
*/
const SPA_API_PREFIXES = [
@ -17,9 +19,11 @@ const SPA_API_PREFIXES = [
const DEFAULT_PROD_API = 'https://api.ideship.com'
function prodApiOrigin(): string {
function prodApiOrigin(): string | null {
const override = (import.meta.env.VITE_API_ORIGIN as string | undefined)?.trim()
return (override || DEFAULT_PROD_API).replace(/\/$/, '')
if (override) return override.replace(/\/$/, '')
if (import.meta.env.DEV) return null
return DEFAULT_PROD_API
}
function isItfxSpaPath(afterApi: string): boolean {
@ -29,15 +33,17 @@ function isItfxSpaPath(afterApi: string): boolean {
)
}
/** 生产:遗留路径 → https://api.ideship.com/{itfx|track|admin}/... */
/** 遗留路径 → {apiOrigin}/{itfx|track|admin}/... */
export function rewriteBrowserApiPath(url: string): string {
if (!url || import.meta.env.DEV) return url
if (!url) return url
if (/^https?:\/\//i.test(url) || url.startsWith('data:') || url.startsWith('blob:')) {
return url
}
let path = url.startsWith('/') ? url : `/${url}`
const origin = prodApiOrigin()
if (!origin) return url
let path = url.startsWith('/') ? url : `/${url}`
// 已是绝对 PATHBASE 相对路径 → 挂到 api 域名
if (

View File

@ -207,7 +207,7 @@ const PRESET_DEFS: Array<{
defaults: {
configCode: TRACK_SERVICE_CONFIG_CODE,
enabled: true,
baseUrl: 'http://api.idtms.com/track',
baseUrl: 'https://api.ideship.com/track',
timeoutSeconds: 30,
},
meta: {
@ -226,6 +226,7 @@ const PRESET_DEFS: Array<{
defaults: {
configCode: WECHAT_MP_CONFIG_CODE,
enabled: true,
baseUrl: 'https://ideship.com',
timeoutSeconds: 30,
},
meta: {