feat: Iteration 1 — 审计日志IP记录、文件上传、医护端API、小程序角色切换
Iteration 1 六项任务全部完成: 1. 审计日志IP记录 — task_local RequestInfo 自动注入 IP/user_agent 2. 文件上传服务 — multipart 上传 + ServeDir 静态文件服务 3. 医护端后端API — 医生工作台仪表盘 + 患者标签CRUD + 会话已读 4. 小程序角色切换 — 登录后根据角色跳转医护台/患者首页 5. 小程序安全加固 — secure-storage 开发模式警告 6. 讨论记录归档 — docs/discussions/
This commit is contained in:
71
apps/miniprogram/src/pages/doctor/index.scss
Normal file
71
apps/miniprogram/src/pages/doctor/index.scss
Normal file
@@ -0,0 +1,71 @@
|
||||
.doctor-home {
|
||||
min-height: 100vh;
|
||||
background: #f0f4f8;
|
||||
padding: 32px;
|
||||
|
||||
&__header {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
&__greeting {
|
||||
font-size: 28px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
&__section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
&__section-title {
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
color: #334155;
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
&__card {
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
&__card-num {
|
||||
font-size: 48px;
|
||||
font-weight: 700;
|
||||
color: #0891b2;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&__card-label {
|
||||
font-size: 24px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
margin-top: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__logout {
|
||||
color: #ef4444;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
48
apps/miniprogram/src/pages/doctor/index.tsx
Normal file
48
apps/miniprogram/src/pages/doctor/index.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import Taro from '@tarojs/taro';
|
||||
import './index.scss';
|
||||
|
||||
export default function DoctorHome() {
|
||||
const { user, logout } = useAuthStore();
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
Taro.redirectTo({ url: '/pages/login/index' });
|
||||
};
|
||||
|
||||
return (
|
||||
<View className='doctor-home'>
|
||||
<View className='doctor-home__header'>
|
||||
<Text className='doctor-home__title'>医护工作台</Text>
|
||||
<Text className='doctor-home__greeting'>{user?.display_name || user?.username || '医生'},您好</Text>
|
||||
</View>
|
||||
|
||||
<View className='doctor-home__section'>
|
||||
<Text className='doctor-home__section-title'>工作概览</Text>
|
||||
<View className='doctor-home__grid'>
|
||||
<View className='doctor-home__card' onClick={() => Taro.showToast({ title: '开发中', icon: 'none' })}>
|
||||
<Text className='doctor-home__card-num'>-</Text>
|
||||
<Text className='doctor-home__card-label'>待回复咨询</Text>
|
||||
</View>
|
||||
<View className='doctor-home__card' onClick={() => Taro.showToast({ title: '开发中', icon: 'none' })}>
|
||||
<Text className='doctor-home__card-num'>-</Text>
|
||||
<Text className='doctor-home__card-label'>待处理随访</Text>
|
||||
</View>
|
||||
<View className='doctor-home__card' onClick={() => Taro.showToast({ title: '开发中', icon: 'none' })}>
|
||||
<Text className='doctor-home__card-num'>-</Text>
|
||||
<Text className='doctor-home__card-label'>今日咨询</Text>
|
||||
</View>
|
||||
<View className='doctor-home__card' onClick={() => Taro.showToast({ title: '开发中', icon: 'none' })}>
|
||||
<Text className='doctor-home__card-num'>-</Text>
|
||||
<Text className='doctor-home__card-label'>我的患者</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className='doctor-home__footer'>
|
||||
<Text className='doctor-home__logout' onClick={handleLogout}>退出登录</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,17 @@ export default function Login() {
|
||||
const [agreed, setAgreed] = useState(false);
|
||||
const { login, bindPhone, loading } = useAuthStore();
|
||||
|
||||
const { login, bindPhone, loading, isMedicalStaff } = useAuthStore();
|
||||
|
||||
/** 登录/绑定成功后根据角色跳转 */
|
||||
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' });
|
||||
@@ -18,7 +29,7 @@ export default function Login() {
|
||||
const { code } = await Taro.login();
|
||||
const result = await login(code);
|
||||
if (result) {
|
||||
Taro.switchTab({ url: '/pages/index/index' });
|
||||
navigateAfterLogin();
|
||||
} else {
|
||||
setNeedBind(true);
|
||||
Taro.showToast({ title: '请授权手机号完成绑定', icon: 'none' });
|
||||
@@ -41,7 +52,7 @@ export default function Login() {
|
||||
const { encryptedData, iv } = e.detail;
|
||||
const success = await bindPhone(encryptedData, iv);
|
||||
if (success) {
|
||||
Taro.switchTab({ url: '/pages/index/index' });
|
||||
navigateAfterLogin();
|
||||
} else {
|
||||
Taro.showToast({ title: '绑定失败,请重试', icon: 'none' });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user