Files
prop-ai-hr/mobile-uni/src/services/auth.ts
T

134 lines
4.6 KiB
TypeScript

import type { LoginResult } from '@/types/api';
export const tokenKey = 'aihr_mobile_access_token';
export const clientIdKey = 'aihr_mobile_client_id';
export const phoneKey = 'aihr_mobile_phone';
export const loginRedirectKey = 'aihr_mobile_login_redirect';
export const positionKey = 'aihr_mobile_position';
export const phonePattern = /^1[3-9]\d{9}$/;
export const userPositionOptions = ['生活顾问', '保安', '保洁', '保修', '客服'] as const;
export type UserPosition = typeof userPositionOptions[number];
export interface UserPositionProfile {
value: UserPosition;
heroTitle: string;
quickQuestions: string[];
tip: string;
}
export interface AuthState {
token: string;
clientId: string;
phone: string;
position: UserPosition | '';
}
const positionProfiles: Record<UserPosition, UserPositionProfile> = {
生活顾问: {
value: '生活顾问',
heroTitle: '客服管家',
quickQuestions: ['催费话术', '投诉应对', '收费标准'],
tip: '今日小贴士:催费沟通先共情,再说明,再给方案。'
},
保安: {
value: '保安',
heroTitle: '秩序岗',
quickQuestions: ['门岗核验', '巡逻异常', '车辆指引'],
tip: '今日小贴士:异常先确认人车物,再登记,再同步主管。'
},
保洁: {
value: '保洁',
heroTitle: '环境岗',
quickQuestions: ['公区清洁', '垃圾分类', '消杀标准'],
tip: '今日小贴士:高频区域先看地面、扶手、电梯按钮。'
},
保修: {
value: '保修',
heroTitle: '工程维修',
quickQuestions: ['报修接单', '上门话术', '安全检查'],
tip: '今日小贴士:上门前确认故障、工具、预约时间。'
},
客服: {
value: '客服',
heroTitle: '服务前台',
quickQuestions: ['来访接待', '投诉登记', '工单跟进'],
tip: '今日小贴士:复杂诉求先复述确认,再记录责任人与时限。'
}
};
const cleanText = (value: unknown) => String(value || '').trim();
export const normalizePosition = (value: unknown): UserPosition | '' => {
const text = cleanText(value);
if (!text) return '';
if (text.includes('生活顾问') || text.includes('客服管家') || text.includes('物业管家') || text.includes('管家')) {
return '生活顾问';
}
if (text.includes('保安') || text.includes('秩序') || text.includes('安保')) return '保安';
if (text.includes('保洁') || text.includes('环境')) return '保洁';
if (text.includes('保修') || text.includes('维修') || text.includes('工程')) return '保修';
if (text.includes('客服') || text.includes('前台')) return '客服';
return (userPositionOptions as readonly string[]).includes(text) ? (text as UserPosition) : '';
};
export const hasSelectedPosition = () => Boolean(normalizePosition(uni.getStorageSync(positionKey)));
export const getSelectedPosition = (): UserPosition =>
normalizePosition(uni.getStorageSync(positionKey)) || '生活顾问';
export const getPositionProfile = (position: unknown) =>
positionProfiles[normalizePosition(position) || '生活顾问'];
export const getSelectedPositionProfile = () => getPositionProfile(getSelectedPosition());
export const saveSelectedPosition = (position: unknown) => {
const normalized = normalizePosition(position);
if (!normalized) return '';
uni.setStorageSync(positionKey, normalized);
return normalized;
};
export const getAuth = (): AuthState => ({
token: uni.getStorageSync(tokenKey) || '',
clientId: uni.getStorageSync(clientIdKey) || '',
phone: uni.getStorageSync(phoneKey) || '',
position: normalizePosition(uni.getStorageSync(positionKey))
});
export const isLoggedIn = () => {
const auth = getAuth();
return Boolean(auth.token && auth.clientId && auth.phone);
};
export const saveAuth = (result: LoginResult, phone: string) => {
const previousPhone = uni.getStorageSync(phoneKey) || '';
if (previousPhone && previousPhone !== phone) {
uni.removeStorageSync(positionKey);
}
uni.setStorageSync(tokenKey, result.access_token);
uni.setStorageSync(clientIdKey, result.client_id);
uni.setStorageSync(phoneKey, phone);
};
export const clearAuth = () => {
uni.removeStorageSync(tokenKey);
uni.removeStorageSync(clientIdKey);
uni.removeStorageSync(phoneKey);
uni.removeStorageSync(positionKey);
uni.removeStorageSync(loginRedirectKey);
};
export const rememberLoginRedirect = (url: string) => {
uni.setStorageSync(loginRedirectKey, url);
};
export const consumeLoginRedirect = () => {
const url = uni.getStorageSync(loginRedirectKey) || '';
uni.removeStorageSync(loginRedirectKey);
return url;
};
export const validatePhone = (phone: string) => phonePattern.test(phone);