Files
profession-web/src/assets/config/host.config.ts
T
lijing 3bfe966a17
build / build (push) Successful in 5m40s
feat(theme): 接入云海子主题通道(A 类免插件,规范 v1.12 §2/§3)
- index.html 插 A 类 loader:唯一接入点,FOUC 门/manifest 预取/主题 link 追加与排序
  全由通道 yh-theme-init.js 承担,主题升级走 /static 通道,本应用无需重新构建
- vite.config 加 /static dev 代理(YH_THEME_PROXY_TARGET 可覆盖,默认线上通道)
- host.config 回写 __APP_CONFIG__.serviceHost(仅同源):init 的 appearance 请求有硬性
  同源限制,跨源会被直接跳过;本地 dev 保持空串走同源 /api 代理
- 顶栏头像接平台键 yh-avatar,监听 yh-appearance-updated,userInfo 兜底
- view-ui-plus 声明锁 1.3.24(对齐通道皮肤生成版本)
2026-10-21 17:35:56 +08:00

110 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { BaseConf } from "@/types/Basics";
/**
* 配置优先级(高 → 低):
* ① window.__APP_CONFIG__:线上运行时配置,index.html 引导脚本在应用模块加载前同步拉取
* /<contextPath>/api/env-config?target=<部署目录名>(本应用部署于 /{contextPath}/front/,
* 故为 front,对应后端键 yh.env-config.source.front,projman 配置管理维护)写入
* ② import.meta.env.VITE_*:仅本地开发/演示(vite dev --mode dev 读 .env.dev、--mode mock 读 .env.mock);
* build 产物不读任何 .env.*(.env.base/.env.ld/.env.prod 已删),VITE_* 恒为 undefined,
* 本层自动跳过,产物不含任何环境值
* ③ 同域推导兜底:env-config 未配置/拉取失败时框架至少能渲染并调通同源 API;
* ssoHost 为空 → 登出跳转不可用——与后端未就绪状态一致,可接受。
*/
const env = import.meta.env;
// ③ 同域推导兜底:context 段取当前路径首段(/{contextPath}/front/ → contextPath,即后端上下文),
// 与服务端 context-path 对齐(本地无、base/prod /familyactivity);本地 dev/mock 在根路径运行(无段),
// serviceHost 留空走 vite 同源代理(规避 CAS 过滤器不回 CORS 头)
const seg = window.location.pathname.split("/").filter(Boolean);
const origin = window.location.origin;
let conf: BaseConf = {
baseHost: origin,
ssoHost: "",
serviceHost: seg.length >= 2 ? `${origin}/${seg[0]}` : "",
relayConf: {
ziyuankuHost: "",
zhuanxiangHost: "",
},
isMock: false,
isDebug: env.DEV,
};
// 逐键覆盖:只覆盖来源里实际出现且非空的键,未出现的键沿用底层值
const applyConf = (target: any, source: any) => {
if (!source || typeof source !== "object") return;
Object.keys(source).forEach(key => {
if (source[key] !== undefined && source[key] !== null && source[key] !== "") {
(target as any)[key] = source[key];
}
});
};
// ② 本地开发/演示(build 产物中恒 undefined → 自动跳过)
applyConf(conf, {
baseHost: env.VITE_BASE_HOST,
ssoHost: env.VITE_SSO_HOST,
serviceHost: env.VITE_IS_MOCK === "true" ? "" : env.VITE_SERVICE_HOST,
relayConf: {
ziyuankuHost: env.VITE_ZIYUANKU_HOST,
zhuanxiangHost: env.VITE_ZHUANXIANG_HOST,
},
isMock: env.VITE_IS_MOCK === "true",
});
// ① 线上运行时配置(最高优先,覆盖前面所有);relayConf 为嵌套对象,按子键合并,
// 运行时 JSON 只配部分资源库地址时未配的键沿用兜底值
const runtime = (window as any).__APP_CONFIG__;
applyConf(conf, runtime);
if (runtime && typeof runtime === "object" && runtime.relayConf) {
applyConf(conf.relayConf, runtime.relayConf);
}
// HTTPS 自动升级:当前页面是 https 时,将所有 http:// 配置项升级为 https://
var ishttps = "https:" == document.location.protocol ? true : false;
if (ishttps) {
Object.keys(conf).forEach(element => {
if (typeof conf[element] === "string" && conf[element].indexOf("http://") > -1) {
conf[element] = conf[element].replace("http://", "https://");
}
});
// relayConf 内部也需要处理
if (conf.relayConf) {
Object.keys(conf.relayConf).forEach(key => {
const val = (conf.relayConf as any)[key];
if (typeof val === "string" && val.indexOf("http://") > -1) {
(conf.relayConf as any)[key] = val.replace("http://", "https://");
}
});
}
}
/**
* 回写 __APP_CONFIG__.serviceHost(仅同源场景)——云海子 A 类接入 §3 外观三键。
* 主题通道 yh-theme-init.js 的 appearance 请求有硬性同源限制:
* if (!url || !appearanceSameOrigin(url)) return; → 跨源会被直接跳过、连请求都不发。
* 本地 dev:serviceHost 是 VITE_SERVICE_HOST 的绝对地址(跨源),此时不能回写,
* 保持空串让 init 走同源 "/api/appearance",由 vite 代理转发到后端。
* 生产:serviceHost = 同域 ctx(https://base.../<contextPath>),同源,回写后 init 请求正确前缀。
* 已有 env-config 下发值时不动(以平台配置为准)。
*/
try {
const w = window as any;
w.__APP_CONFIG__ = w.__APP_CONFIG__ || {};
if (!w.__APP_CONFIG__.serviceHost) {
const candidate = conf.serviceHost || "";
let sameOrigin = !candidate;
try {
sameOrigin = new URL(candidate, window.location.href).origin === window.location.origin;
} catch {
sameOrigin = false;
}
if (sameOrigin) w.__APP_CONFIG__.serviceHost = candidate;
}
} catch {
/* 极端环境无 window:忽略,保持同源兜底 */
}
export default conf;