fix(mobile): distinguish auth failure from HR mismatch on position sync page
问题:登录态失效(token 冻结/无效,后端返 401)时,同步岗位页把认证错误 误显示成「人力系统中未匹配到当前手机号的在职岗位,请联系 HR」,员工被 困在该页无路可退。 修复: - api.ts: 新增 ApiError(statusCode/bizCode) 类型化错误与 isAuthApiError, readPayload/parsePayloadText/XHR 路径统一抛出带状态码的错误,消息不变 - position.ts: fetchOrgPositionResult 返回四态判别结果 matched/unmatched/unauthorized/error;hydratePositionFromOrg 行为不变 - position/index.vue: 按四态分支处理—— · unauthorized -> 清除登录态并自动回登录页(保留 redirect) · error -> 提示「网络异常…请重试」,保留重试按钮 · unmatched -> 才显示联系 HR 文案 并新增「退出重新登录」链接(确认弹窗后清登录态回登录页), 避免任何异常场景下用户被困无退出路径 验证(构建产物 + 生产 API,Playwright 五场景全过,截图见 .data/visual-audit-20260718/position-fix/): S1 固定码真实登录->今日页(保洁岗匹配) S2 无效token->自动回登录 S3 断网->网络异常提示留在本页 S4 有效token->自动通过 S5 退出链接->确认->回登录且登录态已清 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { MobileIdentity, RoleKey } from '@/types/api';
|
||||
import { apiRequest } from './api';
|
||||
import { apiRequest, isAuthApiError } from './api';
|
||||
import {
|
||||
clearOrgPosition,
|
||||
getSelectedPosition,
|
||||
@@ -63,7 +63,13 @@ export const goToMobileTarget = (url: string) => {
|
||||
uni.redirectTo({ url });
|
||||
};
|
||||
|
||||
export const hydratePositionFromOrg = async (): Promise<UserPosition | ''> => {
|
||||
export type OrgPositionResult =
|
||||
| { status: 'matched'; position: UserPosition }
|
||||
| { status: 'unmatched' }
|
||||
| { status: 'unauthorized' }
|
||||
| { status: 'error' };
|
||||
|
||||
export const fetchOrgPositionResult = async (): Promise<OrgPositionResult> => {
|
||||
try {
|
||||
const identity = await apiRequest<MobileIdentity>({
|
||||
url: '/api/aihr/mobile/me',
|
||||
@@ -72,13 +78,23 @@ export const hydratePositionFromOrg = async (): Promise<UserPosition | ''> => {
|
||||
clearAuthOnUnauthorized: false
|
||||
});
|
||||
const officialPosition = saveOrgPosition(identity.positionName);
|
||||
if (!officialPosition) clearOrgPosition();
|
||||
return officialPosition;
|
||||
} catch {
|
||||
return hasOrgPosition() ? getSelectedPosition() : '';
|
||||
if (!officialPosition) {
|
||||
clearOrgPosition();
|
||||
return { status: 'unmatched' };
|
||||
}
|
||||
return { status: 'matched', position: officialPosition };
|
||||
} catch (error) {
|
||||
return { status: isAuthApiError(error) ? 'unauthorized' : 'error' };
|
||||
}
|
||||
};
|
||||
|
||||
export const hydratePositionFromOrg = async (): Promise<UserPosition | ''> => {
|
||||
const result = await fetchOrgPositionResult();
|
||||
if (result.status === 'matched') return result.position;
|
||||
if (result.status === 'unmatched') return '';
|
||||
return hasOrgPosition() ? getSelectedPosition() : '';
|
||||
};
|
||||
|
||||
export const nextUserRouteAfterLogin = async (redirect: string) => {
|
||||
const role = await hydrateMobileRole();
|
||||
const roleRoute = routeForMobileRole(role, redirect);
|
||||
|
||||
Reference in New Issue
Block a user