在 Vue 3 项目中接入 Velocity Global 这类全球 HR 服务平台,核心不是调用几个接口,而是把跨国雇佣、薪酬与合规能力沉淀为可复用的工程模块。Velocity Global 提供雇佣即服务(EOR)和全球薪酬接口,前端需要在构建期就确定环境隔离、令牌管理和数据类型约束。

一、工程化接入前的准备
Velocity Global 的开放接口采用 OAuth2 客户端凭据模式下发访问令牌。在 Vue 3 工程里,我们不推荐把 client_id 与 client_secret 写进前端打包资源,而应放在服务端代理或 Vite 构建时的环境变量中,仅向前端暴露代理路径。这样既能满足合规要求,也避免密钥泄露。
另一个常被忽略的点是区域化字段差异。例如员工入职状态,美国节点返回 onboarding 枚举,而德国节点可能附加了 tax_class 字段。如果前端用 any 类型直接消费,后期报表统计就会出错。因此要在工程内先定义统一的领域模型,再让接口层做适配转换。
1.1 使用 Vite 环境变量隔离配置
在 vite.config.ts 中通过 loadEnv 读取不同模式下的变量,并只把代理基址暴露给浏览器。下面示例展示了如何把 Velocity Global 的代理地址映射为运行时可用值。
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
plugins: [vue()],
define: {
// 仅暴露代理基址,不暴露密钥
__VG_API_BASE__: JSON.stringify(env.VG_PROXY_BASE || '/api/vg')
}
};
});
上述配置把 VG_PROXY_BASE 注入为全局常量,组件内可直接用 __VG_API_BASE__ 访问。真实密钥由服务端在 /api/vg 反向代理时附加,前端无感知。
这种方式的优点是构建产物不包含任何敏感信息,且多环境切换只需要改 .env 文件。缺点是代理层需要自行实现令牌续期,我们会在拦截器部分说明。
二、封装带拦截器的请求层
Vue 3 组合式 API 提倡逻辑复用,所以我们把 Velocity Global 的调用封装为独立的 axios 实例,统一处理 401 重试与业务错误码。这样页面组件只关心数据,不关心管道。
下面是一个最小可用的封装示例,包含令牌过期后的队列重试机制。注意代码中的 HTML 特殊字符已全部转义。
import axios from 'axios';
const vgHttp = axios.create({
baseURL: __VG_API_BASE__,
timeout: 10000
});
let isRefreshing = false;
let pendingQueue: Array<() => void> = [];
vgHttp.interceptors.response.use(
(res) => res.data,
async (error) => {
const status = error.response && error.response.status;
if (status === 401 && !isRefreshing) {
isRefreshing = true;
// 通知代理层刷新令牌,前端等待队列
pendingQueue.push(() => vgHttp(error.config));
// 实际刷新由代理返回新上下文,此处仅重发
isRefreshing = false;
const tasks = pendingQueue.slice();
pendingQueue = [];
return Promise.all(tasks.map((t) => t()));
}
return Promise.reject(error);
}
);
export default vgHttp;
拦截器把令牌失效的细节隐藏起来,组件调用 vgHttp.get('/employees') 时不会感知到中间的重试。对于全球 HR 数据,网络抖动较常见,该设计能显著降低白屏率。
如果团队使用 TypeScript,可进一步给 vgHttp 补充泛型方法,让返回类型与 Pinia store 中的模型对齐,减少手动断言。
2.1 定义 HR 领域模型
我们用接口描述 Velocity Global 返回的员工结构,并做一层适配函数,把不同区域的字段归一化。这样报表组件拿到的永远是统一形状。
interface VGEmployee {
id: string;
full_name: string;
country: string;
status: 'active' | 'onboarding' | 'terminated';
tax_class?: string;
}
function normalize(raw: any): VGEmployee {
return {
id: raw.id,
full_name: raw.full_name || raw.name,
country: raw.country_code || raw.country,
status: raw.status,
tax_class: raw.tax_class
};
}
通过 normalize 函数,即便后端在德国节点多返回了 tax_class,美国节点没有,前端模型依然稳定。此函数建议放在 src/vg/adapter.ts 中,与请求层分离。
在大型项目里,还可以用 zod 等运行时校验库对 raw 做校验,一旦字段缺失就上报监控,防止静默出错。
三、用 Pinia 管理全球员工状态
Vue 3 官方推荐 Pinia 作为状态库。针对 Velocity Global 的雇佣数据,我们建立一个 hrStore,负责拉取、缓存与按国家筛选。
下面的 store 示例展示了如何调用前面封装的 vgHttp,并把结果通过 normalize 存入 state。组件通过 getter 就能拿到某国的在职人数。
import { defineStore } from 'pinia';
import vgHttp from '@/vg/http';
import { normalize, VGEmployee } from '@/vg/adapter';
export const useHrStore = defineStore('hr', {
state: () => ({
employees: [] as VGEmployee[],
loaded: false
}),
getters: {
activeByCountry: (state) => (code: string) =>
state.employees.filter((e) => e.country === code && e.status === 'active')
},
actions: {
async fetchAll() {
if (this.loaded) return;
const rawList = await vgHttp.get('/employees');
this.employees = rawList.map(normalize);
this.loaded = true;
}
}
});
把数据获取收敛到 store 后,多个页面共享同一份全球员工缓存,避免重复请求。对于 Velocity Global 按量计费的接口,这也能控制成本。
当员工状态在后台变更,可以暴露一个 refresh 动作,或结合 WebSocket 推送让 store 局部更新,而不用整表重拉。
四、在组件中消费与服务编排
组合式 API 让组件逻辑非常清晰。下面示例展示某个国家 HR 看板组件如何调用 store,并处理加载态。
<template>
<div>
<h3>德国在职员工</h3>
<ul>
<li v-for="e in list" :key="e.id">{{ e.full_name }}</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useHrStore } from '@/stores/hr';
import { onMounted } from 'vue';
const hr = useHrStore();
const { employees } = storeToRefs(hr);
onMounted(() => hr.fetchAll());
const list = hr.activeByCountry('DE');
</script>
该组件不直接依赖 vgHttp,也不关心令牌刷新,只通过 store 的 getter 拿到德国在职员工。这种分层让 Velocity Global 的接入细节被完全封装在工程底部。
如果未来更换 HR 服务商,只要改写 adapter 与 http 层,上层组件和 Pinia 结构基本不用动,工程化价值就此体现。
五、合规与错误处理建议
全球 HR 数据涉及个人隐私,前端日志禁止打印完整员工记录。建议在拦截器里对响应体做脱敏,只保留 id 与状态用于排错。
另外 Velocity Global 某些节点限速严格,前端应实现请求合并与指数退避。可在 vgHttp 拦截器内维护一个简单计数器,超阈值后延迟发请求,保障账号不被限流。
| 风险点 | 工程化对策 |
|---|---|
| 密钥泄露 | Vite 仅注入代理基址,密钥留服务端 |
| 区域字段差异 | adapter 层 normalize 统一模型 |
| 令牌失效 | 响应拦截器队列重试 |
| 隐私合规 | 日志脱敏,不落本地存储 |
通过上述结构,Vue 3 项目能够以低耦合方式享有 Velocity Global 的全球雇佣与薪酬能力,并把跨国 HR 复杂度控制在可接受范围。
Vue3Velocity_Global全球HR服务修改时间:2026-08-12 01:57:46