- 新增迁移 m20260510_000133:为所有租户创建 patient 角色并分配 19 个权限 - wechat_service: bind_phone 自动 assign_patient_role + ensure_patient_record - find_or_create_user_by_phone 新用户自动获得 patient 角色和患者档案 - 小程序 auth store: bindPhone 抛出异常而非静默返回 false - 小程序登录页: 捕获绑定错误并显示可操作的对话框
134 lines
4.3 KiB
TypeScript
134 lines
4.3 KiB
TypeScript
import { useState } from 'react';
|
||
import { View, Text, Button, ScrollView } from '@tarojs/components';
|
||
import Taro from '@tarojs/taro';
|
||
import { useAuthStore } from '../../stores/auth';
|
||
import { useElderClass } from '../../hooks/useElderClass';
|
||
import './index.scss';
|
||
|
||
export default function Login() {
|
||
const modeClass = useElderClass();
|
||
const [needBind, setNeedBind] = useState(false);
|
||
const [agreed, setAgreed] = useState(false);
|
||
const { login, bindPhone, loading, isMedicalStaff } = useAuthStore();
|
||
|
||
// 登录页不应用关怀模式(正常模式尺寸已足够大)
|
||
const loginClass = '';
|
||
|
||
const navigateAfterLogin = () => {
|
||
if (isMedicalStaff()) {
|
||
Taro.redirectTo({ url: '/pages/doctor/index' });
|
||
} else {
|
||
Taro.switchTab({ url: '/pages/index/index' });
|
||
}
|
||
};
|
||
|
||
const handleWechatLogin = async () => {
|
||
if (!agreed) {
|
||
Taro.showToast({ title: '请先阅读并同意用户协议', icon: 'none' });
|
||
return;
|
||
}
|
||
try {
|
||
const { code } = await Taro.login();
|
||
const result = await login(code);
|
||
if (result) {
|
||
navigateAfterLogin();
|
||
} else {
|
||
setNeedBind(true);
|
||
Taro.showToast({ title: '请授权手机号完成绑定', icon: 'none' });
|
||
}
|
||
} catch (err: any) {
|
||
const msg = err?.message || '登录失败,请重试';
|
||
Taro.showToast({ title: msg.substring(0, 20), icon: 'none', duration: 3000 });
|
||
}
|
||
};
|
||
|
||
const handleGetPhone = async (e: { detail: { errMsg: string; encryptedData: string; iv: string } }) => {
|
||
if (!agreed) {
|
||
Taro.showToast({ title: '请先阅读并同意用户协议', icon: 'none' });
|
||
return;
|
||
}
|
||
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
|
||
Taro.showToast({ title: '需要授权手机号', icon: 'none' });
|
||
return;
|
||
}
|
||
const { encryptedData, iv } = e.detail;
|
||
try {
|
||
const success = await bindPhone(encryptedData, iv);
|
||
if (success) {
|
||
navigateAfterLogin();
|
||
}
|
||
} catch (err: any) {
|
||
const msg = err?.message || '绑定失败';
|
||
Taro.showModal({
|
||
title: '绑定手机号失败',
|
||
content: msg,
|
||
confirmText: '重新登录',
|
||
cancelText: '取消',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
setNeedBind(false);
|
||
}
|
||
},
|
||
});
|
||
}
|
||
};
|
||
|
||
return (
|
||
<ScrollView scrollY className={`login-scroll ${loginClass}`}>
|
||
<View className='login-page'>
|
||
{/* 品牌区 */}
|
||
<View className='login-brand'>
|
||
<View className='login-logo'>
|
||
<Text className='login-logo-mark'>+</Text>
|
||
</View>
|
||
<Text className='login-title'>健康管理</Text>
|
||
<Text className='login-subtitle'>您的专属健康管家</Text>
|
||
</View>
|
||
|
||
{/* 装饰线 */}
|
||
<View className='login-divider'>
|
||
<View className='login-divider-line' />
|
||
</View>
|
||
|
||
{/* 登录按钮 */}
|
||
<View className='login-body'>
|
||
{!needBind ? (
|
||
<Button className='login-btn' onClick={handleWechatLogin} loading={loading}>
|
||
微信一键登录
|
||
</Button>
|
||
) : (
|
||
<Button
|
||
className='login-btn'
|
||
openType='getPhoneNumber'
|
||
onGetPhoneNumber={handleGetPhone}
|
||
loading={loading}
|
||
>
|
||
授权手机号完成绑定
|
||
</Button>
|
||
)}
|
||
</View>
|
||
|
||
{/* 协议 */}
|
||
<View className='agreement-row'>
|
||
<View className={`agreement-check ${agreed ? 'checked' : ''}`} onClick={() => setAgreed(!agreed)}>
|
||
{agreed && <Text className='agreement-check-mark'>✓</Text>}
|
||
</View>
|
||
<Text className='agreement-text'>
|
||
我已阅读并同意
|
||
<Text className='agreement-link' onClick={() => Taro.navigateTo({ url: '/pages/legal/user-agreement' })}>《用户服务协议》</Text>
|
||
和
|
||
<Text className='agreement-link' onClick={() => Taro.navigateTo({ url: '/pages/legal/privacy-policy' })}>《隐私政策》</Text>
|
||
</Text>
|
||
</View>
|
||
|
||
{/* 暂不登录 */}
|
||
<View className='skip-row'>
|
||
<Text className='skip-btn' onClick={() => Taro.reLaunch({ url: '/pages/index/index' })}>
|
||
暂不登录,先看看
|
||
</Text>
|
||
</View>
|
||
</View>
|
||
</ScrollView>
|
||
);
|
||
}
|