You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
6.7 KiB
173 lines
6.7 KiB
import { Alert, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
|
|
import { colors } from '../../../src/theme';
|
|
import { CARRIER_LABEL } from '../../../src/constants';
|
|
import { useAgreementGate, useCarrierPhone, useLogin, useOnboarding } from '../../../src/hooks';
|
|
import { useAuth } from '../../../src/context/AuthContext';
|
|
import { ScreenShell } from '../ui/ScreenShell';
|
|
import { Illustration } from '../ui/Illustration';
|
|
import { AgreementCheckbox } from '../ui/AgreementCheckbox';
|
|
import { PrimaryButton } from '../ui/PrimaryButton';
|
|
import { SupportFooter } from '../ui/SupportFooter';
|
|
import { AgreementModal } from '../ui/AgreementModal';
|
|
|
|
/**
|
|
* P2Q 一键登录确认:本机号码认证。
|
|
*
|
|
* 取号(运营商 SDK)与换登录态是两步,本页负责串起来:
|
|
* 1. 进入页面即取号(useCarrierPhone)→ 展示掩码号码;
|
|
* 2. 点「一键登录」→ 用取号令牌换正式登录态 → 写登录态 → 把号码写回引导资料 → 进 P3。
|
|
*
|
|
* 原先这里读的是 `data.phone`(只有短信登录才会写),运营商通道的号码既没取也没存,
|
|
* 所以永远显示占位「本机号码」;登录接口返回的 phone 也被直接丢掉。
|
|
* 现在取号失败时不再假装号码还在:「一键登录」置灰,同时给出「重新获取」与「改用验证码登录」。
|
|
*/
|
|
export function P2QuickLogin() {
|
|
const { data, setData, navigate, back } = useOnboarding();
|
|
const { gate, modalProps } = useAgreementGate();
|
|
const { carrierToken, maskedPhone, carrier, ready, loading: fetching, error: fetchError, refresh } =
|
|
useCarrierPhone();
|
|
const { loginByCarrier, loading: logging, error: loginError } = useLogin();
|
|
/** 登录态写入:此前本页只跳 P3 不写 token */
|
|
const { login: writeAuth } = useAuth();
|
|
|
|
const agreed = data.agreed;
|
|
const carrierName = CARRIER_LABEL[carrier];
|
|
/** 取号失败:号码与令牌都没有,本页只能提供重试或改走验证码登录 */
|
|
const failed = !fetching && !ready;
|
|
const busy = fetching || logging;
|
|
|
|
/** 一键登录:用取号令牌换登录态,成功后才进 P3 */
|
|
const handleLogin = async () => {
|
|
try {
|
|
const result = await loginByCarrier(carrierToken);
|
|
writeAuth(result.token);
|
|
// 号码写回引导资料:后续步骤(P2P/P2R 预填、B3 联系人电话)都以这里为准
|
|
setData({ phone: result.phone });
|
|
} catch {
|
|
// 失败原因由 useLogin 记录,页面下方展示
|
|
return;
|
|
}
|
|
navigate('P3');
|
|
};
|
|
|
|
/** 运营商认证服务条款由运营商在认证页内提供,本仓库没有该文档,不冒充能打开它 */
|
|
const showCarrierTerms = () => {
|
|
Alert.alert(
|
|
`${carrierName}认证服务条款`,
|
|
`一键登录的认证服务由${carrierName}提供,服务条款以认证页展示的内容为准。`,
|
|
);
|
|
};
|
|
|
|
return (
|
|
<ScreenShell showBack onBack={back}>
|
|
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.content}>
|
|
<View style={styles.brandArea}>
|
|
<Illustration name="logo" size={88} radius={22} />
|
|
</View>
|
|
|
|
{ready ? (
|
|
<Text style={styles.phone}>{maskedPhone}</Text>
|
|
) : (
|
|
<Text style={[styles.phonePending, failed && styles.phoneFailed]}>
|
|
{failed ? '未能获取本机号码' : '正在获取本机号码…'}
|
|
</Text>
|
|
)}
|
|
<Text style={styles.subtitle}>
|
|
{failed ? '可重新获取,或改用验证码登录' : '首次验证通过即注册有职账号'}
|
|
</Text>
|
|
|
|
<View style={styles.btnArea}>
|
|
<PrimaryButton
|
|
label="一键登录"
|
|
active={ready && !busy}
|
|
loading={logging}
|
|
onPress={() => gate(handleLogin)}
|
|
/>
|
|
|
|
{failed ? (
|
|
<View style={styles.fallbackRow}>
|
|
<Pressable style={styles.fallbackBtn} onPress={refresh} hitSlop={6}>
|
|
<Text style={styles.fallbackText}>重新获取</Text>
|
|
</Pressable>
|
|
<Pressable
|
|
style={styles.fallbackBtn}
|
|
onPress={() => gate(() => navigate('P2'))}
|
|
hitSlop={6}
|
|
>
|
|
<Text style={styles.fallbackText}>改用验证码登录</Text>
|
|
</Pressable>
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
|
|
{loginError ? <Text style={styles.formError}>{loginError.message}</Text> : null}
|
|
{fetchError && !loginError ? (
|
|
<Text style={styles.formError}>{fetchError.message}</Text>
|
|
) : null}
|
|
|
|
<View style={styles.agree}>
|
|
<AgreementCheckbox
|
|
checked={agreed}
|
|
onToggle={() => setData({ agreed: !agreed })}
|
|
text={
|
|
<Text style={styles.agreeText}>
|
|
已阅读并同意
|
|
<Text style={styles.link} onPress={showCarrierTerms}>
|
|
《{carrierName}认证服务条款》
|
|
</Text>
|
|
、
|
|
<Text style={styles.link} onPress={() => navigate('B2')}>《有职用户协议》</Text>
|
|
和
|
|
<Text style={styles.link} onPress={() => navigate('B2')}>《隐私政策》</Text>
|
|
,允许有职统一管理本人账号信息
|
|
</Text>
|
|
}
|
|
/>
|
|
</View>
|
|
</ScrollView>
|
|
|
|
<View style={styles.footer}>
|
|
<SupportFooter />
|
|
<Text style={styles.carrierNote}>认证服务由{carrierName}提供</Text>
|
|
</View>
|
|
|
|
<AgreementModal {...modalProps} />
|
|
</ScreenShell>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
content: { flexGrow: 1 },
|
|
brandArea: { alignItems: 'center', marginTop: '16%' },
|
|
phone: {
|
|
textAlign: 'center',
|
|
fontSize: 30,
|
|
fontWeight: '800',
|
|
color: colors.textPrimary,
|
|
marginTop: 40,
|
|
},
|
|
phonePending: {
|
|
textAlign: 'center',
|
|
fontSize: 22,
|
|
fontWeight: '700',
|
|
color: colors.textHint,
|
|
marginTop: 44,
|
|
},
|
|
phoneFailed: { fontSize: 18, color: colors.dangerText },
|
|
subtitle: { textAlign: 'center', fontSize: 14, color: colors.textSecondary, marginTop: 12 },
|
|
btnArea: { marginTop: 36 },
|
|
fallbackRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'center',
|
|
gap: 24,
|
|
marginTop: 18,
|
|
},
|
|
fallbackBtn: { paddingVertical: 6, paddingHorizontal: 4 },
|
|
fallbackText: { fontSize: 14, fontWeight: '600', color: colors.primaryText },
|
|
formError: { marginTop: 10, textAlign: 'center', fontSize: 12, color: colors.danger },
|
|
agree: { marginTop: 20 },
|
|
agreeText: { fontSize: 12, color: colors.textSecondary, lineHeight: 18 },
|
|
link: { color: colors.primary, fontWeight: '600' },
|
|
footer: { paddingTop: 16, paddingBottom: 8 },
|
|
carrierNote: { textAlign: 'center', fontSize: 12, color: colors.textHint, marginTop: 12 },
|
|
});
|
|
|