# 后端联调 · 前端实现说明 > 适用范围:`有职`(youzhi)App 前端对接《职来后端接口联调说明》(`job.youthome.com.cn` 规范) > 关联文件:`src/api/http.ts`、`src/api/auth.ts`、`src/lib/token-store.ts`、`src/context/AuthContext.tsx`、`src/types/user.ts` > 本文只记录**前端已落地的地基与契约映射**,完整接口字段以运行时 OpenAPI 为唯一依据(规范 §7)。 ## 一、本次已落地(地基,不涉及业务端点) | 层 | 文件 | 内容 | |---|---|---| | 请求层 | `src/api/http.ts` | 统一出口:`Base URL` + `Bearer` 注入 + 信封解析 + **401 单飞刷新** + `X-Request-Id` + 状态码语义 | | 令牌 | `src/lib/token-store.ts` | `accessToken` + `refreshToken` 内存单例 + AsyncStorage 持久化 | | 鉴权 | `src/api/auth.ts` | `sendSmsCode` / `loginByPassword` / `loginBySms` / `fetchCurrentUser` / `requestLogout` / `registerCompany` | | 会话 | `src/context/AuthContext.tsx` | `setSession(access,refresh,expiresAt)`;启动时 `hydrateTokens`;注册 401 清会话回调 | | 角色 | `src/types/user.ts` + `auth.ts` | `AppRole` 扩 `admin`;`mapBackendRole(STUDENT→candidate / COMPANY→enterprise / ADMIN→admin)` | | 环境 | `app.config.js` | 默认 `apiBaseUrl = https://job.youthome.com.cn/api/v1`(保留 `API_BASE_URL` 环境变量覆盖) | | mock 开关 | `app.config.js` + `http.ts` | `extra.apiUseMock`(默认 `true`);`isMockMode()` 决定业务函数走 mock 还是真实请求;联调期置 `false` | 业务端点按 **mock 开关** 分阶段落地:开发期(`apiUseMock=true`)返回本地数据不触网,联调期(`false`)直连后端。`jobs` / `profile` / `messages` 等 100+ mock 函数**逐个替换**为真实 `request()` 调用,页面与 hook 零改动。 ## 二、规范条款逐条对照 | 规范 | 前端现状 | |---|---| | §1 基地址 / 健康检查 / OpenAPI | 基地址已接 `API_BASE_URL`;`checkHealth()` 已实现对 `/health`(UP 判定);OpenAPI 为后端准绳,前端不手抄 | | §3 信封 `code/message/data/requestId/timestamp` | `request()` 解析 envelope;`code!==200` 抛 `ApiError`;后端 `message` 优先(更具体),无 message 时回退状态码文案 | | §3 `Authorization: Bearer` | 自动注入;匿名接口(登录/短信/刷新)显式 `auth:false` 不带头 | | §4 双 Token + `/auth/refresh` | `token-store` 持久化 `access+refresh`;401 触发刷新 | | §4 一次串行刷新 + 重放 | 模块级 `refreshPromise` 单飞闸门:并发 401 只刷一次,成功后重放原请求 | | §4 刷新失败清会话 | 清 Token + `unauthorizedHandler`(AuthContext 注册为清登录态) | | §4 Token 不打印/上报/进 URL | 令牌仅在 `http.ts` 内层使用,错误对象不回吐原始 Token | | §5 角色以后端 `/auth/me` 为准 | `fetchCurrentUser()` 返回映射后角色;密码登录页(`P2PasswordLogin`)登录后调 `/auth/me` 并 `setRole`,与本地选择不一致时纠正路由 | | §6 企业注册 | `registerCompany()` 已实现对 `/auth/company/register`;客户端不提交 `userId/role/verified/passwordHash` | | §8 状态码语义 | `pickHttpMessage` 覆盖 400/401/403/404/409/429/500/503;网络异常降级为 `httpStatus=0` | | §10 安全 | 不写 Token/验证码/密码到日志或前端 DOM;`X-Request-Id` 用于联调报障 | ## 三、业务端点转换进度(mock 开关 + 岗位域) > 转换规则:保留函数签名与返回类型 `T`(即 AGENTS.md「保留签名、只换函数体」),`if (isMockMode())` 分支保留本地数据,真实分支走 `request(path, { auth, query })`。路径按规范 §7 重映射(旧 `@url` 多带 `/api` 前缀、未带 `/v1`,已校正)。 ### 3.1 已完成(岗位域 · 候选侧读取) | 函数 | mock 分支 | 真实路径(§7) | 鉴权 | 说明 | |---|---|---|---|---| | `fetchJobList` | 本地筛选/排序/分页 | `GET /jobs` | 否 | query 映射:`pageSize→size`;数组多选逗号拼接;`keyword/industry/city/education` 等空值跳过 | | `fetchJobDetail` | 本地详情 | `GET /jobs/{id}` | 否 | 公开岗位详情 | | `fetchJobOverallScore` | 本地八维缩放 | `GET /jobs/{id}/score` | 否 | 综合评分;响应结构以 OpenAPI 为准 | | `fetchJobPreference` | `resolveJobPreference()` 派生 | `GET /profile/me/job-preference` | 是 | 求职者偏好(§5 STUDENT 前缀) | | `fetchFavorites` | 本地收藏子集 | `GET /profile/me/favorites` | 是 | 当前用户收藏 | | `fetchJobProgress` | 本地进度 | `GET /tools/job-progress` | 否 | 求职进度工具数据 | > 鉴权列「是」= 默认带 Bearer;「否」= `auth:false` 匿名读取(§7 公开岗位)。 ### 3.2 待转(下一阶段,按业务域分批) - **岗位详情子资源**:`fetchSalaryData` / `fetchEmployeeReviews` / `createJobReview` / `fetchCompareData`(仍处于 `/api/jobs/:id/...` 旧路径,需校正)。 - **企业端岗位**:`fetchJobManagement` / `fetchJobPublishForm` / `fetchJobEvaluationManagement` / `fetchJobEvaluationEmptyState`(§7 未列,需 OpenAPI 确认前缀)。 - **简历 / 资料**:`fetchResume` / `fetchUserProfile` / `fetchProfileXxx`(STUDENT 前缀)。 - **消息 / 沟通**:`fetchConversations` / `fetchNotifications` / `fetchMessages`(§7 未列)。 - **其余公开读取**:`fetchJobFilters` / `fetchJobSearch` 等若后端拆成独立端点,需补映射。 ## 四、明确未做(下一阶段) - **WebSocket**:`wss://job.youthome.com.cn/api/v1/ws` 未接入(无对应实时功能)。 - **企业入驻状态机**:`/companies/me/onboarding` 的 `missingFields` / `allowedActions` 驱动 UI 尚未接。 - **其余入口页角色纠正**:仅密码登录页已接 `/auth/me`;微信登录、验证码登录等入口需在登录后补齐角色权威化。 ## 五、命名待确认(非阻塞) - 域名 `youthome.com.cn`(青年家)与 App 品牌「有职 / youzhi」不一致;Storage 前缀仍为历史遗留 `qingsongpin:`,**勿擅自改名**(会导致老用户本地态失效)。