feat(mobile): finish employee app page polish

This commit is contained in:
2026-07-11 18:59:30 +08:00
parent ca84e6756c
commit c66fc4e4b0
12 changed files with 1873 additions and 658 deletions
+11 -7
View File
@@ -12,6 +12,7 @@ export interface RequestOptions {
header?: Record<string, string>;
timeout?: number;
auth?: boolean;
clearAuthOnUnauthorized?: boolean;
}
const normalizeUrl = (url: string) => `${apiBase}${url.startsWith('/') ? url : `/${url}`}`;
@@ -27,11 +28,11 @@ export const authHeaders = (json = true, includeAuth = true) => {
};
};
export const readPayload = <T>(statusCode: number, data: unknown): T => {
export const readPayload = <T>(statusCode: number, data: unknown, clearAuthOnUnauthorized = true): T => {
const payload = data as ApiPayload<T>;
const code = typeof payload?.code === 'number' ? payload.code : undefined;
if (statusCode < 200 || statusCode >= 300 || (code !== undefined && code !== 200)) {
if (statusCode === 401 || statusCode === 403 || code === 401 || code === 403) {
if (clearAuthOnUnauthorized && (statusCode === 401 || statusCode === 403 || code === 401 || code === 403)) {
clearAuth();
}
throw new Error(payload?.msg || `HTTP ${statusCode}`);
@@ -40,11 +41,11 @@ export const readPayload = <T>(statusCode: number, data: unknown): T => {
return payload?.data as T;
};
export const parsePayloadText = (statusCode: number, text: string) => {
export const parsePayloadText = (statusCode: number, text: string, clearAuthOnUnauthorized = true) => {
try {
return JSON.parse(text || '{}');
} catch (error) {
if (statusCode === 401 || statusCode === 403) clearAuth();
if (clearAuthOnUnauthorized && (statusCode === 401 || statusCode === 403)) clearAuth();
throw error instanceof SyntaxError
? new Error(statusCode >= 400 ? `HTTP ${statusCode}` : '响应解析失败')
: error;
@@ -67,7 +68,10 @@ const requestWithXhr = async <T>(options: RequestOptions): Promise<T> => {
}).forEach(([key, value]) => xhr.setRequestHeader(key, value));
xhr.onload = () => {
try {
resolve({ status: xhr.status, data: parsePayloadText(xhr.status, xhr.responseText || 'null') });
resolve({
status: xhr.status,
data: parsePayloadText(xhr.status, xhr.responseText || 'null', options.clearAuthOnUnauthorized !== false)
});
} catch {
reject(new Error(xhr.status >= 400 ? `HTTP ${xhr.status}` : '响应解析失败'));
}
@@ -77,7 +81,7 @@ const requestWithXhr = async <T>(options: RequestOptions): Promise<T> => {
xhr.send(hasBody ? JSON.stringify(options.data) : undefined);
});
return readPayload<T>(response.status, response.data);
return readPayload<T>(response.status, response.data, options.clearAuthOnUnauthorized !== false);
};
export const apiRequest = async <T>(options: RequestOptions): Promise<T> => {
@@ -100,7 +104,7 @@ export const apiRequest = async <T>(options: RequestOptions): Promise<T> => {
});
});
return readPayload<T>(response.statusCode, response.data);
return readPayload<T>(response.statusCode, response.data, options.clearAuthOnUnauthorized !== false);
};
export const authenticatedFileUrl = async (url: string): Promise<string> => {
+1 -1
View File
@@ -30,7 +30,7 @@ const positionProfiles: Record<UserPosition, UserPositionProfile> = {
value: '生活顾问',
heroTitle: '客服管家',
quickQuestions: ['催费话术', '投诉应对', '收费标准'],
tip: '今日小贴士:催费沟通先共情,再说明,再给方案。'
tip: '接待客户三步法:听清诉求 → 共情理解 → 解决闭环'
},
保安: {
value: '保安',
+2 -1
View File
@@ -35,7 +35,8 @@ export const hydratePositionFromOrg = async (phone = getAuth().phone): Promise<U
const snapshot = await apiRequest<OrgSnapshotResponse>({
url: `/api/aihr/org/snapshot?keyword=${encodeURIComponent(keyword)}&status=active&pageSize=1`,
method: 'GET',
timeout: 15000
timeout: 15000,
clearAuthOnUnauthorized: false
});
const officialPosition = snapshot.rows?.[0]?.positionName || '';
return saveSelectedPosition(officialPosition);